Skip to content

Commit da6e98f

Browse files
committed
Merge remote-tracking branch 'origin/main' into v2-merge-main
2 parents cf8d611 + 52d81be commit da6e98f

File tree

20 files changed

+392
-374
lines changed

20 files changed

+392
-374
lines changed

.changeset/empty-sites-tie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@builder.io/qwik': patch
3+
---
4+
5+
:zap: the qwikloader is no longer embedded in the SSR results. Instead, the same techniques are used as for the preloader to ensure that the qwikloader is active as soon as possible, loaded from a separate bundle. This reduces SSR page size by several kB end ensures that subsequent qwikloader loads are nearly instant.

packages/docs/src/entry.ssr.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ export default function (opts: RenderToStreamOptions) {
3434
}
3535
}
3636
return renderToStream(<Root />, {
37-
qwikLoader: {
38-
// The docs can be long so make sure to intercept events before the end of the document.
39-
position: 'top',
40-
},
4137
...opts,
4238
containerAttributes: {
4339
lang: 'en',

packages/docs/src/repl/bundled.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import qCoreInternalDts from '../../node_modules/@qwik.dev/core/dist/core-intern
1717
import qCoreMinMjs from '../../node_modules/@qwik.dev/core/dist/core.min.mjs?raw-source';
1818
import qPreloaderMjs from '../../node_modules/@qwik.dev/core/dist/preloader.mjs?raw-source';
1919
import qHandlersMjs from '../../node_modules/@qwik.dev/core/handlers.mjs?raw-source';
20+
// we use the debug version for the repl so it's understandable
21+
import qQwikLoaderJs from '../../node_modules/@builder.io/qwik/dist/qwikloader.debug.js?raw-source';
2022
import qCoreMjs from '../../node_modules/@qwik.dev/core/dist/core.mjs?raw-source';
2123
import qOptimizerCjs from '../../node_modules/@qwik.dev/core/dist/optimizer.cjs?raw-source';
2224
import qServerCjs from '../../node_modules/@qwik.dev/core/dist/server.cjs?raw-source';
@@ -66,6 +68,7 @@ export const bundled: PkgUrls = {
6668
'/dist/server.cjs': qServerCjs,
6769
'/dist/server.d.ts': qServerDts,
6870
'/dist/preloader.mjs': qPreloaderMjs,
71+
'/dist/qwikloader.js': qQwikLoaderJs,
6972
'/handlers.mjs': qHandlersMjs,
7073
'/bindings/qwik.wasm.cjs': qWasmCjs,
7174
'/bindings/qwik_wasm_bg.wasm': qWasmBinUrl,

packages/docs/src/repl/worker/repl-plugins.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's
9797
return rsp.text();
9898
}
9999
}
100-
100+
// this id is unchanged because it's an entry point
101+
if (id === '@builder.io/qwik/qwikloader.js') {
102+
const rsp = await depResponse('@builder.io/qwik', '/qwikloader.js');
103+
if (rsp) {
104+
return rsp.text();
105+
}
106+
}
101107
// We're the fallback, we know all the files
102108
if (/\.[jt]sx?$/.test(id)) {
103109
throw new Error(`load: unknown module ${id}`);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@
482482
}
483483
],
484484
"kind": "Interface",
485-
"content": "The metadata of the build. One of its uses is storing where QRL symbols are located.\n\n\n```typescript\nexport interface QwikManifest \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[assets?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikAsset](#qwikasset)<!-- -->; }\n\n\n</td><td>\n\n_(Optional)_ All assets. The key is the fileName relative to the rootDir\n\n\n</td></tr>\n<tr><td>\n\n[bundleGraph?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikBundleGraph](#qwikbundlegraph)\n\n\n</td><td>\n\n_(Optional)_ All bundles in a compact graph format with probabilities\n\n\n</td></tr>\n<tr><td>\n\n[bundleGraphAsset?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The bundle graph fileName\n\n\n</td></tr>\n<tr><td>\n\n[bundles](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikBundle](#qwikbundle)<!-- -->; }\n\n\n</td><td>\n\nAll code bundles, used to know the import graph. The key is the bundle fileName relative to \"build/\"\n\n\n</td></tr>\n<tr><td>\n\n[core?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The Qwik core bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[injections?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[GlobalInjections](#globalinjections)<!-- -->\\[\\]\n\n\n</td><td>\n\n_(Optional)_ CSS etc to inject in the document head\n\n\n</td></tr>\n<tr><td>\n\n[manifestHash](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nContent hash of the manifest, if this changes, the code changed\n\n\n</td></tr>\n<tr><td>\n\n[mapping](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: string; }\n\n\n</td><td>\n\nWhere QRLs are located. The key is the symbol name, the value is the bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[options?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ target?: string; buildMode?: string; entryStrategy?: { type: [EntryStrategy](#entrystrategy)<!-- -->\\['type'\\]; }; }\n\n\n</td><td>\n\n_(Optional)_ The options used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[platform?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[name: string\\]: string; }\n\n\n</td><td>\n\n_(Optional)_ The platform used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[preloader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The preloader bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[symbols](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: [QwikSymbol](#qwiksymbol)<!-- -->; }\n\n\n</td><td>\n\nQRL symbols\n\n\n</td></tr>\n<tr><td>\n\n[version](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nThe version of the manifest\n\n\n</td></tr>\n</tbody></table>",
485+
"content": "The metadata of the build. One of its uses is storing where QRL symbols are located.\n\n\n```typescript\nexport interface QwikManifest \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[assets?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikAsset](#qwikasset)<!-- -->; }\n\n\n</td><td>\n\n_(Optional)_ All assets. The key is the fileName relative to the rootDir\n\n\n</td></tr>\n<tr><td>\n\n[bundleGraph?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikBundleGraph](#qwikbundlegraph)\n\n\n</td><td>\n\n_(Optional)_ All bundles in a compact graph format with probabilities\n\n\n</td></tr>\n<tr><td>\n\n[bundleGraphAsset?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The bundle graph fileName\n\n\n</td></tr>\n<tr><td>\n\n[bundles](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikBundle](#qwikbundle)<!-- -->; }\n\n\n</td><td>\n\nAll code bundles, used to know the import graph. The key is the bundle fileName relative to \"build/\"\n\n\n</td></tr>\n<tr><td>\n\n[core?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The Qwik core bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[injections?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[GlobalInjections](#globalinjections)<!-- -->\\[\\]\n\n\n</td><td>\n\n_(Optional)_ CSS etc to inject in the document head\n\n\n</td></tr>\n<tr><td>\n\n[manifestHash](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nContent hash of the manifest, if this changes, the code changed\n\n\n</td></tr>\n<tr><td>\n\n[mapping](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: string; }\n\n\n</td><td>\n\nWhere QRLs are located. The key is the symbol name, the value is the bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[options?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ target?: string; buildMode?: string; entryStrategy?: { type: [EntryStrategy](#entrystrategy)<!-- -->\\['type'\\]; }; }\n\n\n</td><td>\n\n_(Optional)_ The options used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[platform?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[name: string\\]: string; }\n\n\n</td><td>\n\n_(Optional)_ The platform used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[preloader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The preloader bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[qwikLoader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The Qwik loader bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[symbols](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: [QwikSymbol](#qwiksymbol)<!-- -->; }\n\n\n</td><td>\n\nQRL symbols\n\n\n</td></tr>\n<tr><td>\n\n[version](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nThe version of the manifest\n\n\n</td></tr>\n</tbody></table>",
486486
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
487487
"mdFile": "core.qwikmanifest.md"
488488
},
@@ -684,7 +684,7 @@
684684
}
685685
],
686686
"kind": "TypeAlias",
687-
"content": "The manifest values that are needed for SSR.\n\n\n```typescript\nexport type ServerQwikManifest = Pick<QwikManifest, 'manifestHash' | 'injections' | 'bundleGraph' | 'bundleGraphAsset' | 'mapping' | 'preloader' | 'core'>;\n```\n**References:** [QwikManifest](#qwikmanifest)",
687+
"content": "The manifest values that are needed for SSR.\n\n\n```typescript\nexport type ServerQwikManifest = Pick<QwikManifest, 'manifestHash' | 'injections' | 'bundleGraph' | 'bundleGraphAsset' | 'mapping' | 'preloader' | 'core' | 'qwikLoader'>;\n```\n**References:** [QwikManifest](#qwikmanifest)",
688688
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
689689
"mdFile": "core.serverqwikmanifest.md"
690690
},

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,21 @@ _(Optional)_ The preloader bundle fileName
16391639
</td></tr>
16401640
<tr><td>
16411641

1642+
[qwikLoader?](#)
1643+
1644+
</td><td>
1645+
1646+
</td><td>
1647+
1648+
string
1649+
1650+
</td><td>
1651+
1652+
_(Optional)_ The Qwik loader bundle fileName
1653+
1654+
</td></tr>
1655+
<tr><td>
1656+
16421657
[symbols](#)
16431658

16441659
</td><td>
@@ -2842,6 +2857,7 @@ export type ServerQwikManifest = Pick<
28422857
| "mapping"
28432858
| "preloader"
28442859
| "core"
2860+
| "qwikLoader"
28452861
>;
28462862
```
28472863

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@
138138
}
139139
],
140140
"kind": "Interface",
141-
"content": "```typescript\nexport interface QwikLoaderOptions \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[include?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| 'never' \\| 'auto'\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[position?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'top' \\| 'bottom'\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>",
141+
"content": "```typescript\nexport interface QwikLoaderOptions \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[include?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| 'never' \\| 'auto'\n\n\n</td><td>\n\n_(Optional)_ Whether to include the qwikloader script in the document. Normally you don't need to worry about this, but in case of multi-container apps using different Qwik versions, you might want to only enable it on one of the containers.\n\nDefaults to `'auto'`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[position?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'top' \\| 'bottom'\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>",
142142
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts",
143143
"mdFile": "core.qwikloaderoptions.md"
144144
},

packages/docs/src/routes/api/qwik-server/index.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,9 @@ Description
575575

576576
</td><td>
577577

578-
_(Optional)_
578+
_(Optional)_ Whether to include the qwikloader script in the document. Normally you don't need to worry about this, but in case of multi-container apps using different Qwik versions, you might want to only enable it on one of the containers.
579+
580+
Defaults to `'auto'`.
579581

580582
</td></tr>
581583
<tr><td>

packages/qwik/src/core/ssr/ssr-render-jsx.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ function processJSXNode(
185185

186186
enqueue(ssr.closeElement);
187187

188+
enqueue(ssr.emitQwikLoaderAtTopIfNeeded);
188189
if (type === 'head') {
189-
ssr.emitPreloaderPre();
190+
enqueue(ssr.emitPreloaderPre);
190191
enqueue(ssr.additionalHeadNodes);
191-
enqueue(ssr.emitQwikLoaderAtTopIfNeeded);
192192
} else if (type === 'body') {
193193
enqueue(ssr.additionalBodyNodes);
194194
}

packages/qwik/src/core/tests/render-api.spec.tsx

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ describe('render api', () => {
376376
});
377377
});
378378
describe('qwikLoader', () => {
379-
it('should render at bottom by default', async () => {
379+
it('should render at bottom as fallback', async () => {
380380
const result = await renderToStringAndSetPlatform(<Counter />, {
381381
containerTagName: 'div',
382382
});
@@ -386,57 +386,11 @@ describe('render api', () => {
386386
?.previousSibling as HTMLElement;
387387
expect(qwikLoaderScriptElement?.tagName.toLowerCase()).toEqual('script');
388388
expect(qwikLoaderScriptElement?.getAttribute('id')).toEqual('qwikloader');
389-
});
390-
it('should render at bottom', async () => {
391-
const result = await renderToStringAndSetPlatform(<Counter />, {
392-
containerTagName: 'div',
393-
qwikLoader: {
394-
position: 'bottom',
395-
},
396-
});
397-
const document = createDocument({ html: result.html });
398-
// qwik loader is one before last
399-
const qwikLoaderScriptElement = document.body.firstChild?.lastChild
400-
?.previousSibling as HTMLElement;
401-
expect(qwikLoaderScriptElement?.tagName.toLowerCase()).toEqual('script');
402-
expect(qwikLoaderScriptElement?.getAttribute('id')).toEqual('qwikloader');
403-
// should not contain qwik events script for top position
404-
expect(document.head.lastChild?.textContent ?? '').not.toContain('window.qwikevents.push');
405-
});
406-
it('should render at top', async () => {
407-
const result = await renderToStringAndSetPlatform(
408-
[
409-
<head>
410-
<script></script>
411-
</head>,
412-
<body>
413-
<ManyEventsComponent />
414-
</body>,
415-
],
416-
{
417-
containerTagName: 'html',
418-
qwikLoader: {
419-
position: 'top',
420-
},
421-
}
422-
);
423-
const document = createDocument({ html: result.html });
424-
// should render in head
425-
const head = document.head as HTMLButtonElement;
426-
// qwik events should be the last script
427-
const firstQwikEventsScriptElement = head.lastChild as HTMLElement;
428-
// qwik loader should be one before qwik events script
429-
const qwikLoaderScriptElement = firstQwikEventsScriptElement.previousSibling as HTMLElement;
430389
// qwik events should be the last script of body
431-
const secondQwikEventsScriptElement = document.body.lastChild as HTMLElement;
432-
433-
expect(firstQwikEventsScriptElement.textContent).toContain(
434-
'window.qwikevents.push("click", "input")'
390+
const eventsScriptElement = document.body.lastChild as HTMLElement;
391+
expect(eventsScriptElement.textContent).toContain(
392+
'(window.qwikevents||(window.qwikevents=[]))'
435393
);
436-
expect(secondQwikEventsScriptElement.textContent).toContain('window.qwikevents.push');
437-
438-
expect(qwikLoaderScriptElement?.tagName.toLowerCase()).toEqual('script');
439-
expect(qwikLoaderScriptElement?.getAttribute('id')).toEqual('qwikloader');
440394
});
441395
it('should always render', async () => {
442396
const result = await renderToStringAndSetPlatform(<div>static</div>, {
@@ -447,7 +401,7 @@ describe('render api', () => {
447401
});
448402
const document = createDocument({ html: result.html });
449403
// should not contain qwik events script for top position
450-
expect(document.head.lastChild?.textContent ?? '').not.toContain('window.qwikevents.push');
404+
expect(document.head.lastChild?.textContent ?? '').not.toContain('window.qwikevents');
451405
expect(document.querySelectorAll('script[id=qwikloader]')).toHaveLength(1);
452406
});
453407
it('should not render for static content and auto include', async () => {
@@ -485,7 +439,7 @@ describe('render api', () => {
485439
const eventScript = document.querySelector('script[id=qwikloader]')
486440
?.nextSibling as HTMLElement;
487441
expect(eventScript.textContent).toContain(
488-
'window.qwikevents.push("focus", "click", "dblclick", "blur")'
442+
'(window.qwikevents||(window.qwikevents=[])).push("focus", "click", "dblclick", "blur")'
489443
);
490444
});
491445
});
@@ -713,15 +667,15 @@ describe('render api', () => {
713667
containerTagName: 'div',
714668
debug: true,
715669
});
716-
expect(cleanupAttrs(result.html)).toContain('<script id="qwikloader">debug</script>');
670+
expect(cleanupAttrs(result.html)).toContain('<script id="qwikloader" async>debug</script>');
717671
});
718672

719673
it('should emit qwik loader without debug mode', async () => {
720674
const result = await renderToStringAndSetPlatform(<Counter />, {
721675
containerTagName: 'div',
722676
debug: false,
723677
});
724-
expect(cleanupAttrs(result.html)).toContain('<script id="qwikloader">min</script>');
678+
expect(cleanupAttrs(result.html)).toContain('<script id="qwikloader" async>min</script>');
725679
});
726680
});
727681
describe('snapshotResult', () => {
@@ -974,7 +928,7 @@ describe('render api', () => {
974928
streaming,
975929
});
976930
// This can change when the size of the output changes
977-
expect(stream.write).toHaveBeenCalledTimes(6);
931+
expect(stream.write).toHaveBeenCalledTimes(7);
978932
});
979933
});
980934
});

0 commit comments

Comments
 (0)