@qwik.dev/router 2.0.0-beta.37 → 2.0.0-beta.39
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/cloudflare-pages/vite/index.mjs +2 -2
- package/lib/adapters/shared/vite/index.d.ts +3 -4
- package/lib/adapters/shared/vite/index.mjs +158 -143
- package/lib/chunks/dev-preloaded-route-loader.mjs +3 -0
- package/lib/chunks/fs.mjs +6 -2
- package/lib/chunks/head.qwik.mjs +814 -93
- package/lib/chunks/request-body-limit.mjs +37 -0
- package/lib/chunks/request-path.mjs +2 -2
- package/lib/chunks/routes.mjs +47 -0
- package/lib/chunks/server-error.mjs +19 -0
- package/lib/chunks/system.mjs +2 -1
- package/lib/chunks/use-functions.qwik.mjs +1 -1
- package/lib/chunks/{worker-thread.qwik.mjs → user-response.mjs} +1053 -1749
- package/lib/chunks/worker-thread.mjs +317 -0
- package/lib/index.d.ts +89 -55
- package/lib/index.qwik.mjs +178 -100
- package/lib/middleware/azure-swa/index.mjs +13 -9
- package/lib/middleware/cloudflare-pages/index.mjs +2 -2
- package/lib/middleware/deno/index.d.ts +2 -0
- package/lib/middleware/deno/index.mjs +2 -1
- package/lib/middleware/netlify-edge/index.mjs +2 -2
- package/lib/middleware/node/index.d.ts +9 -1
- package/lib/middleware/node/index.mjs +28 -3
- package/lib/middleware/request-handler/index.d.ts +9 -10
- package/lib/middleware/request-handler/index.mjs +26 -1105
- package/lib/middleware/vercel-edge/index.mjs +2 -2
- package/lib/ssg/index.d.ts +2 -10
- package/lib/ssg/index.mjs +10 -50
- package/lib/vite/index.d.ts +8 -0
- package/lib/vite/index.mjs +406 -117
- package/package.json +5 -4
- package/lib/chunks/action-handler.mjs +0 -782
- package/lib/chunks/deepFreeze.qwik.mjs +0 -608
- package/lib/chunks/error-handler.mjs +0 -57
- package/lib/chunks/not-found-wrapper.qwik.mjs +0 -25
package/lib/vite/index.mjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { mergeConfig, normalizePath as normalizePath$1, loadEnv } from 'vite';
|
|
2
2
|
import fs, { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import path, { join, dirname, basename, resolve, isAbsolute, extname } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
+
import { findExports, findStaticImports } from 'mlly';
|
|
6
|
+
import { g as getExtension, r as removeExtension, i as isIndexModule, a as isErrorName, b as isPageModuleExt, c as isModuleExt, d as isMarkdownExt, e as isLayoutModule, f as isEntryName, h as isMenuFileName, j as isServiceWorkerName, k as normalizePath, l as getPathnameFromDirPath, m as getMenuPathname, o as createFileId, p as parseRouteIndexName, q as errorBoundaryName, s as isPluginModule, t as isPageExt } from '../chunks/fs.mjs';
|
|
5
7
|
import { a as addError, b as addWarning } from '../chunks/format.mjs';
|
|
6
8
|
import { i as isSameOriginUrl, e as ensureSlash } from '../chunks/pathname.mjs';
|
|
9
|
+
import { c as createRouteTester } from '../chunks/routes.mjs';
|
|
7
10
|
import { marked } from 'marked';
|
|
8
11
|
import { createHash } from 'node:crypto';
|
|
9
12
|
import { SourceMapGenerator } from 'source-map';
|
|
@@ -16,6 +19,8 @@ import { toString } from 'hast-util-to-string';
|
|
|
16
19
|
import { refractor } from 'refractor';
|
|
17
20
|
import tsxLang from 'refractor/lang/tsx.js';
|
|
18
21
|
import { optimize } from 'svgo';
|
|
22
|
+
import { r as recognizeRequest, I as IsQLoader, t as trimRecognizedInternalPathname, a as resolveValidInternalFullPathname } from '../chunks/request-path.mjs';
|
|
23
|
+
import { d as devPreloadedRouteLoaders } from '../chunks/dev-preloaded-route-loader.mjs';
|
|
19
24
|
|
|
20
25
|
function extendConfig(baseConfigExport, serverConfigExport) {
|
|
21
26
|
return async (env) => {
|
|
@@ -263,43 +268,6 @@ function parseRoutePathname(basePathname, pathname) {
|
|
|
263
268
|
};
|
|
264
269
|
}
|
|
265
270
|
|
|
266
|
-
function routeSortCompare(a, b) {
|
|
267
|
-
const maxSegments = Math.max(a.segments.length, b.segments.length);
|
|
268
|
-
for (let i = 0; i < maxSegments; i += 1) {
|
|
269
|
-
const sa = a.segments[i];
|
|
270
|
-
const sb = b.segments[i];
|
|
271
|
-
if (!sa) {
|
|
272
|
-
return a.pathname.includes("[...") ? 1 : -1;
|
|
273
|
-
}
|
|
274
|
-
if (!sb) {
|
|
275
|
-
return b.pathname.includes("[...") ? -1 : 1;
|
|
276
|
-
}
|
|
277
|
-
const maxParts = Math.max(sa.length, sb.length);
|
|
278
|
-
for (let i2 = 0; i2 < maxParts; i2 += 1) {
|
|
279
|
-
const pa = sa[i2];
|
|
280
|
-
const pb = sb[i2];
|
|
281
|
-
if (pa === void 0) {
|
|
282
|
-
return pb.dynamic ? -1 : 1;
|
|
283
|
-
}
|
|
284
|
-
if (pb === void 0) {
|
|
285
|
-
return pa.dynamic ? 1 : -1;
|
|
286
|
-
}
|
|
287
|
-
if (pa.dynamic !== pb.dynamic) {
|
|
288
|
-
return pa.dynamic ? 1 : -1;
|
|
289
|
-
}
|
|
290
|
-
if (pa.dynamic) {
|
|
291
|
-
if (pa.rest !== pb.rest) {
|
|
292
|
-
return pa.rest ? 1 : -1;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
if (a.pathname === b.pathname) {
|
|
298
|
-
return a.ext > b.ext ? -1 : 1;
|
|
299
|
-
}
|
|
300
|
-
return a.pathname < b.pathname ? -1 : 1;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
271
|
const LAYOUT_ID = "layout";
|
|
304
272
|
const LAYOUT_NAMED_PREFIX = LAYOUT_ID + "-";
|
|
305
273
|
const LAYOUT_TOP_SUFFIX = "!";
|
|
@@ -335,8 +303,9 @@ function resolveRoute(opts, appLayouts, sourceFile) {
|
|
|
335
303
|
const routesDir = opts.routesDir;
|
|
336
304
|
const { layoutName, layoutStop } = parseRouteIndexName(sourceFile.extlessName);
|
|
337
305
|
let pathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
|
|
338
|
-
|
|
339
|
-
|
|
306
|
+
const boundary = errorBoundaryName(sourceFile.extlessName);
|
|
307
|
+
if (boundary) {
|
|
308
|
+
pathname += boundary + ".html";
|
|
340
309
|
}
|
|
341
310
|
if (!layoutStop) {
|
|
342
311
|
let currentDir = normalizePath(dirname(filePath));
|
|
@@ -374,6 +343,43 @@ function resolveRoute(opts, appLayouts, sourceFile) {
|
|
|
374
343
|
};
|
|
375
344
|
}
|
|
376
345
|
|
|
346
|
+
function routeSortCompare(a, b) {
|
|
347
|
+
const maxSegments = Math.max(a.segments.length, b.segments.length);
|
|
348
|
+
for (let i = 0; i < maxSegments; i += 1) {
|
|
349
|
+
const sa = a.segments[i];
|
|
350
|
+
const sb = b.segments[i];
|
|
351
|
+
if (!sa) {
|
|
352
|
+
return a.pathname.includes("[...") ? 1 : -1;
|
|
353
|
+
}
|
|
354
|
+
if (!sb) {
|
|
355
|
+
return b.pathname.includes("[...") ? -1 : 1;
|
|
356
|
+
}
|
|
357
|
+
const maxParts = Math.max(sa.length, sb.length);
|
|
358
|
+
for (let i2 = 0; i2 < maxParts; i2 += 1) {
|
|
359
|
+
const pa = sa[i2];
|
|
360
|
+
const pb = sb[i2];
|
|
361
|
+
if (pa === void 0) {
|
|
362
|
+
return pb.dynamic ? -1 : 1;
|
|
363
|
+
}
|
|
364
|
+
if (pb === void 0) {
|
|
365
|
+
return pa.dynamic ? 1 : -1;
|
|
366
|
+
}
|
|
367
|
+
if (pa.dynamic !== pb.dynamic) {
|
|
368
|
+
return pa.dynamic ? 1 : -1;
|
|
369
|
+
}
|
|
370
|
+
if (pa.dynamic) {
|
|
371
|
+
if (pa.rest !== pb.rest) {
|
|
372
|
+
return pa.rest ? 1 : -1;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (a.pathname === b.pathname) {
|
|
378
|
+
return a.ext > b.ext ? -1 : 1;
|
|
379
|
+
}
|
|
380
|
+
return a.pathname < b.pathname ? -1 : 1;
|
|
381
|
+
}
|
|
382
|
+
|
|
377
383
|
function parseDirName(name) {
|
|
378
384
|
if (name.startsWith("(") && name.endsWith(")")) {
|
|
379
385
|
return {
|
|
@@ -412,7 +418,6 @@ async function walkRouteDir(node, dirPath) {
|
|
|
412
418
|
if (!child) {
|
|
413
419
|
child = {
|
|
414
420
|
_files: [],
|
|
415
|
-
_dirPath: itemPath,
|
|
416
421
|
children: /* @__PURE__ */ new Map()
|
|
417
422
|
};
|
|
418
423
|
node.children.set(itemName, child);
|
|
@@ -423,7 +428,6 @@ async function walkRouteDir(node, dirPath) {
|
|
|
423
428
|
if (!child) {
|
|
424
429
|
child = {
|
|
425
430
|
_files: [],
|
|
426
|
-
_dirPath: itemPath,
|
|
427
431
|
children: /* @__PURE__ */ new Map()
|
|
428
432
|
};
|
|
429
433
|
if (parsed.paramName) {
|
|
@@ -457,7 +461,6 @@ async function walkRoutes(routesDir) {
|
|
|
457
461
|
const dirPath = normalizePath(routesDir);
|
|
458
462
|
const root = {
|
|
459
463
|
_files: [],
|
|
460
|
-
_dirPath: dirPath,
|
|
461
464
|
children: /* @__PURE__ */ new Map()
|
|
462
465
|
};
|
|
463
466
|
await walkRouteDir(root, dirPath);
|
|
@@ -642,7 +645,7 @@ function rewriteRoutes(ctx, routes) {
|
|
|
642
645
|
function applyRewriteRoutes(root, rewriteConfigs) {
|
|
643
646
|
const routables = [];
|
|
644
647
|
function walk(node, steps) {
|
|
645
|
-
const hasRoute = node._files.some((f) => f.type === "route" && f.extlessName
|
|
648
|
+
const hasRoute = node._files.some((f) => f.type === "route" && !isErrorName(f.extlessName));
|
|
646
649
|
if (hasRoute) {
|
|
647
650
|
routables.push({
|
|
648
651
|
steps: [
|
|
@@ -672,7 +675,12 @@ function applyRewriteRoutes(root, rewriteConfigs) {
|
|
|
672
675
|
for (const config of rewriteConfigs) {
|
|
673
676
|
const translations = config.paths || {};
|
|
674
677
|
const translatable = new Set(Object.keys(translations).map((k) => k.toLowerCase()));
|
|
678
|
+
const isExcluded = config.exclude?.length ? createRouteTester("/", config.exclude, void 0) : void 0;
|
|
675
679
|
for (const { steps } of routables) {
|
|
680
|
+
const originalKeyPath = steps.map((s) => s.key).join("/");
|
|
681
|
+
if (isExcluded?.("/" + originalKeyPath)) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
676
684
|
const hasTranslatable = steps.some((s) => translatable.has(s.key));
|
|
677
685
|
if (!hasTranslatable && !config.prefix) {
|
|
678
686
|
continue;
|
|
@@ -680,7 +688,6 @@ function applyRewriteRoutes(root, rewriteConfigs) {
|
|
|
680
688
|
if (steps.length === 0 && !config.prefix) {
|
|
681
689
|
continue;
|
|
682
690
|
}
|
|
683
|
-
const originalKeyPath = steps.map((s) => s.key).join("/");
|
|
684
691
|
const translatedSteps = [];
|
|
685
692
|
if (config.prefix) {
|
|
686
693
|
translatedSteps.push({
|
|
@@ -704,7 +711,6 @@ function applyRewriteRoutes(root, rewriteConfigs) {
|
|
|
704
711
|
if (!child) {
|
|
705
712
|
child = {
|
|
706
713
|
_files: [],
|
|
707
|
-
_dirPath: "",
|
|
708
714
|
children: /* @__PURE__ */ new Map()
|
|
709
715
|
};
|
|
710
716
|
if (step.paramName) {
|
|
@@ -832,7 +838,6 @@ function createBuildContext(rootDir, viteBasePath, userOpts, target, dynamicImpo
|
|
|
832
838
|
opts: normalizeOptions(rootDir, viteBasePath, userOpts),
|
|
833
839
|
routeTrie: {
|
|
834
840
|
_files: [],
|
|
835
|
-
_dirPath: "",
|
|
836
841
|
children: /* @__PURE__ */ new Map()
|
|
837
842
|
},
|
|
838
843
|
routes: [],
|
|
@@ -1290,6 +1295,20 @@ function resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, targetName) {
|
|
|
1290
1295
|
}
|
|
1291
1296
|
return result;
|
|
1292
1297
|
}
|
|
1298
|
+
function buildLoaderChainExpr(extlessName, loaderExpr, ancestorLayouts, nodeLayouts) {
|
|
1299
|
+
const { layoutName, layoutStop } = parseRouteIndexName(extlessName);
|
|
1300
|
+
if (layoutStop) {
|
|
1301
|
+
return `[ ${loaderExpr} ]`;
|
|
1302
|
+
}
|
|
1303
|
+
if (layoutName) {
|
|
1304
|
+
const chain = resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, layoutName);
|
|
1305
|
+
return `[ ${[
|
|
1306
|
+
...chain.map((l) => l.id),
|
|
1307
|
+
loaderExpr
|
|
1308
|
+
].join(", ")} ]`;
|
|
1309
|
+
}
|
|
1310
|
+
return loaderExpr;
|
|
1311
|
+
}
|
|
1293
1312
|
function getClientRouteBundleNames(qwikPlugin, r) {
|
|
1294
1313
|
const bundlesNames = [];
|
|
1295
1314
|
const manifest = qwikPlugin.api.getManifest();
|
|
@@ -1318,7 +1337,7 @@ function getClientRouteBundleNames(qwikPlugin, r) {
|
|
|
1318
1337
|
}
|
|
1319
1338
|
return bundlesNames;
|
|
1320
1339
|
}
|
|
1321
|
-
function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap,
|
|
1340
|
+
function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap, ancestorLayouts, isSSR, indent, loadersByFile, routeLoaderSourceFiles) {
|
|
1322
1341
|
const lines = [];
|
|
1323
1342
|
const nextIndent = indent + " ";
|
|
1324
1343
|
if (node._P) {
|
|
@@ -1335,7 +1354,6 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1335
1354
|
}
|
|
1336
1355
|
let layoutExpr;
|
|
1337
1356
|
let indexExpr;
|
|
1338
|
-
let indexIsOverride = false;
|
|
1339
1357
|
let errorExpr;
|
|
1340
1358
|
let notFoundExpr;
|
|
1341
1359
|
let menuExpr;
|
|
@@ -1376,28 +1394,14 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1376
1394
|
if (!loaderExpr) {
|
|
1377
1395
|
continue;
|
|
1378
1396
|
}
|
|
1379
|
-
const
|
|
1380
|
-
const
|
|
1381
|
-
if (
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
notFoundExpr = loaderExpr;
|
|
1386
|
-
notFoundFiles.set(node._dirPath, file.filePath);
|
|
1397
|
+
const expr = buildLoaderChainExpr(file.extlessName, loaderExpr, ancestorLayouts, nodeLayouts);
|
|
1398
|
+
const boundary = errorBoundaryName(file.extlessName);
|
|
1399
|
+
if (boundary === "404") {
|
|
1400
|
+
notFoundExpr = expr;
|
|
1401
|
+
} else if (boundary === "error") {
|
|
1402
|
+
errorExpr = expr;
|
|
1387
1403
|
} else {
|
|
1388
|
-
|
|
1389
|
-
if (layoutStop) {
|
|
1390
|
-
indexExpr = `[ ${loaderExpr} ]`;
|
|
1391
|
-
indexIsOverride = true;
|
|
1392
|
-
} else if (layoutName) {
|
|
1393
|
-
const chain = resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, layoutName);
|
|
1394
|
-
const chainExprs = chain.map((l) => l.id);
|
|
1395
|
-
chainExprs.push(loaderExpr);
|
|
1396
|
-
indexExpr = `[ ${chainExprs.join(", ")} ]`;
|
|
1397
|
-
indexIsOverride = true;
|
|
1398
|
-
} else {
|
|
1399
|
-
indexExpr = loaderExpr;
|
|
1400
|
-
}
|
|
1404
|
+
indexExpr = expr;
|
|
1401
1405
|
bundleRoute = ctx.routes.find((r) => r.filePath === file.filePath);
|
|
1402
1406
|
}
|
|
1403
1407
|
}
|
|
@@ -1405,11 +1409,7 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1405
1409
|
lines.push(`${nextIndent}_L: ${layoutExpr},`);
|
|
1406
1410
|
}
|
|
1407
1411
|
if (indexExpr) {
|
|
1408
|
-
|
|
1409
|
-
lines.push(`${nextIndent}_I: ${indexExpr},`);
|
|
1410
|
-
} else {
|
|
1411
|
-
lines.push(`${nextIndent}_I: ${indexExpr},`);
|
|
1412
|
-
}
|
|
1412
|
+
lines.push(`${nextIndent}_I: ${indexExpr},`);
|
|
1413
1413
|
if (isSSR && bundleRoute) {
|
|
1414
1414
|
const bundleNames = getClientRouteBundleNames(qwikPlugin, bundleRoute);
|
|
1415
1415
|
if (bundleNames.length > 0) {
|
|
@@ -1418,16 +1418,22 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1418
1418
|
}
|
|
1419
1419
|
}
|
|
1420
1420
|
{
|
|
1421
|
-
const routeFiles =
|
|
1421
|
+
const routeFiles = [];
|
|
1422
|
+
for (const file of node._files.filter((f) => f.type === "layout" || f.type === "route" && routeIdMap.has(f.filePath))) {
|
|
1423
|
+
routeFiles.push(file.filePath, ...routeLoaderSourceFiles?.get(file.filePath) ?? []);
|
|
1424
|
+
}
|
|
1422
1425
|
if (node === ctx.routeTrie) {
|
|
1423
1426
|
for (const plugin of ctx.serverPlugins) {
|
|
1424
|
-
routeFiles.push(plugin.filePath);
|
|
1427
|
+
routeFiles.push(plugin.filePath, ...routeLoaderSourceFiles?.get(plugin.filePath) ?? []);
|
|
1425
1428
|
}
|
|
1426
1429
|
}
|
|
1427
|
-
|
|
1430
|
+
const routeLoaderFiles = [
|
|
1431
|
+
...new Set(routeFiles)
|
|
1432
|
+
];
|
|
1433
|
+
if (routeLoaderFiles.length > 0) {
|
|
1428
1434
|
if (loadersByFile) {
|
|
1429
1435
|
const nodeLoaderHashes = [];
|
|
1430
|
-
for (const filePath of
|
|
1436
|
+
for (const filePath of routeLoaderFiles) {
|
|
1431
1437
|
const hashes = loadersByFile.get(filePath);
|
|
1432
1438
|
if (hashes) {
|
|
1433
1439
|
nodeLoaderHashes.push(...hashes);
|
|
@@ -1437,7 +1443,7 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1437
1443
|
lines.push(`${nextIndent}_R: ${JSON.stringify(nodeLoaderHashes)},`);
|
|
1438
1444
|
}
|
|
1439
1445
|
} else {
|
|
1440
|
-
const placeholder = `__LOADERS:${
|
|
1446
|
+
const placeholder = `__LOADERS:${routeLoaderFiles.join("|")}__`;
|
|
1441
1447
|
lines.push(`${nextIndent}_R: ${JSON.stringify(placeholder)},`);
|
|
1442
1448
|
}
|
|
1443
1449
|
}
|
|
@@ -1474,7 +1480,7 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1474
1480
|
groupChildren.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1475
1481
|
const groupStrs = [];
|
|
1476
1482
|
for (const [_key, child] of groupChildren) {
|
|
1477
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap,
|
|
1483
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, childAncestors, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1478
1484
|
if (childStr !== "{}") {
|
|
1479
1485
|
groupStrs.push(childStr);
|
|
1480
1486
|
}
|
|
@@ -1484,7 +1490,7 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1484
1490
|
}
|
|
1485
1491
|
}
|
|
1486
1492
|
for (const [key, child] of regularChildren) {
|
|
1487
|
-
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap,
|
|
1493
|
+
const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, childAncestors, isSSR, nextIndent, loadersByFile, routeLoaderSourceFiles);
|
|
1488
1494
|
if (childStr !== "{}") {
|
|
1489
1495
|
const keyStr = JSON.stringify(key);
|
|
1490
1496
|
lines.push(`${nextIndent}${keyStr}: ${childStr},`);
|
|
@@ -1497,14 +1503,12 @@ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menu
|
|
|
1497
1503
|
${lines.join("\n")}
|
|
1498
1504
|
${indent}}`;
|
|
1499
1505
|
}
|
|
1500
|
-
function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile) {
|
|
1506
|
+
function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
1501
1507
|
const includeEndpoints = isSSR;
|
|
1502
1508
|
const dynamicImports = ctx.dynamicImports;
|
|
1503
1509
|
const layoutIdMap = /* @__PURE__ */ new Map();
|
|
1504
1510
|
const routeIdMap = /* @__PURE__ */ new Map();
|
|
1505
1511
|
const menuIdMap = /* @__PURE__ */ new Map();
|
|
1506
|
-
const errorFiles = /* @__PURE__ */ new Map();
|
|
1507
|
-
const notFoundFiles = /* @__PURE__ */ new Map();
|
|
1508
1512
|
let layoutCount = 0;
|
|
1509
1513
|
let routeCount = 0;
|
|
1510
1514
|
let menuCount = 0;
|
|
@@ -1556,6 +1560,9 @@ function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile) {
|
|
|
1556
1560
|
/** Qwik Router Routes (${routeCount}) */`);
|
|
1557
1561
|
for (const route of ctx.routes) {
|
|
1558
1562
|
if (isPageExt(route.ext)) {
|
|
1563
|
+
if (serverExcludePaths?.has(route.filePath)) {
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1559
1566
|
const importPath = getImportPath(route.filePath);
|
|
1560
1567
|
let loaderExpr;
|
|
1561
1568
|
if (dynamicImports) {
|
|
@@ -1571,7 +1578,7 @@ function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile) {
|
|
|
1571
1578
|
routeIdMap.set(route.filePath, `()=>${route.id}`);
|
|
1572
1579
|
}
|
|
1573
1580
|
}
|
|
1574
|
-
const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap,
|
|
1581
|
+
const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap, [], isSSR, "", loadersByFile, routeLoaderSourceFiles);
|
|
1575
1582
|
const baseSegments = ctx.opts.basePathname.split("/").filter((s) => s.length > 0);
|
|
1576
1583
|
let routesExpr = trieStr;
|
|
1577
1584
|
for (let j = baseSegments.length - 1; j >= 0; j--) {
|
|
@@ -1596,7 +1603,7 @@ function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
|
|
|
1596
1603
|
c.push(`];`);
|
|
1597
1604
|
}
|
|
1598
1605
|
|
|
1599
|
-
function generateQwikRouterConfig(ctx, qwikPlugin, isSSR, loadersByFile) {
|
|
1606
|
+
function generateQwikRouterConfig(ctx, qwikPlugin, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles) {
|
|
1600
1607
|
const esmImports = [];
|
|
1601
1608
|
const c = [];
|
|
1602
1609
|
c.push(`
|
|
@@ -1607,7 +1614,7 @@ import { isDev } from '@qwik.dev/core/build';`);
|
|
|
1607
1614
|
esmImports.push(`import 'virtual:qwik-router-server-fns';`);
|
|
1608
1615
|
}
|
|
1609
1616
|
createServerPlugins(ctx, qwikPlugin, c, esmImports, isSSR);
|
|
1610
|
-
createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile);
|
|
1617
|
+
createRoutes(ctx, qwikPlugin, c, esmImports, isSSR, loadersByFile, serverExcludePaths, routeLoaderSourceFiles);
|
|
1611
1618
|
createEntries(ctx, c);
|
|
1612
1619
|
c.push(`export const trailingSlash = ${JSON.stringify(!globalThis.__NO_TRAILING_SLASH__)};`);
|
|
1613
1620
|
c.push(`export const basePathname = ${JSON.stringify(ctx.opts.basePathname)};`);
|
|
@@ -1633,6 +1640,76 @@ function generateServiceWorkerRegister(ctx, swRegister) {
|
|
|
1633
1640
|
return `export default ${JSON.stringify(swReg)};`;
|
|
1634
1641
|
}
|
|
1635
1642
|
|
|
1643
|
+
const NON_GET_HANDLERS = /* @__PURE__ */ new Set([
|
|
1644
|
+
"onRequest",
|
|
1645
|
+
"onPost",
|
|
1646
|
+
"onPut",
|
|
1647
|
+
"onPatch",
|
|
1648
|
+
"onDelete",
|
|
1649
|
+
"onHead",
|
|
1650
|
+
"onOptions"
|
|
1651
|
+
]);
|
|
1652
|
+
const ROUTER_MODULE = "@qwik.dev/router";
|
|
1653
|
+
const SERVER_QRL = /\b(?:routeLoader|routeAction|globalAction|server)(?:\$|Qrl)/;
|
|
1654
|
+
function isServerFreeSource(code) {
|
|
1655
|
+
for (const e of findExports(code)) {
|
|
1656
|
+
if (e.specifier) {
|
|
1657
|
+
return false;
|
|
1658
|
+
}
|
|
1659
|
+
const names = [
|
|
1660
|
+
...e.name ? [
|
|
1661
|
+
e.name
|
|
1662
|
+
] : [],
|
|
1663
|
+
...e.names ?? []
|
|
1664
|
+
];
|
|
1665
|
+
if (names.some((n) => NON_GET_HANDLERS.has(n))) {
|
|
1666
|
+
return false;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
for (const imp of findStaticImports(code)) {
|
|
1670
|
+
if (imp.specifier === ROUTER_MODULE && SERVER_QRL.test(imp.code)) {
|
|
1671
|
+
return false;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return true;
|
|
1675
|
+
}
|
|
1676
|
+
function isFileServerFree(filePath, cache) {
|
|
1677
|
+
let pending = cache.get(filePath);
|
|
1678
|
+
if (!pending) {
|
|
1679
|
+
pending = readFile(filePath, "utf-8").then(isServerFreeSource).catch(() => false);
|
|
1680
|
+
cache.set(filePath, pending);
|
|
1681
|
+
}
|
|
1682
|
+
return pending;
|
|
1683
|
+
}
|
|
1684
|
+
async function isRouteServerFree(route, cache) {
|
|
1685
|
+
if (!isMarkdownExt(route.ext) && !await isFileServerFree(route.filePath, cache)) {
|
|
1686
|
+
return false;
|
|
1687
|
+
}
|
|
1688
|
+
for (const layout of route.layouts) {
|
|
1689
|
+
if (!await isFileServerFree(layout.filePath, cache)) {
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
return true;
|
|
1694
|
+
}
|
|
1695
|
+
async function getServerExcludedRoutes(ctx, ssg) {
|
|
1696
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
1697
|
+
if (!ssg?.include?.length) {
|
|
1698
|
+
return excluded;
|
|
1699
|
+
}
|
|
1700
|
+
const isPrerendered = createRouteTester(ctx.opts.basePathname, ssg.include, ssg.exclude);
|
|
1701
|
+
const serverFreeByFile = /* @__PURE__ */ new Map();
|
|
1702
|
+
await Promise.all(ctx.routes.map(async (route) => {
|
|
1703
|
+
if (!isPageExt(route.ext) || route.paramNames.length > 0 || /\/(?:404|error)\.html$/.test(route.pathname) || !isPrerendered(route.pathname)) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
if (await isRouteServerFree(route, serverFreeByFile)) {
|
|
1707
|
+
excluded.add(route.filePath);
|
|
1708
|
+
}
|
|
1709
|
+
}));
|
|
1710
|
+
return excluded;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1636
1713
|
function isBundlePartOfRoute(bundle, routeAndLayoutPaths) {
|
|
1637
1714
|
if (!bundle.origins) {
|
|
1638
1715
|
return false;
|
|
@@ -1806,8 +1883,22 @@ function createVirtualImageJsxId(pathId, params) {
|
|
|
1806
1883
|
const queryString = query.toString();
|
|
1807
1884
|
return `${VIRTUAL_IMAGE_JSX_PREFIX}${normalizePath$1(pathId)}${VIRTUAL_IMAGE_JSX_SUFFIX}${queryString ? `?${queryString}` : ""}`;
|
|
1808
1885
|
}
|
|
1809
|
-
function
|
|
1810
|
-
const
|
|
1886
|
+
function createImageJsxDirectives(params, userOpts) {
|
|
1887
|
+
const overrides = Object.fromEntries(params.entries());
|
|
1888
|
+
delete overrides[JSX_QUERY_PARAM];
|
|
1889
|
+
delete overrides[INTERNAL_IMAGE_JSX_QUERY_PARAM];
|
|
1890
|
+
return new URLSearchParams({
|
|
1891
|
+
format: "webp",
|
|
1892
|
+
quality: "75",
|
|
1893
|
+
w: "200;400;600;800;1200",
|
|
1894
|
+
withoutEnlargement: "",
|
|
1895
|
+
...userOpts?.imageOptimization?.jsxDirectives,
|
|
1896
|
+
...overrides,
|
|
1897
|
+
as: "jsx"
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
function createImageJsxImportId(pathId, params, userOpts) {
|
|
1901
|
+
const query = createImageJsxDirectives(params, userOpts);
|
|
1811
1902
|
query.set(INTERNAL_IMAGE_JSX_QUERY_PARAM, "");
|
|
1812
1903
|
return `${normalizePath$1(pathId)}?${query.toString()}`;
|
|
1813
1904
|
}
|
|
@@ -1835,9 +1926,10 @@ function getToImg() {
|
|
|
1835
1926
|
: _jsxSplit("img", null, {decoding, height: h, loading, srcSet: s, width: w});
|
|
1836
1927
|
`;
|
|
1837
1928
|
}
|
|
1838
|
-
function createImageJsxModule(pathId, params) {
|
|
1929
|
+
function createImageJsxModule(pathId, params, userOpts) {
|
|
1930
|
+
const importId = createImageJsxImportId(pathId, params, userOpts);
|
|
1839
1931
|
return `
|
|
1840
|
-
import { srcSet, width, height } from ${JSON.stringify(
|
|
1932
|
+
import { srcSet, width, height } from ${JSON.stringify(importId)};
|
|
1841
1933
|
import toImg from ${JSON.stringify(TO_IMG_ID)};
|
|
1842
1934
|
|
|
1843
1935
|
export default toImg(srcSet, width, height);
|
|
@@ -1935,18 +2027,7 @@ function imagePlugin(userOpts) {
|
|
|
1935
2027
|
},
|
|
1936
2028
|
defaultDirectives: (url) => {
|
|
1937
2029
|
if (url.searchParams.has(JSX_QUERY_PARAM)) {
|
|
1938
|
-
|
|
1939
|
-
delete params[JSX_QUERY_PARAM];
|
|
1940
|
-
delete params[INTERNAL_IMAGE_JSX_QUERY_PARAM];
|
|
1941
|
-
return new URLSearchParams({
|
|
1942
|
-
format: "webp",
|
|
1943
|
-
quality: "75",
|
|
1944
|
-
w: "200;400;600;800;1200",
|
|
1945
|
-
withoutEnlargement: "",
|
|
1946
|
-
...userOpts?.imageOptimization?.jsxDirectives,
|
|
1947
|
-
...params,
|
|
1948
|
-
as: "jsx"
|
|
1949
|
-
});
|
|
2030
|
+
return createImageJsxDirectives(url.searchParams, userOpts);
|
|
1950
2031
|
}
|
|
1951
2032
|
return new URLSearchParams();
|
|
1952
2033
|
}
|
|
@@ -1960,9 +2041,9 @@ function imagePlugin(userOpts) {
|
|
|
1960
2041
|
order: "pre",
|
|
1961
2042
|
async handler(id, importer, options) {
|
|
1962
2043
|
if (parseVirtualImageJsxId(id)) {
|
|
1963
|
-
return
|
|
2044
|
+
return id;
|
|
1964
2045
|
}
|
|
1965
|
-
if (id.endsWith(TO_IMG_ID)) {
|
|
2046
|
+
if (id.endsWith(TO_IMG_ID) || id === VIRTUAL_TO_IMG_ID) {
|
|
1966
2047
|
return VIRTUAL_TO_IMG_ID;
|
|
1967
2048
|
}
|
|
1968
2049
|
const { pathId, params } = parseId(id);
|
|
@@ -2028,7 +2109,7 @@ function imagePlugin(userOpts) {
|
|
|
2028
2109
|
}
|
|
2029
2110
|
if (supportedExtensions.includes(imageId.extension)) {
|
|
2030
2111
|
return {
|
|
2031
|
-
code: createImageJsxModule(imageId.pathId, imageId.params),
|
|
2112
|
+
code: createImageJsxModule(imageId.pathId, imageId.params, userOpts),
|
|
2032
2113
|
map: null
|
|
2033
2114
|
};
|
|
2034
2115
|
}
|
|
@@ -2074,15 +2155,21 @@ async function collectServerFnModuleIds(routingContext, resolvedVirtualId, plugi
|
|
|
2074
2155
|
continue;
|
|
2075
2156
|
}
|
|
2076
2157
|
const moduleInfo = await pluginContext.load({
|
|
2077
|
-
id: resolved.id
|
|
2158
|
+
id: resolved.id,
|
|
2159
|
+
resolveDependencies: true
|
|
2078
2160
|
});
|
|
2079
2161
|
if (moduleInfo.code == null) {
|
|
2080
2162
|
continue;
|
|
2081
2163
|
}
|
|
2164
|
+
const qwikDeps = moduleInfo.meta?.qwikdeps ?? [];
|
|
2082
2165
|
if (moduleInfo.code.includes("serverQrl(")) {
|
|
2083
2166
|
serverFnModules.add(moduleInfo.id);
|
|
2084
2167
|
}
|
|
2085
|
-
const resolvedImports =
|
|
2168
|
+
const resolvedImports = [
|
|
2169
|
+
...moduleInfo.importedIds,
|
|
2170
|
+
...moduleInfo.dynamicallyImportedIds,
|
|
2171
|
+
...qwikDeps
|
|
2172
|
+
];
|
|
2086
2173
|
for (let i = 0; i < resolvedImports.length; i++) {
|
|
2087
2174
|
const resolvedImport = resolvedImports[i];
|
|
2088
2175
|
if (resolvedImport && !seenModuleIds.has(resolvedImport)) {
|
|
@@ -2244,7 +2331,7 @@ class HtmlTransformPatcher {
|
|
|
2244
2331
|
try {
|
|
2245
2332
|
const fakeHtml = `<html><head>[FAKE_HEAD]</head><body>[FAKE_BODY]</body></html>`;
|
|
2246
2333
|
const transformedHtml = await this.server.transformIndexHtml(this.request.url || "/", fakeHtml);
|
|
2247
|
-
const hmrBridge = this.server.hot ? `<script type="module" src="
|
|
2334
|
+
const hmrBridge = this.server.hot ? `<script type="module" src="${this.server.config.base}@id/@qwik-hmr-bridge"><\/script>` : "";
|
|
2248
2335
|
const fakeHeadIndex = transformedHtml.indexOf("[FAKE_HEAD]");
|
|
2249
2336
|
const fakeHeadCloseIndex = transformedHtml.indexOf("</head>", fakeHeadIndex);
|
|
2250
2337
|
if (fakeHeadIndex === -1 || fakeHeadCloseIndex === -1) {
|
|
@@ -2325,6 +2412,66 @@ function wrapResponseForHtmlTransform(request, response, server) {
|
|
|
2325
2412
|
return response;
|
|
2326
2413
|
}
|
|
2327
2414
|
|
|
2415
|
+
const FULLPATH_HEADER = "X-Qwik-fullpath";
|
|
2416
|
+
const ROUTE_PATH_HEADER = "X-Qwik-route-path";
|
|
2417
|
+
function getDevMiddlewareRequestPath(req) {
|
|
2418
|
+
return req.originalUrl || req.url;
|
|
2419
|
+
}
|
|
2420
|
+
async function loadSsrModule(server, filePath) {
|
|
2421
|
+
return server.ssrLoadModule(getImportPath(normalizePath(filePath)));
|
|
2422
|
+
}
|
|
2423
|
+
function matchesLoaderId(loader, loaderId) {
|
|
2424
|
+
return loader.__id === loaderId || loader.__qrl.getHash() === loaderId;
|
|
2425
|
+
}
|
|
2426
|
+
function isLoaderInternal(value) {
|
|
2427
|
+
return typeof value === "function" && value.__brand === "server_loader";
|
|
2428
|
+
}
|
|
2429
|
+
function findMatchingLoader(mod, loaderId) {
|
|
2430
|
+
for (const value of Object.values(mod)) {
|
|
2431
|
+
if (isLoaderInternal(value) && matchesLoaderId(value, loaderId)) {
|
|
2432
|
+
return value;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
async function preloadQLoaderRouteLoader(server, ctx, req) {
|
|
2437
|
+
const requestPath = getDevMiddlewareRequestPath(req);
|
|
2438
|
+
if (!requestPath) {
|
|
2439
|
+
return void 0;
|
|
2440
|
+
}
|
|
2441
|
+
let requestUrl;
|
|
2442
|
+
try {
|
|
2443
|
+
requestUrl = new URL(requestPath, "http://qwik.dev");
|
|
2444
|
+
} catch {
|
|
2445
|
+
return void 0;
|
|
2446
|
+
}
|
|
2447
|
+
const recognized = recognizeRequest(requestUrl.pathname);
|
|
2448
|
+
if (recognized?.type !== IsQLoader || !recognized.data?.loaderId) {
|
|
2449
|
+
return void 0;
|
|
2450
|
+
}
|
|
2451
|
+
const loaderId = recognized.data.loaderId;
|
|
2452
|
+
const headerValue = req.headers[FULLPATH_HEADER.toLowerCase()] ?? req.headers[ROUTE_PATH_HEADER.toLowerCase()];
|
|
2453
|
+
const fullPathHeader = Array.isArray(headerValue) ? headerValue[0] : headerValue ?? null;
|
|
2454
|
+
const loaderPathname = trimRecognizedInternalPathname(requestUrl.pathname, recognized);
|
|
2455
|
+
const pathname = resolveValidInternalFullPathname(loaderPathname, fullPathHeader) ?? loaderPathname;
|
|
2456
|
+
const route = ctx.routes.filter((route2) => isPageExt(route2.ext)).slice().sort(routeSortCompare).find((route2) => route2.pattern.test(pathname));
|
|
2457
|
+
if (!route) {
|
|
2458
|
+
return void 0;
|
|
2459
|
+
}
|
|
2460
|
+
const routeRootFiles = [
|
|
2461
|
+
...route.layouts.map((layout) => layout.filePath),
|
|
2462
|
+
route.filePath
|
|
2463
|
+
];
|
|
2464
|
+
const modules = await Promise.all([
|
|
2465
|
+
...ctx.serverPlugins.map((plugin) => loadSsrModule(server, plugin.filePath)),
|
|
2466
|
+
...routeRootFiles.map((filePath) => loadSsrModule(server, filePath))
|
|
2467
|
+
]);
|
|
2468
|
+
for (const mod of modules) {
|
|
2469
|
+
const loader = findMatchingLoader(mod, loaderId);
|
|
2470
|
+
if (loader) {
|
|
2471
|
+
return loader;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2328
2475
|
const makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
2329
2476
|
let mod;
|
|
2330
2477
|
try {
|
|
@@ -2344,6 +2491,11 @@ const makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
|
|
|
2344
2491
|
await updateRoutingContext(ctx);
|
|
2345
2492
|
ctx.isDirty = false;
|
|
2346
2493
|
}
|
|
2494
|
+
const preloadedRouteLoader = await preloadQLoaderRouteLoader(server, ctx, req);
|
|
2495
|
+
if (preloadedRouteLoader) {
|
|
2496
|
+
await server.ssrLoadModule("@qwik-router-config");
|
|
2497
|
+
devPreloadedRouteLoaders.set(req, preloadedRouteLoader);
|
|
2498
|
+
}
|
|
2347
2499
|
const entry = ctx.entries.find((e) => req.url === `${server.config.base}${e.chunkFileName}`);
|
|
2348
2500
|
if (entry) {
|
|
2349
2501
|
const entryContents = await server.transformRequest(`/@fs${entry.filePath.startsWith("/") ? "" : "/"}${entry.filePath}`);
|
|
@@ -2421,6 +2573,9 @@ const getCssUrls = (server) => {
|
|
|
2421
2573
|
});
|
|
2422
2574
|
if ((isEntryCSS || hasJSImporter) && !hasCSSImporter && !cssImportedByCSS.has(mod.url)) {
|
|
2423
2575
|
cssModules.add(`${mod.url}${mod.lastHMRTimestamp ? `?t=${mod.lastHMRTimestamp}` : ""}`);
|
|
2576
|
+
if (mod.file) {
|
|
2577
|
+
server.watcher.add(mod.file);
|
|
2578
|
+
}
|
|
2424
2579
|
}
|
|
2425
2580
|
}
|
|
2426
2581
|
}
|
|
@@ -2435,10 +2590,36 @@ const getRouterIndexTags = (server) => {
|
|
|
2435
2590
|
tag: "link",
|
|
2436
2591
|
attrs: {
|
|
2437
2592
|
rel: "stylesheet",
|
|
2438
|
-
href: url
|
|
2593
|
+
href: server.config.base + url.slice(1)
|
|
2439
2594
|
}
|
|
2440
2595
|
}));
|
|
2441
2596
|
};
|
|
2597
|
+
const sendRouterCssHotUpdate = (server, file, timestamp) => {
|
|
2598
|
+
const { client, ssr } = server.environments;
|
|
2599
|
+
if (!isCssPath(file) || client.moduleGraph.getModulesByFile(file)?.size) {
|
|
2600
|
+
return false;
|
|
2601
|
+
}
|
|
2602
|
+
const paths = /* @__PURE__ */ new Set();
|
|
2603
|
+
for (const mod of ssr.moduleGraph.getModulesByFile(file) ?? []) {
|
|
2604
|
+
mod.lastHMRTimestamp = timestamp;
|
|
2605
|
+
paths.add(mod.url.split("?")[0]);
|
|
2606
|
+
}
|
|
2607
|
+
if (!paths.size) {
|
|
2608
|
+
return false;
|
|
2609
|
+
}
|
|
2610
|
+
client.hot.send({
|
|
2611
|
+
type: "update",
|
|
2612
|
+
updates: [
|
|
2613
|
+
...paths
|
|
2614
|
+
].map((path) => ({
|
|
2615
|
+
type: "css-update",
|
|
2616
|
+
path,
|
|
2617
|
+
acceptedPath: path,
|
|
2618
|
+
timestamp
|
|
2619
|
+
}))
|
|
2620
|
+
});
|
|
2621
|
+
return true;
|
|
2622
|
+
};
|
|
2442
2623
|
|
|
2443
2624
|
const QWIK_ROUTER_CONFIG_ID = "@qwik-router-config";
|
|
2444
2625
|
const QWIK_ROUTER_ENTRIES_ID = "@qwik-router-entries";
|
|
@@ -2491,6 +2672,75 @@ function isRouterSourceFileForContext(filePath, ctx) {
|
|
|
2491
2672
|
const normalizedPath = normalizePath(filePath);
|
|
2492
2673
|
return isRouterSourceFilePath(normalizedPath) && (isPathInDir(normalizedPath, ctx.opts.routesDir) || isPathInDir(normalizedPath, ctx.opts.serverPluginsDir));
|
|
2493
2674
|
}
|
|
2675
|
+
function isDiscoveredRouteLoaderSource(filePath, sourceFiles) {
|
|
2676
|
+
if (!sourceFiles) {
|
|
2677
|
+
return false;
|
|
2678
|
+
}
|
|
2679
|
+
const normalizedPath = normalizePath(filePath);
|
|
2680
|
+
for (const files of sourceFiles.values()) {
|
|
2681
|
+
if (files.includes(normalizedPath)) {
|
|
2682
|
+
return true;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
return false;
|
|
2686
|
+
}
|
|
2687
|
+
function collectRouteLoaderOwners(node, owners) {
|
|
2688
|
+
for (const file of node._files) {
|
|
2689
|
+
if (file.type === "layout" || file.type === "route") {
|
|
2690
|
+
owners.add(file.filePath);
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
for (const child of node.children.values()) {
|
|
2694
|
+
collectRouteLoaderOwners(child, owners);
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
async function collectReExportSources(owner, filePath, resolveSource, sources, seen = /* @__PURE__ */ new Set([
|
|
2698
|
+
owner
|
|
2699
|
+
])) {
|
|
2700
|
+
let code, exportEntries;
|
|
2701
|
+
try {
|
|
2702
|
+
code = await readFile(filePath, "utf-8");
|
|
2703
|
+
exportEntries = findExports(code);
|
|
2704
|
+
if (!exportEntries) {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
} catch {
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
await Promise.all(exportEntries.map(async (exp) => {
|
|
2711
|
+
if (!exp.specifier) {
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
const resolved = await resolveSource(exp.specifier, filePath);
|
|
2715
|
+
if (!resolved || resolved.charCodeAt(0) === 0) {
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
const resolvedPath = normalizePath(resolved.split(/[?#]/, 1)[0]);
|
|
2719
|
+
let ownerSources = sources.get(owner);
|
|
2720
|
+
if (!ownerSources) {
|
|
2721
|
+
sources.set(owner, ownerSources = []);
|
|
2722
|
+
}
|
|
2723
|
+
if (!ownerSources.includes(resolvedPath)) {
|
|
2724
|
+
ownerSources.push(resolvedPath);
|
|
2725
|
+
}
|
|
2726
|
+
if (!seen.has(resolvedPath)) {
|
|
2727
|
+
seen.add(resolvedPath);
|
|
2728
|
+
await collectReExportSources(owner, resolvedPath, resolveSource, sources, seen);
|
|
2729
|
+
}
|
|
2730
|
+
}));
|
|
2731
|
+
}
|
|
2732
|
+
async function findRouteLoaderSourceFiles(ctx, resolveSource) {
|
|
2733
|
+
const sources = /* @__PURE__ */ new Map();
|
|
2734
|
+
const owners = /* @__PURE__ */ new Set();
|
|
2735
|
+
collectRouteLoaderOwners(ctx.routeTrie, owners);
|
|
2736
|
+
for (const plugin of ctx.serverPlugins) {
|
|
2737
|
+
owners.add(plugin.filePath);
|
|
2738
|
+
}
|
|
2739
|
+
await Promise.all([
|
|
2740
|
+
...owners
|
|
2741
|
+
].map((owner) => collectReExportSources(owner, owner, resolveSource, sources)));
|
|
2742
|
+
return sources;
|
|
2743
|
+
}
|
|
2494
2744
|
function invalidateRouterConfigModules(server) {
|
|
2495
2745
|
const modules = [];
|
|
2496
2746
|
const moduleGraphs = /* @__PURE__ */ new Set();
|
|
@@ -2545,6 +2795,8 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2545
2795
|
const routesDir = userOpts?.routesDir ?? "src/routes";
|
|
2546
2796
|
const serverPluginsDir = userOpts?.serverPluginsDir ?? routesDir;
|
|
2547
2797
|
const loadersByFile = /* @__PURE__ */ new Map();
|
|
2798
|
+
let reExportedRouteLoaderSources;
|
|
2799
|
+
let ssgRoutePatterns;
|
|
2548
2800
|
const api = {
|
|
2549
2801
|
getBasePathname: () => ctx?.opts.basePathname ?? "/",
|
|
2550
2802
|
getRoutes: () => {
|
|
@@ -2552,6 +2804,12 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2552
2804
|
},
|
|
2553
2805
|
getServiceWorkers: () => {
|
|
2554
2806
|
return ctx?.serviceWorkers.slice() ?? [];
|
|
2807
|
+
},
|
|
2808
|
+
_setSsgRoutes: (include, exclude) => {
|
|
2809
|
+
ssgRoutePatterns = include?.length ? {
|
|
2810
|
+
include,
|
|
2811
|
+
exclude
|
|
2812
|
+
} : void 0;
|
|
2555
2813
|
}
|
|
2556
2814
|
};
|
|
2557
2815
|
const plugin = {
|
|
@@ -2635,7 +2893,7 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2635
2893
|
return updatedViteConfig;
|
|
2636
2894
|
},
|
|
2637
2895
|
configEnvironment(name, _config, _env) {
|
|
2638
|
-
if (name === "ssr") {
|
|
2896
|
+
if (name === "ssr" || name === "ssg") {
|
|
2639
2897
|
return {
|
|
2640
2898
|
resolve: {
|
|
2641
2899
|
external: [
|
|
@@ -2703,11 +2961,24 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2703
2961
|
};
|
|
2704
2962
|
}
|
|
2705
2963
|
},
|
|
2706
|
-
handleHotUpdate({ file, modules, server }) {
|
|
2707
|
-
if (
|
|
2964
|
+
handleHotUpdate({ file, modules, server, timestamp }) {
|
|
2965
|
+
if (sendRouterCssHotUpdate(server, file, timestamp)) {
|
|
2966
|
+
return [];
|
|
2967
|
+
}
|
|
2968
|
+
const clearedLoaderHashes = clearRouteLoaderHashes(loadersByFile, file);
|
|
2969
|
+
if (!ctx) {
|
|
2970
|
+
return;
|
|
2971
|
+
}
|
|
2972
|
+
if (!isRouterSourceFileForContext(file, ctx)) {
|
|
2973
|
+
if (clearedLoaderHashes || isDiscoveredRouteLoaderSource(file, reExportedRouteLoaderSources)) {
|
|
2974
|
+
const configModules2 = invalidateRouterConfigModules(server);
|
|
2975
|
+
return [
|
|
2976
|
+
...modules,
|
|
2977
|
+
...configModules2
|
|
2978
|
+
];
|
|
2979
|
+
}
|
|
2708
2980
|
return;
|
|
2709
2981
|
}
|
|
2710
|
-
clearRouteLoaderHashes(loadersByFile, file);
|
|
2711
2982
|
ctx.isDirty = true;
|
|
2712
2983
|
const configModules = invalidateRouterConfigModules(server);
|
|
2713
2984
|
return [
|
|
@@ -2755,7 +3026,15 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2755
3026
|
});
|
|
2756
3027
|
}
|
|
2757
3028
|
if (isRouterConfig) {
|
|
2758
|
-
|
|
3029
|
+
const isServerConsumer = this.environment.config.consumer === "server";
|
|
3030
|
+
const serverExcludePaths = isServerConsumer && !devServer && this.environment.name !== "ssg" ? await getServerExcludedRoutes(ctx, ssgRoutePatterns) : void 0;
|
|
3031
|
+
reExportedRouteLoaderSources = await findRouteLoaderSourceFiles(ctx, async (specifier, importer) => {
|
|
3032
|
+
const resolved = await this.resolve(specifier, importer, {
|
|
3033
|
+
skipSelf: true
|
|
3034
|
+
});
|
|
3035
|
+
return resolved?.id;
|
|
3036
|
+
});
|
|
3037
|
+
return generateQwikRouterConfig(ctx, qwikPlugin, isServerConsumer, devServer ? loadersByFile : void 0, serverExcludePaths, reExportedRouteLoaderSources);
|
|
2759
3038
|
}
|
|
2760
3039
|
if (isSwRegister) {
|
|
2761
3040
|
return generateServiceWorkerRegister(ctx, swRegister);
|
|
@@ -2809,6 +3088,15 @@ function qwikRouterPlugin(userOpts, buildContextRef) {
|
|
|
2809
3088
|
return null;
|
|
2810
3089
|
},
|
|
2811
3090
|
generateBundle(_, bundles) {
|
|
3091
|
+
const manifest = qwikPlugin.api.getManifest();
|
|
3092
|
+
if (manifest) {
|
|
3093
|
+
const srcDir = qwikPlugin.api.getOptions().srcDir;
|
|
3094
|
+
for (const symbol of Object.values(manifest.symbols)) {
|
|
3095
|
+
if (symbol.ctxName === "routeLoader$" && symbol.origin) {
|
|
3096
|
+
addRouteLoaderHash(loadersByFile, resolve(srcDir, symbol.origin), symbol.hash);
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
2812
3100
|
for (const chunk of Object.values(bundles)) {
|
|
2813
3101
|
if (chunk.type === "chunk" && chunk.code.includes("__LOADERS:")) {
|
|
2814
3102
|
chunk.code = replaceLoaderPlaceholders(chunk.code, loadersByFile);
|
|
@@ -2901,7 +3189,8 @@ function serverFnsPlugin(buildContextRef) {
|
|
|
2901
3189
|
}
|
|
2902
3190
|
return [
|
|
2903
3191
|
...serverFnModules
|
|
2904
|
-
].map((mod) => `import ${JSON.stringify(mod)}
|
|
3192
|
+
].map((mod, index) => `import * as serverFnModule${index} from ${JSON.stringify(mod)};
|
|
3193
|
+
Object.values(serverFnModule${index});`).join("\n");
|
|
2905
3194
|
}
|
|
2906
3195
|
return null;
|
|
2907
3196
|
}
|