Skip to content

Commit adb1f82

Browse files
export symbol mapper
1 parent a2aead6 commit adb1f82

4 files changed

Lines changed: 59 additions & 35 deletions

File tree

packages/docs/src/routes/api/qwik/api.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,7 +1760,7 @@
17601760
}
17611761
],
17621762
"kind": "Function",
1763-
"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 nonce?: string;\n}) => JSXNode<\"script\">\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nopts\n\n\n</td><td>\n\n{ base?: string; manifestHash?: string; manifestURL?: string; nonce?: string; }\n\n\n</td><td>\n\n_(Optional)_ Options for the loading prefetch graph.\n\n- `base` - Base of the graph. For a default installation this will default to the q:base value `/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.\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\n[JSXNode](#jsxnode)<!-- -->&lt;\"script\"&gt;",
1763+
"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 nonce?: string;\n}) => JSXNode<\"script\">\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nopts\n\n\n</td><td>\n\n{ base?: string; manifestHash?: string; manifestURL?: string; nonce?: string; }\n\n\n</td><td>\n\n_(Optional)_ Options for the loading prefetch graph.\n\n- `base` - Base of the graph. For a default installation this will default to the q:base value `/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.\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\nJSXNode&lt;\"script\"&gt;",
17641764
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts",
17651765
"mdFile": "qwik.prefetchgraph.md"
17661766
},
@@ -1774,7 +1774,7 @@
17741774
}
17751775
],
17761776
"kind": "Function",
1777-
"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 scope?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n nonce?: string;\n}) => JSXNode<'script'>\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nopts\n\n\n</td><td>\n\n{ base?: string; scope?: string; path?: string; verbose?: boolean; fetchBundleGraph?: boolean; nonce?: string; }\n\n\n</td><td>\n\nOptions for the prefetch service worker.\n\n- `base` - Base URL for the service worker `import.meta.env.BASE_URL` or `/`<!-- -->. Default is `import.meta.env.BASE_URL` - `scope` - Base URL for when the service-worker will activate. Default is `/` - `path` - Path to the service worker. Default is `qwik-prefetch-service-worker.js` unless you pass a path that starts with a `/` then the base is ignored. Default is `qwik-prefetch-service-worker.js` - `verbose` - Verbose logging for the service worker installation. Default is `false` - `nonce` - Optional nonce value for security purposes, defaults to `undefined`<!-- -->.\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\n[JSXNode](#jsxnode)<!-- -->&lt;'script'&gt;",
1777+
"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 scope?: string;\n path?: string;\n verbose?: boolean;\n fetchBundleGraph?: boolean;\n nonce?: string;\n}) => JSXNode<'script'>\n```\n\n\n<table><thead><tr><th>\n\nParameter\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\nopts\n\n\n</td><td>\n\n{ base?: string; scope?: string; path?: string; verbose?: boolean; fetchBundleGraph?: boolean; nonce?: string; }\n\n\n</td><td>\n\nOptions for the prefetch service worker.\n\n- `base` - Base URL for the service worker `import.meta.env.BASE_URL` or `/`<!-- -->. Default is `import.meta.env.BASE_URL` - `scope` - Base URL for when the service-worker will activate. Default is `/` - `path` - Path to the service worker. Default is `qwik-prefetch-service-worker.js` unless you pass a path that starts with a `/` then the base is ignored. Default is `qwik-prefetch-service-worker.js` - `verbose` - Verbose logging for the service worker installation. Default is `false` - `nonce` - Optional nonce value for security purposes, defaults to `undefined`<!-- -->.\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\nJSXNode&lt;'script'&gt;",
17781778
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts",
17791779
"mdFile": "qwik.prefetchserviceworker.md"
17801780
},

packages/docs/src/routes/api/qwik/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3625,7 +3625,7 @@ _(Optional)_ Options for the loading prefetch graph.
36253625
</tbody></table>
36263626
**Returns:**
36273627
3628-
[JSXNode](#jsxnode)&lt;"script"&gt;
3628+
JSXNode&lt;"script"&gt;
36293629
36303630
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts)
36313631
@@ -3679,7 +3679,7 @@ Options for the prefetch service worker.
36793679
</tbody></table>
36803680
**Returns:**
36813681
3682-
[JSXNode](#jsxnode)&lt;'script'&gt;
3682+
JSXNode&lt;'script'&gt;
36833683
36843684
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/components/prefetch.ts)
36853685

packages/qwik/src/optimizer/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { createOptimizer } from './optimizer';
2+
export { symbolMapper } from './plugins/vite-dev-server';
23
export { versions } from './versions';
34

45
export type {

packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import clickToComponent from './click-to-component.html?raw';
1414
import perfWarning from './perf-warning.html?raw';
1515
import errorHost from './error-host.html?raw';
1616
import { SYNC_QRL } from '../../../core/qrl/qrl-class';
17+
import path from 'path';
1718

1819
function getOrigin(req: IncomingMessage) {
1920
const { PROTOCOL_HEADER, HOST_HEADER } = process.env;
@@ -27,6 +28,56 @@ function getOrigin(req: IncomingMessage) {
2728
return `${protocol}://${host}`;
2829
}
2930

31+
// We must encode the chunk so that e.g. + doesn't get converted to space etc
32+
const encode = (url: string) => encodeURIComponent(url).replaceAll('%2F', '/');
33+
34+
function createSymbolMapper(
35+
base: string,
36+
opts: NormalizedQwikPluginOptions,
37+
foundQrls: Map<string, string>
38+
): (symbolName: string, mapper: any, parent: string | undefined) => [string, string] {
39+
return (symbolName: string, mapper: any, parent: string | undefined): [string, string] => {
40+
if (symbolName === SYNC_QRL) {
41+
return [symbolName, ''];
42+
}
43+
const hash = getSymbolHash(symbolName);
44+
const chunk = mapper && mapper[hash];
45+
if (chunk) {
46+
return [chunk[0], encode(chunk[1])];
47+
}
48+
parent ||= foundQrls.get(hash);
49+
if (!parent) {
50+
console.error(
51+
'qwik vite-dev-server symbolMapper: unknown qrl requested without parent:',
52+
symbolName
53+
);
54+
return [symbolName, `${base}${symbolName.toLowerCase()}.js`];
55+
}
56+
const parentPath = path.dirname(parent);
57+
const parentFile = path.basename(parent);
58+
const qrlPath = parentPath.startsWith(opts.rootDir)
59+
? path.posix.normalize(path.relative(opts.rootDir, parentPath))
60+
: `@fs${path.posix.normalize(parentPath)}`;
61+
const qrlFile = `${encode(qrlPath)}/${symbolName.toLowerCase()}.js?_qrl_parent=${encode(parentFile)}`;
62+
return [symbolName, `${base}${qrlFile}`];
63+
};
64+
}
65+
66+
/**
67+
* ```
68+
* For a given symbol (QRL such as `onKeydown$`) the server needs to know which bundle the symbol is in.
69+
*
70+
* Normally this is provided by Qwik's `q-manifest` . But `q-manifest` only exists after a full client build.
71+
*
72+
* This would be a problem in dev mode. So in dev mode the symbol is mapped to the expected URL using the symbolMapper function above. For Vite the given path is fixed for a given symbol.
73+
*
74+
* We export this symbolMapper function for systems that do not use Qwik's ssr dev server.
75+
* ```
76+
*/
77+
export let symbolMapper:
78+
| ((symbolName: string, mapper: any, parent: string | undefined) => [string, string])
79+
| undefined;
80+
3081
export async function configureDevServer(
3182
base: string,
3283
server: ViteDevServer,
@@ -133,43 +184,15 @@ export async function configureDevServer(
133184
});
134185
});
135186

136-
// We must encode the chunk so that e.g. + doesn't get converted to space etc
137-
const encode = (url: string) => encodeURIComponent(url).replaceAll('%2F', '/');
187+
symbolMapper = createSymbolMapper(base, opts, foundQrls);
188+
138189
const renderOpts: RenderToStreamOptions = {
139190
debug: true,
140191
locale: serverData.locale,
141192
stream: res,
142193
snapshot: !isClientDevOnly,
143194
manifest: isClientDevOnly ? undefined : manifest,
144-
symbolMapper: isClientDevOnly
145-
? undefined
146-
: (symbolName, mapper, parent) => {
147-
if (symbolName === SYNC_QRL) {
148-
return [symbolName, ''];
149-
}
150-
const hash = getSymbolHash(symbolName);
151-
const chunk = mapper && mapper[hash];
152-
if (chunk) {
153-
return [chunk[0], encode(chunk[1])];
154-
}
155-
parent ||= foundQrls.get(hash);
156-
if (!parent) {
157-
console.error(
158-
'qwik vite-dev-server symbolMapper: unknown qrl requested without parent:',
159-
symbolName
160-
);
161-
return [symbolName, `${base}${symbolName.toLowerCase()}.js`];
162-
}
163-
const parentPath = path.dirname(parent);
164-
const parentFile = path.basename(parent);
165-
// DX: if the file isn't under the source dir (e.g. a symlink from node_modules)
166-
// use the full path, otherwise relative to the source
167-
const qrlPath = parentPath.startsWith(opts.rootDir)
168-
? path.posix.normalize(path.relative(opts.rootDir, parentPath))
169-
: `@fs${path.posix.normalize(parentPath)}`;
170-
const qrlFile = `${encode(qrlPath)}/${symbolName.toLowerCase()}.js?_qrl_parent=${encode(parentFile)}`;
171-
return [symbolName, `${base}${qrlFile}`];
172-
},
195+
symbolMapper: isClientDevOnly ? undefined : symbolMapper,
173196
prefetchStrategy: null,
174197
serverData,
175198
containerAttributes: { ...serverData.containerAttributes },

0 commit comments

Comments
 (0)