A web component for pre-fetching the code for additional components used later in the app.
By default the browser fetches the component code as-needed when a component is added to the DOM.
In certain cases this be problematic when network latency is bad or disconnected. An example is when pages are separate components the code must be downloaded prior to the page rendering, this may result in a noticeable lag between when a user clicks on a nav element and when the page actually transitions.
A number of other cases where this is an issue are discussed here along with a proposed prefetchComponent() api: ionic-team/stencil#1558
Hopefully one day that api will come to fruition. Until then we have this component.
See the demo: https://beck24.github.io/stencil-component-prefetch/
See the component properties/methods: https://github.com/beck24/stencil-component-prefetch/blob/master/src/components/stencil-component-prefetch/readme.md
Install the module
npm install @beck24/stencil-component-prefetch
In your app-root
component:
Add the pre-fetch component to your rendered markup
<stencil-component-prefetch />
Import Build
and Element
from stencil core
import { Component, h, Build, Element } from '@stencil/core';
Make an element reference variable
export class AppRoot {
@Element() el: HTMLElement;
Use the componentDidLoad
lifecycle hook to fetch a reference to the prefetcher and pre-fetch your components
componentDidLoad() {
const componentsConfig = [
{
tag: 'my-custom-toast'
},
{
tag: 'app-menu',
},
{
tag: 'page-search',
props: {
prefetching: true,
}
},
{
tag: 'my-other-heavy-component',
props: {
enabled: true,
name: 'some-name'
}
}
];
if (Build.isBrowser) {
// only pre-fetch if it's a real browser
const prefetch = this.el.querySelector('stencil-component-prefetch');
prefetch.setComponents(componentsConfig);
}
}
By default the components are pre-fetched after a delay of 1500ms to ensure it isn't interfering with more immediate loading/rendering tasks.
This behavior can be changed with the setDelay
method if desired
// set a delay of 0 - fetch immediately
prefetch.setDelay(0).then(() => {
prefetch.setComponents(componentsConfig);
});
The component forces pre-fetching by sequentially adding registered components to the DOM in a hidden div and immediately removing them.
The addition of the component triggers the browser to fetch the code if it hasn't already. The immediate removal keeps the DOM clean of unwanted/duplicate components.
This seems to work well, with a few things to watch out for.
You should not pre-fetch components that:
- automatically change the route
- automatically manipulate DOM elements outside of themselves
- automatically change/affect state
- automatically make API calls that may be unwanted/unnecessary immediately
There are ways to work around these limitations if they are your own stencil components.
If you have a component you want to prefetch, but it modifies state you can add a new prop to the component
@Prop() prefetching: boolean = false;
Prevent the component actually rendering if prefetching
render() {
if (this.prefetching) {
return null;
}
return (
<div>My rendered component</div>
)
}
Early-return on lifecycle hooks that perform actions unwanted during pre-fetching
componentWillLoad() {
if (this.prefetching) {
return;
}
// all state stuff ignored during pre-fetch
this.store.mapStateToProps(this, state => {
});
}
componentDidLoad() {
if (this.prefetching) {
return;
}
// state-modifying stuff
}
When prefetching this component just set the prop prefetching
to true in the app-root
componentDidLoad() {
const componentsConfig = [
{
tag: 'my-state-changing-component',
props: {
prefetching: true,
}
}
];
if (Build.isBrowser) {
const prefetch = this.el.querySelector('stencil-component-prefetch');
prefetch.setComponents(componentsConfig);
}
}