@qwik.dev/router 2.0.0-beta.43 → 2.0.0-beta.47
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.d.ts +2 -2
- package/lib/adapters/azure-swa/vite/index.mjs +2 -1
- package/lib/adapters/bun-server/vite/index.d.ts +2 -2
- package/lib/adapters/bun-server/vite/index.mjs +2 -1
- package/lib/adapters/cloud-run/vite/index.d.ts +2 -2
- package/lib/adapters/cloud-run/vite/index.mjs +2 -1
- package/lib/adapters/cloudflare-pages/vite/index.d.ts +2 -2
- package/lib/adapters/cloudflare-pages/vite/index.mjs +2 -1
- package/lib/adapters/deno-server/vite/index.d.ts +2 -2
- package/lib/adapters/deno-server/vite/index.mjs +2 -1
- package/lib/adapters/netlify-edge/vite/index.d.ts +2 -2
- package/lib/adapters/netlify-edge/vite/index.mjs +2 -1
- package/lib/adapters/node-server/vite/index.d.ts +2 -2
- package/lib/adapters/node-server/vite/index.mjs +2 -1
- package/lib/adapters/shared/vite/index.d.ts +1 -1
- package/lib/adapters/shared/vite/index.mjs +36 -32
- package/lib/adapters/ssg/vite/index.d.ts +1 -1
- package/lib/adapters/ssg/vite/index.mjs +4 -2
- package/lib/adapters/vercel-edge/vite/index.d.ts +2 -2
- package/lib/adapters/vercel-edge/vite/index.mjs +18 -15
- package/lib/chunks/fs.mjs +28 -25
- package/lib/chunks/head.qwik.mjs +731 -448
- 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/route-trie-key.mjs +10 -0
- package/lib/chunks/routes.mjs +14 -14
- package/lib/chunks/server-error.mjs +28 -6
- package/lib/chunks/{url.mjs → static-file.mjs} +12 -2
- package/lib/chunks/system.mjs +31 -25
- package/lib/chunks/user-response.mjs +455 -348
- package/lib/chunks/worker-thread.mjs +90 -88
- package/lib/index.d.ts +94 -63
- package/lib/index.qwik.mjs +615 -523
- 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.d.ts +102 -2
- package/lib/middleware/request-handler/index.mjs +30 -34
- package/lib/middleware/vercel-edge/index.mjs +4 -2
- package/lib/service-worker/index.mjs +2 -1
- package/lib/ssg/index.mjs +23 -18
- package/lib/vite/index.d.ts +1 -1
- package/lib/vite/index.mjs +669 -604
- package/package.json +5 -5
package/lib/vite/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { r as isSameOriginUrl, t as ensureSlash } from "../chunks/pathname.mjs";
|
|
2
2
|
import { c as resolveValidInternalFullPathname, s as recognizeRequest, u as trimRecognizedInternalPathname } from "../chunks/request-path.mjs";
|
|
3
|
+
import { t as escapeStaticTrieKey } from "../chunks/route-trie-key.mjs";
|
|
3
4
|
import { n as addWarning, t as addError } from "../chunks/format.mjs";
|
|
4
|
-
import { _ as normalizePath$1, a as getPathnameFromDirPath, b as parseRouteIndexName, c as isIndexModule, d as isMenuFileName, f as isModuleExt, g as isServiceWorkerName, h as isPluginModule, i as getMenuPathname, l as isLayoutModule, m as isPageModuleExt, n as
|
|
5
|
+
import { _ as normalizePath$1, a as getPathnameFromDirPath, b as parseRouteIndexName, c as isIndexModule, d as isMenuFileName, f as isModuleExt, g as isServiceWorkerName, h as isPluginModule, i as getMenuPathname, l as isLayoutModule, m as isPageModuleExt, n as createFileId, o as isEntryName, p as isPageExt, r as getExtension, s as isErrorName, t as caughtErrorName, u as isMarkdownExt, v as normalizePathKey, x as removeExtension } from "../chunks/fs.mjs";
|
|
5
6
|
import { t as devPreloadedRouteLoaders } from "../chunks/dev-preloaded-route-loader.mjs";
|
|
6
7
|
import { t as createRouteTester } from "../chunks/routes.mjs";
|
|
7
8
|
import fs, { existsSync } from "node:fs";
|
|
@@ -21,7 +22,8 @@ import { toString } from "hast-util-to-string";
|
|
|
21
22
|
import { refractor } from "refractor";
|
|
22
23
|
import tsxLang from "refractor/lang/tsx.js";
|
|
23
24
|
import { optimize } from "svgo";
|
|
24
|
-
/** @public */
|
|
25
|
+
/** @public */
|
|
26
|
+
function extendConfig(baseConfigExport, serverConfigExport) {
|
|
25
27
|
return async (env) => {
|
|
26
28
|
let resolvedBase = await baseConfigExport;
|
|
27
29
|
if (typeof resolvedBase === "function") resolvedBase = await resolvedBase(env);
|
|
@@ -30,7 +32,6 @@ import { optimize } from "svgo";
|
|
|
30
32
|
return mergeConfig(resolvedBase, resolvedServer);
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
|
-
var sw_register_build_default = "export default\"\"";
|
|
34
35
|
function getSourceFile(fileName) {
|
|
35
36
|
const ext = getExtension(fileName);
|
|
36
37
|
const extlessName = removeExtension(fileName);
|
|
@@ -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,13 +212,15 @@ 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 = [];
|
|
218
220
|
const routesDir = opts.routesDir;
|
|
219
221
|
const { layoutName, layoutStop } = parseRouteIndexName(sourceFile.extlessName);
|
|
220
222
|
let pathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
|
|
221
|
-
const boundary =
|
|
223
|
+
const boundary = caughtErrorName(sourceFile.extlessName);
|
|
222
224
|
if (boundary) pathname += boundary + ".html";
|
|
223
225
|
if (!layoutStop) {
|
|
224
226
|
let currentDir = normalizePath$1(dirname(filePath));
|
|
@@ -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,173 +974,17 @@ 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
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
/**
|
|
973
|
-
* For a named layout `index@name.tsx`, walk up ancestors to find the named layout and collect
|
|
974
|
-
* default layouts above it.
|
|
975
|
-
*
|
|
976
|
-
* Returns the layout chain in order: [outermost default..., named layout]
|
|
977
|
-
*/ function resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, targetName) {
|
|
978
|
-
const allLayouts = [...ancestorLayouts, ...nodeLayouts];
|
|
979
|
-
const result = [];
|
|
980
|
-
let foundNamed = false;
|
|
981
|
-
for (let i = allLayouts.length - 1; i >= 0; i--) {
|
|
982
|
-
const layout = allLayouts[i];
|
|
983
|
-
if (!foundNamed) {
|
|
984
|
-
if (layout.layoutName === targetName) {
|
|
985
|
-
result.unshift(layout);
|
|
986
|
-
foundNamed = true;
|
|
987
|
-
}
|
|
988
|
-
} else if (layout.layoutName === "") {
|
|
989
|
-
result.unshift(layout);
|
|
990
|
-
if (layout.layoutType === "top") break;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
return result;
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* The `_I`/`_E`/`_4` loader expression: a bare loader (runtime prepends gathered layouts), or an
|
|
997
|
-
* override chain for `!` (layout stop) / `@name` (named layout).
|
|
998
|
-
*/ function buildLoaderChainExpr(extlessName, loaderExpr, ancestorLayouts, nodeLayouts) {
|
|
999
|
-
const { layoutName, layoutStop } = parseRouteIndexName(extlessName);
|
|
1000
|
-
if (layoutStop) return `[ ${loaderExpr} ]`;
|
|
1001
|
-
if (layoutName) return `[ ${[...resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, layoutName).map((l) => l.id), loaderExpr].join(", ")} ]`;
|
|
1002
|
-
return loaderExpr;
|
|
981
|
+
/** The runtime trie key for a build trie key; `_W`/`_A` are the only non-static ones. */
|
|
982
|
+
function toRuntimeTrieKey(key) {
|
|
983
|
+
return key === "_W" || key === "_A" ? key : escapeStaticTrieKey(key);
|
|
1003
984
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1021
|
-
for (const layout of r.layouts) addRouteFile(layout.filePath);
|
|
1022
|
-
addRouteFile(r.filePath);
|
|
1023
|
-
}
|
|
1024
|
-
return bundlesNames;
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Serialize a BuildTrieNode to a JS object literal string.
|
|
1028
|
-
*
|
|
1029
|
-
* The ancestor stack tracks layouts from parent nodes for layout chain resolution (needed for
|
|
1030
|
-
* layout stops and named layouts).
|
|
1031
|
-
*/ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap, ancestorLayouts, isSSR, indent, loadersByFile, routeLoaderSourceFiles) {
|
|
1032
|
-
const lines = [];
|
|
1033
|
-
const nextIndent = indent + " ";
|
|
1034
|
-
if (node._P) lines.push(`${nextIndent}_P: ${JSON.stringify(node._P)},`);
|
|
1035
|
-
if (node._0) lines.push(`${nextIndent}_0: ${JSON.stringify(node._0)},`);
|
|
1036
|
-
if (node._9) lines.push(`${nextIndent}_9: ${JSON.stringify(node._9)},`);
|
|
1037
|
-
if (node._G != null) lines.push(`${nextIndent}_G: ${JSON.stringify(node._G)},`);
|
|
1038
|
-
let layoutExpr;
|
|
1039
|
-
let indexExpr;
|
|
1040
|
-
let errorExpr;
|
|
1041
|
-
let notFoundExpr;
|
|
1042
|
-
let menuExpr;
|
|
1043
|
-
let bundleRoute;
|
|
1044
|
-
const nodeLayouts = [];
|
|
1045
|
-
for (const file of node._files) if (file.type === "menu") {
|
|
1046
|
-
const menuId = menuIdMap.get(file.filePath);
|
|
1047
|
-
if (menuId) menuExpr = menuId;
|
|
1048
|
-
} else if (file.type === "layout") {
|
|
1049
|
-
const layoutId = layoutIdMap.get(file.filePath);
|
|
1050
|
-
if (layoutId) {
|
|
1051
|
-
let extlessName = file.extlessName;
|
|
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;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
for (const file of node._files) {
|
|
1067
|
-
if (file.type !== "route") continue;
|
|
1068
|
-
const loaderExpr = routeIdMap.get(file.filePath);
|
|
1069
|
-
if (!loaderExpr) continue;
|
|
1070
|
-
const expr = buildLoaderChainExpr(file.extlessName, loaderExpr, ancestorLayouts, nodeLayouts);
|
|
1071
|
-
const boundary = errorBoundaryName(file.extlessName);
|
|
1072
|
-
if (boundary === "404") notFoundExpr = expr;
|
|
1073
|
-
else if (boundary === "error") errorExpr = expr;
|
|
1074
|
-
else {
|
|
1075
|
-
indexExpr = expr;
|
|
1076
|
-
bundleRoute = ctx.routes.find((r) => r.filePath === file.filePath);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
if (layoutExpr) lines.push(`${nextIndent}_L: ${layoutExpr},`);
|
|
1080
|
-
if (indexExpr) {
|
|
1081
|
-
lines.push(`${nextIndent}_I: ${indexExpr},`);
|
|
1082
|
-
if (isSSR && bundleRoute) {
|
|
1083
|
-
const bundleNames = getClientRouteBundleNames(qwikPlugin, bundleRoute);
|
|
1084
|
-
if (bundleNames.length > 0) lines.push(`${nextIndent}_B: ${JSON.stringify(bundleNames)},`);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
{
|
|
1088
|
-
const routeFiles = [];
|
|
1089
|
-
for (const file of node._files.filter((f) => f.type === "layout" || f.type === "route" && routeIdMap.has(f.filePath))) routeFiles.push(file.filePath, ...routeLoaderSourceFiles?.get(file.filePath) ?? []);
|
|
1090
|
-
if (node === ctx.routeTrie) for (const plugin of ctx.serverPlugins) routeFiles.push(plugin.filePath, ...routeLoaderSourceFiles?.get(plugin.filePath) ?? []);
|
|
1091
|
-
const routeLoaderFiles = [...new Set(routeFiles)];
|
|
1092
|
-
if (routeLoaderFiles.length > 0) {
|
|
1093
|
-
if (loadersByFile) {
|
|
1094
|
-
const nodeLoaderHashes = [];
|
|
1095
|
-
for (const filePath of routeLoaderFiles) {
|
|
1096
|
-
const hashes = loadersByFile.get(normalizePathKey(filePath));
|
|
1097
|
-
if (hashes) nodeLoaderHashes.push(...hashes);
|
|
1098
|
-
}
|
|
1099
|
-
if (nodeLoaderHashes.length > 0) lines.push(`${nextIndent}_R: ${JSON.stringify(nodeLoaderHashes)},`);
|
|
1100
|
-
} else {
|
|
1101
|
-
const placeholder = `__LOADERS:${routeLoaderFiles.join("|")}__`;
|
|
1102
|
-
lines.push(`${nextIndent}_R: ${JSON.stringify(placeholder)},`);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
if (errorExpr) lines.push(`${nextIndent}_E: ${errorExpr},`);
|
|
1107
|
-
if (notFoundExpr) lines.push(`${nextIndent}_4: ${notFoundExpr},`);
|
|
1108
|
-
if (menuExpr) lines.push(`${nextIndent}_N: ${menuExpr},`);
|
|
1109
|
-
const childAncestors = [...ancestorLayouts, ...nodeLayouts];
|
|
1110
|
-
const groupChildren = [];
|
|
1111
|
-
const regularChildren = [];
|
|
1112
|
-
for (const [key, child] of node.children) if (isGroupKey(key)) groupChildren.push([key, child]);
|
|
1113
|
-
else regularChildren.push([key, child]);
|
|
1114
|
-
if (groupChildren.length > 0) {
|
|
1115
|
-
groupChildren.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1116
|
-
const groupStrs = [];
|
|
1117
|
-
for (const [_key, child] of groupChildren) {
|
|
1118
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, childAncestors, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1119
|
-
if (childStr !== "{}") groupStrs.push(childStr);
|
|
1120
|
-
}
|
|
1121
|
-
if (groupStrs.length > 0) lines.push(`${nextIndent}_M: [${groupStrs.join(", ")}],`);
|
|
1122
|
-
}
|
|
1123
|
-
for (const [key, child] of regularChildren) {
|
|
1124
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, childAncestors, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1125
|
-
if (childStr !== "{}") {
|
|
1126
|
-
const keyStr = JSON.stringify(key);
|
|
1127
|
-
lines.push(`${nextIndent}${keyStr}: ${childStr},`);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
if (lines.length === 0) return "{}";
|
|
1131
|
-
return `{\n${lines.join("\n")}\n${indent}}`;
|
|
985
|
+
/** A rewrite target or base path with each segment converted to its runtime trie key. */
|
|
986
|
+
function toRuntimeTriePath(path) {
|
|
987
|
+
return path.split("/").map(toRuntimeTrieKey).join("/");
|
|
1132
988
|
}
|
|
1133
989
|
/**
|
|
1134
990
|
* Serialize the build trie into JS code.
|
|
@@ -1139,7 +995,8 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1139
995
|
* - Route/page imports and lazy loaders
|
|
1140
996
|
* - Menu imports and lazy loaders
|
|
1141
997
|
* - The route trie object literal with _L, _I, _G, _B, _4, _E, _N, _P, _0, _9, _M
|
|
1142
|
-
*/
|
|
998
|
+
*/
|
|
999
|
+
function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
1143
1000
|
const includeEndpoints = isSSR;
|
|
1144
1001
|
const dynamicImports = ctx.dynamicImports;
|
|
1145
1002
|
const layoutIdMap = /* @__PURE__ */ new Map();
|
|
@@ -1201,12 +1058,140 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1201
1058
|
esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
|
|
1202
1059
|
routeIdMap.set(route.filePath, `()=>${route.id}`);
|
|
1203
1060
|
}
|
|
1204
|
-
const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap,
|
|
1061
|
+
const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap, isSSR, "", loadersByFile, routeLoaderSourceFiles);
|
|
1205
1062
|
const baseSegments = ctx.opts.basePathname.split("/").filter((s) => s.length > 0);
|
|
1206
1063
|
let routesExpr = trieStr;
|
|
1207
|
-
for (let j = baseSegments.length - 1; j >= 0; j--) routesExpr = `{ ${JSON.stringify(baseSegments[j])}: ${routesExpr} }`;
|
|
1064
|
+
for (let j = baseSegments.length - 1; j >= 0; j--) routesExpr = `{ ${JSON.stringify(escapeStaticTrieKey(baseSegments[j]))}: ${routesExpr} }`;
|
|
1208
1065
|
c.push(`export const routes = ${routesExpr};`);
|
|
1209
1066
|
}
|
|
1067
|
+
function collectFiles(node, cb) {
|
|
1068
|
+
for (const file of node._files) cb(file, node);
|
|
1069
|
+
for (const child of node.children.values()) collectFiles(child, cb);
|
|
1070
|
+
}
|
|
1071
|
+
/** Serialize a BuildTrieNode using the resolved route layout chains. */
|
|
1072
|
+
function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap, isSSR, indent, loadersByFile, routeLoaderSourceFiles) {
|
|
1073
|
+
const lines = [];
|
|
1074
|
+
const nextIndent = indent + " ";
|
|
1075
|
+
if (node._P) lines.push(`${nextIndent}_P: ${JSON.stringify(node._P)},`);
|
|
1076
|
+
if (node._0) lines.push(`${nextIndent}_0: ${JSON.stringify(node._0)},`);
|
|
1077
|
+
if (node._9) lines.push(`${nextIndent}_9: ${JSON.stringify(node._9)},`);
|
|
1078
|
+
if (node._G != null) {
|
|
1079
|
+
const target = toRuntimeTriePath(ctx.opts.basePathname + node._G);
|
|
1080
|
+
lines.push(`${nextIndent}_G: ${JSON.stringify(target)},`);
|
|
1081
|
+
}
|
|
1082
|
+
let layoutExpr;
|
|
1083
|
+
let indexExpr;
|
|
1084
|
+
let errorExpr;
|
|
1085
|
+
let notFoundExpr;
|
|
1086
|
+
let menuExpr;
|
|
1087
|
+
let bundleRoute;
|
|
1088
|
+
let pageLayouts;
|
|
1089
|
+
for (const file of node._files) if (file.type === "menu") {
|
|
1090
|
+
const menuId = menuIdMap.get(file.filePath);
|
|
1091
|
+
if (menuId) menuExpr = menuId;
|
|
1092
|
+
} else if (file.type === "layout") {
|
|
1093
|
+
const layoutId = layoutIdMap.get(file.filePath);
|
|
1094
|
+
if (layoutId) {
|
|
1095
|
+
if (file.extlessName === "layout" || file.extlessName === "layout!") layoutExpr = layoutId;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
for (const file of node._files) {
|
|
1099
|
+
if (file.type !== "route") continue;
|
|
1100
|
+
const loaderExpr = routeIdMap.get(file.filePath);
|
|
1101
|
+
if (!loaderExpr) continue;
|
|
1102
|
+
const route = ctx.routes.find((route) => route.filePath === file.filePath);
|
|
1103
|
+
const expr = buildLoaderChainExpr(file.extlessName, loaderExpr, route?.layouts ?? []);
|
|
1104
|
+
const boundary = caughtErrorName(file.extlessName);
|
|
1105
|
+
if (boundary === "404") notFoundExpr = expr;
|
|
1106
|
+
else if (boundary === "error") errorExpr = expr;
|
|
1107
|
+
else {
|
|
1108
|
+
indexExpr = expr;
|
|
1109
|
+
const { layoutName, layoutStop } = parseRouteIndexName(file.extlessName);
|
|
1110
|
+
pageLayouts = layoutStop || layoutName ? route?.layouts ?? [] : void 0;
|
|
1111
|
+
bundleRoute = route;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (layoutExpr) lines.push(`${nextIndent}_L: ${layoutExpr},`);
|
|
1115
|
+
if (indexExpr) {
|
|
1116
|
+
lines.push(`${nextIndent}_I: ${indexExpr},`);
|
|
1117
|
+
if (isSSR && bundleRoute) {
|
|
1118
|
+
const bundleNames = getClientRouteBundleNames(qwikPlugin, bundleRoute);
|
|
1119
|
+
if (bundleNames.length > 0) lines.push(`${nextIndent}_B: ${JSON.stringify(bundleNames)},`);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
const pluginFiles = ctx.serverPlugins.map((plugin) => plugin.filePath);
|
|
1123
|
+
const layoutFiles = node._files.filter((file) => file.type === "layout" && !file.extlessName.startsWith("layout-")).map((file) => file.filePath);
|
|
1124
|
+
if (node === ctx.routeTrie) layoutFiles.push(...pluginFiles);
|
|
1125
|
+
const pageFiles = bundleRoute ? [bundleRoute.filePath] : [];
|
|
1126
|
+
if (pageLayouts) pageFiles.push(...pageLayouts.map((layout) => layout.filePath), ...pluginFiles);
|
|
1127
|
+
for (const [field, routeFiles] of [["_R", layoutFiles], ["_D", pageFiles]]) {
|
|
1128
|
+
const routeLoaderFiles = [...new Set(routeFiles.flatMap((path) => [path, ...routeLoaderSourceFiles?.get(path) ?? []]))];
|
|
1129
|
+
if (routeLoaderFiles.length === 0) continue;
|
|
1130
|
+
if (loadersByFile) {
|
|
1131
|
+
const hashes = routeLoaderFiles.flatMap((filePath) => loadersByFile.get(normalizePathKey(filePath)) ?? []);
|
|
1132
|
+
if (hashes.length > 0) lines.push(`${nextIndent}${field}: ${JSON.stringify(hashes)},`);
|
|
1133
|
+
} else {
|
|
1134
|
+
const placeholder = `__LOADERS:${routeLoaderFiles.join("|")}__`;
|
|
1135
|
+
lines.push(`${nextIndent}${field}: ${JSON.stringify(placeholder)},`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (errorExpr) lines.push(`${nextIndent}_E: ${errorExpr},`);
|
|
1139
|
+
if (notFoundExpr) lines.push(`${nextIndent}_4: ${notFoundExpr},`);
|
|
1140
|
+
if (menuExpr) lines.push(`${nextIndent}_N: ${menuExpr},`);
|
|
1141
|
+
const groupChildren = [];
|
|
1142
|
+
const regularChildren = [];
|
|
1143
|
+
for (const [key, child] of node.children) if (isGroupKey(key)) groupChildren.push([key, child]);
|
|
1144
|
+
else regularChildren.push([key, child]);
|
|
1145
|
+
if (groupChildren.length > 0) {
|
|
1146
|
+
groupChildren.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1147
|
+
const groupStrs = [];
|
|
1148
|
+
for (const [_key, child] of groupChildren) {
|
|
1149
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1150
|
+
if (childStr !== "{}") groupStrs.push(childStr);
|
|
1151
|
+
}
|
|
1152
|
+
if (groupStrs.length > 0) lines.push(`${nextIndent}_M: [${groupStrs.join(", ")}],`);
|
|
1153
|
+
}
|
|
1154
|
+
for (const [key, child] of regularChildren) {
|
|
1155
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1156
|
+
if (childStr !== "{}") {
|
|
1157
|
+
const keyStr = JSON.stringify(toRuntimeTrieKey(key));
|
|
1158
|
+
lines.push(`${nextIndent}${keyStr}: ${childStr},`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (lines.length === 0) return "{}";
|
|
1162
|
+
return `{\n${lines.join("\n")}\n${indent}}`;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* The `_I`/`_E`/`_4` loader expression: a bare loader (runtime prepends gathered layouts), or an
|
|
1166
|
+
* override chain for `!` (layout stop) / `@name` (named layout).
|
|
1167
|
+
*/
|
|
1168
|
+
function buildLoaderChainExpr(extlessName, loaderExpr, layouts) {
|
|
1169
|
+
const { layoutName, layoutStop } = parseRouteIndexName(extlessName);
|
|
1170
|
+
if (layoutStop || layoutName) return `[ ${[...layouts.map((layout) => layout.id), loaderExpr].join(", ")} ]`;
|
|
1171
|
+
return loaderExpr;
|
|
1172
|
+
}
|
|
1173
|
+
function getClientRouteBundleNames(qwikPlugin, r) {
|
|
1174
|
+
const bundlesNames = [];
|
|
1175
|
+
const manifest = qwikPlugin.api.getManifest();
|
|
1176
|
+
if (manifest) {
|
|
1177
|
+
const manifestBundleNames = Object.keys(manifest.bundles);
|
|
1178
|
+
const addRouteFile = (filePath) => {
|
|
1179
|
+
filePath = removeExtension(filePath);
|
|
1180
|
+
for (const bundleName of manifestBundleNames) {
|
|
1181
|
+
const bundle = manifest.bundles[bundleName];
|
|
1182
|
+
if (bundle.origins) for (const bundleOrigin of bundle.origins) {
|
|
1183
|
+
const originPath = removeExtension(bundleOrigin);
|
|
1184
|
+
if (filePath.endsWith(originPath)) {
|
|
1185
|
+
if (!bundlesNames.includes(bundleName)) bundlesNames.push(bundleName);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
};
|
|
1190
|
+
for (const layout of r.layouts) addRouteFile(layout.filePath);
|
|
1191
|
+
addRouteFile(r.filePath);
|
|
1192
|
+
}
|
|
1193
|
+
return bundlesNames;
|
|
1194
|
+
}
|
|
1210
1195
|
function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
|
|
1211
1196
|
c.push(`\n/** Qwik Router ServerPlugins (${ctx.serverPlugins.length}) */`);
|
|
1212
1197
|
c.push(`export const serverPlugins = [`);
|
|
@@ -1219,40 +1204,49 @@ function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
|
|
|
1219
1204
|
}
|
|
1220
1205
|
c.push(`];`);
|
|
1221
1206
|
}
|
|
1222
|
-
/**
|
|
1207
|
+
/** The URL of the app's service worker entry, when the routes define one. */
|
|
1208
|
+
function resolveServiceWorkerUrl(ctx) {
|
|
1209
|
+
if (ctx.serviceWorkers.length === 0) return;
|
|
1210
|
+
const sw = ctx.serviceWorkers.sort((a, b) => a.chunkFileName.length < b.chunkFileName.length ? -1 : 1)[0];
|
|
1211
|
+
return ctx.opts.basePathname + sw.chunkFileName;
|
|
1212
|
+
}
|
|
1213
|
+
/** The `@qwik-router-sw-register` module, kept for apps that import it themselves. */
|
|
1214
|
+
function generateServiceWorkerRegister(ctx) {
|
|
1215
|
+
return `import { _getServiceWorkerScript } from '@qwik.dev/router';\nexport default _getServiceWorkerScript(${JSON.stringify(resolveServiceWorkerUrl(ctx))});\n`;
|
|
1216
|
+
}
|
|
1217
|
+
/** Generates the Qwik Router Config runtime code */
|
|
1218
|
+
function generateQwikRouterConfig(ctx, qwikPlugin, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
1223
1219
|
const esmImports = [];
|
|
1224
1220
|
const c = [];
|
|
1225
1221
|
c.push(`\n/** Qwik Router Config */`);
|
|
1226
1222
|
c.push(`\nimport { isDev } from '@qwik.dev/core/build';`);
|
|
1227
|
-
if (isSSR) esmImports.push(`import 'virtual:qwik-router-server-fns';`);
|
|
1223
|
+
if (isSSR) esmImports.push(`import { importEagerModules } from 'virtual:qwik-router-server-fns';`, `export { importEagerModules } from 'virtual:qwik-router-server-fns';`, `import { _setRouterConfig } from '@qwik.dev/router';`);
|
|
1228
1224
|
createServerPlugins(ctx, qwikPlugin, c, esmImports, isSSR);
|
|
1229
1225
|
createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles);
|
|
1230
1226
|
createEntries(ctx, c);
|
|
1231
|
-
c.push(`export const trailingSlash =
|
|
1227
|
+
c.push(`export const trailingSlash = !globalThis.__NO_TRAILING_SLASH__;`);
|
|
1232
1228
|
c.push(`export const basePathname = ${JSON.stringify(ctx.opts.basePathname)};`);
|
|
1233
1229
|
c.push(`export const cacheModules = !isDev;`);
|
|
1234
|
-
c.push(`export
|
|
1230
|
+
c.push(`export const serviceWorkerUrl = ${JSON.stringify(resolveServiceWorkerUrl(ctx))};`);
|
|
1231
|
+
const fields = [
|
|
1232
|
+
"routes",
|
|
1233
|
+
"serverPlugins",
|
|
1234
|
+
"trailingSlash",
|
|
1235
|
+
"basePathname",
|
|
1236
|
+
"cacheModules",
|
|
1237
|
+
"serviceWorkerUrl"
|
|
1238
|
+
];
|
|
1239
|
+
if (isSSR) fields.push("importEagerModules");
|
|
1240
|
+
c.push(`const config = { ${fields.join(", ")} };`);
|
|
1241
|
+
c.push(`export default config;`);
|
|
1242
|
+
if (isSSR) c.push(`_setRouterConfig(config);`);
|
|
1235
1243
|
return esmImports.join("\n") + c.join("\n");
|
|
1236
1244
|
}
|
|
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
|
-
function generateServiceWorkerRegister(ctx, swRegister) {
|
|
1241
|
-
let swReg;
|
|
1242
|
-
let swUrl = "/service-worker.js";
|
|
1243
|
-
if (ctx.serviceWorkers.length === 0) swReg = SW_UNREGISTER;
|
|
1244
|
-
else {
|
|
1245
|
-
swReg = swRegister;
|
|
1246
|
-
const sw = ctx.serviceWorkers.sort((a, b) => a.chunkFileName.length < b.chunkFileName.length ? -1 : 1)[0];
|
|
1247
|
-
swUrl = ctx.opts.basePathname + sw.chunkFileName;
|
|
1248
|
-
}
|
|
1249
|
-
swReg = swReg.replace("__url", swUrl);
|
|
1250
|
-
return `export default ${JSON.stringify(swReg)};`;
|
|
1251
|
-
}
|
|
1252
1245
|
/**
|
|
1253
1246
|
* Non-GET RouteModule handlers keep a route server-side (onGet is served statically). Typed against
|
|
1254
1247
|
* keyof RouteModule so a renamed/added handler fails to compile until classified.
|
|
1255
|
-
*/
|
|
1248
|
+
*/
|
|
1249
|
+
var NON_GET_HANDLERS = /* @__PURE__ */ new Set([
|
|
1256
1250
|
"onRequest",
|
|
1257
1251
|
"onPost",
|
|
1258
1252
|
"onPut",
|
|
@@ -1266,11 +1260,13 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1266
1260
|
* Imports tying a route to the server — loaders, actions, and server$ (which POSTs to the route's
|
|
1267
1261
|
* own URL). Matched on the import statement (the optimizer's ctxName isn't available
|
|
1268
1262
|
* pre-transform); fail-safe, so a stray match only keeps a route.
|
|
1269
|
-
*/
|
|
1263
|
+
*/
|
|
1264
|
+
var SERVER_QRL = /\b(?:routeLoader|routeAction|globalAction|server)(?:\$|Qrl)/;
|
|
1270
1265
|
/**
|
|
1271
1266
|
* True when the module exports no non-GET handler and imports no loader/action/server$ from the
|
|
1272
1267
|
* router. Pure (no I/O) for direct unit testing.
|
|
1273
|
-
*/
|
|
1268
|
+
*/
|
|
1269
|
+
function isServerFreeSource(code) {
|
|
1274
1270
|
for (const e of findExports(code)) {
|
|
1275
1271
|
if (e.specifier) return false;
|
|
1276
1272
|
if ([...e.name ? [e.name] : [], ...e.names ?? []].some((n) => NON_GET_HANDLERS.has(n))) return false;
|
|
@@ -1279,28 +1275,13 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1279
1275
|
return true;
|
|
1280
1276
|
}
|
|
1281
1277
|
/**
|
|
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
1278
|
* Route file paths to drop from the production server route plan — prerendered, static, server-free
|
|
1299
1279
|
* pages (own module and every layout) — so they tree-shake out of size-capped edge bundles.
|
|
1300
1280
|
* Candidates come from the SSG include/exclude; server surfaces are detected in route/layout source
|
|
1301
1281
|
* only. Fail-safe: dynamic routes, re-exports, and read errors keep the route. A loader/action
|
|
1302
1282
|
* route stays whole — stripping just its dead component needs optimizer segment data.
|
|
1303
|
-
*/
|
|
1283
|
+
*/
|
|
1284
|
+
async function getServerExcludedRoutes(ctx, ssg) {
|
|
1304
1285
|
const excluded = /* @__PURE__ */ new Set();
|
|
1305
1286
|
if (!ssg?.include?.length) return excluded;
|
|
1306
1287
|
const isPrerendered = createRouteTester(ctx.opts.basePathname, ssg.include, ssg.exclude);
|
|
@@ -1311,12 +1292,23 @@ var ROUTER_MODULE = "@qwik.dev/router";
|
|
|
1311
1292
|
}));
|
|
1312
1293
|
return excluded;
|
|
1313
1294
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1295
|
+
/** The route's own module and every layout wrapping it must be free of server code. */
|
|
1296
|
+
async function isRouteServerFree(route, cache) {
|
|
1297
|
+
if (!isMarkdownExt(route.ext) && !await isFileServerFree(route.filePath, cache)) return false;
|
|
1298
|
+
for (const layout of route.layouts) if (!await isFileServerFree(layout.filePath, cache)) return false;
|
|
1299
|
+
return true;
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Read + lex a module once, memoized by path. Returns the cached in-flight promise (not async) so
|
|
1303
|
+
* concurrent callers share one read; read/parse failure keeps the route.
|
|
1304
|
+
*/
|
|
1305
|
+
function isFileServerFree(filePath, cache) {
|
|
1306
|
+
let pending = cache.get(filePath);
|
|
1307
|
+
if (!pending) {
|
|
1308
|
+
pending = readFile(filePath, "utf-8").then(isServerFreeSource).catch(() => false);
|
|
1309
|
+
cache.set(filePath, pending);
|
|
1310
|
+
}
|
|
1311
|
+
return pending;
|
|
1320
1312
|
}
|
|
1321
1313
|
function getRouteImports(routes, manifest) {
|
|
1322
1314
|
const result = {};
|
|
@@ -1338,13 +1330,13 @@ function getRouteImports(routes, manifest) {
|
|
|
1338
1330
|
}
|
|
1339
1331
|
return result;
|
|
1340
1332
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1333
|
+
function isBundlePartOfRoute(bundle, routeAndLayoutPaths) {
|
|
1334
|
+
if (!bundle.origins) return false;
|
|
1335
|
+
return bundle.origins.some((bundleOrigin) => {
|
|
1336
|
+
const originPath = removeExtension(bundleOrigin);
|
|
1337
|
+
return routeAndLayoutPaths.some((path) => path.endsWith(originPath));
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1348
1340
|
var findLocation = (e) => {
|
|
1349
1341
|
const stack = e.stack;
|
|
1350
1342
|
if (typeof stack === "string") {
|
|
@@ -1382,6 +1374,13 @@ var findLocation = (e) => {
|
|
|
1382
1374
|
}
|
|
1383
1375
|
}
|
|
1384
1376
|
};
|
|
1377
|
+
var safeParseInt = (nu) => {
|
|
1378
|
+
try {
|
|
1379
|
+
return parseInt(nu, 10);
|
|
1380
|
+
} catch {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1385
1384
|
var splitRE = /\r?\n/;
|
|
1386
1385
|
var range = 2;
|
|
1387
1386
|
function posToNumber(source, pos) {
|
|
@@ -1508,60 +1507,9 @@ function createImageJsxModule(pathId, params, userOpts) {
|
|
|
1508
1507
|
function createSvgJsxModule(attrs) {
|
|
1509
1508
|
return `export default p => <svg {...p} {...${JSON.stringify(attrs)}} />`;
|
|
1510
1509
|
}
|
|
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({
|
|
1510
|
+
/** @public */
|
|
1511
|
+
function imagePlugin(userOpts) {
|
|
1512
|
+
return [import("vite-imagetools").then(({ imagetools }) => imagetools({
|
|
1565
1513
|
exclude: [],
|
|
1566
1514
|
extendOutputFormats(builtins) {
|
|
1567
1515
|
const jsx = () => (metadatas) => {
|
|
@@ -1654,6 +1602,58 @@ function optimizeSvg({ code, path }, userOpts) {
|
|
|
1654
1602
|
}
|
|
1655
1603
|
}];
|
|
1656
1604
|
}
|
|
1605
|
+
function optimizeSvg({ code, path }, userOpts) {
|
|
1606
|
+
const svgAttributes = {};
|
|
1607
|
+
const prefixIdsConfiguration = userOpts?.imageOptimization?.svgo?.prefixIds;
|
|
1608
|
+
const maybePrefixIdsPlugin = prefixIdsConfiguration !== false ? [{
|
|
1609
|
+
name: "prefixIds",
|
|
1610
|
+
params: prefixIdsConfiguration
|
|
1611
|
+
}] : [];
|
|
1612
|
+
const userPlugins = userOpts?.imageOptimization?.svgo?.plugins?.filter((plugin) => {
|
|
1613
|
+
if (plugin === "preset-default" || typeof plugin === "object" && plugin.name === "preset-default") {
|
|
1614
|
+
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.`);
|
|
1615
|
+
return false;
|
|
1616
|
+
}
|
|
1617
|
+
if (plugin === "prefixIds" || typeof plugin === "object" && plugin.name === "prefixIds") {
|
|
1618
|
+
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.`);
|
|
1619
|
+
return false;
|
|
1620
|
+
}
|
|
1621
|
+
return true;
|
|
1622
|
+
}) || [];
|
|
1623
|
+
const data = optimize(code, {
|
|
1624
|
+
floatPrecision: userOpts?.imageOptimization?.svgo?.floatPrecision,
|
|
1625
|
+
multipass: userOpts?.imageOptimization?.svgo?.multipass,
|
|
1626
|
+
path,
|
|
1627
|
+
plugins: [
|
|
1628
|
+
{
|
|
1629
|
+
name: "preset-default",
|
|
1630
|
+
params: { overrides: {
|
|
1631
|
+
removeViewBox: false,
|
|
1632
|
+
...userOpts?.imageOptimization?.svgo?.defaultPresetOverrides
|
|
1633
|
+
} }
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
name: "customPluginName",
|
|
1637
|
+
fn: () => {
|
|
1638
|
+
return { element: { exit: (node) => {
|
|
1639
|
+
if (node.name === "svg") {
|
|
1640
|
+
node.name = "g";
|
|
1641
|
+
Object.assign(svgAttributes, node.attributes);
|
|
1642
|
+
node.attributes = {};
|
|
1643
|
+
}
|
|
1644
|
+
} } };
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
...maybePrefixIdsPlugin,
|
|
1648
|
+
...userPlugins
|
|
1649
|
+
]
|
|
1650
|
+
}).data;
|
|
1651
|
+
svgAttributes.dangerouslySetInnerHTML = data.slice(3, -4);
|
|
1652
|
+
return {
|
|
1653
|
+
data,
|
|
1654
|
+
svgAttributes
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
1657
|
async function collectServerFnModuleIds(routingContext, resolvedVirtualId, pluginContext) {
|
|
1658
1658
|
const serverFnModules = /* @__PURE__ */ new Set();
|
|
1659
1659
|
const queuedModuleIds = /* @__PURE__ */ new Set();
|
|
@@ -1725,11 +1725,23 @@ function formatError(e) {
|
|
|
1725
1725
|
}
|
|
1726
1726
|
return e;
|
|
1727
1727
|
}
|
|
1728
|
+
var State = /* @__PURE__ */ function(State) {
|
|
1729
|
+
/** Collecting content until <body> is found */
|
|
1730
|
+
State[State["BUFFERING"] = 0] = "BUFFERING";
|
|
1731
|
+
/** Transforming the head portion */
|
|
1732
|
+
State[State["PROCESSING_HEAD"] = 1] = "PROCESSING_HEAD";
|
|
1733
|
+
/** Streaming transformed content until </body> */
|
|
1734
|
+
State[State["STREAMING_BODY"] = 2] = "STREAMING_BODY";
|
|
1735
|
+
/** Passing through content unchanged */
|
|
1736
|
+
State[State["PASSTHROUGH"] = 3] = "PASSTHROUGH";
|
|
1737
|
+
return State;
|
|
1738
|
+
}(State || {});
|
|
1728
1739
|
/**
|
|
1729
1740
|
* Patches a response object to intercept HTML streams and transform them using Vite's
|
|
1730
1741
|
* transformIndexHtml.
|
|
1731
|
-
*/
|
|
1732
|
-
|
|
1742
|
+
*/
|
|
1743
|
+
var HtmlTransformPatcher = class {
|
|
1744
|
+
state = State.BUFFERING;
|
|
1733
1745
|
buffer = "";
|
|
1734
1746
|
headInnerIndex = -1;
|
|
1735
1747
|
bodyInnerIndex = -1;
|
|
@@ -1782,7 +1794,7 @@ function formatError(e) {
|
|
|
1782
1794
|
};
|
|
1783
1795
|
}
|
|
1784
1796
|
handleWrite(chunk, encoding, callback) {
|
|
1785
|
-
if (!this.isHtmlResponse || this.state ===
|
|
1797
|
+
if (!this.isHtmlResponse || this.state === State.PASSTHROUGH) return this.origWrite(chunk, encoding, callback);
|
|
1786
1798
|
if (typeof encoding === "function") {
|
|
1787
1799
|
callback = encoding;
|
|
1788
1800
|
encoding = void 0;
|
|
@@ -1794,7 +1806,7 @@ function formatError(e) {
|
|
|
1794
1806
|
else data = chunk?.toString() || "";
|
|
1795
1807
|
this.buffer += data;
|
|
1796
1808
|
switch (this.state) {
|
|
1797
|
-
case
|
|
1809
|
+
case State.BUFFERING:
|
|
1798
1810
|
if (this.headInnerIndex === -1) {
|
|
1799
1811
|
const headMatch = this.buffer.match(/<head[^>]*>/i);
|
|
1800
1812
|
if (headMatch) {
|
|
@@ -1805,15 +1817,15 @@ function formatError(e) {
|
|
|
1805
1817
|
if (this.headInnerIndex !== -1) {
|
|
1806
1818
|
const bodyMatch = this.buffer.slice(this.headInnerIndex).match(/<body[^>]*>/i);
|
|
1807
1819
|
if (bodyMatch) {
|
|
1808
|
-
this.state =
|
|
1820
|
+
this.state = State.PROCESSING_HEAD;
|
|
1809
1821
|
const bodyOuterIndex = this.buffer.indexOf(bodyMatch[0]);
|
|
1810
1822
|
this.bodyInnerIndex = bodyOuterIndex + bodyMatch[0].length;
|
|
1811
1823
|
this.processingPromise = this.processHead();
|
|
1812
1824
|
}
|
|
1813
1825
|
}
|
|
1814
1826
|
break;
|
|
1815
|
-
case
|
|
1816
|
-
case
|
|
1827
|
+
case State.PROCESSING_HEAD: break;
|
|
1828
|
+
case State.STREAMING_BODY:
|
|
1817
1829
|
this.handleStreamingBodyState();
|
|
1818
1830
|
break;
|
|
1819
1831
|
default: throw new Error(`Invalid state: ${this.state}`);
|
|
@@ -1840,7 +1852,7 @@ function formatError(e) {
|
|
|
1840
1852
|
if (headCloseIndex === -1) throw new Error("Buffered HTML does not contain </head>");
|
|
1841
1853
|
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
1854
|
if (this.bodyPostContent.length > 0) {
|
|
1843
|
-
this.state =
|
|
1855
|
+
this.state = State.STREAMING_BODY;
|
|
1844
1856
|
this.handleStreamingBodyState();
|
|
1845
1857
|
return;
|
|
1846
1858
|
}
|
|
@@ -1863,7 +1875,7 @@ function formatError(e) {
|
|
|
1863
1875
|
this.flushBuffer(6);
|
|
1864
1876
|
}
|
|
1865
1877
|
transitionToPassthrough() {
|
|
1866
|
-
this.state =
|
|
1878
|
+
this.state = State.PASSTHROUGH;
|
|
1867
1879
|
this.flushBuffer();
|
|
1868
1880
|
}
|
|
1869
1881
|
flushBuffer(keep = 0) {
|
|
@@ -1892,7 +1904,8 @@ function formatError(e) {
|
|
|
1892
1904
|
this.origEnd(callback);
|
|
1893
1905
|
}
|
|
1894
1906
|
};
|
|
1895
|
-
/** Patches a response to enable HTML transformation using Vite's transformIndexHtml */
|
|
1907
|
+
/** Patches a response to enable HTML transformation using Vite's transformIndexHtml */
|
|
1908
|
+
function wrapResponseForHtmlTransform(request, response, server) {
|
|
1896
1909
|
new HtmlTransformPatcher(request, response, server);
|
|
1897
1910
|
return response;
|
|
1898
1911
|
}
|
|
@@ -1901,43 +1914,6 @@ var ROUTE_PATH_HEADER = "X-Qwik-route-path";
|
|
|
1901
1914
|
function getDevMiddlewareRequestPath(req) {
|
|
1902
1915
|
return req.originalUrl || req.url;
|
|
1903
1916
|
}
|
|
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
1917
|
var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
1942
1918
|
let mod;
|
|
1943
1919
|
try {
|
|
@@ -1974,12 +1950,11 @@ var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
|
1974
1950
|
res.end("/* Qwik Router Dev Service Worker */self.addEventListener('install', () => self.skipWaiting());self.addEventListener('activate', (ev) => ev.waitUntil(self.clients.claim()));");
|
|
1975
1951
|
return;
|
|
1976
1952
|
}
|
|
1977
|
-
globalThis.__qwik = void 0;
|
|
1978
1953
|
const { createQwikRouter } = await server.ssrLoadModule("@qwik.dev/router/middleware/node");
|
|
1979
1954
|
try {
|
|
1980
|
-
const render = async (opts) => {
|
|
1955
|
+
const render = (async (opts) => {
|
|
1981
1956
|
return await renderer(opts);
|
|
1982
|
-
};
|
|
1957
|
+
});
|
|
1983
1958
|
const { router, staticFile } = createQwikRouter({
|
|
1984
1959
|
render,
|
|
1985
1960
|
platform: ctx.opts.platform
|
|
@@ -1997,6 +1972,43 @@ var makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
|
1997
1972
|
return;
|
|
1998
1973
|
}
|
|
1999
1974
|
};
|
|
1975
|
+
async function preloadQLoaderRouteLoader(server, ctx, req) {
|
|
1976
|
+
const requestPath = getDevMiddlewareRequestPath(req);
|
|
1977
|
+
if (!requestPath) return;
|
|
1978
|
+
let requestUrl;
|
|
1979
|
+
try {
|
|
1980
|
+
requestUrl = new URL(requestPath, "http://qwik.dev");
|
|
1981
|
+
} catch {
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
const recognized = recognizeRequest(requestUrl.pathname);
|
|
1985
|
+
if (recognized?.type !== "@isQLoader" || !recognized.data?.loaderId) return;
|
|
1986
|
+
const loaderId = recognized.data.loaderId;
|
|
1987
|
+
const headerValue = req.headers[FULLPATH_HEADER.toLowerCase()] ?? req.headers[ROUTE_PATH_HEADER.toLowerCase()];
|
|
1988
|
+
const fullPathHeader = Array.isArray(headerValue) ? headerValue[0] : headerValue ?? null;
|
|
1989
|
+
const loaderPathname = trimRecognizedInternalPathname(requestUrl.pathname, recognized);
|
|
1990
|
+
const pathname = resolveValidInternalFullPathname(loaderPathname, fullPathHeader) ?? loaderPathname;
|
|
1991
|
+
const route = ctx.routes.filter((route) => isPageExt(route.ext)).slice().sort(routeSortCompare).find((route) => route.pattern.test(pathname));
|
|
1992
|
+
if (!route) return;
|
|
1993
|
+
const routeRootFiles = [...route.layouts.map((layout) => layout.filePath), route.filePath];
|
|
1994
|
+
const modules = await Promise.all([...ctx.serverPlugins.map((plugin) => loadSsrModule(server, plugin.filePath)), ...routeRootFiles.map((filePath) => loadSsrModule(server, filePath))]);
|
|
1995
|
+
for (const mod of modules) {
|
|
1996
|
+
const loader = findMatchingLoader(mod, loaderId);
|
|
1997
|
+
if (loader) return loader;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
async function loadSsrModule(server, filePath) {
|
|
2001
|
+
return server.ssrLoadModule(getImportPath(normalizePath$1(filePath)));
|
|
2002
|
+
}
|
|
2003
|
+
function findMatchingLoader(mod, loaderId) {
|
|
2004
|
+
for (const value of Object.values(mod)) if (isLoaderInternal(value) && matchesLoaderId(value, loaderId)) return value;
|
|
2005
|
+
}
|
|
2006
|
+
function matchesLoaderId(loader, loaderId) {
|
|
2007
|
+
return loader.__id === loaderId || loader.__qrl.getHash() === loaderId;
|
|
2008
|
+
}
|
|
2009
|
+
function isLoaderInternal(value) {
|
|
2010
|
+
return typeof value === "function" && value.__brand === "server_loader";
|
|
2011
|
+
}
|
|
2000
2012
|
var CSS_EXTENSIONS = [
|
|
2001
2013
|
".css",
|
|
2002
2014
|
".scss",
|
|
@@ -2008,13 +2020,22 @@ var CSS_EXTENSIONS = [
|
|
|
2008
2020
|
var JS_EXTENSIONS = /\.[mc]?[tj]sx?$/;
|
|
2009
2021
|
var isCssPath = (url) => CSS_EXTENSIONS.some((ext) => url.endsWith(ext));
|
|
2010
2022
|
/**
|
|
2023
|
+
* The URL the Vite dev server serves a module under. For a file, the module graph URL is already
|
|
2024
|
+
* one (`/src/a.css`, `/@fs/...`). A virtual module from a plugin has its id as URL, and Vite serves
|
|
2025
|
+
* it under `/@id/` with the `\0` written as `__x00__`, the same as Vite's own `wrapId`.
|
|
2026
|
+
*
|
|
2027
|
+
* `\0virtual:theme.css` -> `/@id/__x00__virtual:theme.css`
|
|
2028
|
+
*/
|
|
2029
|
+
var toDevServerUrl = (url) => url.startsWith("/") ? url : `/@id/${url.replace("\0", "__x00__")}`;
|
|
2030
|
+
/**
|
|
2011
2031
|
* Qwik handles CSS imports itself, meaning vite doesn't get to see them, so we need to manually
|
|
2012
2032
|
* inject the CSS URLs.
|
|
2013
2033
|
*
|
|
2014
2034
|
* We check both the client and SSR module graphs because on the first page request only the SSR
|
|
2015
2035
|
* graph has been populated (via ssrLoadModule). The client graph is empty until the browser
|
|
2016
2036
|
* actually fetches modules through Vite's dev server.
|
|
2017
|
-
*/
|
|
2037
|
+
*/
|
|
2038
|
+
var getCssUrls = (server) => {
|
|
2018
2039
|
const clientGraph = server.environments.client.moduleGraph;
|
|
2019
2040
|
const ssrGraph = server.environments.ssr.moduleGraph;
|
|
2020
2041
|
const cssModules = /* @__PURE__ */ new Set();
|
|
@@ -2034,8 +2055,8 @@ var isCssPath = (url) => CSS_EXTENSIONS.some((ext) => url.endsWith(ext));
|
|
|
2034
2055
|
return importerPath && JS_EXTENSIONS.test(importerPath);
|
|
2035
2056
|
});
|
|
2036
2057
|
if ((isEntryCSS || hasJSImporter) && !hasCSSImporter && !cssImportedByCSS.has(mod.url)) {
|
|
2037
|
-
cssModules.add(`${mod.url}${mod.lastHMRTimestamp ? `?t=${mod.lastHMRTimestamp}` : ""}`);
|
|
2038
|
-
if (mod.file) server.watcher.add(mod.file);
|
|
2058
|
+
cssModules.add(`${toDevServerUrl(mod.url)}${mod.lastHMRTimestamp ? `?t=${mod.lastHMRTimestamp}` : ""}`);
|
|
2059
|
+
if (mod.file && mod.url.startsWith("/")) server.watcher.add(mod.file);
|
|
2039
2060
|
}
|
|
2040
2061
|
}
|
|
2041
2062
|
}
|
|
@@ -2053,7 +2074,8 @@ var getRouterIndexTags = (server) => {
|
|
|
2053
2074
|
/**
|
|
2054
2075
|
* Live-reload route CSS that Qwik injects as `<link>` tags; it only lives in the SSR graph, so Vite
|
|
2055
2076
|
* skips HMR. Emit a `css-update` to swap the `<link>` in place. Returns `true` when handled.
|
|
2056
|
-
*/
|
|
2077
|
+
*/
|
|
2078
|
+
var sendRouterCssHotUpdate = (server, file, timestamp) => {
|
|
2057
2079
|
const { client, ssr } = server.environments;
|
|
2058
2080
|
if (!isCssPath(file) || client.moduleGraph.getModulesByFile(file)?.size) return false;
|
|
2059
2081
|
const paths = /* @__PURE__ */ new Set();
|
|
@@ -2077,19 +2099,37 @@ var QWIK_ROUTER_CONFIG_ID = "@qwik-router-config";
|
|
|
2077
2099
|
/**
|
|
2078
2100
|
* This virtual module is used to generate dynamic entries for user route files, which are added as
|
|
2079
2101
|
* dynamic imports to the qwik-router-config as a way to create new entry points for the build.
|
|
2080
|
-
*/
|
|
2102
|
+
*/
|
|
2103
|
+
var QWIK_ROUTER_ENTRIES_ID = "@qwik-router-entries";
|
|
2081
2104
|
var QWIK_ROUTER = "@qwik.dev/router";
|
|
2082
2105
|
var QWIK_ROUTER_SW_REGISTER = "@qwik-router-sw-register";
|
|
2083
2106
|
var VIRTUAL_SERVER_FNS = "virtual:qwik-router-server-fns";
|
|
2084
|
-
/**
|
|
2085
|
-
|
|
2107
|
+
/**
|
|
2108
|
+
* @deprecated Use `qwikRouter` instead. Will be removed in V3
|
|
2109
|
+
* @public
|
|
2110
|
+
*/
|
|
2111
|
+
function qwikCity(userOpts) {
|
|
2112
|
+
return qwikRouter(userOpts);
|
|
2113
|
+
}
|
|
2114
|
+
/** @public */
|
|
2115
|
+
function qwikRouter(userOpts) {
|
|
2116
|
+
const buildContextRef = { current: null };
|
|
2117
|
+
return [
|
|
2118
|
+
qwikRouterPlugin(userOpts, buildContextRef),
|
|
2119
|
+
serverFnsPlugin(buildContextRef),
|
|
2120
|
+
...imagePlugin(userOpts)
|
|
2121
|
+
];
|
|
2122
|
+
}
|
|
2123
|
+
/** Replace or strip loader placeholders in a bundle chunk. */
|
|
2124
|
+
function replaceLoaderPlaceholders(code, loadersByFile) {
|
|
2125
|
+
return code.replace(/(_R|_D)\s*:\s*(["'`])__LOADERS:([^"'`]+)__\2\s*,?/g, (_match, field, _q, paths) => {
|
|
2086
2126
|
const filePaths = JSON.parse(`"${paths}"`).split("|");
|
|
2087
2127
|
const hashes = [];
|
|
2088
2128
|
for (const filePath of filePaths) {
|
|
2089
2129
|
const fileHashes = loadersByFile.get(normalizePathKey(filePath));
|
|
2090
2130
|
if (fileHashes) hashes.push(...fileHashes);
|
|
2091
2131
|
}
|
|
2092
|
-
if (hashes.length > 0) return
|
|
2132
|
+
if (hashes.length > 0) return `${field}: ${JSON.stringify(hashes)},`;
|
|
2093
2133
|
return "";
|
|
2094
2134
|
});
|
|
2095
2135
|
}
|
|
@@ -2127,6 +2167,14 @@ function isDiscoveredRouteLoaderSource(filePath, sourceFiles) {
|
|
|
2127
2167
|
for (const files of sourceFiles.values()) if (files.includes(normalizedPath)) return true;
|
|
2128
2168
|
return false;
|
|
2129
2169
|
}
|
|
2170
|
+
async function findRouteLoaderSourceFiles(ctx, resolveSource) {
|
|
2171
|
+
const sources = /* @__PURE__ */ new Map();
|
|
2172
|
+
const owners = /* @__PURE__ */ new Set();
|
|
2173
|
+
collectRouteLoaderOwners(ctx.routeTrie, owners);
|
|
2174
|
+
for (const plugin of ctx.serverPlugins) owners.add(plugin.filePath);
|
|
2175
|
+
await Promise.all([...owners].map((owner) => collectRouteLoaderSources(owner, owner, resolveSource, sources)));
|
|
2176
|
+
return sources;
|
|
2177
|
+
}
|
|
2130
2178
|
function collectRouteLoaderOwners(node, owners) {
|
|
2131
2179
|
for (const file of node._files) if (file.type === "layout" || file.type === "route") owners.add(file.filePath);
|
|
2132
2180
|
for (const child of node.children.values()) collectRouteLoaderOwners(child, owners);
|
|
@@ -2166,14 +2214,6 @@ async function collectRouteLoaderSources(owner, filePath, resolveSource, sources
|
|
|
2166
2214
|
}
|
|
2167
2215
|
}
|
|
2168
2216
|
}
|
|
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
2217
|
function invalidateRouterConfigModules(server) {
|
|
2178
2218
|
const modules = [];
|
|
2179
2219
|
const moduleGraphs = /* @__PURE__ */ new Set();
|
|
@@ -2192,21 +2232,6 @@ function invalidateRouterConfigModules(server) {
|
|
|
2192
2232
|
}
|
|
2193
2233
|
return modules;
|
|
2194
2234
|
}
|
|
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
2235
|
function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
2211
2236
|
let ctx = null;
|
|
2212
2237
|
let mdxTransform = null;
|
|
@@ -2218,9 +2243,13 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2218
2243
|
let devSsrServer = userOpts?.devSsrServer;
|
|
2219
2244
|
const routesDir = userOpts?.routesDir ?? "src/routes";
|
|
2220
2245
|
const serverPluginsDir = userOpts?.serverPluginsDir ?? routesDir;
|
|
2221
|
-
/** Map from source file path to array of routeLoader$ hashes found in that file */
|
|
2246
|
+
/** Map from source file path to array of routeLoader$ hashes found in that file */
|
|
2247
|
+
const loadersByFile = /* @__PURE__ */ new Map();
|
|
2222
2248
|
let reExportedRouteLoaderSources;
|
|
2223
|
-
/** SSG include/exclude from the adapter (see `_setSsgRoutes`); drives the server-route prune. */
|
|
2249
|
+
/** SSG include/exclude from the adapter (see `_setSsgRoutes`); drives the server-route prune. */
|
|
2250
|
+
let ssgRoutePatterns;
|
|
2251
|
+
/** Extensionless ids of the server entries that must import the generated config. */
|
|
2252
|
+
let serverEntryIds = [];
|
|
2224
2253
|
return {
|
|
2225
2254
|
name: "vite-plugin-qwik-router",
|
|
2226
2255
|
enforce: "pre",
|
|
@@ -2245,6 +2274,7 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2245
2274
|
define: {
|
|
2246
2275
|
"globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__": JSON.stringify(userOpts?.defaultLoadersSerializationStrategy || "never"),
|
|
2247
2276
|
"globalThis.__NO_TRAILING_SLASH__": JSON.stringify(userOpts?.trailingSlash === false),
|
|
2277
|
+
"globalThis.__QWIK_ROUTER_BASE_PATHNAME__": JSON.stringify(resolveBasePathname(userOpts, _viteConfig.base || "/")),
|
|
2248
2278
|
"globalThis.__SSR_CACHE_SIZE__": JSON.stringify(viteEnv.command === "serve" ? 0 : userOpts?.ssrCacheSize ?? 50),
|
|
2249
2279
|
"globalThis.__STRICT_LOADERS__": JSON.stringify(userOpts?.strictLoaders !== false)
|
|
2250
2280
|
},
|
|
@@ -2332,6 +2362,7 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2332
2362
|
return getRouteImports(ctx.routes, manifest);
|
|
2333
2363
|
});
|
|
2334
2364
|
outDir = config.build?.outDir;
|
|
2365
|
+
serverEntryIds = getServerEntryIds(rootDir, qwikPlugin.api.getOptions().srcDir ?? void 0, config.build?.ssr, config.build?.rolldownOptions?.input);
|
|
2335
2366
|
},
|
|
2336
2367
|
async configureServer(server) {
|
|
2337
2368
|
devServer = server;
|
|
@@ -2372,6 +2403,10 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2372
2403
|
},
|
|
2373
2404
|
buildStart() {
|
|
2374
2405
|
resetBuildContext(ctx);
|
|
2406
|
+
if (this.environment.mode === "build" && this.environment.config.consumer === "client") this.emitFile({
|
|
2407
|
+
type: "chunk",
|
|
2408
|
+
id: QWIK_ROUTER_CONFIG_ID
|
|
2409
|
+
});
|
|
2375
2410
|
},
|
|
2376
2411
|
resolveId(id) {
|
|
2377
2412
|
if (id === "@qwik-router-config" || id === QWIK_ROUTER_ENTRIES_ID) return {
|
|
@@ -2402,12 +2437,16 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2402
2437
|
});
|
|
2403
2438
|
return generateQwikRouterConfig(ctx, qwikPlugin, isServerConsumer, devServer ? loadersByFile : void 0, serverExcludePaths, reExportedRouteLoaderSources);
|
|
2404
2439
|
}
|
|
2405
|
-
if (isSwRegister) return generateServiceWorkerRegister(ctx
|
|
2440
|
+
if (isSwRegister) return generateServiceWorkerRegister(ctx);
|
|
2406
2441
|
}
|
|
2407
2442
|
}
|
|
2408
2443
|
return null;
|
|
2409
2444
|
},
|
|
2410
2445
|
async transform(code, id) {
|
|
2446
|
+
if (this.environment.config.consumer === "server" && isServerEntryId(id, serverEntryIds)) return {
|
|
2447
|
+
code: `${code}\nimport '${QWIK_ROUTER_CONFIG_ID}';`,
|
|
2448
|
+
map: null
|
|
2449
|
+
};
|
|
2411
2450
|
if (id.startsWith("\0")) return;
|
|
2412
2451
|
const ext = extname(id).toLowerCase();
|
|
2413
2452
|
if (ctx && (ext === ".md" || ext === ".mdx")) {
|
|
@@ -2472,11 +2511,27 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2472
2511
|
}
|
|
2473
2512
|
};
|
|
2474
2513
|
}
|
|
2514
|
+
async function generateServerPackageJson(outDir) {
|
|
2515
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
2516
|
+
const serverPackageJsonPath = join(outDir, "package.json");
|
|
2517
|
+
let packageJson = {};
|
|
2518
|
+
if (fs.existsSync(serverPackageJsonPath)) {
|
|
2519
|
+
const content = await fs.promises.readFile(serverPackageJsonPath, "utf-8");
|
|
2520
|
+
packageJson = { ...JSON.parse(content) };
|
|
2521
|
+
}
|
|
2522
|
+
packageJson = {
|
|
2523
|
+
...packageJson,
|
|
2524
|
+
type: "module"
|
|
2525
|
+
};
|
|
2526
|
+
const serverPackageJsonCode = JSON.stringify(packageJson, null, 2);
|
|
2527
|
+
await fs.promises.writeFile(serverPackageJsonPath, serverPackageJsonCode);
|
|
2528
|
+
}
|
|
2475
2529
|
/**
|
|
2476
2530
|
* Separate plugin that tracks modules containing server$ functions during SSR builds and generates
|
|
2477
2531
|
* `virtual:qwik-router-server-fns` — a virtual module that statically imports all such modules so
|
|
2478
2532
|
* their `_regSymbol` side effects run before any RPC request arrives.
|
|
2479
|
-
*/
|
|
2533
|
+
*/
|
|
2534
|
+
function serverFnsPlugin(buildContextRef) {
|
|
2480
2535
|
const RESOLVED_ID = "\0virtual:qwik-router-server-fns";
|
|
2481
2536
|
const serverFnModules = /* @__PURE__ */ new Set();
|
|
2482
2537
|
let serverFnsReady = null;
|
|
@@ -2515,26 +2570,36 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2515
2570
|
const isServerBuild = this.environment.config.consumer === "server" && this.environment.mode === "build";
|
|
2516
2571
|
if (id === RESOLVED_ID) {
|
|
2517
2572
|
if (isServerBuild) await collectServerFnModules.call(this);
|
|
2518
|
-
if (!isServerBuild || serverFnModules.size === 0) return "
|
|
2519
|
-
return [...serverFnModules].map((mod
|
|
2573
|
+
if (!isServerBuild || serverFnModules.size === 0) return "export const importEagerModules = () => Promise.resolve();\n";
|
|
2574
|
+
return "export const importEagerModules = () =>\n Promise.all([\n" + [...serverFnModules].map((mod) => ` import(${JSON.stringify(mod)}),`).join("\n") + "\n ]);\n";
|
|
2520
2575
|
}
|
|
2521
2576
|
return null;
|
|
2522
2577
|
}
|
|
2523
2578
|
}
|
|
2524
2579
|
};
|
|
2525
2580
|
}
|
|
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
2581
|
/**
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
2537
|
-
*/
|
|
2538
|
-
|
|
2582
|
+
* The server entries: `src/entry.ssr` (what the dev server renders through) plus the configured SSR
|
|
2583
|
+
* build inputs, which may be virtual ids.
|
|
2584
|
+
*/
|
|
2585
|
+
function getServerEntryIds(rootDir, srcDir, buildSsr, input) {
|
|
2586
|
+
const candidates = [];
|
|
2587
|
+
if (srcDir) candidates.push(resolve(srcDir, "entry.ssr"));
|
|
2588
|
+
if (typeof buildSsr === "string") candidates.push(buildSsr);
|
|
2589
|
+
if (typeof input === "string") candidates.push(input);
|
|
2590
|
+
else if (Array.isArray(input)) candidates.push(...input);
|
|
2591
|
+
else if (input) candidates.push(...Object.values(input));
|
|
2592
|
+
return candidates.map((candidate) => normalizeEntryId(candidate, rootDir));
|
|
2593
|
+
}
|
|
2594
|
+
function isServerEntryId(id, serverEntryIds) {
|
|
2595
|
+
const entryId = normalizeEntryId(id.split("?", 1)[0], "");
|
|
2596
|
+
return serverEntryIds.includes(entryId);
|
|
2597
|
+
}
|
|
2598
|
+
var isVirtualEntryId = (id) => id.startsWith("@") || id.startsWith("\0");
|
|
2599
|
+
/** Absolute path without its script extension, or the id itself for a virtual entry. */
|
|
2600
|
+
function normalizeEntryId(id, rootDir) {
|
|
2601
|
+
if (isVirtualEntryId(id)) return id;
|
|
2602
|
+
const absolute = rootDir ? resolve(rootDir, id) : id;
|
|
2603
|
+
return normalizePath$1(absolute).replace(/\.[cm]?[jt]sx?$/, "");
|
|
2539
2604
|
}
|
|
2540
2605
|
export { extendConfig, qwikCity, qwikRouter };
|