Skip to content

Commit 3645426

Browse files
committed
chore(core): support finding qrl through dev data WIP
1 parent 3e24f80 commit 3645426

File tree

21 files changed

+346
-130
lines changed

21 files changed

+346
-130
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@
644644
}
645645
],
646646
"kind": "TypeAlias",
647-
"content": "```typescript\nexport type SymbolMapperFn = (symbolName: string, mapper: SymbolMapper | undefined) => readonly [symbol: string, chunk: string] | undefined;\n```\n**References:** [SymbolMapper](#symbolmapper)",
647+
"content": "```typescript\nexport type SymbolMapperFn = (symbolName: string, mapper: SymbolMapper | undefined, parent?: string) => readonly [symbol: string, chunk: string] | undefined;\n```\n**References:** [SymbolMapper](#symbolmapper)",
648648
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
649649
"mdFile": "qwik.symbolmapperfn.md"
650650
},

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,6 +2768,7 @@ export type SymbolMapper = Record<
27682768
export type SymbolMapperFn = (
27692769
symbolName: string,
27702770
mapper: SymbolMapper | undefined,
2771+
parent?: string,
27712772
) => readonly [symbol: string, chunk: string] | undefined;
27722773
```
27732774

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@
544544
}
545545
],
546546
"kind": "Interface",
547-
"content": "Low-level API for platform abstraction.\n\nDifferent platforms (browser, node, service workers) may have different ways of handling things such as `requestAnimationFrame` and imports. To make Qwik platform-independent Qwik uses the `CorePlatform` API to access the platform API.\n\n`CorePlatform` also is responsible for importing symbols. The import map is different on the client (browser) then on the server. For this reason, the server has a manifest that is used to map symbols to javascript chunks. The manifest is encapsulated in `CorePlatform`<!-- -->, for this reason, the `CorePlatform` can't be global as there may be multiple applications running at server concurrently.\n\nThis is a low-level API and there should not be a need for you to access this.\n\n\n```typescript\nexport interface CorePlatform \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\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\n[chunkForSymbol](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(symbolName: string, chunk: string \\| null) =&gt; readonly \\[symbol: string, chunk: string\\] \\| undefined\n\n\n</td><td>\n\nRetrieve chunk name for the symbol.\n\nWhen the application is running on the server the symbols may be imported from different files (as server build is typically a single javascript chunk.) For this reason, it is necessary to convert the chunks from server format to client (browser) format. This is done by looking up symbols (which are globally unique) in the manifest. (Manifest is the mapping of symbols to the client chunk names.)\n\n\n</td></tr>\n<tr><td>\n\n[importSymbol](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(containerEl: Element \\| undefined, url: string \\| URL \\| undefined \\| null, symbol: string) =&gt; [ValueOrPromise](#valueorpromise)<!-- -->&lt;any&gt;\n\n\n</td><td>\n\nRetrieve a symbol value from QRL.\n\nQwik needs to lazy load data and closures. For this Qwik uses QRLs that are serializable references of resources that are needed. The QRLs contain all the information necessary to retrieve the reference using `importSymbol`<!-- -->.\n\nWhy not use `import()`<!-- -->? Because `import()` is relative to the current file, and the current file is always the Qwik framework. So QRLs have additional information that allows them to serialize imports relative to application base rather than the Qwik framework file.\n\n\n</td></tr>\n<tr><td>\n\n[isServer](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\nTrue of running on the server platform.\n\n\n</td></tr>\n<tr><td>\n\n[nextTick](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(fn: () =&gt; any) =&gt; Promise&lt;any&gt;\n\n\n</td><td>\n\nPerform operation on next tick.\n\n\n</td></tr>\n<tr><td>\n\n[raf](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(fn: () =&gt; any) =&gt; Promise&lt;any&gt;\n\n\n</td><td>\n\nPerform operation on next request-animation-frame.\n\n\n</td></tr>\n</tbody></table>",
547+
"content": "Low-level API for platform abstraction.\n\nDifferent platforms (browser, node, service workers) may have different ways of handling things such as `requestAnimationFrame` and imports. To make Qwik platform-independent Qwik uses the `CorePlatform` API to access the platform API.\n\n`CorePlatform` also is responsible for importing symbols. The import map is different on the client (browser) then on the server. For this reason, the server has a manifest that is used to map symbols to javascript chunks. The manifest is encapsulated in `CorePlatform`<!-- -->, for this reason, the `CorePlatform` can't be global as there may be multiple applications running at server concurrently.\n\nThis is a low-level API and there should not be a need for you to access this.\n\n\n```typescript\nexport interface CorePlatform \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\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\n[chunkForSymbol](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(symbolName: string, chunk: string \\| null, parent?: string) =&gt; readonly \\[symbol: string, chunk: string\\] \\| undefined\n\n\n</td><td>\n\nRetrieve chunk name for the symbol.\n\nWhen the application is running on the server the symbols may be imported from different files (as server build is typically a single javascript chunk.) For this reason, it is necessary to convert the chunks from server format to client (browser) format. This is done by looking up symbols (which are globally unique) in the manifest. (Manifest is the mapping of symbols to the client chunk names.)\n\n\n</td></tr>\n<tr><td>\n\n[importSymbol](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(containerEl: Element \\| undefined, url: string \\| URL \\| undefined \\| null, symbol: string) =&gt; [ValueOrPromise](#valueorpromise)<!-- -->&lt;any&gt;\n\n\n</td><td>\n\nRetrieve a symbol value from QRL.\n\nQwik needs to lazy load data and closures. For this Qwik uses QRLs that are serializable references of resources that are needed. The QRLs contain all the information necessary to retrieve the reference using `importSymbol`<!-- -->.\n\nWhy not use `import()`<!-- -->? Because `import()` is relative to the current file, and the current file is always the Qwik framework. So QRLs have additional information that allows them to serialize imports relative to application base rather than the Qwik framework file.\n\n\n</td></tr>\n<tr><td>\n\n[isServer](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\nTrue of running on the server platform.\n\n\n</td></tr>\n<tr><td>\n\n[nextTick](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(fn: () =&gt; any) =&gt; Promise&lt;any&gt;\n\n\n</td><td>\n\nPerform operation on next tick.\n\n\n</td></tr>\n<tr><td>\n\n[raf](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(fn: () =&gt; any) =&gt; Promise&lt;any&gt;\n\n\n</td><td>\n\nPerform operation on next request-animation-frame.\n\n\n</td></tr>\n</tbody></table>",
548548
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/platform/types.ts",
549549
"mdFile": "qwik.coreplatform.md"
550550
},

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ Description
15581558
15591559
</td><td>
15601560
1561-
(symbolName: string, chunk: string \| null) =&gt; readonly [symbol: string, chunk: string] \| undefined
1561+
(symbolName: string, chunk: string \| null, parent?: string) =&gt; readonly [symbol: string, chunk: string] \| undefined
15621562
15631563
</td><td>
15641564

packages/qwik/src/core/api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export interface ContextId<STATE> {
142142

143143
// @public
144144
export interface CorePlatform {
145-
chunkForSymbol: (symbolName: string, chunk: string | null) => readonly [symbol: string, chunk: string] | undefined;
145+
chunkForSymbol: (symbolName: string, chunk: string | null, parent?: string) => readonly [symbol: string, chunk: string] | undefined;
146146
importSymbol: (containerEl: Element | undefined, url: string | URL | undefined | null, symbol: string) => ValueOrPromise<any>;
147147
isServer: boolean;
148148
nextTick: (fn: () => any) => Promise<any>;
@@ -542,6 +542,9 @@ export type NativeWheelEvent = WheelEvent;
542542
// @internal (undocumented)
543543
export const _noopQrl: <T>(symbolName: string, lexicalScopeCapture?: any[]) => QRL<T>;
544544

545+
// @internal (undocumented)
546+
export const _noopQrlDEV: <T>(symbolName: string, opts: QRLDev, lexicalScopeCapture?: any[]) => QRL<T>;
547+
545548
// @public
546549
export type NoSerialize<T> = (T & {
547550
__no_serialize__: true;

packages/qwik/src/core/internal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { _pauseFromContexts, _serializeData } from './container/pause';
2-
export { _noopQrl, _regSymbol } from './qrl/qrl';
2+
export { _noopQrl, _noopQrlDEV, _regSymbol } from './qrl/qrl';
33
export { _renderSSR } from './render/ssr/render-ssr';
44
export { _hW } from './render/dom/notify-render';
55
export { _wrapSignal, _wrapProp } from './state/signal';

packages/qwik/src/core/platform/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ export interface CorePlatform {
9797
// </docs>
9898
chunkForSymbol: (
9999
symbolName: string,
100-
chunk: string | null
100+
chunk: string | null,
101+
parent?: string
101102
) => readonly [symbol: string, chunk: string] | undefined;
102103
}
103104

packages/qwik/src/core/qrl/qrl.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ export const _noopQrl = <T>(
124124
return createQRL<T>(null, symbolName, null, null, null, lexicalScopeCapture, null);
125125
};
126126

127+
/** @internal */
128+
export const _noopQrlDEV = <T>(
129+
symbolName: string,
130+
opts: QRLDev,
131+
lexicalScopeCapture: any[] = EMPTY_ARRAY
132+
): QRL<T> => {
133+
const newQrl = _noopQrl(symbolName, lexicalScopeCapture) as QRLInternal<T>;
134+
newQrl.dev = opts;
135+
return newQrl;
136+
};
137+
127138
/** @internal */
128139
export const qrlDEV = <T = any>(
129140
chunkOrFn: string | (() => Promise<any>),
@@ -163,12 +174,14 @@ export const serializeQRL = (qrl: QRLInternal, opts: QRLSerializeOptions = {}) =
163174
const platform = getPlatform();
164175

165176
if (platform) {
166-
const result = platform.chunkForSymbol(refSymbol, chunk);
177+
const result = platform.chunkForSymbol(refSymbol, chunk, qrl.dev?.file);
167178
if (result) {
168179
chunk = result[1];
169180
if (!qrl.$refSymbol$) {
170181
symbol = result[0];
171182
}
183+
} else {
184+
console.error('serializeQRL: Cannot resolve symbol', symbol, 'in', chunk, qrl.dev?.file);
172185
}
173186
}
174187

@@ -197,7 +210,7 @@ export const serializeQRL = (qrl: QRLInternal, opts: QRLSerializeOptions = {}) =
197210
throwErrorAndStop('Sync QRL without containerState');
198211
}
199212
}
200-
let output = `${chunk}#${symbol}`;
213+
let output = `${encodeURI(chunk)}#${symbol}`;
201214
const capture = qrl.$capture$;
202215
const captureRef = qrl.$captureRef$;
203216
if (captureRef && captureRef.length) {
@@ -232,7 +245,7 @@ export const parseQRL = <T = any>(qrl: string, containerEl?: Element): QRLIntern
232245
throw new Error(`Invalid QRL format "${qrl}"`);
233246
}
234247
const { c, a, s, p } = parse.groups!;
235-
const chunk = `${c}${a ? `#${a}` : ''}`;
248+
const chunk = `${decodeURI(c)}${a ? `#${a}` : ''}`;
236249
const symbol = s || 'default';
237250
const capture = p ? p.split(' ') : [];
238251

packages/qwik/src/core/qrl/qrl.unit.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ describe('serialization', () => {
9595
$symbol$: 'symbol',
9696
$capture$: ['2'],
9797
});
98+
matchProps(parseQRL('src/routes/%5B...index%5D/c#exp#symbol[2]'), {
99+
$chunk$: 'src/routes/[...index]/c#exp',
100+
$symbol$: 'symbol',
101+
$capture$: ['2'],
102+
});
98103
});
99104

100105
test('serialize qrls', () => {
@@ -109,6 +114,12 @@ describe('serialization', () => {
109114
serializeQRL(createQRL('c', 's1', null, null, [1 as any, '2'], null, null)),
110115
'c#s1[1 2]'
111116
);
117+
assert.equal(
118+
serializeQRL(
119+
createQRL('src/routes/[...index]/c#exp', 's1', null, null, [1 as any, '2'], null, null)
120+
),
121+
'src/routes/%5B...index%5D/c#exp#s1[1 2]'
122+
);
112123
});
113124

114125
test('should parse reference', () => {

packages/qwik/src/core/use/use-task.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,10 @@ const getTaskHandlerQrl = (task: SubscriberEffect): QRL<(ev: Event) => void> =>
793793
[task],
794794
taskQrl.$symbol$
795795
);
796+
// Needed for chunk lookup in dev mode
797+
if (taskQrl.dev) {
798+
taskHandler.dev = taskQrl.dev;
799+
}
796800
return taskHandler;
797801
};
798802

0 commit comments

Comments
 (0)