MaastrichtU-BISS / lawnotation

Legal text annotation platform for researchers, legal practioners and more!
https://app.lawnotation.org
Apache License 2.0
5 stars 0 forks source link

Render Breadcrumb-component serverside to prevent unexpected layout shift #43

Open eensander opened 5 months ago

eensander commented 5 months ago

Are there different words to describe cumulative-layout shift or more generally elements that are not instantly loaded and hence cause a "jumping" effect in the web view?

Current state

The breadcrumb contains the hierarchy of pages that lead to the current page. Currently, the <Breadcrumb> component is defined in the Page components (pages/<Page>.vue), since the state of the breadcrumb items sometimes depends on variables that are defined inside of these pages. The Breadcrumb component is usually defined at the top of the Page component. The exact location doesn't matter, since it the resulting element is teleported to its designated container in the related layout using Nuxts' <Teleport>-tag.

The problem

As per the Teleport documentation:

The to target of expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to "body" only, with client-side support for other targets using a wrapper.

Because we too have to wrap the Teleport component in the ClientOnly component, the Breadcrumb component is only rendered when the client is ready. Therefore, "jumping" effect occurs as the breadcrumb appears (commonly know as an unexpected layout shift).

Another considered solution is simply placing the Breadcrumb component in the correct location in the layout and communicating the breadcrumb state via a store or composable. The problem with this approach is that the page component is generally loaded after the breadcrumb component is loaded. Hence, it is not guaranteed that the breadcrumb state is available at the moment the breadcrumb is rendered.

Solution

Block loading Breadcrumb component until the Page is loaded

The solve the last issue in the problem definition, the following comment outlines a method to wait until the Page component is loaded before loading the Breadcrumb component, or any other component that is dependent on the script of the Page to be loaded:

The author of this comment has also crafted a npm package for this exact problem:

Although this approach appears very promising, there is one drawback: it requires that pages that provide data on which other components depend using this newly introduced component execute a method at the bottom of its script: renderPageDependencies(). Though this is not a big problem, and the package provides a convenient way to determine if there are pages that do not call this method, it is still a liability to have to call this on every page. Nevertheless, a start using this solution was started on the branch lawnotation/fix-lazy-objects

Another consideration to make with this proposed solution, is that it should be somehow caught that when navigating to other the breadcrumb state should first be cleared, in order to prevent the breadcrumb to persist when navigating to a page which doesn't have a breadcrumb defined for it (such as the homepage). Alternatively, it could be enforced that all pages that rely on a layout that use the breadcrumb provide a setter for the breadcrumb state.

EDIT: It is also worth noting that when I was just testing, it seems like the NuxtPageDependency plugin might not be required for the state solution to work. Although, further investigation is needed to get consistent results.