Skip to content

Commit 361e497

Browse files
shairezwmertens
andcommitted
chore(router): put routes bundles into the bundle graph
Co-authored-by: Wout Mertens <[email protected]>
1 parent b7bb821 commit 361e497

File tree

10 files changed

+401
-133
lines changed

10 files changed

+401
-133
lines changed

Diff for: packages/docs/src/routes/api/qwik-optimizer/api.json

+29-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@
1919
"content": "```typescript\nbasename(path: string, ext?: string): string;\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\npath\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\next\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>\n**Returns:**\n\nstring",
2020
"mdFile": "qwik.path.basename.md"
2121
},
22+
{
23+
"name": "BundleGraphModifier",
24+
"id": "bundlegraphmodifier",
25+
"hierarchy": [
26+
{
27+
"name": "BundleGraphModifier",
28+
"id": "bundlegraphmodifier"
29+
}
30+
],
31+
"kind": "TypeAlias",
32+
"content": "A function that creates a modified version of the bundle graph. Used to inject routes and their dependencies into the bundle graph.\n\n\n```typescript\nexport type BundleGraphModifier = (graph: QwikBundleGraph, manifest: QwikManifest) => QwikBundleGraph;\n```\n**References:** [QwikBundleGraph](#qwikbundlegraph)<!-- -->, [QwikManifest](#qwikmanifest)",
33+
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/plugins/bundle-graph.ts",
34+
"mdFile": "qwik.bundlegraphmodifier.md"
35+
},
2236
{
2337
"name": "ComponentEntryStrategy",
2438
"id": "componententrystrategy",
@@ -410,6 +424,20 @@
410424
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
411425
"mdFile": "qwik.qwikbundle.md"
412426
},
427+
{
428+
"name": "QwikBundleGraph",
429+
"id": "qwikbundlegraph",
430+
"hierarchy": [
431+
{
432+
"name": "QwikBundleGraph",
433+
"id": "qwikbundlegraph"
434+
}
435+
],
436+
"kind": "TypeAlias",
437+
"content": "Bundle graph.\n\nFormat: \\[ 'bundle-a.js', 3, 5 // Depends on 'bundle-b.js' and 'bundle-c.js' 'bundle-b.js', 5, // Depends on 'bundle-c.js' 'bundle-c.js', \\]\n\n\n```typescript\nexport type QwikBundleGraph = Array<string | number>;\n```",
438+
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
439+
"mdFile": "qwik.qwikbundlegraph.md"
440+
},
413441
{
414442
"name": "QwikManifest",
415443
"id": "qwikmanifest",
@@ -518,7 +546,7 @@
518546
}
519547
],
520548
"kind": "Interface",
521-
"content": "```typescript\nexport interface QwikVitePluginApi \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[getAssetsDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| undefined\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getClientOutDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getClientPublicOutDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getInsightsManifest](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(clientOutDir?: string \\| null) =&gt; Promise&lt;[InsightManifest](#insightmanifest) \\| null&gt;\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getManifest](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; [QwikManifest](#qwikmanifest) \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getOptimizer](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; [Optimizer](#optimizer) \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getOptions](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; NormalizedQwikPluginOptions\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getRootDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n</tbody></table>",
549+
"content": "```typescript\nexport interface QwikVitePluginApi \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[getAssetsDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| undefined\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getClientOutDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getClientPublicOutDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getInsightsManifest](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(clientOutDir?: string \\| null) =&gt; Promise&lt;[InsightManifest](#insightmanifest) \\| null&gt;\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getManifest](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; [QwikManifest](#qwikmanifest) \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getOptimizer](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; [Optimizer](#optimizer) \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getOptions](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; NormalizedQwikPluginOptions\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[getRootDir](#)\n\n\n</td><td>\n\n\n</td><td>\n\n() =&gt; string \\| null\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[registerBundleGraphModifier](#)\n\n\n</td><td>\n\n\n</td><td>\n\n(modifier: [BundleGraphModifier](#bundlegraphmodifier)<!-- -->) =&gt; void\n\n\n</td><td>\n\n\n</td></tr>\n</tbody></table>",
522550
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/plugins/vite.ts",
523551
"mdFile": "qwik.qwikvitepluginapi.md"
524552
},

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

+40
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ _(Optional)_
5252

5353
string
5454

55+
## BundleGraphModifier
56+
57+
A function that creates a modified version of the bundle graph. Used to inject routes and their dependencies into the bundle graph.
58+
59+
```typescript
60+
export type BundleGraphModifier = (
61+
graph: QwikBundleGraph,
62+
manifest: QwikManifest,
63+
) => QwikBundleGraph;
64+
```
65+
66+
**References:** [QwikBundleGraph](#qwikbundlegraph), [QwikManifest](#qwikmanifest)
67+
68+
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/plugins/bundle-graph.ts)
69+
5570
## ComponentEntryStrategy
5671

5772
```typescript
@@ -1395,6 +1410,18 @@ _(Optional)_
13951410

13961411
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts)
13971412

1413+
## QwikBundleGraph
1414+
1415+
Bundle graph.
1416+
1417+
Format: [ 'bundle-a.js', 3, 5 // Depends on 'bundle-b.js' and 'bundle-c.js' 'bundle-b.js', 5, // Depends on 'bundle-c.js' 'bundle-c.js', ]
1418+
1419+
```typescript
1420+
export type QwikBundleGraph = Array<string | number>;
1421+
```
1422+
1423+
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts)
1424+
13981425
## QwikManifest
13991426

14001427
The metadata of the build. One of its uses is storing where QRL symbols are located.
@@ -2220,6 +2247,19 @@ Description
22202247

22212248
</td><td>
22222249

2250+
</td></tr>
2251+
<tr><td>
2252+
2253+
[registerBundleGraphModifier](#)
2254+
2255+
</td><td>
2256+
2257+
</td><td>
2258+
2259+
(modifier: [BundleGraphModifier](#bundlegraphmodifier)) =&gt; void
2260+
2261+
</td><td>
2262+
22232263
</td></tr>
22242264
</tbody></table>
22252265

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { QwikBundle, QwikBundleGraph, QwikManifest } from '@builder.io/qwik/optimizer';
2+
import { removeExtension } from '../../utils/fs';
3+
import type { BuildRoute } from '../types';
4+
5+
export function modifyBundleGraph(
6+
routes: BuildRoute[],
7+
originalGraph: QwikBundleGraph,
8+
manifest: QwikManifest
9+
) {
10+
const graph = [...originalGraph];
11+
12+
routes.forEach((route) => {
13+
const routePath = removeExtension(route.filePath);
14+
const layoutPaths = route.layouts
15+
? route.layouts.map((layout) => removeExtension(layout.filePath))
16+
: [];
17+
const routeAndLayoutPaths = [routePath, ...layoutPaths];
18+
19+
const routeDeps = [];
20+
21+
for (const [bundleName, bundle] of Object.entries(manifest.bundles)) {
22+
if (isBundlePartOfRoute(bundle, routeAndLayoutPaths)) {
23+
const bundleIndex = originalGraph.indexOf(bundleName);
24+
if (bundleIndex !== -1) {
25+
routeDeps.push(bundleIndex);
26+
}
27+
}
28+
}
29+
if (routeDeps.length > 0) {
30+
graph.push(route.routeName, ...routeDeps);
31+
}
32+
});
33+
return graph;
34+
}
35+
36+
function isBundlePartOfRoute(bundle: QwikBundle, routeAndLayoutPaths: string[]) {
37+
if (!bundle.origins) {
38+
return false;
39+
}
40+
for (const bundleOrigin of bundle.origins) {
41+
const originPath = removeExtension(bundleOrigin);
42+
return routeAndLayoutPaths.some((path) => path.endsWith(originPath));
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import {
2+
type QwikBundle,
3+
type QwikBundleGraph,
4+
type QwikManifest,
5+
} from '@builder.io/qwik/optimizer';
6+
import { describe, expect, test } from 'vitest';
7+
import type { BuildLayout, BuildRoute } from '../types';
8+
import { modifyBundleGraph } from './bundle-graph-modifier';
9+
10+
describe('modifyBundleGraph', () => {
11+
test(`GIVEN 2 routes, one with a layout
12+
AND a manifest with 3 bundles
13+
THEN the bundle graph should contain the routes and their dependencies`, () => {
14+
const fakeManifest = {
15+
bundles: {
16+
'fake-bundle1.js': {
17+
size: 0,
18+
imports: ['fake-bundle-static-dep.js'],
19+
origins: ['src/routes/index.tsx'],
20+
},
21+
'fake-bundle-static-dep.js': {
22+
size: 0,
23+
dynamicImports: ['fake-bundle-dynamic-dep.js'],
24+
},
25+
'fake-bundle-dynamic-dep.js': {
26+
size: 0,
27+
},
28+
'fake-bundle-part-of-sub-route.js': {
29+
size: 0,
30+
origins: ['src/routes/subroute/index.tsx', 'src/some/other/component.tsx'],
31+
},
32+
'fake-bundle-part-of-layout.js': {
33+
size: 0,
34+
origins: ['src/routes/layout.tsx'],
35+
},
36+
} as Record<string, QwikBundle>,
37+
} as QwikManifest;
38+
39+
const fakeBundleGraph: QwikBundleGraph = [
40+
'fake-bundle1.js',
41+
2,
42+
'fake-bundle-static-dep.js',
43+
-1,
44+
4,
45+
'fake-bundle-dynamic-dep.js',
46+
'fake-bundle-part-of-sub-route.js',
47+
'fake-bundle-part-of-layout.js',
48+
];
49+
50+
const fakeRoutes: BuildRoute[] = [
51+
{
52+
routeName: '/',
53+
filePath: '/home/qwik-app/src/routes/index.tsx',
54+
},
55+
{
56+
routeName: '/subroute',
57+
filePath: '/home/qwik-app/src/routes/subroute/index.tsx',
58+
layouts: [
59+
{
60+
filePath: '/home/qwik-app/src/routes/layout.tsx',
61+
},
62+
] as BuildLayout[],
63+
},
64+
] as BuildRoute[];
65+
66+
const actualResult = modifyBundleGraph(fakeRoutes, fakeBundleGraph, fakeManifest);
67+
68+
const expectedResult: QwikBundleGraph = [
69+
...fakeBundleGraph,
70+
'/',
71+
0, // fake-bundle1.js
72+
'/subroute',
73+
6, // fake-bundle-part-of-sub-route.js
74+
7, // fake-bundle-part-of-layout.js
75+
];
76+
77+
expect(actualResult).toEqual(expectedResult);
78+
});
79+
80+
test(`GIVEN a mismatch between the bundle graph and the manifest
81+
THEN the resulted bundle graph routes should not contain -1 (not found) indices `, () => {
82+
const fakeManifest = {
83+
bundles: {
84+
'fake-bundle1.js': {
85+
size: 0,
86+
origins: ['src/routes/index.tsx'],
87+
},
88+
// 👇 doesn't exist in the bundle graph for some reason
89+
'fake-bundle2.js': {
90+
size: 0,
91+
origins: ['src/routes/index.tsx'],
92+
},
93+
} as Record<string, QwikBundle>,
94+
} as QwikManifest;
95+
96+
const fakeBundleGraph: QwikBundleGraph = ['fake-bundle1.js'];
97+
98+
const fakeRoutes: BuildRoute[] = [
99+
{
100+
routeName: '/',
101+
filePath: '/home/qwik-app/src/routes/index.tsx',
102+
},
103+
] as BuildRoute[];
104+
105+
const actualResult = modifyBundleGraph(fakeRoutes, fakeBundleGraph, fakeManifest);
106+
107+
const expectedResult: QwikBundleGraph = [
108+
...fakeBundleGraph,
109+
'/',
110+
0, // fake-bundle1.js
111+
];
112+
113+
expect(actualResult).toEqual(expectedResult);
114+
});
115+
});

Diff for: packages/qwik-city/src/buildtime/vite/plugin.ts

+25-19
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
1+
import type { QwikVitePlugin } from '@builder.io/qwik/optimizer';
12
import swRegister from '@qwik-city-sw-register-build';
2-
import { createMdxTransformer, type MdxTransform } from '../markdown/mdx';
3-
import { basename, join, resolve, extname } from 'node:path';
4-
import type { Plugin, PluginOption, UserConfig, Rollup } from 'vite';
3+
import fs from 'node:fs';
4+
import { basename, extname, join, resolve } from 'node:path';
5+
import type { Plugin, PluginOption, Rollup, UserConfig } from 'vite';
56
import { loadEnv } from 'vite';
6-
import { generateQwikCityPlan } from '../runtime-generation/generate-qwik-city-plan';
7-
import type { BuildContext } from '../types';
8-
import { createBuildContext, resetBuildContext } from '../context';
7+
import {
8+
NOT_FOUND_PATHS_ID,
9+
RESOLVED_NOT_FOUND_PATHS_ID,
10+
RESOLVED_STATIC_PATHS_ID,
11+
STATIC_PATHS_ID,
12+
} from '../../adapters/shared/vite';
13+
import { postBuild } from '../../adapters/shared/vite/post-build';
14+
import { patchGlobalThis } from '../../middleware/node/node-fetch';
915
import { isMenuFileName, normalizePath, removeExtension } from '../../utils/fs';
10-
import { validatePlugin } from './validate-plugin';
11-
import type { QwikCityPluginApi, QwikCityVitePluginOptions } from './types';
1216
import { build } from '../build';
13-
import { ssrDevMiddleware, staticDistMiddleware } from './dev-server';
17+
import { createBuildContext, resetBuildContext } from '../context';
18+
import { createMdxTransformer, type MdxTransform } from '../markdown/mdx';
1419
import { transformMenu } from '../markdown/menu';
1520
import { generateQwikCityEntries } from '../runtime-generation/generate-entries';
16-
import { patchGlobalThis } from '../../middleware/node/node-fetch';
17-
import type { QwikVitePlugin } from '@builder.io/qwik/optimizer';
18-
import fs from 'node:fs';
21+
import { generateQwikCityPlan } from '../runtime-generation/generate-qwik-city-plan';
1922
import {
2023
generateServiceWorkerRegister,
2124
prependManifestToServiceWorker,
2225
} from '../runtime-generation/generate-service-worker';
23-
import {
24-
NOT_FOUND_PATHS_ID,
25-
RESOLVED_NOT_FOUND_PATHS_ID,
26-
RESOLVED_STATIC_PATHS_ID,
27-
STATIC_PATHS_ID,
28-
} from '../../adapters/shared/vite';
29-
import { postBuild } from '../../adapters/shared/vite/post-build';
26+
import type { BuildContext } from '../types';
27+
import { modifyBundleGraph } from './bundle-graph-modifier';
28+
import { ssrDevMiddleware, staticDistMiddleware } from './dev-server';
3029
import { imagePlugin } from './image-jsx';
30+
import type { QwikCityPluginApi, QwikCityVitePluginOptions } from './types';
31+
import { validatePlugin } from './validate-plugin';
3132

3233
/** @public */
3334
export function qwikCity(userOpts?: QwikCityVitePluginOptions): PluginOption[] {
@@ -172,6 +173,7 @@ function qwikCityPlugin(userOpts?: QwikCityVitePluginOptions): any {
172173
if (isCityPlan || isSwRegister) {
173174
if (!ctx.isDevServer && ctx.isDirty) {
174175
await build(ctx);
176+
175177
ctx.isDirty = false;
176178
ctx.diagnostics.forEach((d) => {
177179
this.warn(d.message);
@@ -237,6 +239,10 @@ function qwikCityPlugin(userOpts?: QwikCityVitePluginOptions): any {
237239
generateBundle(_, bundles) {
238240
// client bundles
239241
if (ctx?.target === 'client') {
242+
qwikPlugin!.api.registerBundleGraphModifier((graph, manifest) => {
243+
return modifyBundleGraph(ctx!.routes, graph, manifest);
244+
});
245+
240246
const entries = [...ctx.entries, ...ctx.serviceWorkers].map((entry) => {
241247
return {
242248
chunkFileName: entry.chunkFileName,

Diff for: packages/qwik/src/optimizer/src/api.md

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
import type { Plugin as Plugin_2 } from 'vite';
88

9+
// @public
10+
export type BundleGraphModifier = (graph: QwikBundleGraph, manifest: QwikManifest) => QwikBundleGraph;
11+
912
// @public (undocumented)
1013
export interface ComponentEntryStrategy {
1114
// (undocumented)
@@ -187,6 +190,9 @@ export interface QwikBundle {
187190
symbols?: string[];
188191
}
189192

193+
// @public
194+
export type QwikBundleGraph = Array<string | number>;
195+
190196
// @public
191197
export interface QwikManifest {
192198
bundles: {
@@ -300,6 +306,8 @@ export interface QwikVitePluginApi {
300306
getOptions: () => NormalizedQwikPluginOptions;
301307
// (undocumented)
302308
getRootDir: () => string | null;
309+
// (undocumented)
310+
registerBundleGraphModifier: (modifier: BundleGraphModifier) => void;
303311
}
304312

305313
// Warning: (ae-forgotten-export) The symbol "QwikVitePluginCSROptions" needs to be exported by the entry point index.d.ts

0 commit comments

Comments
 (0)