Skip to content

Commit

Permalink
WIP: added PrefetchGraph component
Browse files Browse the repository at this point in the history
  • Loading branch information
mhevery committed Jan 3, 2024
1 parent 5d1a9d0 commit f8edf04
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 22 deletions.
16 changes: 15 additions & 1 deletion packages/docs/src/routes/api/qwik/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
},
Expand Down
22 changes: 22 additions & 0 deletions packages/docs/src/routes/api/qwik/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1664,10 +1664,32 @@ export interface ParamHTMLAttributes<T extends Element> 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;
Expand Down
9 changes: 8 additions & 1 deletion packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,14 @@ export interface ParamHTMLAttributes<T extends Element> extends Attrs<'base', T,
// @internal
export const _pauseFromContexts: (allContexts: QContext[], containerState: ContainerState, fallbackGetObjId?: GetObjID, textNodes?: Map<string, string>) => Promise<SnapshotResult>;

// @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;
Expand Down
93 changes: 74 additions & 19 deletions packages/qwik/src/core/components/prefetch.ts
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -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 = {
Expand All @@ -37,20 +41,18 @@ export const PrefetchServiceWorker = (opts: {
'navigator.serviceWorker',
'window.qwikPrefetchSW||(window.qwikPrefetchSW=[])',
resolvedOpts.verbose,
resolvedOpts.fetchBundleGraph,
].join(','),
');',
].join(''),
};
return _jsxC('script', props, 0, 'prefetch-service-worker');
};

const CODE = /*#__PURE__*/ ((
qc: HTMLElement,
c: ServiceWorkerContainer,
q: Array<any[]>,
v: boolean,
f: boolean,
const PREFETCH_CODE = /*#__PURE__*/ ((
qc: HTMLElement, // QwikContainer Element
c: ServiceWorkerContainer, // Service worker container
q: Array<any[]>, // Queue of messages to send to the service worker.
v: boolean, // Verbose mode
b?: string,
h?: string
) => {
Expand All @@ -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<any[]>, // 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();
2 changes: 1 addition & 1 deletion packages/qwik/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export type {
//////////////////////////////////////////////////////////////////////////////////////////
// Components
//////////////////////////////////////////////////////////////////////////////////////////
export { PrefetchServiceWorker } from './components/prefetch';
export { PrefetchServiceWorker, PrefetchGraph } from './components/prefetch';

//////////////////////////////////////////////////////////////////////////////////////////
// INTERNAL
Expand Down

0 comments on commit f8edf04

Please sign in to comment.