// A component whose code is fetched the first time it is shown. // // Every static `import` reachable from app.js is downloaded before anything // renders, whether or not the visitor ever opens it: the Videos app, the video // player and the search page used to cost a member who only chats. Wrapping a // component here moves its module out of that first download and into the // moment it is needed; once loaded it is the component itself, rendered with // the same props, and every later mount is immediate. // // A failed fetch (a network drop on a phone) is not remembered: the next time // the component is shown it asks again, rather than failing for the session. import { html, useState, useEffect } from './vendor/htm-preact.js'; const SPINNER = html`
`; function lazy(load, name, placeholder = SPINNER) { let Loaded = null; let pending = null; function Lazy(props) { const [, setReady] = useState(Loaded !== null); useEffect(() => { if (Loaded) return undefined; let alive = true; if (!pending) { pending = load().then( (m) => { Loaded = m[name]; }, (e) => { pending = null; throw e; }); } pending.then(() => { if (alive) setReady(true); }, () => {}); return () => { alive = false; }; }, []); if (!Loaded) return placeholder; return html`<${Loaded} ...${props} />`; } Lazy.displayName = `Lazy(${name})`; return Lazy; } export { lazy };