diff --git a/packages/docs/src/routes/api/qwik/api.json b/packages/docs/src/routes/api/qwik/api.json index b5ec34ceb86..024488bd267 100644 --- a/packages/docs/src/routes/api/qwik/api.json +++ b/packages/docs/src/routes/api/qwik/api.json @@ -1688,6 +1688,20 @@ "editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/render/jsx/types/jsx-generated.ts", "mdFile": "qwik.paramhtmlattributes.md" }, + { + "name": "PrefetchGraph", + "id": "prefetchgraph", + "hierarchy": [ + { + "name": "PrefetchGraph", + "id": "prefetchgraph" + } + ], + "kind": "Variable", + "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nLoad the prefetch graph for the container.\n\nEach Qwik container needs to include its own prefetch graph.\n\n\n```typescript\nPrefetchGraph: (opts?: {\n base?: string;\n manifestHash?: string;\n manifestURL?: string;\n}) => import(\"@builder.io/qwik/jsx-runtime\").JSXNode<\"script\">\n```", + "editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts", + "mdFile": "qwik.prefetchgraph.md" + }, { "name": "PrefetchServiceWorker", "id": "prefetchserviceworker", @@ -1698,7 +1712,7 @@ } ], "kind": "Variable", - "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\n\n```typescript\nPrefetchServiceWorker: (opts: {\n base?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n}) => import(\"@builder.io/qwik/jsx-runtime\").JSXNode<\"script\">\n```", + "content": "> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.\n> \n\nInstall a service worker which will prefetch the bundles.\n\nThere can only be one service worker per page. Because there can be many separate Qwik Containers on the page each container needs to load its prefetch graph using `PrefetchGraph` component.\n\n\n```typescript\nPrefetchServiceWorker: (opts: {\n base?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n}) => import(\"@builder.io/qwik/jsx-runtime\").JSXNode<\"script\">\n```", "editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts", "mdFile": "qwik.prefetchserviceworker.md" }, diff --git a/packages/docs/src/routes/api/qwik/index.md b/packages/docs/src/routes/api/qwik/index.md index 82ecc257a44..d5d10e6de13 100644 --- a/packages/docs/src/routes/api/qwik/index.md +++ b/packages/docs/src/routes/api/qwik/index.md @@ -1664,10 +1664,32 @@ export interface ParamHTMLAttributes extends Attrs<'base', T, [Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/render/jsx/types/jsx-generated.ts) +## PrefetchGraph + +> This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. + +Load the prefetch graph for the container. + +Each Qwik container needs to include its own prefetch graph. + +```typescript +PrefetchGraph: (opts?: { + base?: string; + manifestHash?: string; + manifestURL?: string; +}) => import("@builder.io/qwik/jsx-runtime").JSXNode<"script">; +``` + +[Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts) + ## PrefetchServiceWorker > This API is provided as an alpha preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. +Install a service worker which will prefetch the bundles. + +There can only be one service worker per page. Because there can be many separate Qwik Containers on the page each container needs to load its prefetch graph using `PrefetchGraph` component. + ```typescript PrefetchServiceWorker: (opts: { base?: string; diff --git a/packages/qwik/src/core/api.md b/packages/qwik/src/core/api.md index 3bbd1138eb3..f1d11592bf7 100644 --- a/packages/qwik/src/core/api.md +++ b/packages/qwik/src/core/api.md @@ -582,7 +582,14 @@ export interface ParamHTMLAttributes extends Attrs<'base', T, // @internal export const _pauseFromContexts: (allContexts: QContext[], containerState: ContainerState, fallbackGetObjId?: GetObjID, textNodes?: Map) => Promise; -// @alpha (undocumented) +// @alpha +export const PrefetchGraph: (opts?: { + base?: string; + manifestHash?: string; + manifestURL?: string; +}) => JSXNode_2<"script">; + +// @alpha export const PrefetchServiceWorker: (opts: { base?: string; path?: string; diff --git a/packages/qwik/src/core/components/prefetch.ts b/packages/qwik/src/core/components/prefetch.ts index aa4ddd8118c..2eebda0bec4 100644 --- a/packages/qwik/src/core/components/prefetch.ts +++ b/packages/qwik/src/core/components/prefetch.ts @@ -1,12 +1,17 @@ +import { isDev } from '@builder.io/qwik/build'; import { _jsxC } from '../internal'; /** + * Install a service worker which will prefetch the bundles. + * + * There can only be one service worker per page. Because there can be many separate Qwik Containers + * on the page each container needs to load its prefetch graph using `PrefetchGraph` component. + * * @param opts - Options for the prefetch service worker. * - * - `base` Base URL for the service worker. - * - `path` Path to the service worker. + * - `base` - Base URL for the service worker. + * - `path` - Path to the service worker. * - * @returns * @alpha */ export const PrefetchServiceWorker = (opts: { @@ -18,15 +23,14 @@ export const PrefetchServiceWorker = (opts: { const resolvedOpts = { base: '/', verbose: false, - fetchBundleGraph: true, path: 'qwik-prefetch-service-worker.js', ...opts, }; - let code = CODE.replace('URL', resolvedOpts.base + resolvedOpts.path).replace( + let code = PREFETCH_CODE.replace('URL', resolvedOpts.base + resolvedOpts.path).replace( 'SCOPE', resolvedOpts.base ); - if (!resolvedOpts.verbose) { + if (!isDev) { code = code.replaceAll(/\s+/gm, ''); } const props = { @@ -37,7 +41,6 @@ export const PrefetchServiceWorker = (opts: { 'navigator.serviceWorker', 'window.qwikPrefetchSW||(window.qwikPrefetchSW=[])', resolvedOpts.verbose, - resolvedOpts.fetchBundleGraph, ].join(','), ');', ].join(''), @@ -45,12 +48,11 @@ export const PrefetchServiceWorker = (opts: { return _jsxC('script', props, 0, 'prefetch-service-worker'); }; -const CODE = /*#__PURE__*/ (( - qc: HTMLElement, - c: ServiceWorkerContainer, - q: Array, - v: boolean, - f: boolean, +const PREFETCH_CODE = /*#__PURE__*/ (( + qc: HTMLElement, // QwikContainer Element + c: ServiceWorkerContainer, // Service worker container + q: Array, // Queue of messages to send to the service worker. + v: boolean, // Verbose mode b?: string, h?: string ) => { @@ -68,10 +70,63 @@ const CODE = /*#__PURE__*/ (( } ); v && q.push(['verbose']); - f && - document.addEventListener( - 'qprefetch', - (e: any) => e.detail.bundles && q.push(['prefetch', b, ...e.detail.bundles]) - ); - q.push(['graph-url', b, `q-bundle-graph-${h}.json`]); + document.addEventListener( + 'qprefetch', + (e: any) => e.detail.bundles && q.push(['prefetch', b, ...e.detail.bundles]) + ); +}).toString(); + +/** + * Load the prefetch graph for the container. + * + * Each Qwik container needs to include its own prefetch graph. + * + * @param opts - Options for the loading prefetch graph. + * + * - `base` - Base of the graph. For a default installation this will default to `/build/`. But if + * more than one MFE is installed on the page, then each MFE needs to have its own base. + * - `manifestHash` - Hash of the manifest file to load. If not provided the hash will be extracted + * from the container attribute `q:manifest-hash` and assume the default build file + * `${base}/q-bundle-graph-${manifestHash}.json`. + * - `manifestURL` - URL of the manifest file to load if non-standard bundle graph location name. + * + * @alpha + */ +export const PrefetchGraph = ( + opts: { base?: string; manifestHash?: string; manifestURL?: string } = {} +) => { + const resolvedOpts = { + base: '/build/', + manifestHash: null, + manifestURL: null, + ...opts, + }; + let code = PREFETCH_GRAPH_CODE; + if (!isDev) { + code = code.replaceAll(/\s+/gm, ''); + } + const props = { + dangerouslySetInnerHTML: [ + '(' + code + ')(', + [ + "document.currentScript.closest('[q\\\\:container]')", + 'window.qwikPrefetchSW||(window.qwikPrefetchSW=[])', + JSON.stringify(resolvedOpts.base), + JSON.stringify(resolvedOpts.manifestHash), + JSON.stringify(resolvedOpts.manifestURL), + ].join(','), + ');', + ].join(''), + }; + return _jsxC('script', props, 0, 'prefetch-graph'); +}; + +const PREFETCH_GRAPH_CODE = /*#__PURE__*/ (( + qc: HTMLElement, // QwikContainer Element + q: Array, // Queue of messages to send to the service worker. + b: string, // Base URL + h: string | null, // Manifest hash + u: string | null // Manifest URL +) => { + q.push(['graph-url', b, u || `q-bundle-graph-${h || qc.getAttribute('q:manifest-hash')}.json`]); }).toString(); diff --git a/packages/qwik/src/core/index.ts b/packages/qwik/src/core/index.ts index d1a8df7b307..c671f437e05 100644 --- a/packages/qwik/src/core/index.ts +++ b/packages/qwik/src/core/index.ts @@ -162,7 +162,7 @@ export type { ////////////////////////////////////////////////////////////////////////////////////////// // Components ////////////////////////////////////////////////////////////////////////////////////////// -export { PrefetchServiceWorker } from './components/prefetch'; +export { PrefetchServiceWorker, PrefetchGraph } from './components/prefetch'; ////////////////////////////////////////////////////////////////////////////////////////// // INTERNAL