@qwik.dev/router 2.0.0-beta.43 → 2.0.0-beta.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/adapters/azure-swa/vite/index.mjs +2 -1
- package/lib/adapters/bun-server/vite/index.mjs +2 -1
- package/lib/adapters/cloud-run/vite/index.mjs +2 -1
- package/lib/adapters/cloudflare-pages/vite/index.mjs +2 -1
- package/lib/adapters/deno-server/vite/index.mjs +2 -1
- package/lib/adapters/netlify-edge/vite/index.mjs +2 -1
- package/lib/adapters/node-server/vite/index.mjs +2 -1
- package/lib/adapters/shared/vite/index.mjs +35 -31
- package/lib/adapters/ssg/vite/index.mjs +4 -2
- package/lib/adapters/vercel-edge/vite/index.mjs +18 -15
- package/lib/chunks/fs.mjs +26 -23
- package/lib/chunks/head.qwik.mjs +611 -445
- package/lib/chunks/http-error.qwik.mjs +8 -7
- package/lib/chunks/pathname.mjs +9 -8
- package/lib/chunks/request-path.mjs +8 -4
- package/lib/chunks/routes.mjs +14 -14
- package/lib/chunks/server-error.mjs +11 -5
- package/lib/chunks/{url.mjs → static-file.mjs} +12 -2
- package/lib/chunks/system.mjs +18 -17
- package/lib/chunks/user-response.mjs +419 -323
- package/lib/chunks/worker-thread.mjs +87 -86
- package/lib/index.d.ts +47 -59
- package/lib/index.qwik.mjs +550 -496
- package/lib/middleware/aws-lambda/index.mjs +6 -3
- package/lib/middleware/azure-swa/index.mjs +4 -2
- package/lib/middleware/bun/index.mjs +12 -12
- package/lib/middleware/cloudflare-pages/index.mjs +19 -4
- package/lib/middleware/deno/index.mjs +12 -12
- package/lib/middleware/firebase/index.mjs +4 -2
- package/lib/middleware/netlify-edge/index.mjs +4 -2
- package/lib/middleware/node/index.mjs +16 -15
- package/lib/middleware/request-handler/index.mjs +35 -24
- package/lib/middleware/vercel-edge/index.mjs +4 -2
- package/lib/service-worker/index.mjs +2 -1
- package/lib/ssg/index.mjs +20 -16
- package/lib/vite/index.d.ts +1 -1
- package/lib/vite/index.mjs +596 -586
- package/package.json +5 -5
package/lib/vite/index.mjs
CHANGED
|
@@ -21,7 +21,8 @@ import { toString } from "hast-util-to-string";
|
|
|
21
21
|
import { refractor } from "refractor";
|
|
22
22
|
import tsxLang from "refractor/lang/tsx.js";
|
|
23
23
|
import { optimize } from "svgo";
|
|
24
|
-
/** @public */
|
|
24
|
+
/** @public */
|
|
25
|
+
function extendConfig(baseConfigExport, serverConfigExport) {
|
|
25
26
|
return async (env) => {
|
|
26
27
|
let resolvedBase = await baseConfigExport;
|
|
27
28
|
if (typeof resolvedBase === "function") resolvedBase = await resolvedBase(env);
|
|
@@ -84,6 +85,11 @@ function createMenu(opts, filePath) {
|
|
|
84
85
|
function resolveMenu(opts, menuSourceFile) {
|
|
85
86
|
return createMenu(opts, menuSourceFile.filePath);
|
|
86
87
|
}
|
|
88
|
+
async function transformMenu(opts, filePath, content) {
|
|
89
|
+
const parsedMenu = parseMenu(opts, filePath, content);
|
|
90
|
+
const id = createFileId(opts.routesDir, filePath);
|
|
91
|
+
return `${`const ${id} = ${JSON.stringify(parsedMenu, null, 2)};`} export default ${id}`;
|
|
92
|
+
}
|
|
87
93
|
function parseMenu(opts, filePath, content, checkFileExists = true) {
|
|
88
94
|
const tokens = marked.lexer(content, {});
|
|
89
95
|
let currentDepth = 0;
|
|
@@ -127,18 +133,12 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
|
|
|
127
133
|
if (stack.length === 0) throw new Error(`Menu must start with an h1 in the index: ${filePath}`);
|
|
128
134
|
return stack[0];
|
|
129
135
|
}
|
|
130
|
-
async function transformMenu(opts, filePath, content) {
|
|
131
|
-
const parsedMenu = parseMenu(opts, filePath, content);
|
|
132
|
-
const id = createFileId(opts.routesDir, filePath);
|
|
133
|
-
return `${`const ${id} = ${JSON.stringify(parsedMenu, null, 2)};`} export default ${id}`;
|
|
134
|
-
}
|
|
135
|
-
var PARAM_PATTERN = /^(\.\.\.)?(\w+)?$/;
|
|
136
|
-
var DYNAMIC_SEGMENT = /\[(.+?)\]/;
|
|
137
136
|
/**
|
|
138
137
|
* Adopted from SvelteKit
|
|
139
138
|
*
|
|
140
139
|
* https://github.com/sveltejs/kit/blob/master/LICENSE
|
|
141
|
-
*/
|
|
140
|
+
*/
|
|
141
|
+
function parseRoutePathname(basePathname, pathname) {
|
|
142
142
|
if (pathname === basePathname) return {
|
|
143
143
|
pattern: new RegExp("^" + pathname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$"),
|
|
144
144
|
routeName: pathname,
|
|
@@ -190,8 +190,8 @@ var DYNAMIC_SEGMENT = /\[(.+?)\]/;
|
|
|
190
190
|
})
|
|
191
191
|
};
|
|
192
192
|
}
|
|
193
|
-
var
|
|
194
|
-
var
|
|
193
|
+
var PARAM_PATTERN = /^(\.\.\.)?(\w+)?$/;
|
|
194
|
+
var DYNAMIC_SEGMENT = /\[(.+?)\]/;
|
|
195
195
|
function resolveLayout(opts, layoutSourceFile) {
|
|
196
196
|
let extlessName = layoutSourceFile.extlessName;
|
|
197
197
|
const filePath = layoutSourceFile.filePath;
|
|
@@ -202,7 +202,7 @@ function resolveLayout(opts, layoutSourceFile) {
|
|
|
202
202
|
layoutType = "top";
|
|
203
203
|
extlessName = extlessName.slice(0, extlessName.length - 1);
|
|
204
204
|
} else layoutType = "nested";
|
|
205
|
-
if (extlessName.startsWith(LAYOUT_NAMED_PREFIX)) layoutName = extlessName.slice(
|
|
205
|
+
if (extlessName.startsWith(LAYOUT_NAMED_PREFIX)) layoutName = extlessName.slice(LAYOUT_NAMED_PREFIX.length);
|
|
206
206
|
else layoutName = "";
|
|
207
207
|
return {
|
|
208
208
|
id: createFileId(opts.routesDir, filePath),
|
|
@@ -212,6 +212,8 @@ function resolveLayout(opts, layoutSourceFile) {
|
|
|
212
212
|
layoutName
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
|
+
var LAYOUT_NAMED_PREFIX = "layout-";
|
|
216
|
+
var LAYOUT_TOP_SUFFIX = "!";
|
|
215
217
|
function resolveRoute(opts, appLayouts, sourceFile) {
|
|
216
218
|
const filePath = sourceFile.filePath;
|
|
217
219
|
const layouts = [];
|
|
@@ -247,7 +249,8 @@ function resolveRoute(opts, appLayouts, sourceFile) {
|
|
|
247
249
|
...parseRoutePathname(opts.basePathname, pathname)
|
|
248
250
|
};
|
|
249
251
|
}
|
|
250
|
-
/** Sort routes by pathname, then by extension. Longer routes are sorted first. */
|
|
252
|
+
/** Sort routes by pathname, then by extension. Longer routes are sorted first. */
|
|
253
|
+
function routeSortCompare(a, b) {
|
|
251
254
|
const maxSegments = Math.max(a.segments.length, b.segments.length);
|
|
252
255
|
for (let i = 0; i < maxSegments; i += 1) {
|
|
253
256
|
const sa = a.segments[i];
|
|
@@ -277,7 +280,8 @@ function resolveRoute(opts, appLayouts, sourceFile) {
|
|
|
277
280
|
* - `[...rest]` → `{ key: '_A', paramName: 'rest' }`
|
|
278
281
|
* - `pre[slug]post` → `{ key: '_W', paramName: 'slug', prefix: 'pre', suffix: 'post' }`
|
|
279
282
|
* - `blog` → `{ key: 'blog' }` (lowercased)
|
|
280
|
-
*/
|
|
283
|
+
*/
|
|
284
|
+
function parseDirName(name) {
|
|
281
285
|
if (name.startsWith("(") && name.endsWith(")")) return { key: null };
|
|
282
286
|
const restMatch = /^\[\.\.\.(\w+)\]$/.exec(name);
|
|
283
287
|
if (restMatch) return {
|
|
@@ -293,49 +297,8 @@ function resolveRoute(opts, appLayouts, sourceFile) {
|
|
|
293
297
|
};
|
|
294
298
|
return { key: name.toLowerCase() };
|
|
295
299
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
await Promise.all(dirItemNames.map(async (itemName) => {
|
|
299
|
-
const itemPath = normalizePath$1(join(dirPath, itemName));
|
|
300
|
-
if ((await fs.promises.stat(itemPath)).isDirectory()) {
|
|
301
|
-
const parsed = parseDirName(itemName);
|
|
302
|
-
if (parsed.key === null) {
|
|
303
|
-
let child = node.children.get(itemName);
|
|
304
|
-
if (!child) {
|
|
305
|
-
child = {
|
|
306
|
-
_files: [],
|
|
307
|
-
children: /* @__PURE__ */ new Map()
|
|
308
|
-
};
|
|
309
|
-
node.children.set(itemName, child);
|
|
310
|
-
}
|
|
311
|
-
await walkRouteDir(child, itemPath);
|
|
312
|
-
} else {
|
|
313
|
-
let child = node.children.get(parsed.key);
|
|
314
|
-
if (!child) {
|
|
315
|
-
child = {
|
|
316
|
-
_files: [],
|
|
317
|
-
children: /* @__PURE__ */ new Map()
|
|
318
|
-
};
|
|
319
|
-
if (parsed.paramName) child._P = parsed.paramName;
|
|
320
|
-
if (parsed.prefix) child._0 = parsed.prefix;
|
|
321
|
-
if (parsed.suffix) child._9 = parsed.suffix;
|
|
322
|
-
node.children.set(parsed.key, child);
|
|
323
|
-
}
|
|
324
|
-
await walkRouteDir(child, itemPath);
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
const sourceFileName = getSourceFile(itemName);
|
|
328
|
-
if (sourceFileName !== null) node._files.push({
|
|
329
|
-
...sourceFileName,
|
|
330
|
-
fileName: itemName,
|
|
331
|
-
filePath: itemPath,
|
|
332
|
-
dirName: basename(dirPath),
|
|
333
|
-
dirPath: normalizePath$1(dirPath)
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
}));
|
|
337
|
-
}
|
|
338
|
-
/** Walk the routes directory and return a BuildTrieNode with trie keys. */ async function walkRoutes(routesDir) {
|
|
300
|
+
/** Walk the routes directory and return a BuildTrieNode with trie keys. */
|
|
301
|
+
async function walkRoutes(routesDir) {
|
|
339
302
|
const dirPath = normalizePath$1(routesDir);
|
|
340
303
|
const root = {
|
|
341
304
|
_files: [],
|
|
@@ -344,6 +307,48 @@ async function walkRouteDir(node, dirPath) {
|
|
|
344
307
|
await walkRouteDir(root, dirPath);
|
|
345
308
|
return root;
|
|
346
309
|
}
|
|
310
|
+
async function walkRouteDir(node, dirPath) {
|
|
311
|
+
const dirItemNames = (await fs.promises.readdir(dirPath)).sort();
|
|
312
|
+
const dirItems = await Promise.all(dirItemNames.map(async (itemName) => {
|
|
313
|
+
const itemPath = normalizePath$1(join(dirPath, itemName));
|
|
314
|
+
return {
|
|
315
|
+
itemName,
|
|
316
|
+
itemPath,
|
|
317
|
+
isDirectory: (await fs.promises.stat(itemPath)).isDirectory()
|
|
318
|
+
};
|
|
319
|
+
}));
|
|
320
|
+
const childWalks = [];
|
|
321
|
+
for (const { itemName, itemPath, isDirectory } of dirItems) {
|
|
322
|
+
if (isDirectory) {
|
|
323
|
+
childWalks.push(walkRouteDir(getOrCreateChildNode(node, itemName), itemPath));
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const sourceFileName = getSourceFile(itemName);
|
|
327
|
+
if (sourceFileName !== null) node._files.push({
|
|
328
|
+
...sourceFileName,
|
|
329
|
+
fileName: itemName,
|
|
330
|
+
filePath: itemPath,
|
|
331
|
+
dirName: basename(dirPath),
|
|
332
|
+
dirPath: normalizePath$1(dirPath)
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
await Promise.all(childWalks);
|
|
336
|
+
}
|
|
337
|
+
function getOrCreateChildNode(node, dirName) {
|
|
338
|
+
const parsed = parseDirName(dirName);
|
|
339
|
+
const key = parsed.key ?? dirName;
|
|
340
|
+
const existing = node.children.get(key);
|
|
341
|
+
if (existing) return existing;
|
|
342
|
+
const child = {
|
|
343
|
+
_files: [],
|
|
344
|
+
children: /* @__PURE__ */ new Map()
|
|
345
|
+
};
|
|
346
|
+
if (parsed.paramName) child._P = parsed.paramName;
|
|
347
|
+
if (parsed.prefix) child._0 = parsed.prefix;
|
|
348
|
+
if (parsed.suffix) child._9 = parsed.suffix;
|
|
349
|
+
node.children.set(key, child);
|
|
350
|
+
return child;
|
|
351
|
+
}
|
|
347
352
|
async function walkServerPlugins(opts) {
|
|
348
353
|
const dirPath = opts.serverPluginsDir;
|
|
349
354
|
const dirItemNames = await fs.promises.readdir(dirPath);
|
|
@@ -360,30 +365,40 @@ async function walkServerPlugins(opts) {
|
|
|
360
365
|
}));
|
|
361
366
|
return sourceFiles.sort((a, b) => a.filePath < b.filePath ? -1 : 1);
|
|
362
367
|
}
|
|
363
|
-
function
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
368
|
+
async function parseRoutesDir(ctx) {
|
|
369
|
+
try {
|
|
370
|
+
await updateRoutingContext(ctx);
|
|
371
|
+
validateBuild(ctx);
|
|
372
|
+
} catch (e) {
|
|
373
|
+
addError(ctx, e);
|
|
374
|
+
}
|
|
375
|
+
for (const d of ctx.diagnostics) if (d.type === "error") throw new Error(d.message);
|
|
376
|
+
else console.warn(d.message);
|
|
372
377
|
}
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
function updateRoutingContext(ctx) {
|
|
379
|
+
ctx.activeBuild ||= _updateRoutingContext(ctx).finally(() => {
|
|
380
|
+
ctx.activeBuild = null;
|
|
381
|
+
});
|
|
382
|
+
return ctx.activeBuild;
|
|
383
|
+
}
|
|
384
|
+
async function _updateRoutingContext(ctx) {
|
|
385
|
+
const serverPlugins = await walkServerPlugins(ctx.opts);
|
|
386
|
+
const routeTrie = await walkRoutes(ctx.opts.routesDir);
|
|
387
|
+
if (ctx.opts.rewriteRoutes) applyRewriteRoutes(routeTrie, ctx.opts.rewriteRoutes);
|
|
388
|
+
ctx.routeTrie = routeTrie;
|
|
389
|
+
ctx.serverPlugins = serverPlugins;
|
|
390
|
+
const derived = deriveFromTrie(ctx.opts, routeTrie);
|
|
391
|
+
ctx.layouts = derived.layouts;
|
|
392
|
+
ctx.routes = rewriteRoutes(ctx, derived.routes);
|
|
393
|
+
ctx.entries = derived.entries;
|
|
394
|
+
ctx.serviceWorkers = derived.serviceWorkers;
|
|
395
|
+
ctx.menus = derived.menus;
|
|
382
396
|
}
|
|
383
397
|
/**
|
|
384
398
|
* Walk the trie and extract flat arrays for layouts, routes, entries, menus, service workers. These
|
|
385
399
|
* are needed by generate-entries, generate-menus, generate-service-worker, vite plugin, etc.
|
|
386
|
-
*/
|
|
400
|
+
*/
|
|
401
|
+
function deriveFromTrie(opts, root) {
|
|
387
402
|
const layouts = [];
|
|
388
403
|
const routes = [];
|
|
389
404
|
const entries = [];
|
|
@@ -434,6 +449,47 @@ function resolveServiceWorkerEntry(opts, sourceFile) {
|
|
|
434
449
|
menus
|
|
435
450
|
};
|
|
436
451
|
}
|
|
452
|
+
function resolveEntry(opts, sourceFile) {
|
|
453
|
+
const pathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
|
|
454
|
+
const chunkFileName = pathname.slice(opts.basePathname.length);
|
|
455
|
+
return {
|
|
456
|
+
id: createFileId(opts.routesDir, sourceFile.filePath, "Route"),
|
|
457
|
+
filePath: sourceFile.filePath,
|
|
458
|
+
chunkFileName,
|
|
459
|
+
...parseRoutePathname(opts.basePathname, pathname)
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function resolveServiceWorkerEntry(opts, sourceFile) {
|
|
463
|
+
const pathname = getPathnameFromDirPath(opts, sourceFile.dirPath) + sourceFile.extlessName + ".js";
|
|
464
|
+
const chunkFileName = pathname.slice(opts.basePathname.length);
|
|
465
|
+
return {
|
|
466
|
+
id: createFileId(opts.routesDir, sourceFile.filePath, "ServiceWorker"),
|
|
467
|
+
filePath: sourceFile.filePath,
|
|
468
|
+
chunkFileName,
|
|
469
|
+
...parseRoutePathname(opts.basePathname, pathname)
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Create rewritten route copies for each rewrite config. For backward compat: produces BuiltRoute
|
|
474
|
+
* entries with translated pathnames. At runtime, codegen emits /G nodes in the trie instead.
|
|
475
|
+
*/
|
|
476
|
+
function rewriteRoutes(ctx, routes) {
|
|
477
|
+
if (!ctx.opts.rewriteRoutes) return routes;
|
|
478
|
+
const translatedRoutes = [];
|
|
479
|
+
let segmentsToTranslate = ctx.opts.rewriteRoutes.flatMap((rewriteConfig) => {
|
|
480
|
+
return Object.keys(rewriteConfig.paths || {});
|
|
481
|
+
});
|
|
482
|
+
segmentsToTranslate = Array.from(new Set(segmentsToTranslate));
|
|
483
|
+
routes.forEach((route) => {
|
|
484
|
+
translatedRoutes.push(route);
|
|
485
|
+
if (route.pathname.split("/").some((segment) => segmentsToTranslate.includes(segment)) || route.pathname === "/") ctx.opts.rewriteRoutes.forEach((config, configIndex) => {
|
|
486
|
+
if (route.pathname === "/" && !config.prefix) return;
|
|
487
|
+
const routeToPush = translateRoute(route, config, configIndex);
|
|
488
|
+
if (!translatedRoutes.some((item) => item.pathname === routeToPush.pathname && item.routeName === routeToPush.routeName)) translatedRoutes.push(routeToPush);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
return translatedRoutes.sort(routeSortCompare);
|
|
492
|
+
}
|
|
437
493
|
function translateRoute(route, config, configIndex) {
|
|
438
494
|
const replacePath = (part) => (config.paths || {})[part] ?? part;
|
|
439
495
|
const pathnamePrefix = config.prefix ? "/" + config.prefix : "";
|
|
@@ -470,26 +526,6 @@ function translateRoute(route, config, configIndex) {
|
|
|
470
526
|
};
|
|
471
527
|
}
|
|
472
528
|
/**
|
|
473
|
-
* Create rewritten route copies for each rewrite config. For backward compat: produces BuiltRoute
|
|
474
|
-
* entries with translated pathnames. At runtime, codegen emits /G nodes in the trie instead.
|
|
475
|
-
*/ function rewriteRoutes(ctx, routes) {
|
|
476
|
-
if (!ctx.opts.rewriteRoutes) return routes;
|
|
477
|
-
const translatedRoutes = [];
|
|
478
|
-
let segmentsToTranslate = ctx.opts.rewriteRoutes.flatMap((rewriteConfig) => {
|
|
479
|
-
return Object.keys(rewriteConfig.paths || {});
|
|
480
|
-
});
|
|
481
|
-
segmentsToTranslate = Array.from(new Set(segmentsToTranslate));
|
|
482
|
-
routes.forEach((route) => {
|
|
483
|
-
translatedRoutes.push(route);
|
|
484
|
-
if (route.pathname.split("/").some((segment) => segmentsToTranslate.includes(segment)) || route.pathname === "/") ctx.opts.rewriteRoutes.forEach((config, configIndex) => {
|
|
485
|
-
if (route.pathname === "/" && !config.prefix) return;
|
|
486
|
-
const routeToPush = translateRoute(route, config, configIndex);
|
|
487
|
-
if (!translatedRoutes.some((item) => item.pathname === routeToPush.pathname && item.routeName === routeToPush.routeName)) translatedRoutes.push(routeToPush);
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
return translatedRoutes.sort(routeSortCompare);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
529
|
* Walk the trie and create _G (rewrite) nodes for each rewriteRoutes config.
|
|
494
530
|
*
|
|
495
531
|
* For each route in the trie, if any of its path segments are translatable (listed in a rewrite
|
|
@@ -498,7 +534,8 @@ function translateRoute(route, config, configIndex) {
|
|
|
498
534
|
*
|
|
499
535
|
* The `_G` value is a `/`-separated string of trie keys (skipping group nodes), which the runtime
|
|
500
536
|
* resolver uses to walk the trie and find the target route's loaders and layouts.
|
|
501
|
-
*/
|
|
537
|
+
*/
|
|
538
|
+
function applyRewriteRoutes(root, rewriteConfigs) {
|
|
502
539
|
const routables = [];
|
|
503
540
|
function walk(node, steps) {
|
|
504
541
|
if (node._files.some((f) => f.type === "route" && !isErrorName(f.extlessName))) routables.push({
|
|
@@ -552,25 +589,6 @@ function translateRoute(route, config, configIndex) {
|
|
|
552
589
|
}
|
|
553
590
|
}
|
|
554
591
|
}
|
|
555
|
-
async function _updateRoutingContext(ctx) {
|
|
556
|
-
const serverPlugins = await walkServerPlugins(ctx.opts);
|
|
557
|
-
const routeTrie = await walkRoutes(ctx.opts.routesDir);
|
|
558
|
-
if (ctx.opts.rewriteRoutes) applyRewriteRoutes(routeTrie, ctx.opts.rewriteRoutes);
|
|
559
|
-
ctx.routeTrie = routeTrie;
|
|
560
|
-
ctx.serverPlugins = serverPlugins;
|
|
561
|
-
const derived = deriveFromTrie(ctx.opts, routeTrie);
|
|
562
|
-
ctx.layouts = derived.layouts;
|
|
563
|
-
ctx.routes = rewriteRoutes(ctx, derived.routes);
|
|
564
|
-
ctx.entries = derived.entries;
|
|
565
|
-
ctx.serviceWorkers = derived.serviceWorkers;
|
|
566
|
-
ctx.menus = derived.menus;
|
|
567
|
-
}
|
|
568
|
-
function updateRoutingContext(ctx) {
|
|
569
|
-
ctx.activeBuild ||= _updateRoutingContext(ctx).finally(() => {
|
|
570
|
-
ctx.activeBuild = null;
|
|
571
|
-
});
|
|
572
|
-
return ctx.activeBuild;
|
|
573
|
-
}
|
|
574
592
|
function validateBuild(ctx) {
|
|
575
593
|
const pathnames = Array.from(new Set(ctx.routes.map((r) => r.pathname))).sort();
|
|
576
594
|
for (const pathname of pathnames) {
|
|
@@ -581,15 +599,27 @@ function validateBuild(ctx) {
|
|
|
581
599
|
addWarning(ctx, `The "top" layout feature, which is used by "${l.filePath}" has been deprecated and will be removed from future versions. In most cases the "group" layout feature can be used in its place: https://qwik.dev/docs/advanced/routing/`);
|
|
582
600
|
});
|
|
583
601
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
602
|
+
function createBuildContext(rootDir, viteBasePath, userOpts, target, dynamicImports) {
|
|
603
|
+
return {
|
|
604
|
+
rootDir: normalizePath$1(rootDir),
|
|
605
|
+
opts: normalizeOptions(rootDir, viteBasePath, userOpts),
|
|
606
|
+
routeTrie: {
|
|
607
|
+
_files: [],
|
|
608
|
+
children: /* @__PURE__ */ new Map()
|
|
609
|
+
},
|
|
610
|
+
routes: [],
|
|
611
|
+
serverPlugins: [],
|
|
612
|
+
layouts: [],
|
|
613
|
+
entries: [],
|
|
614
|
+
serviceWorkers: [],
|
|
615
|
+
menus: [],
|
|
616
|
+
diagnostics: [],
|
|
617
|
+
frontmatter: /* @__PURE__ */ new Map(),
|
|
618
|
+
target: target || "ssr",
|
|
619
|
+
dynamicImports: target === "client" || !!dynamicImports,
|
|
620
|
+
isDirty: true,
|
|
621
|
+
activeBuild: null
|
|
622
|
+
};
|
|
593
623
|
}
|
|
594
624
|
function resetBuildContext(ctx) {
|
|
595
625
|
if (ctx) {
|
|
@@ -602,6 +632,15 @@ function resetBuildContext(ctx) {
|
|
|
602
632
|
ctx.isDirty = true;
|
|
603
633
|
}
|
|
604
634
|
}
|
|
635
|
+
/**
|
|
636
|
+
* Resolve the app's base pathname from plugin options and vite's `base`. Shared by option
|
|
637
|
+
* normalization and the `config()`-hook `define` (which runs before the build context exists).
|
|
638
|
+
*/
|
|
639
|
+
function resolveBasePathname(userOpts, viteBasePath) {
|
|
640
|
+
let basePathname = typeof userOpts?.baseUrl === "string" ? userOpts.baseUrl : typeof userOpts?.basePathname === "string" ? userOpts.basePathname : viteBasePath || "/";
|
|
641
|
+
if (!basePathname.endsWith("/")) basePathname = ensureSlash(basePathname);
|
|
642
|
+
return new URL(basePathname, "https://qwik.dev/").pathname;
|
|
643
|
+
}
|
|
605
644
|
function normalizeOptions(rootDir, viteBasePath, userOpts) {
|
|
606
645
|
if (!(viteBasePath.startsWith("/") && viteBasePath.endsWith("/"))) {
|
|
607
646
|
console.error(`warning: vite's config.base must begin and end with /. This will be an error in v2. If you have a valid use case, please open an issue.`);
|
|
@@ -614,47 +653,13 @@ function normalizeOptions(rootDir, viteBasePath, userOpts) {
|
|
|
614
653
|
if (typeof opts.serverPluginsDir !== "string") opts.serverPluginsDir = opts.routesDir;
|
|
615
654
|
else if (!isAbsolute(opts.serverPluginsDir)) opts.serverPluginsDir = resolve(rootDir, opts.serverPluginsDir);
|
|
616
655
|
opts.serverPluginsDir = normalizePath$1(opts.serverPluginsDir);
|
|
617
|
-
if (typeof opts.baseUrl
|
|
618
|
-
|
|
619
|
-
if (!opts.basePathname.endsWith("/")) {
|
|
620
|
-
console.error(`Warning: qwik-router plugin basePathname must end with /. This will be an error in v2`);
|
|
621
|
-
opts.basePathname = ensureSlash(opts.basePathname);
|
|
622
|
-
}
|
|
623
|
-
opts.basePathname = new URL(opts.basePathname, "https://qwik.dev/").pathname;
|
|
656
|
+
if (typeof opts.baseUrl !== "string" && typeof opts.basePathname === "string" && !opts.basePathname.endsWith("/")) console.error(`Warning: qwik-router plugin basePathname must end with /. This will be an error in v2`);
|
|
657
|
+
opts.basePathname = resolveBasePathname(userOpts, viteBasePath);
|
|
624
658
|
opts.mdx = opts.mdx || {};
|
|
625
659
|
opts.platform = opts.platform || {};
|
|
626
660
|
if (opts.strictLoaders === void 0) opts.strictLoaders = true;
|
|
627
661
|
return opts;
|
|
628
662
|
}
|
|
629
|
-
function createBuildContext(rootDir, viteBasePath, userOpts, target, dynamicImports) {
|
|
630
|
-
return {
|
|
631
|
-
rootDir: normalizePath$1(rootDir),
|
|
632
|
-
opts: normalizeOptions(rootDir, viteBasePath, userOpts),
|
|
633
|
-
routeTrie: {
|
|
634
|
-
_files: [],
|
|
635
|
-
children: /* @__PURE__ */ new Map()
|
|
636
|
-
},
|
|
637
|
-
routes: [],
|
|
638
|
-
serverPlugins: [],
|
|
639
|
-
layouts: [],
|
|
640
|
-
entries: [],
|
|
641
|
-
serviceWorkers: [],
|
|
642
|
-
menus: [],
|
|
643
|
-
diagnostics: [],
|
|
644
|
-
frontmatter: /* @__PURE__ */ new Map(),
|
|
645
|
-
target: target || "ssr",
|
|
646
|
-
dynamicImports: target === "client" || !!dynamicImports,
|
|
647
|
-
isDirty: true,
|
|
648
|
-
activeBuild: null
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
function parseFrontmatterAttrs(yaml) {
|
|
652
|
-
if (typeof yaml === "string") {
|
|
653
|
-
yaml = yaml.trim();
|
|
654
|
-
if (yaml !== "") return parse(yaml);
|
|
655
|
-
}
|
|
656
|
-
return null;
|
|
657
|
-
}
|
|
658
663
|
function parseFrontmatter(ctx) {
|
|
659
664
|
return (mdast, vfile) => {
|
|
660
665
|
const attrs = {};
|
|
@@ -665,6 +670,13 @@ function parseFrontmatter(ctx) {
|
|
|
665
670
|
if (Object.keys(attrs).length > 0) ctx.frontmatter.set(normalizePath$1(vfile.path), attrs);
|
|
666
671
|
};
|
|
667
672
|
}
|
|
673
|
+
function parseFrontmatterAttrs(yaml) {
|
|
674
|
+
if (typeof yaml === "string") {
|
|
675
|
+
yaml = yaml.trim();
|
|
676
|
+
if (yaml !== "") return parse(yaml);
|
|
677
|
+
}
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
668
680
|
var metaNames = {
|
|
669
681
|
author: true,
|
|
670
682
|
creator: true,
|
|
@@ -720,17 +732,39 @@ function frontmatterAttrsToDocumentHead(attrs) {
|
|
|
720
732
|
}
|
|
721
733
|
return null;
|
|
722
734
|
}
|
|
723
|
-
function
|
|
735
|
+
function rehypeSlug() {
|
|
724
736
|
return (ast) => {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
});
|
|
733
|
-
};
|
|
737
|
+
const mdast = ast;
|
|
738
|
+
const slugs = new Slugger();
|
|
739
|
+
visit(mdast, "element", (node) => {
|
|
740
|
+
if (headingRank(node) && node.properties) {
|
|
741
|
+
const text = toString(node);
|
|
742
|
+
if (!hasProperty(node, "id")) node.properties.id = slugs.slug(text);
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
function rehypePage(ctx) {
|
|
748
|
+
return (ast, vfile) => {
|
|
749
|
+
const mdast = ast;
|
|
750
|
+
const sourcePath = normalizePath$1(vfile.path);
|
|
751
|
+
updateContentLinks(mdast, ctx.opts, sourcePath);
|
|
752
|
+
exportFrontmatter(ctx, mdast, sourcePath);
|
|
753
|
+
exportContentHead(ctx, mdast, sourcePath);
|
|
754
|
+
exportContentHeadings(mdast);
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function renameClassname() {
|
|
758
|
+
return (ast) => {
|
|
759
|
+
visit(ast, "element", (node) => {
|
|
760
|
+
if (node.properties) {
|
|
761
|
+
if (node.properties.className) {
|
|
762
|
+
node.properties.class = node.properties.className;
|
|
763
|
+
node.properties.className = void 0;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
};
|
|
734
768
|
}
|
|
735
769
|
function wrapTableWithDiv() {
|
|
736
770
|
return (ast) => {
|
|
@@ -756,6 +790,30 @@ function updateContentLinks(mdast, opts, sourcePath) {
|
|
|
756
790
|
}
|
|
757
791
|
});
|
|
758
792
|
}
|
|
793
|
+
function exportFrontmatter(ctx, mdast, sourcePath) {
|
|
794
|
+
createExport(mdast, "frontmatter", ctx.frontmatter.get(sourcePath));
|
|
795
|
+
}
|
|
796
|
+
function exportContentHead(ctx, mdast, sourcePath) {
|
|
797
|
+
const head = frontmatterAttrsToDocumentHead(ctx.frontmatter.get(sourcePath));
|
|
798
|
+
if (head) createExport(mdast, "head", head);
|
|
799
|
+
}
|
|
800
|
+
function exportContentHeadings(mdast) {
|
|
801
|
+
const headings = [];
|
|
802
|
+
visit(mdast, "element", (node) => {
|
|
803
|
+
const level = headingRank(node);
|
|
804
|
+
if (level && node.properties) {
|
|
805
|
+
if (hasProperty(node, "id")) {
|
|
806
|
+
const text = toString(node);
|
|
807
|
+
headings.push({
|
|
808
|
+
text,
|
|
809
|
+
id: node.properties.id,
|
|
810
|
+
level
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
if (headings.length > 0) createExport(mdast, "headings", headings);
|
|
816
|
+
}
|
|
759
817
|
function createExport(mdast, identifierName, val) {
|
|
760
818
|
const mdxjsEsm = {
|
|
761
819
|
type: "mdxjsEsm",
|
|
@@ -785,69 +843,11 @@ function createExport(mdast, identifierName, val) {
|
|
|
785
843
|
};
|
|
786
844
|
mdast.children.unshift(mdxjsEsm);
|
|
787
845
|
}
|
|
788
|
-
function exportFrontmatter(ctx, mdast, sourcePath) {
|
|
789
|
-
createExport(mdast, "frontmatter", ctx.frontmatter.get(sourcePath));
|
|
790
|
-
}
|
|
791
|
-
function exportContentHead(ctx, mdast, sourcePath) {
|
|
792
|
-
const head = frontmatterAttrsToDocumentHead(ctx.frontmatter.get(sourcePath));
|
|
793
|
-
if (head) createExport(mdast, "head", head);
|
|
794
|
-
}
|
|
795
846
|
var own = {}.hasOwnProperty;
|
|
796
847
|
function hasProperty(node, propName) {
|
|
797
848
|
const value = propName && node && typeof node === "object" && node.type === "element" && node.properties && own.call(node.properties, propName) && node.properties[propName];
|
|
798
849
|
return value != null && value !== false;
|
|
799
850
|
}
|
|
800
|
-
function rehypeSlug() {
|
|
801
|
-
return (ast) => {
|
|
802
|
-
const mdast = ast;
|
|
803
|
-
const slugs = new Slugger();
|
|
804
|
-
visit(mdast, "element", (node) => {
|
|
805
|
-
if (headingRank(node) && node.properties) {
|
|
806
|
-
const text = toString(node);
|
|
807
|
-
if (!hasProperty(node, "id")) node.properties.id = slugs.slug(text);
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function exportContentHeadings(mdast) {
|
|
813
|
-
const headings = [];
|
|
814
|
-
visit(mdast, "element", (node) => {
|
|
815
|
-
const level = headingRank(node);
|
|
816
|
-
if (level && node.properties) {
|
|
817
|
-
if (hasProperty(node, "id")) {
|
|
818
|
-
const text = toString(node);
|
|
819
|
-
headings.push({
|
|
820
|
-
text,
|
|
821
|
-
id: node.properties.id,
|
|
822
|
-
level
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
});
|
|
827
|
-
if (headings.length > 0) createExport(mdast, "headings", headings);
|
|
828
|
-
}
|
|
829
|
-
function rehypePage(ctx) {
|
|
830
|
-
return (ast, vfile) => {
|
|
831
|
-
const mdast = ast;
|
|
832
|
-
const sourcePath = normalizePath$1(vfile.path);
|
|
833
|
-
updateContentLinks(mdast, ctx.opts, sourcePath);
|
|
834
|
-
exportFrontmatter(ctx, mdast, sourcePath);
|
|
835
|
-
exportContentHead(ctx, mdast, sourcePath);
|
|
836
|
-
exportContentHeadings(mdast);
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
|
-
function syntaxHighlight(node, lang) {
|
|
840
|
-
const code = toString(node);
|
|
841
|
-
const result = refractor.highlight(code, lang);
|
|
842
|
-
if (result && Array.isArray(node.children)) node.children = result.children;
|
|
843
|
-
}
|
|
844
|
-
function getLanguage(className) {
|
|
845
|
-
if (typeof className === "string") {
|
|
846
|
-
className = className.toLowerCase();
|
|
847
|
-
if (className.startsWith("language-")) return className.slice(9);
|
|
848
|
-
}
|
|
849
|
-
return null;
|
|
850
|
-
}
|
|
851
851
|
function rehypeSyntaxHighlight() {
|
|
852
852
|
refractor.register(tsxLang);
|
|
853
853
|
return async (ast) => {
|
|
@@ -865,6 +865,18 @@ function rehypeSyntaxHighlight() {
|
|
|
865
865
|
});
|
|
866
866
|
};
|
|
867
867
|
}
|
|
868
|
+
function syntaxHighlight(node, lang) {
|
|
869
|
+
const code = toString(node);
|
|
870
|
+
const result = refractor.highlight(code, lang);
|
|
871
|
+
if (result && Array.isArray(node.children)) node.children = result.children;
|
|
872
|
+
}
|
|
873
|
+
function getLanguage(className) {
|
|
874
|
+
if (typeof className === "string") {
|
|
875
|
+
className = className.toLowerCase();
|
|
876
|
+
if (className.startsWith("language-")) return className.slice(9);
|
|
877
|
+
}
|
|
878
|
+
return null;
|
|
879
|
+
}
|
|
868
880
|
async function createMdxTransformer(ctx) {
|
|
869
881
|
const { compile } = await import("@mdx-js/mdx");
|
|
870
882
|
const { default: remarkFrontmatter } = await import("remark-frontmatter");
|
|
@@ -962,118 +974,130 @@ function getImportPath(importPath) {
|
|
|
962
974
|
if (lowerCasePath.endsWith(".ts")) return importPath.slice(0, importPath.length - 3);
|
|
963
975
|
return importPath;
|
|
964
976
|
}
|
|
965
|
-
/** Check if a build trie key is a group directory name like `(common)` */
|
|
977
|
+
/** Check if a build trie key is a group directory name like `(common)` */
|
|
978
|
+
function isGroupKey(key) {
|
|
966
979
|
return key.charCodeAt(0) === 40;
|
|
967
980
|
}
|
|
968
|
-
function collectFiles(node, cb) {
|
|
969
|
-
for (const file of node._files) cb(file, node);
|
|
970
|
-
for (const child of node.children.values()) collectFiles(child, cb);
|
|
971
|
-
}
|
|
972
981
|
/**
|
|
973
|
-
*
|
|
974
|
-
* default layouts above it.
|
|
982
|
+
* Serialize the build trie into JS code.
|
|
975
983
|
*
|
|
976
|
-
*
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
984
|
+
* Emits:
|
|
985
|
+
*
|
|
986
|
+
* - Layout imports and lazy loaders
|
|
987
|
+
* - Route/page imports and lazy loaders
|
|
988
|
+
* - Menu imports and lazy loaders
|
|
989
|
+
* - The route trie object literal with _L, _I, _G, _B, _4, _E, _N, _P, _0, _9, _M
|
|
990
|
+
*/
|
|
991
|
+
function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
992
|
+
const includeEndpoints = isSSR;
|
|
993
|
+
const dynamicImports = ctx.dynamicImports;
|
|
994
|
+
const layoutIdMap = /* @__PURE__ */ new Map();
|
|
995
|
+
const routeIdMap = /* @__PURE__ */ new Map();
|
|
996
|
+
const menuIdMap = /* @__PURE__ */ new Map();
|
|
997
|
+
let layoutCount = 0;
|
|
998
|
+
let routeCount = 0;
|
|
999
|
+
let menuCount = 0;
|
|
1000
|
+
collectFiles(ctx.routeTrie, (file, _node) => {
|
|
1001
|
+
if (file.type === "layout") {
|
|
1002
|
+
const id = ctx.layouts.find((l) => l.filePath === file.filePath)?.id;
|
|
1003
|
+
if (id) {
|
|
1004
|
+
layoutIdMap.set(file.filePath, id);
|
|
1005
|
+
layoutCount++;
|
|
1006
|
+
}
|
|
1007
|
+
} else if (file.type === "route") {
|
|
1008
|
+
if (ctx.routes.find((r) => r.filePath === file.filePath)) routeCount++;
|
|
1009
|
+
} else if (file.type === "menu") {
|
|
1010
|
+
const id = createFileId(ctx.opts.routesDir, file.filePath);
|
|
1011
|
+
menuIdMap.set(file.filePath, id);
|
|
1012
|
+
menuCount++;
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
if (layoutCount > 0) {
|
|
1016
|
+
c.push(`\n/** Qwik Router Layouts (${layoutCount}) */`);
|
|
1017
|
+
for (const [filePath, id] of layoutIdMap) {
|
|
1018
|
+
const importPath = JSON.stringify(getImportPath(filePath));
|
|
1019
|
+
if (dynamicImports) c.push(`const ${id} = ()=>import(${importPath});`);
|
|
1020
|
+
else {
|
|
1021
|
+
esmImports.push(`import * as ${id}_ from ${importPath};`);
|
|
1022
|
+
c.push(`const ${id} = ()=>${id}_;`);
|
|
987
1023
|
}
|
|
988
|
-
} else if (layout.layoutName === "") {
|
|
989
|
-
result.unshift(layout);
|
|
990
|
-
if (layout.layoutType === "top") break;
|
|
991
1024
|
}
|
|
992
1025
|
}
|
|
993
|
-
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (layoutName) return `[ ${[...resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, layoutName).map((l) => l.id), loaderExpr].join(", ")} ]`;
|
|
1002
|
-
return loaderExpr;
|
|
1003
|
-
}
|
|
1004
|
-
function getClientRouteBundleNames(qwikPlugin, r) {
|
|
1005
|
-
const bundlesNames = [];
|
|
1006
|
-
const manifest = qwikPlugin.api.getManifest();
|
|
1007
|
-
if (manifest) {
|
|
1008
|
-
const manifestBundleNames = Object.keys(manifest.bundles);
|
|
1009
|
-
const addRouteFile = (filePath) => {
|
|
1010
|
-
filePath = removeExtension(filePath);
|
|
1011
|
-
for (const bundleName of manifestBundleNames) {
|
|
1012
|
-
const bundle = manifest.bundles[bundleName];
|
|
1013
|
-
if (bundle.origins) for (const bundleOrigin of bundle.origins) {
|
|
1014
|
-
const originPath = removeExtension(bundleOrigin);
|
|
1015
|
-
if (filePath.endsWith(originPath)) {
|
|
1016
|
-
if (!bundlesNames.includes(bundleName)) bundlesNames.push(bundleName);
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1026
|
+
if (menuCount > 0) {
|
|
1027
|
+
c.push(`\n/** Qwik Router Menus (${menuCount}) */`);
|
|
1028
|
+
for (const [filePath, id] of menuIdMap) {
|
|
1029
|
+
const importPath = JSON.stringify(getImportPath(filePath));
|
|
1030
|
+
if (dynamicImports) c.push(`const ${id} = ()=>import(${importPath});`);
|
|
1031
|
+
else {
|
|
1032
|
+
esmImports.push(`import * as ${id}_ from ${importPath};`);
|
|
1033
|
+
c.push(`const ${id} = ()=>${id}_;`);
|
|
1019
1034
|
}
|
|
1020
|
-
}
|
|
1021
|
-
for (const layout of r.layouts) addRouteFile(layout.filePath);
|
|
1022
|
-
addRouteFile(r.filePath);
|
|
1035
|
+
}
|
|
1023
1036
|
}
|
|
1024
|
-
|
|
1037
|
+
c.push(`\n/** Qwik Router Routes (${routeCount}) */`);
|
|
1038
|
+
for (const route of ctx.routes) if (isPageExt(route.ext)) {
|
|
1039
|
+
if (serverExcludePaths?.has(route.filePath)) continue;
|
|
1040
|
+
const importPath = getImportPath(route.filePath);
|
|
1041
|
+
let loaderExpr;
|
|
1042
|
+
if (dynamicImports) loaderExpr = `()=>import(${JSON.stringify(importPath)})`;
|
|
1043
|
+
else {
|
|
1044
|
+
esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
|
|
1045
|
+
loaderExpr = `()=>${route.id}`;
|
|
1046
|
+
}
|
|
1047
|
+
routeIdMap.set(route.filePath, loaderExpr);
|
|
1048
|
+
} else if (includeEndpoints && isModuleExt(route.ext)) {
|
|
1049
|
+
const importPath = getImportPath(route.filePath);
|
|
1050
|
+
esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
|
|
1051
|
+
routeIdMap.set(route.filePath, `()=>${route.id}`);
|
|
1052
|
+
}
|
|
1053
|
+
const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap, isSSR, "", loadersByFile, routeLoaderSourceFiles);
|
|
1054
|
+
const baseSegments = ctx.opts.basePathname.split("/").filter((s) => s.length > 0);
|
|
1055
|
+
let routesExpr = trieStr;
|
|
1056
|
+
for (let j = baseSegments.length - 1; j >= 0; j--) routesExpr = `{ ${JSON.stringify(baseSegments[j])}: ${routesExpr} }`;
|
|
1057
|
+
c.push(`export const routes = ${routesExpr};`);
|
|
1025
1058
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1059
|
+
function collectFiles(node, cb) {
|
|
1060
|
+
for (const file of node._files) cb(file, node);
|
|
1061
|
+
for (const child of node.children.values()) collectFiles(child, cb);
|
|
1062
|
+
}
|
|
1063
|
+
/** Serialize a BuildTrieNode using the resolved route layout chains. */
|
|
1064
|
+
function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap, isSSR, indent, loadersByFile, routeLoaderSourceFiles) {
|
|
1032
1065
|
const lines = [];
|
|
1033
1066
|
const nextIndent = indent + " ";
|
|
1034
1067
|
if (node._P) lines.push(`${nextIndent}_P: ${JSON.stringify(node._P)},`);
|
|
1035
1068
|
if (node._0) lines.push(`${nextIndent}_0: ${JSON.stringify(node._0)},`);
|
|
1036
1069
|
if (node._9) lines.push(`${nextIndent}_9: ${JSON.stringify(node._9)},`);
|
|
1037
|
-
if (node._G != null) lines.push(`${nextIndent}_G: ${JSON.stringify(node._G)},`);
|
|
1070
|
+
if (node._G != null) lines.push(`${nextIndent}_G: ${JSON.stringify(ctx.opts.basePathname + node._G)},`);
|
|
1038
1071
|
let layoutExpr;
|
|
1039
1072
|
let indexExpr;
|
|
1040
1073
|
let errorExpr;
|
|
1041
1074
|
let notFoundExpr;
|
|
1042
1075
|
let menuExpr;
|
|
1043
1076
|
let bundleRoute;
|
|
1044
|
-
|
|
1077
|
+
let pageLayouts;
|
|
1045
1078
|
for (const file of node._files) if (file.type === "menu") {
|
|
1046
1079
|
const menuId = menuIdMap.get(file.filePath);
|
|
1047
1080
|
if (menuId) menuExpr = menuId;
|
|
1048
1081
|
} else if (file.type === "layout") {
|
|
1049
1082
|
const layoutId = layoutIdMap.get(file.filePath);
|
|
1050
1083
|
if (layoutId) {
|
|
1051
|
-
|
|
1052
|
-
let layoutType = "nested";
|
|
1053
|
-
if (extlessName.endsWith("!")) {
|
|
1054
|
-
layoutType = "top";
|
|
1055
|
-
extlessName = extlessName.slice(0, -1);
|
|
1056
|
-
}
|
|
1057
|
-
const layoutName = extlessName.startsWith("layout-") ? extlessName.slice(7) : "";
|
|
1058
|
-
nodeLayouts.push({
|
|
1059
|
-
id: layoutId,
|
|
1060
|
-
layoutName,
|
|
1061
|
-
layoutType
|
|
1062
|
-
});
|
|
1063
|
-
if (layoutName === "") layoutExpr = layoutId;
|
|
1084
|
+
if (file.extlessName === "layout" || file.extlessName === "layout!") layoutExpr = layoutId;
|
|
1064
1085
|
}
|
|
1065
1086
|
}
|
|
1066
1087
|
for (const file of node._files) {
|
|
1067
1088
|
if (file.type !== "route") continue;
|
|
1068
1089
|
const loaderExpr = routeIdMap.get(file.filePath);
|
|
1069
1090
|
if (!loaderExpr) continue;
|
|
1070
|
-
const
|
|
1091
|
+
const route = ctx.routes.find((route) => route.filePath === file.filePath);
|
|
1092
|
+
const expr = buildLoaderChainExpr(file.extlessName, loaderExpr, route?.layouts ?? []);
|
|
1071
1093
|
const boundary = errorBoundaryName(file.extlessName);
|
|
1072
1094
|
if (boundary === "404") notFoundExpr = expr;
|
|
1073
1095
|
else if (boundary === "error") errorExpr = expr;
|
|
1074
1096
|
else {
|
|
1075
1097
|
indexExpr = expr;
|
|
1076
|
-
|
|
1098
|
+
const { layoutName, layoutStop } = parseRouteIndexName(file.extlessName);
|
|
1099
|
+
pageLayouts = layoutStop || layoutName ? route?.layouts ?? [] : void 0;
|
|
1100
|
+
bundleRoute = route;
|
|
1077
1101
|
}
|
|
1078
1102
|
}
|
|
1079
1103
|
if (layoutExpr) lines.push(`${nextIndent}_L: ${layoutExpr},`);
|
|
@@ -1084,29 +1108,25 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1084
1108
|
if (bundleNames.length > 0) lines.push(`${nextIndent}_B: ${JSON.stringify(bundleNames)},`);
|
|
1085
1109
|
}
|
|
1086
1110
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
}
|
|
1101
|
-
const placeholder = `__LOADERS:${routeLoaderFiles.join("|")}__`;
|
|
1102
|
-
lines.push(`${nextIndent}_R: ${JSON.stringify(placeholder)},`);
|
|
1103
|
-
}
|
|
1111
|
+
const pluginFiles = ctx.serverPlugins.map((plugin) => plugin.filePath);
|
|
1112
|
+
const layoutFiles = node._files.filter((file) => file.type === "layout" && !file.extlessName.startsWith("layout-")).map((file) => file.filePath);
|
|
1113
|
+
if (node === ctx.routeTrie) layoutFiles.push(...pluginFiles);
|
|
1114
|
+
const pageFiles = bundleRoute ? [bundleRoute.filePath] : [];
|
|
1115
|
+
if (pageLayouts) pageFiles.push(...pageLayouts.map((layout) => layout.filePath), ...pluginFiles);
|
|
1116
|
+
for (const [field, routeFiles] of [["_R", layoutFiles], ["_D", pageFiles]]) {
|
|
1117
|
+
const routeLoaderFiles = [...new Set(routeFiles.flatMap((path) => [path, ...routeLoaderSourceFiles?.get(path) ?? []]))];
|
|
1118
|
+
if (routeLoaderFiles.length === 0) continue;
|
|
1119
|
+
if (loadersByFile) {
|
|
1120
|
+
const hashes = routeLoaderFiles.flatMap((filePath) => loadersByFile.get(normalizePathKey(filePath)) ?? []);
|
|
1121
|
+
if (hashes.length > 0) lines.push(`${nextIndent}${field}: ${JSON.stringify(hashes)},`);
|
|
1122
|
+
} else {
|
|
1123
|
+
const placeholder = `__LOADERS:${routeLoaderFiles.join("|")}__`;
|
|
1124
|
+
lines.push(`${nextIndent}${field}: ${JSON.stringify(placeholder)},`);
|
|
1104
1125
|
}
|
|
1105
1126
|
}
|
|
1106
1127
|
if (errorExpr) lines.push(`${nextIndent}_E: ${errorExpr},`);
|
|
1107
1128
|
if (notFoundExpr) lines.push(`${nextIndent}_4: ${notFoundExpr},`);
|
|
1108
1129
|
if (menuExpr) lines.push(`${nextIndent}_N: ${menuExpr},`);
|
|
1109
|
-
const childAncestors = [...ancestorLayouts, ...nodeLayouts];
|
|
1110
1130
|
const groupChildren = [];
|
|
1111
1131
|
const regularChildren = [];
|
|
1112
1132
|
for (const [key, child] of node.children) if (isGroupKey(key)) groupChildren.push([key, child]);
|
|
@@ -1115,13 +1135,13 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1115
1135
|
groupChildren.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1116
1136
|
const groupStrs = [];
|
|
1117
1137
|
for (const [_key, child] of groupChildren) {
|
|
1118
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap,
|
|
1138
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1119
1139
|
if (childStr !== "{}") groupStrs.push(childStr);
|
|
1120
1140
|
}
|
|
1121
1141
|
if (groupStrs.length > 0) lines.push(`${nextIndent}_M: [${groupStrs.join(", ")}],`);
|
|
1122
1142
|
}
|
|
1123
1143
|
for (const [key, child] of regularChildren) {
|
|
1124
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap,
|
|
1144
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1125
1145
|
if (childStr !== "{}") {
|
|
1126
1146
|
const keyStr = JSON.stringify(key);
|
|
1127
1147
|
lines.push(`${nextIndent}${keyStr}: ${childStr},`);
|
|
@@ -1131,81 +1151,35 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1131
1151
|
return `{\n${lines.join("\n")}\n${indent}}`;
|
|
1132
1152
|
}
|
|
1133
1153
|
/**
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
const
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
} else if (file.type === "route") {
|
|
1159
|
-
if (ctx.routes.find((r) => r.filePath === file.filePath)) routeCount++;
|
|
1160
|
-
} else if (file.type === "menu") {
|
|
1161
|
-
const id = createFileId(ctx.opts.routesDir, file.filePath);
|
|
1162
|
-
menuIdMap.set(file.filePath, id);
|
|
1163
|
-
menuCount++;
|
|
1164
|
-
}
|
|
1165
|
-
});
|
|
1166
|
-
if (layoutCount > 0) {
|
|
1167
|
-
c.push(`\n/** Qwik Router Layouts (${layoutCount}) */`);
|
|
1168
|
-
for (const [filePath, id] of layoutIdMap) {
|
|
1169
|
-
const importPath = JSON.stringify(getImportPath(filePath));
|
|
1170
|
-
if (dynamicImports) c.push(`const ${id} = ()=>import(${importPath});`);
|
|
1171
|
-
else {
|
|
1172
|
-
esmImports.push(`import * as ${id}_ from ${importPath};`);
|
|
1173
|
-
c.push(`const ${id} = ()=>${id}_;`);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
if (menuCount > 0) {
|
|
1178
|
-
c.push(`\n/** Qwik Router Menus (${menuCount}) */`);
|
|
1179
|
-
for (const [filePath, id] of menuIdMap) {
|
|
1180
|
-
const importPath = JSON.stringify(getImportPath(filePath));
|
|
1181
|
-
if (dynamicImports) c.push(`const ${id} = ()=>import(${importPath});`);
|
|
1182
|
-
else {
|
|
1183
|
-
esmImports.push(`import * as ${id}_ from ${importPath};`);
|
|
1184
|
-
c.push(`const ${id} = ()=>${id}_;`);
|
|
1154
|
+
* The `_I`/`_E`/`_4` loader expression: a bare loader (runtime prepends gathered layouts), or an
|
|
1155
|
+
* override chain for `!` (layout stop) / `@name` (named layout).
|
|
1156
|
+
*/
|
|
1157
|
+
function buildLoaderChainExpr(extlessName, loaderExpr, layouts) {
|
|
1158
|
+
const { layoutName, layoutStop } = parseRouteIndexName(extlessName);
|
|
1159
|
+
if (layoutStop || layoutName) return `[ ${[...layouts.map((layout) => layout.id), loaderExpr].join(", ")} ]`;
|
|
1160
|
+
return loaderExpr;
|
|
1161
|
+
}
|
|
1162
|
+
function getClientRouteBundleNames(qwikPlugin, r) {
|
|
1163
|
+
const bundlesNames = [];
|
|
1164
|
+
const manifest = qwikPlugin.api.getManifest();
|
|
1165
|
+
if (manifest) {
|
|
1166
|
+
const manifestBundleNames = Object.keys(manifest.bundles);
|
|
1167
|
+
const addRouteFile = (filePath) => {
|
|
1168
|
+
filePath = removeExtension(filePath);
|
|
1169
|
+
for (const bundleName of manifestBundleNames) {
|
|
1170
|
+
const bundle = manifest.bundles[bundleName];
|
|
1171
|
+
if (bundle.origins) for (const bundleOrigin of bundle.origins) {
|
|
1172
|
+
const originPath = removeExtension(bundleOrigin);
|
|
1173
|
+
if (filePath.endsWith(originPath)) {
|
|
1174
|
+
if (!bundlesNames.includes(bundleName)) bundlesNames.push(bundleName);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1185
1177
|
}
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
for (const route of ctx.routes) if (isPageExt(route.ext)) {
|
|
1190
|
-
if (serverExcludePaths?.has(route.filePath)) continue;
|
|
1191
|
-
const importPath = getImportPath(route.filePath);
|
|
1192
|
-
let loaderExpr;
|
|
1193
|
-
if (dynamicImports) loaderExpr = `()=>import(${JSON.stringify(importPath)})`;
|
|
1194
|
-
else {
|
|
1195
|
-
esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
|
|
1196
|
-
loaderExpr = `()=>${route.id}`;
|
|
1197
|
-
}
|
|
1198
|
-
routeIdMap.set(route.filePath, loaderExpr);
|
|
1199
|
-
} else if (includeEndpoints && isModuleExt(route.ext)) {
|
|
1200
|
-
const importPath = getImportPath(route.filePath);
|
|
1201
|
-
esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
|
|
1202
|
-
routeIdMap.set(route.filePath, `()=>${route.id}`);
|
|
1178
|
+
};
|
|
1179
|
+
for (const layout of r.layouts) addRouteFile(layout.filePath);
|
|
1180
|
+
addRouteFile(r.filePath);
|
|
1203
1181
|
}
|
|
1204
|
-
|
|
1205
|
-
const baseSegments = ctx.opts.basePathname.split("/").filter((s) => s.length > 0);
|
|
1206
|
-
let routesExpr = trieStr;
|
|
1207
|
-
for (let j = baseSegments.length - 1; j >= 0; j--) routesExpr = `{ ${JSON.stringify(baseSegments[j])}: ${routesExpr} }`;
|
|
1208
|
-
c.push(`export const routes = ${routesExpr};`);
|
|
1182
|
+
return bundlesNames;
|
|
1209
1183
|
}
|
|
1210
1184
|
function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
|
|
1211
1185
|
c.push(`\n/** Qwik Router ServerPlugins (${ctx.serverPlugins.length}) */`);
|
|
@@ -1219,24 +1193,23 @@ function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
|
|
|
1219
1193
|
}
|
|
1220
1194
|
c.push(`];`);
|
|
1221
1195
|
}
|
|
1222
|
-
/** Generates the Qwik Router Config runtime code */
|
|
1196
|
+
/** Generates the Qwik Router Config runtime code */
|
|
1197
|
+
function generateQwikRouterConfig(ctx, qwikPlugin, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
1223
1198
|
const esmImports = [];
|
|
1224
1199
|
const c = [];
|
|
1225
1200
|
c.push(`\n/** Qwik Router Config */`);
|
|
1226
1201
|
c.push(`\nimport { isDev } from '@qwik.dev/core/build';`);
|
|
1227
|
-
if (isSSR) esmImports.push(`import 'virtual:qwik-router-server-fns';`);
|
|
1202
|
+
if (isSSR) esmImports.push(`import { importEagerModules } from 'virtual:qwik-router-server-fns';`, `export { importEagerModules } from 'virtual:qwik-router-server-fns';`);
|
|
1228
1203
|
createServerPlugins(ctx, qwikPlugin, c, esmImports, isSSR);
|
|
1229
1204
|
createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles);
|
|
1230
1205
|
createEntries(ctx, c);
|
|
1231
1206
|
c.push(`export const trailingSlash = ${JSON.stringify(!globalThis.__NO_TRAILING_SLASH__)};`);
|
|
1232
1207
|
c.push(`export const basePathname = ${JSON.stringify(ctx.opts.basePathname)};`);
|
|
1233
1208
|
c.push(`export const cacheModules = !isDev;`);
|
|
1234
|
-
c.push(`export default { routes, serverPlugins, trailingSlash, basePathname, cacheModules };`);
|
|
1209
|
+
if (isSSR) c.push(`export default { routes, serverPlugins, trailingSlash, basePathname, cacheModules, importEagerModules };`);
|
|
1210
|
+
else c.push(`export default { routes, serverPlugins, trailingSlash, basePathname, cacheModules };`);
|
|
1235
1211
|
return esmImports.join("\n") + c.join("\n");
|
|
1236
1212
|
}
|
|
1237
|
-
var SW_UNREGISTER = `
|
|
1238
|
-
"serviceWorker"in navigator&&navigator.serviceWorker.getRegistrations().then(r=>{for(const e of r){const c='__url'.split("/").pop();e.active?.scriptURL.endsWith(c||"service-worker.js")&&e.unregister().catch(console.error)}}),"caches"in window&&caches.keys().then(r=>{const e=r.find(c=>c.startsWith("QwikBuild"));e&&caches.delete(e).catch(console.error)}).catch(console.error)
|
|
1239
|
-
`;
|
|
1240
1213
|
function generateServiceWorkerRegister(ctx, swRegister) {
|
|
1241
1214
|
let swReg;
|
|
1242
1215
|
let swUrl = "/service-worker.js";
|
|
@@ -1249,10 +1222,14 @@ function generateServiceWorkerRegister(ctx, swRegister) {
|
|
|
1249
1222
|
swReg = swReg.replace("__url", swUrl);
|
|
1250
1223
|
return `export default ${JSON.stringify(swReg)};`;
|
|
1251
1224
|
}
|
|
1225
|
+
var SW_UNREGISTER = `
|
|
1226
|
+
"serviceWorker"in navigator&&navigator.serviceWorker.getRegistrations().then(r=>{for(const e of r){const c='__url'.split("/").pop();e.active?.scriptURL.endsWith(c||"service-worker.js")&&e.unregister().catch(console.error)}}),"caches"in window&&caches.keys().then(r=>{const e=r.find(c=>c.startsWith("QwikBuild"));e&&caches.delete(e).catch(console.error)}).catch(console.error)
|
|
1227
|
+
`;
|
|
1252
1228
|
/**
|
|
1253
1229
|
* Non-GET RouteModule handlers keep a route server-side (onGet is served statically). Typed against
|
|
1254
1230
|
* keyof RouteModule so a renamed/added handler fails to compile until classified.
|
|
1255
|
-
*/
|
|
1231
|
+
*/
|
|
1232
|
+
var NON_GET_HANDLERS = /* @__PURE__ */ new Set([
|
|
1256
1233
|
"onRequest",
|
|
1257
1234
|
"onPost",
|
|
1258
1235
|
"onPut",
|
|
@@ -1266,11 +1243,13 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1266
1243
|
* Imports tying a route to the server — loaders, actions, and server$ (which POSTs to the route's
|
|
1267
1244
|
* own URL). Matched on the import statement (the optimizer's ctxName isn't available
|
|
1268
1245
|
* pre-transform); fail-safe, so a stray match only keeps a route.
|
|
1269
|
-
*/
|
|
1246
|
+
*/
|
|
1247
|
+
var SERVER_QRL = /\b(?:routeLoader|routeAction|globalAction|server)(?:\$|Qrl)/;
|
|
1270
1248
|
/**
|
|
1271
1249
|
* True when the module exports no non-GET handler and imports no loader/action/server$ from the
|
|
1272
1250
|
* router. Pure (no I/O) for direct unit testing.
|
|
1273
|
-
*/
|
|
1251
|
+
*/
|
|
1252
|
+
function isServerFreeSource(code) {
|
|
1274
1253
|
for (const e of findExports(code)) {
|
|
1275
1254
|
if (e.specifier) return false;
|
|
1276
1255
|
if ([...e.name ? [e.name] : [], ...e.names ?? []].some((n) => NON_GET_HANDLERS.has(n))) return false;
|
|
@@ -1279,28 +1258,13 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1279
1258
|
return true;
|
|
1280
1259
|
}
|
|
1281
1260
|
/**
|
|
1282
|
-
* Read + lex a module once, memoized by path. Returns the cached in-flight promise (not async) so
|
|
1283
|
-
* concurrent callers share one read; read/parse failure keeps the route.
|
|
1284
|
-
*/ function isFileServerFree(filePath, cache) {
|
|
1285
|
-
let pending = cache.get(filePath);
|
|
1286
|
-
if (!pending) {
|
|
1287
|
-
pending = readFile(filePath, "utf-8").then(isServerFreeSource).catch(() => false);
|
|
1288
|
-
cache.set(filePath, pending);
|
|
1289
|
-
}
|
|
1290
|
-
return pending;
|
|
1291
|
-
}
|
|
1292
|
-
/** The route's own module and every layout wrapping it must be free of server code. */ async function isRouteServerFree(route, cache) {
|
|
1293
|
-
if (!isMarkdownExt(route.ext) && !await isFileServerFree(route.filePath, cache)) return false;
|
|
1294
|
-
for (const layout of route.layouts) if (!await isFileServerFree(layout.filePath, cache)) return false;
|
|
1295
|
-
return true;
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
1261
|
* Route file paths to drop from the production server route plan — prerendered, static, server-free
|
|
1299
1262
|
* pages (own module and every layout) — so they tree-shake out of size-capped edge bundles.
|
|
1300
1263
|
* Candidates come from the SSG include/exclude; server surfaces are detected in route/layout source
|
|
1301
1264
|
* only. Fail-safe: dynamic routes, re-exports, and read errors keep the route. A loader/action
|
|
1302
1265
|
* route stays whole — stripping just its dead component needs optimizer segment data.
|
|
1303
|
-
*/
|
|
1266
|
+
*/
|
|
1267
|
+
async function getServerExcludedRoutes(ctx, ssg) {
|
|
1304
1268
|
const excluded = /* @__PURE__ */ new Set();
|
|
1305
1269
|
if (!ssg?.include?.length) return excluded;
|
|
1306
1270
|
const isPrerendered = createRouteTester(ctx.opts.basePathname, ssg.include, ssg.exclude);
|
|
@@ -1311,12 +1275,23 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1311
1275
|
}));
|
|
1312
1276
|
return excluded;
|
|
1313
1277
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1278
|
+
/** The route's own module and every layout wrapping it must be free of server code. */
|
|
1279
|
+
async function isRouteServerFree(route, cache) {
|
|
1280
|
+
if (!isMarkdownExt(route.ext) && !await isFileServerFree(route.filePath, cache)) return false;
|
|
1281
|
+
for (const layout of route.layouts) if (!await isFileServerFree(layout.filePath, cache)) return false;
|
|
1282
|
+
return true;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Read + lex a module once, memoized by path. Returns the cached in-flight promise (not async) so
|
|
1286
|
+
* concurrent callers share one read; read/parse failure keeps the route.
|
|
1287
|
+
*/
|
|
1288
|
+
function isFileServerFree(filePath, cache) {
|
|
1289
|
+
let pending = cache.get(filePath);
|
|
1290
|
+
if (!pending) {
|
|
1291
|
+
pending = readFile(filePath, "utf-8").then(isServerFreeSource).catch(() => false);
|
|
1292
|
+
cache.set(filePath, pending);
|
|
1293
|
+
}
|
|
1294
|
+
return pending;
|
|
1320
1295
|
}
|
|
1321
1296
|
function getRouteImports(routes, manifest) {
|
|
1322
1297
|
const result = {};
|
|
@@ -1338,13 +1313,13 @@ function getRouteImports(routes, manifest) {
|
|
|
1338
1313
|
}
|
|
1339
1314
|
return result;
|
|
1340
1315
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1316
|
+
function isBundlePartOfRoute(bundle, routeAndLayoutPaths) {
|
|
1317
|
+
if (!bundle.origins) return false;
|
|
1318
|
+
return bundle.origins.some((bundleOrigin) => {
|
|
1319
|
+
const originPath = removeExtension(bundleOrigin);
|
|
1320
|
+
return routeAndLayoutPaths.some((path) => path.endsWith(originPath));
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1348
1323
|
var findLocation = (e) => {
|
|
1349
1324
|
const stack = e.stack;
|
|
1350
1325
|
if (typeof stack === "string") {
|
|
@@ -1382,6 +1357,13 @@ var findLocation = (e) => {
|
|
|
1382
1357
|
}
|
|
1383
1358
|
}
|
|
1384
1359
|
};
|
|
1360
|
+
var safeParseInt = (nu) => {
|
|
1361
|
+
try {
|
|
1362
|
+
return parseInt(nu, 10);
|
|
1363
|
+
} catch {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1385
1367
|
var splitRE = /\r?\n/;
|
|
1386
1368
|
var range = 2;
|
|
1387
1369
|
function posToNumber(source, pos) {
|
|
@@ -1508,60 +1490,9 @@ function createImageJsxModule(pathId, params, userOpts) {
|
|
|
1508
1490
|
function createSvgJsxModule(attrs) {
|
|
1509
1491
|
return `export default p => <svg {...p} {...${JSON.stringify(attrs)}} />`;
|
|
1510
1492
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
const maybePrefixIdsPlugin = prefixIdsConfiguration !== false ? [{
|
|
1515
|
-
name: "prefixIds",
|
|
1516
|
-
params: prefixIdsConfiguration
|
|
1517
|
-
}] : [];
|
|
1518
|
-
const userPlugins = userOpts?.imageOptimization?.svgo?.plugins?.filter((plugin) => {
|
|
1519
|
-
if (plugin === "preset-default" || typeof plugin === "object" && plugin.name === "preset-default") {
|
|
1520
|
-
console.warn(`You are trying to use the preset-default SVGO plugin. This plugin is already included by default, you can customize it through the defaultPresetOverrides option.`);
|
|
1521
|
-
return false;
|
|
1522
|
-
}
|
|
1523
|
-
if (plugin === "prefixIds" || typeof plugin === "object" && plugin.name === "prefixIds") {
|
|
1524
|
-
console.warn(`You are trying to use the prefixIds SVGO plugin. This plugin is already included by default, you can customize it through the prefixIds option.`);
|
|
1525
|
-
return false;
|
|
1526
|
-
}
|
|
1527
|
-
return true;
|
|
1528
|
-
}) || [];
|
|
1529
|
-
const data = optimize(code, {
|
|
1530
|
-
floatPrecision: userOpts?.imageOptimization?.svgo?.floatPrecision,
|
|
1531
|
-
multipass: userOpts?.imageOptimization?.svgo?.multipass,
|
|
1532
|
-
path,
|
|
1533
|
-
plugins: [
|
|
1534
|
-
{
|
|
1535
|
-
name: "preset-default",
|
|
1536
|
-
params: { overrides: {
|
|
1537
|
-
removeViewBox: false,
|
|
1538
|
-
...userOpts?.imageOptimization?.svgo?.defaultPresetOverrides
|
|
1539
|
-
} }
|
|
1540
|
-
},
|
|
1541
|
-
{
|
|
1542
|
-
name: "customPluginName",
|
|
1543
|
-
fn: () => {
|
|
1544
|
-
return { element: { exit: (node) => {
|
|
1545
|
-
if (node.name === "svg") {
|
|
1546
|
-
node.name = "g";
|
|
1547
|
-
Object.assign(svgAttributes, node.attributes);
|
|
1548
|
-
node.attributes = {};
|
|
1549
|
-
}
|
|
1550
|
-
} } };
|
|
1551
|
-
}
|
|
1552
|
-
},
|
|
1553
|
-
...maybePrefixIdsPlugin,
|
|
1554
|
-
...userPlugins
|
|
1555
|
-
]
|
|
1556
|
-
}).data;
|
|
1557
|
-
svgAttributes.dangerouslySetInnerHTML = data.slice(3, -4);
|
|
1558
|
-
return {
|
|
1559
|
-
data,
|
|
1560
|
-
svgAttributes
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
/** @public */ function imagePlugin(userOpts) {
|
|
1564
|
-
return [import("vite-imagetools").then((_rawProps) => _rawProps.imagetools({
|
|
1493
|
+
/** @public */
|
|
1494
|
+
function imagePlugin(userOpts) {
|
|
1495
|
+
return [import("vite-imagetools").then(({ imagetools }) => imagetools({
|
|
1565
1496
|
exclude: [],
|
|
1566
1497
|
extendOutputFormats(builtins) {
|
|
1567
1498
|
const jsx = () => (metadatas) => {
|
|
@@ -1654,6 +1585,58 @@ function optimizeSvg({ code, path }, userOpts) {
|
|
|
1654
1585
|
}
|
|
1655
1586
|
}];
|
|
1656
1587
|
}
|
|
1588
|
+
function optimizeSvg({ code, path }, userOpts) {
|
|
1589
|
+
const svgAttributes = {};
|
|
1590
|
+
const prefixIdsConfiguration = userOpts?.imageOptimization?.svgo?.prefixIds;
|
|
1591
|
+
const maybePrefixIdsPlugin = prefixIdsConfiguration !== false ? [{
|
|
1592
|
+
name: "prefixIds",
|
|
1593
|
+
params: prefixIdsConfiguration
|
|
1594
|
+
}] : [];
|
|
1595
|
+
const userPlugins = userOpts?.imageOptimization?.svgo?.plugins?.filter((plugin) => {
|
|
1596
|
+
if (plugin === "preset-default" || typeof plugin === "object" && plugin.name === "preset-default") {
|
|
1597
|
+
console.warn(`You are trying to use the preset-default SVGO plugin. This plugin is already included by default, you can customize it through the defaultPresetOverrides option.`);
|
|
1598
|
+
return false;
|
|
1599
|
+
}
|
|
1600
|
+
if (plugin === "prefixIds" || typeof plugin === "object" && plugin.name === "prefixIds") {
|
|
1601
|
+
console.warn(`You are trying to use the prefixIds SVGO plugin. This plugin is already included by default, you can customize it through the prefixIds option.`);
|
|
1602
|
+
return false;
|
|
1603
|
+
}
|
|
1604
|
+
return true;
|
|
1605
|
+
}) || [];
|
|
1606
|
+
const data = optimize(code, {
|
|
1607
|
+
floatPrecision: userOpts?.imageOptimization?.svgo?.floatPrecision,
|
|
1608
|
+
multipass: userOpts?.imageOptimization?.svgo?.multipass,
|
|
1609
|
+
path,
|
|
1610
|
+
plugins: [
|
|
1611
|
+
{
|
|
1612
|
+
name: "preset-default",
|
|
1613
|
+
params: { overrides: {
|
|
1614
|
+
removeViewBox: false,
|
|
1615
|
+
...userOpts?.imageOptimization?.svgo?.defaultPresetOverrides
|
|
1616
|
+
} }
|
|
1617
|
+
},
|
|
1618
|
+
{
|
|
1619
|
+
name: "customPluginName",
|
|
1620
|
+
fn: () => {
|
|
1621
|
+
return { element: { exit: (node) => {
|
|
1622
|
+
if (node.name === "svg") {
|
|
1623
|
+
node.name = "g";
|
|
1624
|
+
Object.assign(svgAttributes, node.attributes);
|
|
1625
|
+
node.attributes = {};
|
|
1626
|
+
}
|
|
1627
|
+
} } };
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
...maybePrefixIdsPlugin,
|
|
1631
|
+
...userPlugins
|
|
1632
|
+
]
|
|
1633
|
+
}).data;
|
|
1634
|
+
svgAttributes.dangerouslySetInnerHTML = data.slice(3, -4);
|
|
1635
|
+
return {
|
|
1636
|
+
data,
|
|
1637
|
+
svgAttributes
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1657
1640
|
async function collectServerFnModuleIds(routingContext, resolvedVirtualId, pluginContext) {
|
|
1658
1641
|
const serverFnModules = /* @__PURE__ */ new Set();
|
|
1659
1642
|
const queuedModuleIds = /* @__PURE__ */ new Set();
|
|
@@ -1725,11 +1708,23 @@ function formatError(e) {
|
|
|
1725
1708
|
}
|
|
1726
1709
|
return e;
|
|
1727
1710
|
}
|
|
1711
|
+
var State = /* @__PURE__ */ function(State) {
|
|
1712
|
+
/** Collecting content until <body> is found */
|
|
1713
|
+
State[State["BUFFERING"] = 0] = "BUFFERING";
|
|
1714
|
+
/** Transforming the head portion */
|
|
1715
|
+
State[State["PROCESSING_HEAD"] = 1] = "PROCESSING_HEAD";
|
|
1716
|
+
/** Streaming transformed content until </body> */
|
|
1717
|
+
State[State["STREAMING_BODY"] = 2] = "STREAMING_BODY";
|
|
1718
|
+
/** Passing through content unchanged */
|
|
1719
|
+
State[State["PASSTHROUGH"] = 3] = "PASSTHROUGH";
|
|
1720
|
+
return State;
|
|
1721
|
+
}(State || {});
|
|
1728
1722
|
/**
|
|
1729
1723
|
* Patches a response object to intercept HTML streams and transform them using Vite's
|
|
1730
1724
|
* transformIndexHtml.
|
|
1731
|
-
*/
|
|
1732
|
-
|
|
1725
|
+
*/
|
|
1726
|
+
var HtmlTransformPatcher = class {
|
|
1727
|
+
state = State.BUFFERING;
|
|
1733
1728
|
buffer = "";
|
|
1734
1729
|
headInnerIndex = -1;
|
|
1735
1730
|
bodyInnerIndex = -1;
|
|
@@ -1782,7 +1777,7 @@ function formatError(e) {
|
|
|
1782
1777
|
};
|
|
1783
1778
|
}
|
|
1784
1779
|
handleWrite(chunk, encoding, callback) {
|
|
1785
|
-
if (!this.isHtmlResponse || this.state ===
|
|
1780
|
+
if (!this.isHtmlResponse || this.state === State.PASSTHROUGH) return this.origWrite(chunk, encoding, callback);
|
|
1786
1781
|
if (typeof encoding === "function") {
|
|
1787
1782
|
callback = encoding;
|
|
1788
1783
|
encoding = void 0;
|
|
@@ -1794,7 +1789,7 @@ function formatError(e) {
|
|
|
1794
1789
|
else data = chunk?.toString() || "";
|
|
1795
1790
|
this.buffer += data;
|
|
1796
1791
|
switch (this.state) {
|
|
1797
|
-
case
|
|
1792
|
+
case State.BUFFERING:
|
|
1798
1793
|
if (this.headInnerIndex === -1) {
|
|
1799
1794
|
const headMatch = this.buffer.match(/<head[^>]*>/i);
|
|
1800
1795
|
if (headMatch) {
|
|
@@ -1805,15 +1800,15 @@ function formatError(e) {
|
|
|
1805
1800
|
if (this.headInnerIndex !== -1) {
|
|
1806
1801
|
const bodyMatch = this.buffer.slice(this.headInnerIndex).match(/<body[^>]*>/i);
|
|
1807
1802
|
if (bodyMatch) {
|
|
1808
|
-
this.state =
|
|
1803
|
+
this.state = State.PROCESSING_HEAD;
|
|
1809
1804
|
const bodyOuterIndex = this.buffer.indexOf(bodyMatch[0]);
|
|
1810
1805
|
this.bodyInnerIndex = bodyOuterIndex + bodyMatch[0].length;
|
|
1811
1806
|
this.processingPromise = this.processHead();
|
|
1812
1807
|
}
|
|
1813
1808
|
}
|
|
1814
1809
|
break;
|
|
1815
|
-
case
|
|
1816
|
-
case
|
|
1810
|
+
case State.PROCESSING_HEAD: break;
|
|
1811
|
+
case State.STREAMING_BODY:
|
|
1817
1812
|
this.handleStreamingBodyState();
|
|
1818
1813
|
break;
|
|
1819
1814
|
default: throw new Error(`Invalid state: ${this.state}`);
|
|
@@ -1840,7 +1835,7 @@ function formatError(e) {
|
|
|
1840
1835
|
if (headCloseIndex === -1) throw new Error("Buffered HTML does not contain </head>");
|
|
1841
1836
|
this.buffer = this.buffer.slice(0, this.headInnerIndex) + headPreContent + this.buffer.slice(this.headInnerIndex, headCloseIndex) + headPostContent + this.buffer.slice(headCloseIndex, this.bodyInnerIndex) + bodyPreContent + this.buffer.slice(this.bodyInnerIndex);
|
|
1842
1837
|
if (this.bodyPostContent.length > 0) {
|
|
1843
|
-
this.state =
|
|
1838
|
+
this.state = State.STREAMING_BODY;
|
|
1844
1839
|
this.handleStreamingBodyState();
|
|
1845
1840
|
return;
|
|
1846
1841
|
}
|
|
@@ -1863,7 +1858,7 @@ function formatError(e) {
|
|
|
1863
1858
|
this.flushBuffer(6);
|
|
1864
1859
|
}
|
|
1865
1860
|
transitionToPassthrough() {
|
|
1866
|
-
this.state =
|
|
1861
|
+
this.state = State.PASSTHROUGH;
|
|
1867
1862
|
this.flushBuffer();
|
|
1868
1863
|
}
|
|
1869
1864
|
flushBuffer(keep = 0) {
|
|
@@ -1892,7 +1887,8 @@ function formatError(e) {
|
|
|
1892
1887
|
this.origEnd(callback);
|
|
1893
1888
|
}
|
|
1894
1889
|
};
|
|
1895
|
-
/** Patches a response to enable HTML transformation using Vite's transformIndexHtml */
|
|
1890
|
+
/** Patches a response to enable HTML transformation using Vite's transformIndexHtml */
|
|
1891
|
+
function wrapResponseForHtmlTransform(request, response, server) {
|
|
1896
1892
|
new HtmlTransformPatcher(request, response, server);
|
|
1897
1893
|
return response;
|
|
1898
1894
|
}
|
|
@@ -1901,43 +1897,6 @@ var ROUTE_PATH_HEADER = "X-Qwik-route-path";
|
|
|
1901
1897
|
function getDevMiddlewareRequestPath(req) {
|
|
1902
1898
|
return req.originalUrl || req.url;
|
|
1903
1899
|
}
|
|
1904
|
-
async function loadSsrModule(server, filePath) {
|
|
1905
|
-
return server.ssrLoadModule(getImportPath(normalizePath$1(filePath)));
|
|
1906
|
-
}
|
|
1907
|
-
function matchesLoaderId(loader, loaderId) {
|
|
1908
|
-
return loader.__id === loaderId || loader.__qrl.getHash() === loaderId;
|
|
1909
|
-
}
|
|
1910
|
-
function isLoaderInternal(value) {
|
|
1911
|
-
return typeof value === "function" && value.__brand === "server_loader";
|
|
1912
|
-
}
|
|
1913
|
-
function findMatchingLoader(mod, loaderId) {
|
|
1914
|
-
for (const value of Object.values(mod)) if (isLoaderInternal(value) && matchesLoaderId(value, loaderId)) return value;
|
|
1915
|
-
}
|
|
1916
|
-
async function preloadQLoaderRouteLoader(server, ctx, req) {
|
|
1917
|
-
const requestPath = getDevMiddlewareRequestPath(req);
|
|
1918
|
-
if (!requestPath) return;
|
|
1919
|
-
let requestUrl;
|
|
1920
|
-
try {
|
|
1921
|
-
requestUrl = new URL(requestPath, "http://qwik.dev");
|
|
1922
|
-
} catch {
|
|
1923
|
-
return;
|
|
1924
|
-
}
|
|
1925
|
-
const recognized = recognizeRequest(requestUrl.pathname);
|
|
1926
|
-
if (recognized?.type !== "@isQLoader" || !recognized.data?.loaderId) return;
|
|
1927
|
-
const loaderId = recognized.data.loaderId;
|
|
1928
|
-
const headerValue = req.headers[FULLPATH_HEADER.toLowerCase()] ?? req.headers[ROUTE_PATH_HEADER.toLowerCase()];
|
|
1929
|
-
const fullPathHeader = Array.isArray(headerValue) ? headerValue[0] : headerValue ?? null;
|
|
1930
|
-
const loaderPathname = trimRecognizedInternalPathname(requestUrl.pathname, recognized);
|
|
1931
|
-
const pathname = resolveValidInternalFullPathname(loaderPathname, fullPathHeader) ?? loaderPathname;
|
|
1932
|
-
const route = ctx.routes.filter((route) => isPageExt(route.ext)).slice().sort(routeSortCompare).find((route) => route.pattern.test(pathname));
|
|
1933
|
-
if (!route) return;
|
|
1934
|
-
const routeRootFiles = [...route.layouts.map((layout) => layout.filePath), route.filePath];
|
|
1935
|
-
const modules = await Promise.all([...ctx.serverPlugins.map((plugin) => loadSsrModule(server, plugin.filePath)), ...routeRootFiles.map((filePath) => loadSsrModule(server, filePath))]);
|
|
1936
|
-
for (const mod of modules) {
|
|
1937
|
-
const loader = findMatchingLoader(mod, loaderId);
|
|
1938
|
-
if (loader) return loader;
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
1900
|
var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
1942
1901
|
let mod;
|
|
1943
1902
|
try {
|
|
@@ -1977,9 +1936,9 @@ var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
|
1977
1936
|
globalThis.__qwik = void 0;
|
|
1978
1937
|
const { createQwikRouter } = await server.ssrLoadModule("@qwik.dev/router/middleware/node");
|
|
1979
1938
|
try {
|
|
1980
|
-
const render = async (opts) => {
|
|
1939
|
+
const render = (async (opts) => {
|
|
1981
1940
|
return await renderer(opts);
|
|
1982
|
-
};
|
|
1941
|
+
});
|
|
1983
1942
|
const { router, staticFile } = createQwikRouter({
|
|
1984
1943
|
render,
|
|
1985
1944
|
platform: ctx.opts.platform
|
|
@@ -1997,6 +1956,43 @@ var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
|
1997
1956
|
return;
|
|
1998
1957
|
}
|
|
1999
1958
|
};
|
|
1959
|
+
async function preloadQLoaderRouteLoader(server, ctx, req) {
|
|
1960
|
+
const requestPath = getDevMiddlewareRequestPath(req);
|
|
1961
|
+
if (!requestPath) return;
|
|
1962
|
+
let requestUrl;
|
|
1963
|
+
try {
|
|
1964
|
+
requestUrl = new URL(requestPath, "http://qwik.dev");
|
|
1965
|
+
} catch {
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
const recognized = recognizeRequest(requestUrl.pathname);
|
|
1969
|
+
if (recognized?.type !== "@isQLoader" || !recognized.data?.loaderId) return;
|
|
1970
|
+
const loaderId = recognized.data.loaderId;
|
|
1971
|
+
const headerValue = req.headers[FULLPATH_HEADER.toLowerCase()] ?? req.headers[ROUTE_PATH_HEADER.toLowerCase()];
|
|
1972
|
+
const fullPathHeader = Array.isArray(headerValue) ? headerValue[0] : headerValue ?? null;
|
|
1973
|
+
const loaderPathname = trimRecognizedInternalPathname(requestUrl.pathname, recognized);
|
|
1974
|
+
const pathname = resolveValidInternalFullPathname(loaderPathname, fullPathHeader) ?? loaderPathname;
|
|
1975
|
+
const route = ctx.routes.filter((route) => isPageExt(route.ext)).slice().sort(routeSortCompare).find((route) => route.pattern.test(pathname));
|
|
1976
|
+
if (!route) return;
|
|
1977
|
+
const routeRootFiles = [...route.layouts.map((layout) => layout.filePath), route.filePath];
|
|
1978
|
+
const modules = await Promise.all([...ctx.serverPlugins.map((plugin) => loadSsrModule(server, plugin.filePath)), ...routeRootFiles.map((filePath) => loadSsrModule(server, filePath))]);
|
|
1979
|
+
for (const mod of modules) {
|
|
1980
|
+
const loader = findMatchingLoader(mod, loaderId);
|
|
1981
|
+
if (loader) return loader;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
async function loadSsrModule(server, filePath) {
|
|
1985
|
+
return server.ssrLoadModule(getImportPath(normalizePath$1(filePath)));
|
|
1986
|
+
}
|
|
1987
|
+
function findMatchingLoader(mod, loaderId) {
|
|
1988
|
+
for (const value of Object.values(mod)) if (isLoaderInternal(value) && matchesLoaderId(value, loaderId)) return value;
|
|
1989
|
+
}
|
|
1990
|
+
function matchesLoaderId(loader, loaderId) {
|
|
1991
|
+
return loader.__id === loaderId || loader.__qrl.getHash() === loaderId;
|
|
1992
|
+
}
|
|
1993
|
+
function isLoaderInternal(value) {
|
|
1994
|
+
return typeof value === "function" && value.__brand === "server_loader";
|
|
1995
|
+
}
|
|
2000
1996
|
var CSS_EXTENSIONS = [
|
|
2001
1997
|
".css",
|
|
2002
1998
|
".scss",
|
|
@@ -2014,7 +2010,8 @@ var isCssPath = (url) => CSS_EXTENSIONS.some((ext) => url.endsWith(ext));
|
|
|
2014
2010
|
* We check both the client and SSR module graphs because on the first page request only the SSR
|
|
2015
2011
|
* graph has been populated (via ssrLoadModule). The client graph is empty until the browser
|
|
2016
2012
|
* actually fetches modules through Vite's dev server.
|
|
2017
|
-
*/
|
|
2013
|
+
*/
|
|
2014
|
+
var getCssUrls = (server) => {
|
|
2018
2015
|
const clientGraph = server.environments.client.moduleGraph;
|
|
2019
2016
|
const ssrGraph = server.environments.ssr.moduleGraph;
|
|
2020
2017
|
const cssModules = /* @__PURE__ */ new Set();
|
|
@@ -2053,7 +2050,8 @@ var getRouterIndexTags = (server) => {
|
|
|
2053
2050
|
/**
|
|
2054
2051
|
* Live-reload route CSS that Qwik injects as `<link>` tags; it only lives in the SSR graph, so Vite
|
|
2055
2052
|
* skips HMR. Emit a `css-update` to swap the `<link>` in place. Returns `true` when handled.
|
|
2056
|
-
*/
|
|
2053
|
+
*/
|
|
2054
|
+
var sendRouterCssHotUpdate = (server, file, timestamp) => {
|
|
2057
2055
|
const { client, ssr } = server.environments;
|
|
2058
2056
|
if (!isCssPath(file) || client.moduleGraph.getModulesByFile(file)?.size) return false;
|
|
2059
2057
|
const paths = /* @__PURE__ */ new Set();
|
|
@@ -2077,19 +2075,37 @@ var QWIK_ROUTER_CONFIG_ID = "@qwik-router-config";
|
|
|
2077
2075
|
/**
|
|
2078
2076
|
* This virtual module is used to generate dynamic entries for user route files, which are added as
|
|
2079
2077
|
* dynamic imports to the qwik-router-config as a way to create new entry points for the build.
|
|
2080
|
-
*/
|
|
2078
|
+
*/
|
|
2079
|
+
var QWIK_ROUTER_ENTRIES_ID = "@qwik-router-entries";
|
|
2081
2080
|
var QWIK_ROUTER = "@qwik.dev/router";
|
|
2082
2081
|
var QWIK_ROUTER_SW_REGISTER = "@qwik-router-sw-register";
|
|
2083
2082
|
var VIRTUAL_SERVER_FNS = "virtual:qwik-router-server-fns";
|
|
2084
|
-
/**
|
|
2085
|
-
|
|
2083
|
+
/**
|
|
2084
|
+
* @deprecated Use `qwikRouter` instead. Will be removed in V3
|
|
2085
|
+
* @public
|
|
2086
|
+
*/
|
|
2087
|
+
function qwikCity(userOpts) {
|
|
2088
|
+
return qwikRouter(userOpts);
|
|
2089
|
+
}
|
|
2090
|
+
/** @public */
|
|
2091
|
+
function qwikRouter(userOpts) {
|
|
2092
|
+
const buildContextRef = { current: null };
|
|
2093
|
+
return [
|
|
2094
|
+
qwikRouterPlugin(userOpts, buildContextRef),
|
|
2095
|
+
serverFnsPlugin(buildContextRef),
|
|
2096
|
+
...imagePlugin(userOpts)
|
|
2097
|
+
];
|
|
2098
|
+
}
|
|
2099
|
+
/** Replace or strip loader placeholders in a bundle chunk. */
|
|
2100
|
+
function replaceLoaderPlaceholders(code, loadersByFile) {
|
|
2101
|
+
return code.replace(/(_R|_D)\s*:\s*(["'`])__LOADERS:([^"'`]+)__\2\s*,?/g, (_match, field, _q, paths) => {
|
|
2086
2102
|
const filePaths = JSON.parse(`"${paths}"`).split("|");
|
|
2087
2103
|
const hashes = [];
|
|
2088
2104
|
for (const filePath of filePaths) {
|
|
2089
2105
|
const fileHashes = loadersByFile.get(normalizePathKey(filePath));
|
|
2090
2106
|
if (fileHashes) hashes.push(...fileHashes);
|
|
2091
2107
|
}
|
|
2092
|
-
if (hashes.length > 0) return
|
|
2108
|
+
if (hashes.length > 0) return `${field}: ${JSON.stringify(hashes)},`;
|
|
2093
2109
|
return "";
|
|
2094
2110
|
});
|
|
2095
2111
|
}
|
|
@@ -2127,6 +2143,14 @@ function isDiscoveredRouteLoaderSource(filePath, sourceFiles) {
|
|
|
2127
2143
|
for (const files of sourceFiles.values()) if (files.includes(normalizedPath)) return true;
|
|
2128
2144
|
return false;
|
|
2129
2145
|
}
|
|
2146
|
+
async function findRouteLoaderSourceFiles(ctx, resolveSource) {
|
|
2147
|
+
const sources = /* @__PURE__ */ new Map();
|
|
2148
|
+
const owners = /* @__PURE__ */ new Set();
|
|
2149
|
+
collectRouteLoaderOwners(ctx.routeTrie, owners);
|
|
2150
|
+
for (const plugin of ctx.serverPlugins) owners.add(plugin.filePath);
|
|
2151
|
+
await Promise.all([...owners].map((owner) => collectRouteLoaderSources(owner, owner, resolveSource, sources)));
|
|
2152
|
+
return sources;
|
|
2153
|
+
}
|
|
2130
2154
|
function collectRouteLoaderOwners(node, owners) {
|
|
2131
2155
|
for (const file of node._files) if (file.type === "layout" || file.type === "route") owners.add(file.filePath);
|
|
2132
2156
|
for (const child of node.children.values()) collectRouteLoaderOwners(child, owners);
|
|
@@ -2166,14 +2190,6 @@ async function collectRouteLoaderSources(owner, filePath, resolveSource, sources
|
|
|
2166
2190
|
}
|
|
2167
2191
|
}
|
|
2168
2192
|
}
|
|
2169
|
-
async function findRouteLoaderSourceFiles(ctx, resolveSource) {
|
|
2170
|
-
const sources = /* @__PURE__ */ new Map();
|
|
2171
|
-
const owners = /* @__PURE__ */ new Set();
|
|
2172
|
-
collectRouteLoaderOwners(ctx.routeTrie, owners);
|
|
2173
|
-
for (const plugin of ctx.serverPlugins) owners.add(plugin.filePath);
|
|
2174
|
-
await Promise.all([...owners].map((owner) => collectRouteLoaderSources(owner, owner, resolveSource, sources)));
|
|
2175
|
-
return sources;
|
|
2176
|
-
}
|
|
2177
2193
|
function invalidateRouterConfigModules(server) {
|
|
2178
2194
|
const modules = [];
|
|
2179
2195
|
const moduleGraphs = /* @__PURE__ */ new Set();
|
|
@@ -2192,21 +2208,6 @@ function invalidateRouterConfigModules(server) {
|
|
|
2192
2208
|
}
|
|
2193
2209
|
return modules;
|
|
2194
2210
|
}
|
|
2195
|
-
async function generateServerPackageJson(outDir) {
|
|
2196
|
-
await fs.promises.mkdir(outDir, { recursive: true });
|
|
2197
|
-
const serverPackageJsonPath = join(outDir, "package.json");
|
|
2198
|
-
let packageJson = {};
|
|
2199
|
-
if (fs.existsSync(serverPackageJsonPath)) {
|
|
2200
|
-
const content = await fs.promises.readFile(serverPackageJsonPath, "utf-8");
|
|
2201
|
-
packageJson = { ...JSON.parse(content) };
|
|
2202
|
-
}
|
|
2203
|
-
packageJson = {
|
|
2204
|
-
...packageJson,
|
|
2205
|
-
type: "module"
|
|
2206
|
-
};
|
|
2207
|
-
const serverPackageJsonCode = JSON.stringify(packageJson, null, 2);
|
|
2208
|
-
await fs.promises.writeFile(serverPackageJsonPath, serverPackageJsonCode);
|
|
2209
|
-
}
|
|
2210
2211
|
function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
2211
2212
|
let ctx = null;
|
|
2212
2213
|
let mdxTransform = null;
|
|
@@ -2218,9 +2219,11 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2218
2219
|
let devSsrServer = userOpts?.devSsrServer;
|
|
2219
2220
|
const routesDir = userOpts?.routesDir ?? "src/routes";
|
|
2220
2221
|
const serverPluginsDir = userOpts?.serverPluginsDir ?? routesDir;
|
|
2221
|
-
/** Map from source file path to array of routeLoader$ hashes found in that file */
|
|
2222
|
+
/** Map from source file path to array of routeLoader$ hashes found in that file */
|
|
2223
|
+
const loadersByFile = /* @__PURE__ */ new Map();
|
|
2222
2224
|
let reExportedRouteLoaderSources;
|
|
2223
|
-
/** SSG include/exclude from the adapter (see `_setSsgRoutes`); drives the server-route prune. */
|
|
2225
|
+
/** SSG include/exclude from the adapter (see `_setSsgRoutes`); drives the server-route prune. */
|
|
2226
|
+
let ssgRoutePatterns;
|
|
2224
2227
|
return {
|
|
2225
2228
|
name: "vite-plugin-qwik-router",
|
|
2226
2229
|
enforce: "pre",
|
|
@@ -2245,6 +2248,7 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2245
2248
|
define: {
|
|
2246
2249
|
"globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__": JSON.stringify(userOpts?.defaultLoadersSerializationStrategy || "never"),
|
|
2247
2250
|
"globalThis.__NO_TRAILING_SLASH__": JSON.stringify(userOpts?.trailingSlash === false),
|
|
2251
|
+
"globalThis.__QWIK_ROUTER_BASE_PATHNAME__": JSON.stringify(resolveBasePathname(userOpts, _viteConfig.base || "/")),
|
|
2248
2252
|
"globalThis.__SSR_CACHE_SIZE__": JSON.stringify(viteEnv.command === "serve" ? 0 : userOpts?.ssrCacheSize ?? 50),
|
|
2249
2253
|
"globalThis.__STRICT_LOADERS__": JSON.stringify(userOpts?.strictLoaders !== false)
|
|
2250
2254
|
},
|
|
@@ -2372,6 +2376,10 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2372
2376
|
},
|
|
2373
2377
|
buildStart() {
|
|
2374
2378
|
resetBuildContext(ctx);
|
|
2379
|
+
if (this.environment.mode === "build" && this.environment.config.consumer === "client") this.emitFile({
|
|
2380
|
+
type: "chunk",
|
|
2381
|
+
id: QWIK_ROUTER_CONFIG_ID
|
|
2382
|
+
});
|
|
2375
2383
|
},
|
|
2376
2384
|
resolveId(id) {
|
|
2377
2385
|
if (id === "@qwik-router-config" || id === QWIK_ROUTER_ENTRIES_ID) return {
|
|
@@ -2472,11 +2480,27 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2472
2480
|
}
|
|
2473
2481
|
};
|
|
2474
2482
|
}
|
|
2483
|
+
async function generateServerPackageJson(outDir) {
|
|
2484
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
2485
|
+
const serverPackageJsonPath = join(outDir, "package.json");
|
|
2486
|
+
let packageJson = {};
|
|
2487
|
+
if (fs.existsSync(serverPackageJsonPath)) {
|
|
2488
|
+
const content = await fs.promises.readFile(serverPackageJsonPath, "utf-8");
|
|
2489
|
+
packageJson = { ...JSON.parse(content) };
|
|
2490
|
+
}
|
|
2491
|
+
packageJson = {
|
|
2492
|
+
...packageJson,
|
|
2493
|
+
type: "module"
|
|
2494
|
+
};
|
|
2495
|
+
const serverPackageJsonCode = JSON.stringify(packageJson, null, 2);
|
|
2496
|
+
await fs.promises.writeFile(serverPackageJsonPath, serverPackageJsonCode);
|
|
2497
|
+
}
|
|
2475
2498
|
/**
|
|
2476
2499
|
* Separate plugin that tracks modules containing server$ functions during SSR builds and generates
|
|
2477
2500
|
* `virtual:qwik-router-server-fns` — a virtual module that statically imports all such modules so
|
|
2478
2501
|
* their `_regSymbol` side effects run before any RPC request arrives.
|
|
2479
|
-
*/
|
|
2502
|
+
*/
|
|
2503
|
+
function serverFnsPlugin(buildContextRef) {
|
|
2480
2504
|
const RESOLVED_ID = "\0virtual:qwik-router-server-fns";
|
|
2481
2505
|
const serverFnModules = /* @__PURE__ */ new Set();
|
|
2482
2506
|
let serverFnsReady = null;
|
|
@@ -2515,26 +2539,12 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2515
2539
|
const isServerBuild = this.environment.config.consumer === "server" && this.environment.mode === "build";
|
|
2516
2540
|
if (id === RESOLVED_ID) {
|
|
2517
2541
|
if (isServerBuild) await collectServerFnModules.call(this);
|
|
2518
|
-
if (!isServerBuild || serverFnModules.size === 0) return "
|
|
2519
|
-
return [...serverFnModules].map((mod
|
|
2542
|
+
if (!isServerBuild || serverFnModules.size === 0) return "export const importEagerModules = () => Promise.resolve();\n";
|
|
2543
|
+
return "export const importEagerModules = () =>\n Promise.all([\n" + [...serverFnModules].map((mod) => ` import(${JSON.stringify(mod)}),`).join("\n") + "\n ]);\n";
|
|
2520
2544
|
}
|
|
2521
2545
|
return null;
|
|
2522
2546
|
}
|
|
2523
2547
|
}
|
|
2524
2548
|
};
|
|
2525
2549
|
}
|
|
2526
|
-
/** @public */ function qwikRouter(userOpts) {
|
|
2527
|
-
const buildContextRef = { current: null };
|
|
2528
|
-
return [
|
|
2529
|
-
qwikRouterPlugin(userOpts, buildContextRef),
|
|
2530
|
-
serverFnsPlugin(buildContextRef),
|
|
2531
|
-
...imagePlugin(userOpts)
|
|
2532
|
-
];
|
|
2533
|
-
}
|
|
2534
|
-
/**
|
|
2535
|
-
* @deprecated Use `qwikRouter` instead. Will be removed in V3
|
|
2536
|
-
* @public
|
|
2537
|
-
*/ function qwikCity(userOpts) {
|
|
2538
|
-
return qwikRouter(userOpts);
|
|
2539
|
-
}
|
|
2540
2550
|
export { extendConfig, qwikCity, qwikRouter };
|