@qwik.dev/router 2.0.0-beta.28 → 2.0.0-beta.29

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.
Files changed (42) hide show
  1. package/lib/adapters/azure-swa/vite/index.mjs +31 -36
  2. package/lib/adapters/bun-server/vite/index.mjs +0 -3
  3. package/lib/adapters/cloud-run/vite/index.mjs +0 -3
  4. package/lib/adapters/cloudflare-pages/vite/index.mjs +15 -9
  5. package/lib/adapters/deno-server/vite/index.mjs +7 -5
  6. package/lib/adapters/netlify-edge/vite/index.mjs +13 -23
  7. package/lib/adapters/node-server/vite/index.mjs +0 -3
  8. package/lib/adapters/shared/vite/index.d.ts +1 -7
  9. package/lib/adapters/shared/vite/index.mjs +164 -136
  10. package/lib/adapters/ssg/vite/index.mjs +3 -4
  11. package/lib/adapters/vercel-edge/vite/index.mjs +25 -9
  12. package/lib/chunks/error-handler.mjs +26 -26
  13. package/lib/chunks/fs.mjs +28 -138
  14. package/lib/chunks/http-error.qwik.mjs +27 -0
  15. package/lib/chunks/not-found-wrapper.qwik.mjs +25 -0
  16. package/lib/chunks/pathname.mjs +105 -0
  17. package/lib/chunks/routing.qwik.mjs +592 -216
  18. package/lib/chunks/system.mjs +328 -0
  19. package/lib/chunks/use-functions.qwik.mjs +35 -0
  20. package/lib/chunks/worker-thread.mjs +271 -0
  21. package/lib/index.d.ts +136 -102
  22. package/lib/index.qwik.mjs +699 -751
  23. package/lib/middleware/aws-lambda/index.mjs +7 -1
  24. package/lib/middleware/azure-swa/index.mjs +7 -2
  25. package/lib/middleware/bun/index.mjs +20 -5
  26. package/lib/middleware/cloudflare-pages/index.mjs +8 -2
  27. package/lib/middleware/deno/index.mjs +19 -5
  28. package/lib/middleware/netlify-edge/index.mjs +8 -2
  29. package/lib/middleware/node/index.mjs +10 -14
  30. package/lib/middleware/request-handler/index.d.ts +82 -12
  31. package/lib/middleware/request-handler/index.mjs +661 -524
  32. package/lib/middleware/vercel-edge/index.mjs +8 -2
  33. package/lib/modules.d.ts +7 -4
  34. package/lib/ssg/index.d.ts +48 -16
  35. package/lib/ssg/index.mjs +320 -7
  36. package/lib/vite/index.d.ts +6 -0
  37. package/lib/vite/index.mjs +1098 -641
  38. package/modules.d.ts +7 -4
  39. package/package.json +4 -4
  40. package/lib/chunks/format-error.mjs +0 -137
  41. package/lib/chunks/index.mjs +0 -896
  42. package/lib/chunks/types.qwik.mjs +0 -22
@@ -1,8 +1,10 @@
1
1
  import { mergeConfig, loadEnv } from 'vite';
2
2
  import fs, { existsSync } from 'node:fs';
3
3
  import path, { join, dirname, basename, resolve, isAbsolute, extname } from 'node:path';
4
- import { g as getExtension, r as removeExtension, i as isIndexModule, a as isErrorName, b as isLayoutModule, c as isEntryName, d as isMenuFileName, e as isServiceWorkerName, f as isPageModuleExt, h as isModuleExt, j as isMarkdownExt, k as isSameOriginUrl, l as normalizePath, m as getPathnameFromDirPath, o as getMenuPathname, p as createFileId, q as parseRouteIndexName, s as isPluginModule, t as addError, u as addWarning, v as isPageExt } from '../chunks/fs.mjs';
4
+ import { g as getExtension, r as removeExtension, i as isIndexModule, a as isErrorName, b as isLayoutModule, c as isEntryName, d as isMenuFileName, e as isServiceWorkerName, f as isPageModuleExt, h as isModuleExt, j as isMarkdownExt, k as normalizePath, l as getPathnameFromDirPath, m as getMenuPathname, o as createFileId, p as parseRouteIndexName, q as isPluginModule, s as isPageExt } from '../chunks/fs.mjs';
5
+ import { i as isSameOriginUrl, a as addError, b as addWarning } from '../chunks/pathname.mjs';
5
6
  import { marked } from 'marked';
7
+ import { createHash } from 'node:crypto';
6
8
  import { SourceMapGenerator } from 'source-map';
7
9
  import { visit } from 'unist-util-visit';
8
10
  import { parse } from 'yaml';
@@ -13,7 +15,6 @@ import { toString } from 'hast-util-to-string';
13
15
  import { refractor } from 'refractor';
14
16
  import tsxLang from 'refractor/lang/tsx.js';
15
17
  import { optimize } from 'svgo';
16
- import { p as parseId, f as formatError } from '../chunks/format-error.mjs';
17
18
 
18
19
  function extendConfig(baseConfigExport, serverConfigExport) {
19
20
  return async (env) => {
@@ -73,11 +74,9 @@ function getMarkdownRelativeUrl(opts, containingFilePath, url, checkFileExists)
73
74
  const parts = normalizePath(strippedUrl).split("/").filter((p) => p.length > 0);
74
75
  const filePath = isAbsolute ? join(opts.routesDir, ...parts) : join(dirname(containingFilePath), ...parts);
75
76
  if (checkFileExists && !existsSync(filePath)) {
76
- console.warn(
77
- `
77
+ console.warn(`
78
78
  The link "${url}", found within "${containingFilePath}" does not have a matching source file.
79
- `
80
- );
79
+ `);
81
80
  }
82
81
  const fileName = basename(filePath);
83
82
  const sourceFileName = getSourceFile(fileName);
@@ -113,12 +112,6 @@ function createMenu(opts, filePath) {
113
112
  function resolveMenu(opts, menuSourceFile) {
114
113
  return createMenu(opts, menuSourceFile.filePath);
115
114
  }
116
- async function transformMenu(opts, filePath, content) {
117
- const parsedMenu = parseMenu(opts, filePath, content);
118
- const id = createFileId(opts.routesDir, filePath);
119
- const code = `const ${id} = ${JSON.stringify(parsedMenu, null, 2)};`;
120
- return `${code} export default ${id}`;
121
- }
122
115
  function parseMenu(opts, filePath, content, checkFileExists = true) {
123
116
  const tokens = marked.lexer(content, {});
124
117
  let currentDepth = 0;
@@ -130,11 +123,7 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
130
123
  stack.length -= diff + 1;
131
124
  }
132
125
  if (diff < -1) {
133
- throw new Error(
134
- `Menu hierarchy skipped a level, went from <h${"#".repeat(
135
- currentDepth
136
- )}> to <h${"#".repeat(t.depth)}>, in menu: ${filePath}`
137
- );
126
+ throw new Error(`Menu hierarchy skipped a level, went from <h${"#".repeat(currentDepth)}> to <h${"#".repeat(t.depth)}>, in menu: ${filePath}`);
138
127
  }
139
128
  currentDepth = t.depth;
140
129
  const parentNode = stack[stack.length - 1];
@@ -148,9 +137,7 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
148
137
  lastNode.text = h2Token.text;
149
138
  lastNode.href = getMarkdownRelativeUrl(opts, filePath, h2Token.href, checkFileExists);
150
139
  } else {
151
- throw new Error(
152
- `Headings can only be a text or link. Received "${h2Token.type}", value "${h2Token.raw}", in menu: ${filePath}`
153
- );
140
+ throw new Error(`Headings can only be a text or link. Received "${h2Token.type}", value "${h2Token.raw}", in menu: ${filePath}`);
154
141
  }
155
142
  if (parentNode) {
156
143
  parentNode.items = parentNode.items || [];
@@ -167,16 +154,16 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
167
154
  if (liToken.type === "text") {
168
155
  for (const liItem of liToken.tokens) {
169
156
  if (liItem.type === "text") {
170
- parentNode.items.push({ text: liItem.text });
157
+ parentNode.items.push({
158
+ text: liItem.text
159
+ });
171
160
  } else if (liItem.type === "link") {
172
161
  parentNode.items.push({
173
162
  text: liItem.text,
174
163
  href: getMarkdownRelativeUrl(opts, filePath, liItem.href, checkFileExists)
175
164
  });
176
165
  } else {
177
- throw new Error(
178
- `List items can only be a text or link. Received "${liItem.type}", value "${liItem.raw}", in menu: ${filePath}`
179
- );
166
+ throw new Error(`List items can only be a text or link. Received "${liItem.type}", value "${liItem.raw}", in menu: ${filePath}`);
180
167
  }
181
168
  }
182
169
  } else if (liToken.type === "link") {
@@ -185,23 +172,17 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
185
172
  href: getMarkdownRelativeUrl(opts, filePath, liToken.href, checkFileExists)
186
173
  });
187
174
  } else {
188
- throw new Error(
189
- `List items can only be a text or link. Received "${liToken.type}", value "${liToken.raw}", in menu: ${filePath}`
190
- );
175
+ throw new Error(`List items can only be a text or link. Received "${liToken.type}", value "${liToken.raw}", in menu: ${filePath}`);
191
176
  }
192
177
  }
193
178
  } else {
194
- throw new Error(
195
- `Only list items can be used in lists. Received "${li.type}", value "${li.raw}", in menu: ${filePath}`
196
- );
179
+ throw new Error(`Only list items can be used in lists. Received "${li.type}", value "${li.raw}", in menu: ${filePath}`);
197
180
  }
198
181
  }
199
182
  } else if (t.type === "space") {
200
183
  continue;
201
184
  } else {
202
- throw new Error(
203
- `Menu has a "${t.type}" with the value "${t.raw}". However, only headings and lists can be used in the menu: ${filePath}`
204
- );
185
+ throw new Error(`Menu has a "${t.type}" with the value "${t.raw}". However, only headings and lists can be used in the menu: ${filePath}`);
205
186
  }
206
187
  }
207
188
  if (stack.length === 0) {
@@ -209,14 +190,30 @@ function parseMenu(opts, filePath, content, checkFileExists = true) {
209
190
  }
210
191
  return stack[0];
211
192
  }
193
+ async function transformMenu(opts, filePath, content) {
194
+ const parsedMenu = parseMenu(opts, filePath, content);
195
+ const id = createFileId(opts.routesDir, filePath);
196
+ const code = `const ${id} = ${JSON.stringify(parsedMenu, null, 2)};`;
197
+ return `${code} export default ${id}`;
198
+ }
212
199
 
200
+ const PARAM_PATTERN = /^(\.\.\.)?(\w+)?$/;
201
+ const DYNAMIC_SEGMENT = /\[(.+?)\]/;
213
202
  function parseRoutePathname(basePathname, pathname) {
214
203
  if (pathname === basePathname) {
215
204
  return {
216
205
  pattern: new RegExp("^" + pathname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "$"),
217
206
  routeName: pathname,
218
207
  paramNames: [],
219
- segments: [[{ content: "", dynamic: false, rest: false }]]
208
+ segments: [
209
+ [
210
+ {
211
+ content: "",
212
+ dynamic: false,
213
+ rest: false
214
+ }
215
+ ]
216
+ ]
220
217
  };
221
218
  }
222
219
  pathname = pathname.slice(1);
@@ -264,8 +261,6 @@ function parseRoutePathname(basePathname, pathname) {
264
261
  })
265
262
  };
266
263
  }
267
- const PARAM_PATTERN = /^(\.\.\.)?(\w+)?$/;
268
- const DYNAMIC_SEGMENT = /\[(.+?)\]/;
269
264
 
270
265
  function routeSortCompare(a, b) {
271
266
  const maxSegments = Math.max(a.segments.length, b.segments.length);
@@ -304,38 +299,9 @@ function routeSortCompare(a, b) {
304
299
  return a.pathname < b.pathname ? -1 : 1;
305
300
  }
306
301
 
307
- function resolveSourceFiles(opts, sourceFiles) {
308
- const layouts = sourceFiles.filter((s) => s.type === "layout").map((s) => resolveLayout(opts, s)).sort((a, b) => {
309
- return a.id < b.id ? -1 : 1;
310
- });
311
- const routes = sourceFiles.filter((s) => s.type === "route").map((s) => resolveRoute(opts, layouts, s)).sort(routeSortCompare);
312
- const entries = sourceFiles.filter((s) => s.type === "entry").map((s) => resolveEntry(opts, s)).sort((a, b) => {
313
- return a.chunkFileName < b.chunkFileName ? -1 : 1;
314
- });
315
- const serviceWorkers = sourceFiles.filter((s) => s.type === "service-worker").map((p) => resolveServiceWorkerEntry(opts, p)).sort((a, b) => {
316
- return a.chunkFileName < b.chunkFileName ? -1 : 1;
317
- });
318
- const menus = sourceFiles.filter((s) => s.type === "menu").map((p) => resolveMenu(opts, p)).sort((a, b) => {
319
- return a.pathname < b.pathname ? -1 : 1;
320
- });
321
- let inc = 0;
322
- const ids = /* @__PURE__ */ new Set();
323
- const uniqueIds = (b) => {
324
- for (const r of b) {
325
- let id = r.id;
326
- while (ids.has(id)) {
327
- id = `${r.id}_${inc++}`;
328
- }
329
- r.id = id;
330
- ids.add(id);
331
- }
332
- };
333
- uniqueIds(layouts);
334
- uniqueIds(routes);
335
- uniqueIds(entries);
336
- uniqueIds(serviceWorkers);
337
- return { layouts, routes, entries, menus, serviceWorkers };
338
- }
302
+ const LAYOUT_ID = "layout";
303
+ const LAYOUT_NAMED_PREFIX = LAYOUT_ID + "-";
304
+ const LAYOUT_TOP_SUFFIX = "!";
339
305
  function resolveLayout(opts, layoutSourceFile) {
340
306
  let extlessName = layoutSourceFile.extlessName;
341
307
  const filePath = layoutSourceFile.filePath;
@@ -362,16 +328,13 @@ function resolveLayout(opts, layoutSourceFile) {
362
328
  };
363
329
  return layout;
364
330
  }
365
- const LAYOUT_ID = "layout";
366
- const LAYOUT_NAMED_PREFIX = LAYOUT_ID + "-";
367
- const LAYOUT_TOP_SUFFIX = "!";
368
331
  function resolveRoute(opts, appLayouts, sourceFile) {
369
332
  const filePath = sourceFile.filePath;
370
333
  const layouts = [];
371
334
  const routesDir = opts.routesDir;
372
335
  const { layoutName, layoutStop } = parseRouteIndexName(sourceFile.extlessName);
373
336
  let pathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
374
- if (sourceFile.extlessName === "404") {
337
+ if (sourceFile.extlessName === "404" || sourceFile.extlessName === "error") {
375
338
  pathname += sourceFile.extlessName + ".html";
376
339
  }
377
340
  if (!layoutStop) {
@@ -400,7 +363,7 @@ function resolveRoute(opts, appLayouts, sourceFile) {
400
363
  currentDir = normalizePath(dirname(currentDir));
401
364
  }
402
365
  }
403
- const buildRoute = {
366
+ return {
404
367
  id: createFileId(opts.routesDir, filePath, "Route"),
405
368
  filePath,
406
369
  pathname,
@@ -408,152 +371,209 @@ function resolveRoute(opts, appLayouts, sourceFile) {
408
371
  ext: sourceFile.ext,
409
372
  ...parseRoutePathname(opts.basePathname, pathname)
410
373
  };
411
- return buildRoute;
412
374
  }
375
+
376
+ function parseDirName(name) {
377
+ if (name.startsWith("(") && name.endsWith(")")) {
378
+ return {
379
+ key: null
380
+ };
381
+ }
382
+ const restMatch = /^\[\.\.\.(\w+)\]$/.exec(name);
383
+ if (restMatch) {
384
+ return {
385
+ key: "_A",
386
+ paramName: restMatch[1]
387
+ };
388
+ }
389
+ const paramMatch = /^(.*?)\[(\w+)\](.*?)$/.exec(name);
390
+ if (paramMatch) {
391
+ return {
392
+ key: "_W",
393
+ paramName: paramMatch[2],
394
+ prefix: paramMatch[1] || void 0,
395
+ suffix: paramMatch[3] || void 0
396
+ };
397
+ }
398
+ return {
399
+ key: name.toLowerCase()
400
+ };
401
+ }
402
+ async function walkRouteDir(node, dirPath) {
403
+ const dirItemNames = await fs.promises.readdir(dirPath);
404
+ await Promise.all(dirItemNames.map(async (itemName) => {
405
+ const itemPath = normalizePath(join(dirPath, itemName));
406
+ const stat = await fs.promises.stat(itemPath);
407
+ if (stat.isDirectory()) {
408
+ const parsed = parseDirName(itemName);
409
+ if (parsed.key === null) {
410
+ let child = node.children.get(itemName);
411
+ if (!child) {
412
+ child = {
413
+ _files: [],
414
+ _dirPath: itemPath,
415
+ children: /* @__PURE__ */ new Map()
416
+ };
417
+ node.children.set(itemName, child);
418
+ }
419
+ await walkRouteDir(child, itemPath);
420
+ } else {
421
+ let child = node.children.get(parsed.key);
422
+ if (!child) {
423
+ child = {
424
+ _files: [],
425
+ _dirPath: itemPath,
426
+ children: /* @__PURE__ */ new Map()
427
+ };
428
+ if (parsed.paramName) {
429
+ child._P = parsed.paramName;
430
+ }
431
+ if (parsed.prefix) {
432
+ child._0 = parsed.prefix;
433
+ }
434
+ if (parsed.suffix) {
435
+ child._9 = parsed.suffix;
436
+ }
437
+ node.children.set(parsed.key, child);
438
+ }
439
+ await walkRouteDir(child, itemPath);
440
+ }
441
+ } else {
442
+ const sourceFileName = getSourceFile(itemName);
443
+ if (sourceFileName !== null) {
444
+ node._files.push({
445
+ ...sourceFileName,
446
+ fileName: itemName,
447
+ filePath: itemPath,
448
+ dirName: basename(dirPath),
449
+ dirPath: normalizePath(dirPath)
450
+ });
451
+ }
452
+ }
453
+ }));
454
+ }
455
+ async function walkRoutes(routesDir) {
456
+ const dirPath = normalizePath(routesDir);
457
+ const root = {
458
+ _files: [],
459
+ _dirPath: dirPath,
460
+ children: /* @__PURE__ */ new Map()
461
+ };
462
+ await walkRouteDir(root, dirPath);
463
+ return root;
464
+ }
465
+
466
+ async function walkServerPlugins(opts) {
467
+ const dirPath = opts.serverPluginsDir;
468
+ const dirItemNames = await fs.promises.readdir(dirPath);
469
+ const sourceFiles = [];
470
+ await Promise.all(dirItemNames.map(async (itemName) => {
471
+ const itemPath = normalizePath(join(dirPath, itemName));
472
+ const ext = getExtension(itemName);
473
+ const extlessName = removeExtension(itemName);
474
+ if ((isModuleExt(ext) || isPageModuleExt(ext)) && isPluginModule(extlessName)) {
475
+ sourceFiles.push({
476
+ id: createFileId(opts.serverPluginsDir, itemPath, "Plugin"),
477
+ filePath: itemPath,
478
+ ext
479
+ });
480
+ }
481
+ }));
482
+ return sourceFiles;
483
+ }
484
+
413
485
  function resolveEntry(opts, sourceFile) {
414
486
  const pathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
415
487
  const chunkFileName = pathname.slice(opts.basePathname.length);
416
- const buildEntry = {
488
+ return {
417
489
  id: createFileId(opts.routesDir, sourceFile.filePath, "Route"),
418
490
  filePath: sourceFile.filePath,
419
491
  chunkFileName,
420
492
  ...parseRoutePathname(opts.basePathname, pathname)
421
493
  };
422
- return buildEntry;
423
494
  }
424
495
  function resolveServiceWorkerEntry(opts, sourceFile) {
425
496
  const dirPathname = getPathnameFromDirPath(opts, sourceFile.dirPath);
426
497
  const pathname = dirPathname + sourceFile.extlessName + ".js";
427
498
  const chunkFileName = pathname.slice(opts.basePathname.length);
428
- const buildEntry = {
499
+ return {
429
500
  id: createFileId(opts.routesDir, sourceFile.filePath, "ServiceWorker"),
430
501
  filePath: sourceFile.filePath,
431
502
  chunkFileName,
432
503
  ...parseRoutePathname(opts.basePathname, pathname)
433
504
  };
434
- return buildEntry;
435
- }
436
-
437
- async function walkRoutes(routesDir) {
438
- const sourceFiles = [];
439
- await walkRouteDir(sourceFiles, normalizePath(routesDir), basename(routesDir));
440
- return sourceFiles;
441
505
  }
442
- async function walkRouteDir(sourceFiles, dirPath, dirName) {
443
- const dirItemNames = await fs.promises.readdir(dirPath);
444
- await Promise.all(
445
- dirItemNames.map(async (itemName) => {
446
- const itemPath = normalizePath(join(dirPath, itemName));
447
- const stat = await fs.promises.stat(itemPath);
448
- if (stat.isDirectory()) {
449
- await walkRouteDir(sourceFiles, itemPath, itemName);
450
- } else {
451
- const sourceFileName = getSourceFile(itemName);
452
- if (sourceFileName !== null) {
453
- sourceFiles.push({
454
- ...sourceFileName,
455
- fileName: itemName,
456
- filePath: itemPath,
457
- dirName,
458
- dirPath
459
- });
460
- }
461
- }
462
- })
463
- );
464
- }
465
-
466
- async function walkServerPlugins(opts) {
467
- const dirPath = opts.serverPluginsDir;
468
- const dirItemNames = await fs.promises.readdir(dirPath);
469
- const sourceFiles = [];
470
- await Promise.all(
471
- dirItemNames.map(async (itemName) => {
472
- const itemPath = normalizePath(join(dirPath, itemName));
473
- const ext = getExtension(itemName);
474
- const extlessName = removeExtension(itemName);
475
- if ((isModuleExt(ext) || isPageModuleExt(ext)) && isPluginModule(extlessName)) {
476
- sourceFiles.push({
477
- id: createFileId(opts.serverPluginsDir, itemPath, "Plugin"),
478
- filePath: itemPath,
479
- ext
480
- });
481
- }
482
- })
483
- );
484
- return sourceFiles;
485
- }
486
-
487
- async function parseRoutesDir(ctx) {
488
- try {
489
- await updateRoutingContext(ctx);
490
- validateBuild(ctx);
491
- } catch (e) {
492
- addError(ctx, e);
506
+ function deriveFromTrie(opts, root) {
507
+ const layouts = [];
508
+ const routes = [];
509
+ const entries = [];
510
+ const serviceWorkers = [];
511
+ const menus = [];
512
+ const allFiles = [];
513
+ function collectAllFiles(node) {
514
+ allFiles.push(...node._files);
515
+ for (const child of node.children.values()) {
516
+ collectAllFiles(child);
517
+ }
493
518
  }
494
- for (const d of ctx.diagnostics) {
495
- if (d.type === "error") {
496
- throw new Error(d.message);
497
- } else {
498
- console.warn(d.message);
519
+ collectAllFiles(root);
520
+ for (const file of allFiles) {
521
+ if (file.type === "layout") {
522
+ layouts.push(resolveLayout(opts, file));
499
523
  }
500
524
  }
501
- }
502
- function updateRoutingContext(ctx) {
503
- ctx.activeBuild ||= _updateRoutingContext(ctx).finally(() => {
504
- ctx.activeBuild = null;
505
- });
506
- return ctx.activeBuild;
507
- }
508
- async function _updateRoutingContext(ctx) {
509
- const serverPlugins = await walkServerPlugins(ctx.opts);
510
- const sourceFiles = await walkRoutes(ctx.opts.routesDir);
511
- const resolved = resolveSourceFiles(ctx.opts, sourceFiles);
512
- resolved.routes = rewriteRoutes(ctx, resolved.routes);
513
- ctx.serverPlugins = serverPlugins;
514
- ctx.layouts = resolved.layouts;
515
- ctx.routes = resolved.routes;
516
- ctx.entries = resolved.entries;
517
- ctx.serviceWorkers = resolved.serviceWorkers;
518
- ctx.menus = resolved.menus;
519
- }
520
- function rewriteRoutes(ctx, routes) {
521
- if (!ctx.opts.rewriteRoutes) {
522
- return routes;
525
+ for (const file of allFiles) {
526
+ switch (file.type) {
527
+ case "route":
528
+ routes.push(resolveRoute(opts, layouts, file));
529
+ break;
530
+ case "entry":
531
+ entries.push(resolveEntry(opts, file));
532
+ break;
533
+ case "service-worker":
534
+ serviceWorkers.push(resolveServiceWorkerEntry(opts, file));
535
+ break;
536
+ case "menu":
537
+ menus.push(resolveMenu(opts, file));
538
+ break;
539
+ }
523
540
  }
524
- const translatedRoutes = [];
525
- let segmentsToTranslate = ctx.opts.rewriteRoutes.flatMap((rewriteConfig) => {
526
- return Object.keys(rewriteConfig.paths || {});
527
- });
528
- segmentsToTranslate = Array.from(new Set(segmentsToTranslate));
529
- routes.forEach((route) => {
530
- translatedRoutes.push(route);
531
- const currentRouteSegments = route.pathname.split("/");
532
- const foundSegmentToTranslate = currentRouteSegments.some(
533
- (segment) => segmentsToTranslate.includes(segment)
534
- );
535
- if (foundSegmentToTranslate || route.pathname === "/") {
536
- ctx.opts.rewriteRoutes.forEach((config, configIndex) => {
537
- if (route.pathname === "/" && !config.prefix) {
538
- return;
539
- }
540
- const routeToPush = translateRoute(route, config, configIndex);
541
- if (!translatedRoutes.some(
542
- (item) => item.pathname === routeToPush.pathname && item.routeName === routeToPush.routeName
543
- )) {
544
- translatedRoutes.push(routeToPush);
545
- }
546
- });
541
+ let inc = 0;
542
+ const ids = /* @__PURE__ */ new Set();
543
+ const uniqueIds = (items) => {
544
+ for (const item of items) {
545
+ let id = item.id;
546
+ while (ids.has(id)) {
547
+ id = `${item.id}_${inc++}`;
548
+ }
549
+ item.id = id;
550
+ ids.add(id);
547
551
  }
548
- });
549
- return translatedRoutes.sort(routeSortCompare);
552
+ };
553
+ uniqueIds(layouts);
554
+ uniqueIds(routes);
555
+ uniqueIds(entries);
556
+ uniqueIds(serviceWorkers);
557
+ layouts.sort((a, b) => a.id < b.id ? -1 : 1);
558
+ entries.sort((a, b) => a.chunkFileName < b.chunkFileName ? -1 : 1);
559
+ serviceWorkers.sort((a, b) => a.chunkFileName < b.chunkFileName ? -1 : 1);
560
+ menus.sort((a, b) => a.pathname < b.pathname ? -1 : 1);
561
+ return {
562
+ layouts,
563
+ routes,
564
+ entries,
565
+ serviceWorkers,
566
+ menus
567
+ };
550
568
  }
551
569
  function translateRoute(route, config, configIndex) {
552
570
  const replacePath = (part) => (config.paths || {})[part] ?? part;
553
571
  const pathnamePrefix = config.prefix ? "/" + config.prefix : "";
554
572
  const routeNamePrefix = config.prefix ? config.prefix + "/" : "";
555
573
  const idSuffix = config.prefix?.toUpperCase().replace(/-/g, "");
556
- const patternInfix = config.prefix ? [config.prefix] : [];
574
+ const patternInfix = config.prefix ? [
575
+ config.prefix
576
+ ] : [];
557
577
  const splittedPathName = route.pathname.split("/");
558
578
  const translatedPathParts = splittedPathName.map(replacePath);
559
579
  const splittedRouteName = route.routeName.split("/");
@@ -566,13 +586,11 @@ function translateRoute(route, config, configIndex) {
566
586
  ...translatedPatternOthers
567
587
  ];
568
588
  const translatedPatternString = translatedPatternParts.join("\\/");
569
- const translatedRegExp = translatedPatternString.substring(
570
- 1,
571
- route.pathname === "/" ? translatedPatternString.length - 1 : translatedPatternString.length - 2
572
- );
573
- const translatedSegments = route.segments.map(
574
- (segment) => segment.map((item) => ({ ...item, content: replacePath(item.content) }))
575
- );
589
+ const translatedRegExp = translatedPatternString.substring(1, route.pathname === "/" ? translatedPatternString.length - 1 : translatedPatternString.length - 2);
590
+ const translatedSegments = route.segments.map((segment) => segment.map((item) => ({
591
+ ...item,
592
+ content: replacePath(item.content)
593
+ })));
576
594
  if (config.prefix) {
577
595
  translatedSegments.splice(0, 0, [
578
596
  {
@@ -584,7 +602,7 @@ function translateRoute(route, config, configIndex) {
584
602
  }
585
603
  const translatedPath = translatedPathParts.join("/");
586
604
  const translatedRoute = translatedRouteParts.join("/");
587
- const routeToPush = {
605
+ return {
588
606
  ...route,
589
607
  id: route.id + (idSuffix || configIndex),
590
608
  pathname: pathnamePrefix + translatedPath,
@@ -592,47 +610,81 @@ function translateRoute(route, config, configIndex) {
592
610
  pattern: new RegExp(translatedRegExp),
593
611
  segments: translatedSegments
594
612
  };
595
- return routeToPush;
613
+ }
614
+ function rewriteRoutes(ctx, routes) {
615
+ if (!ctx.opts.rewriteRoutes) {
616
+ return routes;
617
+ }
618
+ const translatedRoutes = [];
619
+ let segmentsToTranslate = ctx.opts.rewriteRoutes.flatMap((rewriteConfig) => {
620
+ return Object.keys(rewriteConfig.paths || {});
621
+ });
622
+ segmentsToTranslate = Array.from(new Set(segmentsToTranslate));
623
+ routes.forEach((route) => {
624
+ translatedRoutes.push(route);
625
+ const currentRouteSegments = route.pathname.split("/");
626
+ const foundSegmentToTranslate = currentRouteSegments.some((segment) => segmentsToTranslate.includes(segment));
627
+ if (foundSegmentToTranslate || route.pathname === "/") {
628
+ ctx.opts.rewriteRoutes.forEach((config, configIndex) => {
629
+ if (route.pathname === "/" && !config.prefix) {
630
+ return;
631
+ }
632
+ const routeToPush = translateRoute(route, config, configIndex);
633
+ if (!translatedRoutes.some((item) => item.pathname === routeToPush.pathname && item.routeName === routeToPush.routeName)) {
634
+ translatedRoutes.push(routeToPush);
635
+ }
636
+ });
637
+ }
638
+ });
639
+ return translatedRoutes.sort(routeSortCompare);
640
+ }
641
+ async function _updateRoutingContext(ctx) {
642
+ const serverPlugins = await walkServerPlugins(ctx.opts);
643
+ const routeTrie = await walkRoutes(ctx.opts.routesDir);
644
+ ctx.routeTrie = routeTrie;
645
+ ctx.serverPlugins = serverPlugins;
646
+ const derived = deriveFromTrie(ctx.opts, routeTrie);
647
+ ctx.layouts = derived.layouts;
648
+ ctx.routes = rewriteRoutes(ctx, derived.routes);
649
+ ctx.entries = derived.entries;
650
+ ctx.serviceWorkers = derived.serviceWorkers;
651
+ ctx.menus = derived.menus;
652
+ }
653
+ function updateRoutingContext(ctx) {
654
+ ctx.activeBuild ||= _updateRoutingContext(ctx).finally(() => {
655
+ ctx.activeBuild = null;
656
+ });
657
+ return ctx.activeBuild;
596
658
  }
597
659
  function validateBuild(ctx) {
598
660
  const pathnames = Array.from(new Set(ctx.routes.map((r) => r.pathname))).sort();
599
661
  for (const pathname of pathnames) {
600
662
  const foundRoutes = ctx.routes.filter((r) => r.pathname === pathname);
601
663
  if (foundRoutes.length > 1) {
602
- addError(
603
- ctx,
604
- `More than one route has been found for pathname "${pathname}". Please narrow it down to only one of these:
605
- ${foundRoutes.map((r) => ` - ${r.filePath}`).join("\n")}`
606
- );
664
+ addError(ctx, `More than one route has been found for pathname "${pathname}". Please narrow it down to only one of these:
665
+ ${foundRoutes.map((r) => ` - ${r.filePath}`).join("\n")}`);
607
666
  }
608
667
  }
609
668
  ctx.layouts.filter((l) => l.layoutType === "top").forEach((l) => {
610
- addWarning(
611
- ctx,
612
- `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/`
613
- );
669
+ 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/`);
614
670
  });
615
671
  }
616
-
617
- function createBuildContext(rootDir, viteBasePath, userOpts, target, dynamicImports) {
618
- const ctx = {
619
- rootDir: normalizePath(rootDir),
620
- opts: normalizeOptions(rootDir, viteBasePath, userOpts),
621
- routes: [],
622
- serverPlugins: [],
623
- layouts: [],
624
- entries: [],
625
- serviceWorkers: [],
626
- menus: [],
627
- diagnostics: [],
628
- frontmatter: /* @__PURE__ */ new Map(),
629
- target: target || "ssr",
630
- dynamicImports: target === "client" || !!dynamicImports,
631
- isDirty: true,
632
- activeBuild: null
633
- };
634
- return ctx;
672
+ async function parseRoutesDir(ctx) {
673
+ try {
674
+ await updateRoutingContext(ctx);
675
+ validateBuild(ctx);
676
+ } catch (e) {
677
+ addError(ctx, e);
678
+ }
679
+ for (const d of ctx.diagnostics) {
680
+ if (d.type === "error") {
681
+ throw new Error(d.message);
682
+ } else {
683
+ console.warn(d.message);
684
+ }
685
+ }
635
686
  }
687
+
636
688
  function resetBuildContext(ctx) {
637
689
  if (ctx) {
638
690
  ctx.routes.length = 0;
@@ -646,14 +698,14 @@ function resetBuildContext(ctx) {
646
698
  }
647
699
  function normalizeOptions(rootDir, viteBasePath, userOpts) {
648
700
  if (!(viteBasePath.startsWith("/") && viteBasePath.endsWith("/"))) {
649
- console.error(
650
- `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.`
651
- );
701
+ 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.`);
652
702
  if (!viteBasePath.endsWith("/")) {
653
703
  viteBasePath += "/";
654
704
  }
655
705
  }
656
- const opts = { ...userOpts };
706
+ const opts = {
707
+ ...userOpts
708
+ };
657
709
  if (typeof opts.routesDir !== "string") {
658
710
  opts.routesDir = resolve(rootDir, "src", "routes");
659
711
  } else if (!isAbsolute(opts.routesDir)) {
@@ -673,9 +725,7 @@ function normalizeOptions(rootDir, viteBasePath, userOpts) {
673
725
  opts.basePathname = viteBasePath;
674
726
  }
675
727
  if (!opts.basePathname.endsWith("/")) {
676
- console.error(
677
- `Warning: qwik-router plugin basePathname must end with /. This will be an error in v2`
678
- );
728
+ console.error(`Warning: qwik-router plugin basePathname must end with /. This will be an error in v2`);
679
729
  opts.basePathname += "/";
680
730
  }
681
731
  const url = new URL(opts.basePathname, "https://qwik.dev/");
@@ -684,9 +734,42 @@ function normalizeOptions(rootDir, viteBasePath, userOpts) {
684
734
  opts.platform = opts.platform || {};
685
735
  return opts;
686
736
  }
687
-
688
- function parseFrontmatter(ctx) {
689
- return (mdast, vfile) => {
737
+ function createBuildContext(rootDir, viteBasePath, userOpts, target, dynamicImports) {
738
+ const ctx = {
739
+ rootDir: normalizePath(rootDir),
740
+ opts: normalizeOptions(rootDir, viteBasePath, userOpts),
741
+ routeTrie: {
742
+ _files: [],
743
+ _dirPath: "",
744
+ children: /* @__PURE__ */ new Map()
745
+ },
746
+ routes: [],
747
+ serverPlugins: [],
748
+ layouts: [],
749
+ entries: [],
750
+ serviceWorkers: [],
751
+ menus: [],
752
+ diagnostics: [],
753
+ frontmatter: /* @__PURE__ */ new Map(),
754
+ target: target || "ssr",
755
+ dynamicImports: target === "client" || !!dynamicImports,
756
+ isDirty: true,
757
+ activeBuild: null
758
+ };
759
+ return ctx;
760
+ }
761
+
762
+ function parseFrontmatterAttrs(yaml) {
763
+ if (typeof yaml === "string") {
764
+ yaml = yaml.trim();
765
+ if (yaml !== "") {
766
+ return parse(yaml);
767
+ }
768
+ }
769
+ return null;
770
+ }
771
+ function parseFrontmatter(ctx) {
772
+ return (mdast, vfile) => {
690
773
  const attrs = {};
691
774
  visit(mdast, "yaml", (node) => {
692
775
  const parsedAttrs = parseFrontmatterAttrs(node.value);
@@ -699,15 +782,6 @@ function parseFrontmatter(ctx) {
699
782
  }
700
783
  };
701
784
  }
702
- function parseFrontmatterAttrs(yaml) {
703
- if (typeof yaml === "string") {
704
- yaml = yaml.trim();
705
- if (yaml !== "") {
706
- return parse(yaml);
707
- }
708
- }
709
- return null;
710
- }
711
785
  const metaNames = {
712
786
  author: true,
713
787
  creator: true,
@@ -741,7 +815,9 @@ function frontmatterAttrsToDocumentHead(attrs) {
741
815
  head.title = head.title.replace(/\\@/g, "@");
742
816
  } else if (attrName === "og" || attrName === "opengraph") {
743
817
  if (typeof attrValue === "object") {
744
- for (const opengraph of Array.isArray(attrValue) ? attrValue : [attrValue]) {
818
+ for (const opengraph of Array.isArray(attrValue) ? attrValue : [
819
+ attrValue
820
+ ]) {
745
821
  if (opengraph != null && typeof opengraph === "object" && !Array.isArray(opengraph)) {
746
822
  for (const [property, content] of Object.entries(opengraph)) {
747
823
  if ((property === "title" || property === "description") && content === true) {
@@ -777,31 +853,6 @@ function frontmatterAttrsToDocumentHead(attrs) {
777
853
  return null;
778
854
  }
779
855
 
780
- function rehypeSlug() {
781
- return (ast) => {
782
- const mdast = ast;
783
- const slugs = new Slugger();
784
- visit(mdast, "element", (node) => {
785
- const level = headingRank(node);
786
- if (level && node.properties) {
787
- const text = toString(node);
788
- if (!hasProperty(node, "id")) {
789
- node.properties.id = slugs.slug(text);
790
- }
791
- }
792
- });
793
- };
794
- }
795
- function rehypePage(ctx) {
796
- return (ast, vfile) => {
797
- const mdast = ast;
798
- const sourcePath = normalizePath(vfile.path);
799
- updateContentLinks(mdast, ctx.opts, sourcePath);
800
- exportFrontmatter(ctx, mdast, sourcePath);
801
- exportContentHead(ctx, mdast, sourcePath);
802
- exportContentHeadings(mdast);
803
- };
804
- }
805
856
  function renameClassname() {
806
857
  return (ast) => {
807
858
  const mdast = ast;
@@ -820,11 +871,17 @@ function wrapTableWithDiv() {
820
871
  const mdast = ast;
821
872
  visit(mdast, "element", (node) => {
822
873
  if (node.tagName === "table" && !node.done) {
823
- const table = { ...node };
874
+ const table = {
875
+ ...node
876
+ };
824
877
  table.done = true;
825
878
  node.tagName = "div";
826
- node.properties = { className: "table-wrapper" };
827
- node.children = [table];
879
+ node.properties = {
880
+ className: "table-wrapper"
881
+ };
882
+ node.children = [
883
+ table
884
+ ];
828
885
  }
829
886
  });
830
887
  };
@@ -837,47 +894,12 @@ function updateContentLinks(mdast, opts, sourcePath) {
837
894
  if (isSameOriginUrl(href)) {
838
895
  const ext = getExtension(href);
839
896
  if (isMarkdownExt(ext)) {
840
- node.properties.href = getMarkdownRelativeUrl(
841
- opts,
842
- sourcePath,
843
- node.properties.href,
844
- true
845
- );
897
+ node.properties.href = getMarkdownRelativeUrl(opts, sourcePath, node.properties.href, true);
846
898
  }
847
899
  }
848
900
  }
849
901
  });
850
902
  }
851
- function exportFrontmatter(ctx, mdast, sourcePath) {
852
- const attrs = ctx.frontmatter.get(sourcePath);
853
- createExport(mdast, "frontmatter", attrs);
854
- }
855
- function exportContentHead(ctx, mdast, sourcePath) {
856
- const attrs = ctx.frontmatter.get(sourcePath);
857
- const head = frontmatterAttrsToDocumentHead(attrs);
858
- if (head) {
859
- createExport(mdast, "head", head);
860
- }
861
- }
862
- function exportContentHeadings(mdast) {
863
- const headings = [];
864
- visit(mdast, "element", (node) => {
865
- const level = headingRank(node);
866
- if (level && node.properties) {
867
- if (hasProperty(node, "id")) {
868
- const text = toString(node);
869
- headings.push({
870
- text,
871
- id: node.properties.id,
872
- level
873
- });
874
- }
875
- }
876
- });
877
- if (headings.length > 0) {
878
- createExport(mdast, "headings", headings);
879
- }
880
- }
881
903
  function createExport(mdast, identifierName, val) {
882
904
  const mdxjsEsm = {
883
905
  type: "mdxjsEsm",
@@ -898,7 +920,10 @@ function createExport(mdast, identifierName, val) {
898
920
  declarations: [
899
921
  {
900
922
  type: "VariableDeclarator",
901
- id: { type: "Identifier", name: identifierName },
923
+ id: {
924
+ type: "Identifier",
925
+ name: identifierName
926
+ },
902
927
  init: valueToEstree(val)
903
928
  }
904
929
  ]
@@ -910,31 +935,67 @@ function createExport(mdast, identifierName, val) {
910
935
  };
911
936
  mdast.children.unshift(mdxjsEsm);
912
937
  }
938
+ function exportFrontmatter(ctx, mdast, sourcePath) {
939
+ const attrs = ctx.frontmatter.get(sourcePath);
940
+ createExport(mdast, "frontmatter", attrs);
941
+ }
942
+ function exportContentHead(ctx, mdast, sourcePath) {
943
+ const attrs = ctx.frontmatter.get(sourcePath);
944
+ const head = frontmatterAttrsToDocumentHead(attrs);
945
+ if (head) {
946
+ createExport(mdast, "head", head);
947
+ }
948
+ }
913
949
  const own = {}.hasOwnProperty;
914
950
  function hasProperty(node, propName) {
915
951
  const value = node && typeof node === "object" && node.type === "element" && node.properties && own.call(node.properties, propName) && node.properties[propName];
916
952
  return value != null && value !== false;
917
953
  }
918
-
919
- function rehypeSyntaxHighlight() {
920
- refractor.register(tsxLang);
921
- return async (ast) => {
922
- visit(ast, "element", (node, _index, parent) => {
923
- if (!parent || parent.tagName !== "pre" || node.tagName !== "code" || !Array.isArray(node.properties.className)) {
924
- return;
925
- }
926
- for (let i = 0; i < node.properties.className.length; i++) {
927
- const className = node.properties.className[i];
928
- const lang = getLanguage(className);
929
- if (lang && refractor.registered(lang)) {
930
- node.properties.className[i] = "language-" + lang;
931
- syntaxHighlight(node, lang);
932
- return;
954
+ function rehypeSlug() {
955
+ return (ast) => {
956
+ const mdast = ast;
957
+ const slugs = new Slugger();
958
+ visit(mdast, "element", (node) => {
959
+ const level = headingRank(node);
960
+ if (level && node.properties) {
961
+ const text = toString(node);
962
+ if (!hasProperty(node, "id")) {
963
+ node.properties.id = slugs.slug(text);
933
964
  }
934
965
  }
935
966
  });
936
967
  };
937
968
  }
969
+ function exportContentHeadings(mdast) {
970
+ const headings = [];
971
+ visit(mdast, "element", (node) => {
972
+ const level = headingRank(node);
973
+ if (level && node.properties) {
974
+ if (hasProperty(node, "id")) {
975
+ const text = toString(node);
976
+ headings.push({
977
+ text,
978
+ id: node.properties.id,
979
+ level
980
+ });
981
+ }
982
+ }
983
+ });
984
+ if (headings.length > 0) {
985
+ createExport(mdast, "headings", headings);
986
+ }
987
+ }
988
+ function rehypePage(ctx) {
989
+ return (ast, vfile) => {
990
+ const mdast = ast;
991
+ const sourcePath = normalizePath(vfile.path);
992
+ updateContentLinks(mdast, ctx.opts, sourcePath);
993
+ exportFrontmatter(ctx, mdast, sourcePath);
994
+ exportContentHead(ctx, mdast, sourcePath);
995
+ exportContentHeadings(mdast);
996
+ };
997
+ }
998
+
938
999
  function syntaxHighlight(node, lang) {
939
1000
  const code = toString(node);
940
1001
  const result = refractor.highlight(code, lang);
@@ -951,6 +1012,25 @@ function getLanguage(className) {
951
1012
  }
952
1013
  return null;
953
1014
  }
1015
+ function rehypeSyntaxHighlight() {
1016
+ refractor.register(tsxLang);
1017
+ return async (ast) => {
1018
+ visit(ast, "element", (node, _index, parent) => {
1019
+ if (!parent || parent.tagName !== "pre" || node.tagName !== "code" || !Array.isArray(node.properties.className)) {
1020
+ return;
1021
+ }
1022
+ for (let i = 0; i < node.properties.className.length; i++) {
1023
+ const className = node.properties.className[i];
1024
+ const lang = getLanguage(className);
1025
+ if (lang && refractor.registered(lang)) {
1026
+ node.properties.className[i] = "language-" + lang;
1027
+ syntaxHighlight(node, lang);
1028
+ return;
1029
+ }
1030
+ }
1031
+ });
1032
+ };
1033
+ }
954
1034
 
955
1035
  async function createMdxTransformer(ctx) {
956
1036
  const { compile } = await import('@mdx-js/mdx');
@@ -982,21 +1062,34 @@ async function createMdxTransformer(ctx) {
982
1062
  ...userRemarkPlugins,
983
1063
  ...coreRemarkPlugins,
984
1064
  remarkFrontmatter,
985
- [parseFrontmatter, ctx]
1065
+ [
1066
+ parseFrontmatter,
1067
+ ctx
1068
+ ]
986
1069
  ],
987
1070
  rehypePlugins: [
988
1071
  rehypeSlug,
989
1072
  ...userRehypePlugins,
990
1073
  ...coreRehypePlugins,
991
- [rehypePage, ctx],
1074
+ [
1075
+ rehypePage,
1076
+ ctx
1077
+ ],
992
1078
  renameClassname,
993
1079
  wrapTableWithDiv
994
1080
  ]
995
1081
  };
996
1082
  return async function(code, id) {
997
1083
  const ext = getExtension(id);
998
- if ([".mdx", ".md", ".markdown"].includes(ext)) {
999
- const file = new VFile({ value: code, path: id });
1084
+ if ([
1085
+ ".mdx",
1086
+ ".md",
1087
+ ".markdown"
1088
+ ].includes(ext)) {
1089
+ const file = new VFile({
1090
+ value: code,
1091
+ path: id
1092
+ });
1000
1093
  const compiled = await compile(file, options);
1001
1094
  const output = String(compiled.value);
1002
1095
  const addImport = `import { jsx } from '@qwik.dev/core';
@@ -1015,7 +1108,13 @@ export default WrappedMdxContent;
1015
1108
  if (exportIndex === -1) {
1016
1109
  throw new Error("Could not find default export in mdx output");
1017
1110
  }
1018
- const wrappedOutput = addImport + output.slice(0, exportIndex) + newDefault;
1111
+ let eTagExport = "";
1112
+ if (ext === ".md" || ext === ".markdown") {
1113
+ const hash = createHash("sha256").update(code).digest("hex").slice(0, 16);
1114
+ eTagExport = `export const eTag = ${JSON.stringify(hash)};
1115
+ `;
1116
+ }
1117
+ const wrappedOutput = addImport + output.slice(0, exportIndex) + eTagExport + newDefault;
1019
1118
  return {
1020
1119
  code: wrappedOutput,
1021
1120
  map: compiled.map
@@ -1026,7 +1125,10 @@ export default WrappedMdxContent;
1026
1125
 
1027
1126
  function createEntries(ctx, c) {
1028
1127
  const isClient = ctx.target === "client";
1029
- const entries = [...ctx.entries, ...ctx.serviceWorkers];
1128
+ const entries = [
1129
+ ...ctx.entries,
1130
+ ...ctx.serviceWorkers
1131
+ ];
1030
1132
  if (isClient && entries.length > 0) {
1031
1133
  c.push(`
1032
1134
  /** Qwik Router Entries Entry */`);
@@ -1036,7 +1138,10 @@ function createEntries(ctx, c) {
1036
1138
  }
1037
1139
  function generateQwikRouterEntries(ctx) {
1038
1140
  const c = [];
1039
- const entries = [...ctx.entries, ...ctx.serviceWorkers];
1141
+ const entries = [
1142
+ ...ctx.entries,
1143
+ ...ctx.serviceWorkers
1144
+ ];
1040
1145
  c.push(`
1041
1146
  /** Qwik Router Entries (${entries.length}) */`);
1042
1147
  for (let i = 0; i < entries.length; i++) {
@@ -1057,80 +1162,41 @@ function getImportPath(importPath) {
1057
1162
  return importPath;
1058
1163
  }
1059
1164
 
1060
- function createMenus(ctx, c, esmImports, isSSR) {
1061
- c.push(`
1062
- /** Qwik Router Menus (${ctx.menus.length}) */`);
1063
- c.push(`export const menus = [`);
1064
- const dynamicImports = !isSSR;
1065
- const routesDir = ctx.opts.routesDir;
1066
- for (const m of ctx.menus) {
1067
- const importPath = JSON.stringify(getImportPath(m.filePath));
1068
- if (dynamicImports) {
1069
- c.push(` [${JSON.stringify(m.pathname)}, ()=>import(${importPath})],`);
1070
- } else {
1071
- const id = createFileId(routesDir, m.filePath);
1072
- esmImports.push(`import * as ${id} from ${importPath};`);
1073
- c.push(` [${JSON.stringify(m.pathname)}, ()=>${id}],`);
1074
- }
1075
- }
1076
- c.push(`];`);
1165
+ function isGroupKey(key) {
1166
+ return key.charCodeAt(0) === 40;
1077
1167
  }
1078
-
1079
- function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR) {
1080
- const includeEndpoints = isSSR;
1081
- const dynamicImports = ctx.dynamicImports;
1082
- if (ctx.layouts.length > 0) {
1083
- c.push(`
1084
- /** Qwik Router Layouts (${ctx.layouts.length}) */`);
1085
- for (const layout of ctx.layouts) {
1086
- const importPath = JSON.stringify(getImportPath(layout.filePath));
1087
- if (dynamicImports) {
1088
- c.push(`const ${layout.id} = ()=>import(${importPath});`);
1089
- } else {
1090
- esmImports.push(`import * as ${layout.id}_ from ${importPath};`);
1091
- c.push(`const ${layout.id} = ()=>${layout.id}_;`);
1092
- }
1093
- }
1168
+ function collectFiles(node, cb) {
1169
+ for (const file of node._files) {
1170
+ cb(file, node);
1094
1171
  }
1095
- c.push(`
1096
- /** Qwik Router Routes (${ctx.routes.length}) */`);
1097
- c.push(`export const routes = [`);
1098
- for (const route of ctx.routes) {
1099
- const layouts = [];
1100
- if (isPageExt(route.ext)) {
1101
- for (const layout of route.layouts) {
1102
- layouts.push(layout.id);
1103
- }
1104
- const importPath = getImportPath(route.filePath);
1105
- if (dynamicImports) {
1106
- layouts.push(`()=>import(${JSON.stringify(importPath)})`);
1107
- } else {
1108
- esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
1109
- layouts.push(`()=>${route.id}`);
1172
+ for (const child of node.children.values()) {
1173
+ collectFiles(child, cb);
1174
+ }
1175
+ }
1176
+ function resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, targetName) {
1177
+ const allLayouts = [
1178
+ ...ancestorLayouts,
1179
+ ...nodeLayouts
1180
+ ];
1181
+ const result = [];
1182
+ let foundNamed = false;
1183
+ for (let i = allLayouts.length - 1; i >= 0; i--) {
1184
+ const layout = allLayouts[i];
1185
+ if (!foundNamed) {
1186
+ if (layout.layoutName === targetName) {
1187
+ result.unshift(layout);
1188
+ foundNamed = true;
1110
1189
  }
1111
- } else if (includeEndpoints && isModuleExt(route.ext)) {
1112
- const importPath = getImportPath(route.filePath);
1113
- esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
1114
- for (const layout of route.layouts) {
1115
- layouts.push(layout.id);
1190
+ } else {
1191
+ if (layout.layoutName === "") {
1192
+ result.unshift(layout);
1193
+ if (layout.layoutType === "top") {
1194
+ break;
1195
+ }
1116
1196
  }
1117
- layouts.push(`()=>${route.id}`);
1118
- }
1119
- if (layouts.length > 0) {
1120
- c.push(` ${createRouteData(qwikPlugin, route, layouts, isSSR)},`);
1121
1197
  }
1122
1198
  }
1123
- c.push(`];`);
1124
- }
1125
- function createRouteData(qwikPlugin, r, layouts, isSsr) {
1126
- const routeName = JSON.stringify(r.routeName);
1127
- const moduleLayouts = `[ ${layouts.join(", ")} ]`;
1128
- if (isSsr) {
1129
- const originalPathname = JSON.stringify(r.pathname);
1130
- const clientBundleNames = JSON.stringify(getClientRouteBundleNames(qwikPlugin, r));
1131
- return `[ ${routeName}, ${moduleLayouts}, ${originalPathname}, ${clientBundleNames} ]`;
1132
- }
1133
- return `[ ${routeName}, ${moduleLayouts} ]`;
1199
+ return result;
1134
1200
  }
1135
1201
  function getClientRouteBundleNames(qwikPlugin, r) {
1136
1202
  const bundlesNames = [];
@@ -1152,13 +1218,249 @@ function getClientRouteBundleNames(qwikPlugin, r) {
1152
1218
  }
1153
1219
  }
1154
1220
  }
1155
- };
1156
- for (const layout of r.layouts) {
1157
- addRouteFile(layout.filePath);
1221
+ };
1222
+ for (const layout of r.layouts) {
1223
+ addRouteFile(layout.filePath);
1224
+ }
1225
+ addRouteFile(r.filePath);
1226
+ }
1227
+ return bundlesNames;
1228
+ }
1229
+ function serializeBuildTrie(ctx, qwikPlugin, node, layoutIdMap, routeIdMap, menuIdMap, errorFiles, notFoundFiles, ancestorLayouts, isSSR, indent) {
1230
+ const lines = [];
1231
+ const nextIndent = indent + " ";
1232
+ if (node._P) {
1233
+ lines.push(`${nextIndent}_P: ${JSON.stringify(node._P)},`);
1234
+ }
1235
+ if (node._0) {
1236
+ lines.push(`${nextIndent}_0: ${JSON.stringify(node._0)},`);
1237
+ }
1238
+ if (node._9) {
1239
+ lines.push(`${nextIndent}_9: ${JSON.stringify(node._9)},`);
1240
+ }
1241
+ if (node._G) {
1242
+ lines.push(`${nextIndent}_G: ${JSON.stringify(node._G)},`);
1243
+ }
1244
+ let layoutExpr;
1245
+ let indexExpr;
1246
+ let indexIsOverride = false;
1247
+ let errorExpr;
1248
+ let notFoundExpr;
1249
+ let menuExpr;
1250
+ let bundleRoute;
1251
+ const nodeLayouts = [];
1252
+ for (const file of node._files) {
1253
+ if (file.type === "menu") {
1254
+ const menuId = menuIdMap.get(file.filePath);
1255
+ if (menuId) {
1256
+ menuExpr = menuId;
1257
+ }
1258
+ } else if (file.type === "layout") {
1259
+ const layoutId = layoutIdMap.get(file.filePath);
1260
+ if (layoutId) {
1261
+ let extlessName = file.extlessName;
1262
+ let layoutType = "nested";
1263
+ if (extlessName.endsWith("!")) {
1264
+ layoutType = "top";
1265
+ extlessName = extlessName.slice(0, -1);
1266
+ }
1267
+ const layoutName = extlessName.startsWith("layout-") ? extlessName.slice("layout-".length) : "";
1268
+ nodeLayouts.push({
1269
+ id: layoutId,
1270
+ layoutName,
1271
+ layoutType
1272
+ });
1273
+ if (layoutName === "") {
1274
+ layoutExpr = layoutId;
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+ for (const file of node._files) {
1280
+ if (file.type !== "route") {
1281
+ continue;
1282
+ }
1283
+ const loaderExpr = routeIdMap.get(file.filePath);
1284
+ if (!loaderExpr) {
1285
+ continue;
1286
+ }
1287
+ const isError = file.extlessName === "error";
1288
+ const is404 = file.extlessName === "404";
1289
+ if (isError) {
1290
+ errorExpr = loaderExpr;
1291
+ errorFiles.set(node._dirPath, file.filePath);
1292
+ } else if (is404) {
1293
+ notFoundExpr = loaderExpr;
1294
+ notFoundFiles.set(node._dirPath, file.filePath);
1295
+ } else {
1296
+ const { layoutName, layoutStop } = parseRouteIndexName(file.extlessName);
1297
+ if (layoutStop) {
1298
+ indexExpr = `[ ${loaderExpr} ]`;
1299
+ indexIsOverride = true;
1300
+ } else if (layoutName) {
1301
+ const chain = resolveNamedLayoutChain(ancestorLayouts, nodeLayouts, layoutName);
1302
+ const chainExprs = chain.map((l) => l.id);
1303
+ chainExprs.push(loaderExpr);
1304
+ indexExpr = `[ ${chainExprs.join(", ")} ]`;
1305
+ indexIsOverride = true;
1306
+ } else {
1307
+ indexExpr = loaderExpr;
1308
+ }
1309
+ bundleRoute = ctx.routes.find((r) => r.filePath === file.filePath);
1310
+ }
1311
+ }
1312
+ if (layoutExpr) {
1313
+ lines.push(`${nextIndent}_L: ${layoutExpr},`);
1314
+ }
1315
+ if (indexExpr) {
1316
+ if (indexIsOverride) {
1317
+ lines.push(`${nextIndent}_I: ${indexExpr},`);
1318
+ } else {
1319
+ lines.push(`${nextIndent}_I: ${indexExpr},`);
1320
+ }
1321
+ if (isSSR && bundleRoute) {
1322
+ const bundleNames = getClientRouteBundleNames(qwikPlugin, bundleRoute);
1323
+ if (bundleNames.length > 0) {
1324
+ lines.push(`${nextIndent}_B: ${JSON.stringify(bundleNames)},`);
1325
+ }
1326
+ }
1327
+ }
1328
+ if (errorExpr) {
1329
+ lines.push(`${nextIndent}_E: ${errorExpr},`);
1330
+ }
1331
+ if (notFoundExpr) {
1332
+ lines.push(`${nextIndent}_4: ${notFoundExpr},`);
1333
+ }
1334
+ if (menuExpr) {
1335
+ lines.push(`${nextIndent}_N: ${menuExpr},`);
1336
+ }
1337
+ const childAncestors = [
1338
+ ...ancestorLayouts,
1339
+ ...nodeLayouts
1340
+ ];
1341
+ const groupChildren = [];
1342
+ const regularChildren = [];
1343
+ for (const [key, child] of node.children) {
1344
+ if (isGroupKey(key)) {
1345
+ groupChildren.push([
1346
+ key,
1347
+ child
1348
+ ]);
1349
+ } else {
1350
+ regularChildren.push([
1351
+ key,
1352
+ child
1353
+ ]);
1354
+ }
1355
+ }
1356
+ if (groupChildren.length > 0) {
1357
+ groupChildren.sort((a, b) => a[0].localeCompare(b[0]));
1358
+ const groupStrs = [];
1359
+ for (const [_key, child] of groupChildren) {
1360
+ const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, errorFiles, notFoundFiles, childAncestors, isSSR, nextIndent);
1361
+ if (childStr !== "{}") {
1362
+ groupStrs.push(childStr);
1363
+ }
1364
+ }
1365
+ if (groupStrs.length > 0) {
1366
+ lines.push(`${nextIndent}_M: [${groupStrs.join(", ")}],`);
1367
+ }
1368
+ }
1369
+ for (const [key, child] of regularChildren) {
1370
+ const childStr = serializeBuildTrie(ctx, qwikPlugin, child, layoutIdMap, routeIdMap, menuIdMap, errorFiles, notFoundFiles, childAncestors, isSSR, nextIndent);
1371
+ if (childStr !== "{}") {
1372
+ const keyStr = JSON.stringify(key);
1373
+ lines.push(`${nextIndent}${keyStr}: ${childStr},`);
1374
+ }
1375
+ }
1376
+ if (lines.length === 0) {
1377
+ return "{}";
1378
+ }
1379
+ return `{
1380
+ ${lines.join("\n")}
1381
+ ${indent}}`;
1382
+ }
1383
+ function createRoutes(ctx, qwikPlugin, c, esmImports, isSSR) {
1384
+ const includeEndpoints = isSSR;
1385
+ const dynamicImports = ctx.dynamicImports;
1386
+ const layoutIdMap = /* @__PURE__ */ new Map();
1387
+ const routeIdMap = /* @__PURE__ */ new Map();
1388
+ const menuIdMap = /* @__PURE__ */ new Map();
1389
+ const errorFiles = /* @__PURE__ */ new Map();
1390
+ const notFoundFiles = /* @__PURE__ */ new Map();
1391
+ let layoutCount = 0;
1392
+ let routeCount = 0;
1393
+ let menuCount = 0;
1394
+ collectFiles(ctx.routeTrie, (file, _node) => {
1395
+ if (file.type === "layout") {
1396
+ const id = ctx.layouts.find((l) => l.filePath === file.filePath)?.id;
1397
+ if (id) {
1398
+ layoutIdMap.set(file.filePath, id);
1399
+ layoutCount++;
1400
+ }
1401
+ } else if (file.type === "route") {
1402
+ const route = ctx.routes.find((r) => r.filePath === file.filePath);
1403
+ if (route) {
1404
+ routeCount++;
1405
+ }
1406
+ } else if (file.type === "menu") {
1407
+ const id = createFileId(ctx.opts.routesDir, file.filePath);
1408
+ menuIdMap.set(file.filePath, id);
1409
+ menuCount++;
1410
+ }
1411
+ });
1412
+ if (layoutCount > 0) {
1413
+ c.push(`
1414
+ /** Qwik Router Layouts (${layoutCount}) */`);
1415
+ for (const [filePath, id] of layoutIdMap) {
1416
+ const importPath = JSON.stringify(getImportPath(filePath));
1417
+ if (dynamicImports) {
1418
+ c.push(`const ${id} = ()=>import(${importPath});`);
1419
+ } else {
1420
+ esmImports.push(`import * as ${id}_ from ${importPath};`);
1421
+ c.push(`const ${id} = ()=>${id}_;`);
1422
+ }
1423
+ }
1424
+ }
1425
+ if (menuCount > 0) {
1426
+ c.push(`
1427
+ /** Qwik Router Menus (${menuCount}) */`);
1428
+ for (const [filePath, id] of menuIdMap) {
1429
+ const importPath = JSON.stringify(getImportPath(filePath));
1430
+ if (dynamicImports) {
1431
+ c.push(`const ${id} = ()=>import(${importPath});`);
1432
+ } else {
1433
+ esmImports.push(`import * as ${id}_ from ${importPath};`);
1434
+ c.push(`const ${id} = ()=>${id}_;`);
1435
+ }
1436
+ }
1437
+ }
1438
+ c.push(`
1439
+ /** Qwik Router Routes (${routeCount}) */`);
1440
+ for (const route of ctx.routes) {
1441
+ if (isPageExt(route.ext)) {
1442
+ const importPath = getImportPath(route.filePath);
1443
+ let loaderExpr;
1444
+ if (dynamicImports) {
1445
+ loaderExpr = `()=>import(${JSON.stringify(importPath)})`;
1446
+ } else {
1447
+ esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
1448
+ loaderExpr = `()=>${route.id}`;
1449
+ }
1450
+ routeIdMap.set(route.filePath, loaderExpr);
1451
+ } else if (includeEndpoints && isModuleExt(route.ext)) {
1452
+ const importPath = getImportPath(route.filePath);
1453
+ esmImports.push(`import * as ${route.id} from ${JSON.stringify(importPath)};`);
1454
+ routeIdMap.set(route.filePath, `()=>${route.id}`);
1158
1455
  }
1159
- addRouteFile(r.filePath);
1160
1456
  }
1161
- return bundlesNames;
1457
+ const trieStr = serializeBuildTrie(ctx, qwikPlugin, ctx.routeTrie, layoutIdMap, routeIdMap, menuIdMap, errorFiles, notFoundFiles, [], isSSR, "");
1458
+ const baseSegments = ctx.opts.basePathname.split("/").filter((s) => s.length > 0);
1459
+ let routesExpr = trieStr;
1460
+ for (let j = baseSegments.length - 1; j >= 0; j--) {
1461
+ routesExpr = `{ ${JSON.stringify(baseSegments[j])}: ${routesExpr} }`;
1462
+ }
1463
+ c.push(`export const routes = ${routesExpr};`);
1162
1464
  }
1163
1465
 
1164
1466
  function createServerPlugins(ctx, _qwikPlugin, c, esmImports, isSSR) {
@@ -1186,17 +1488,17 @@ function generateQwikRouterConfig(ctx, qwikPlugin, isSSR) {
1186
1488
  import { isDev } from '@qwik.dev/core/build';`);
1187
1489
  createServerPlugins(ctx, qwikPlugin, c, esmImports, isSSR);
1188
1490
  createRoutes(ctx, qwikPlugin, c, esmImports, isSSR);
1189
- createMenus(ctx, c, esmImports, isSSR);
1190
1491
  createEntries(ctx, c);
1191
1492
  c.push(`export const trailingSlash = ${JSON.stringify(!globalThis.__NO_TRAILING_SLASH__)};`);
1192
1493
  c.push(`export const basePathname = ${JSON.stringify(ctx.opts.basePathname)};`);
1193
1494
  c.push(`export const cacheModules = !isDev;`);
1194
- c.push(
1195
- `export default { routes, serverPlugins, menus, trailingSlash, basePathname, cacheModules };`
1196
- );
1495
+ c.push(`export default { routes, serverPlugins, trailingSlash, basePathname, cacheModules };`);
1197
1496
  return esmImports.join("\n") + c.join("\n");
1198
1497
  }
1199
1498
 
1499
+ const SW_UNREGISTER = `
1500
+ "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)
1501
+ `;
1200
1502
  function generateServiceWorkerRegister(ctx, swRegister) {
1201
1503
  let swReg;
1202
1504
  let swUrl = "/service-worker.js";
@@ -1204,24 +1506,31 @@ function generateServiceWorkerRegister(ctx, swRegister) {
1204
1506
  swReg = SW_UNREGISTER;
1205
1507
  } else {
1206
1508
  swReg = swRegister;
1207
- const sw = ctx.serviceWorkers.sort(
1208
- (a, b) => a.chunkFileName.length < b.chunkFileName.length ? -1 : 1
1209
- )[0];
1509
+ const sw = ctx.serviceWorkers.sort((a, b) => a.chunkFileName.length < b.chunkFileName.length ? -1 : 1)[0];
1210
1510
  swUrl = ctx.opts.basePathname + sw.chunkFileName;
1211
1511
  }
1212
1512
  swReg = swReg.replace("__url", swUrl);
1213
1513
  return `export default ${JSON.stringify(swReg)};`;
1214
1514
  }
1215
- const SW_UNREGISTER = `
1216
- "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)
1217
- `;
1218
1515
 
1516
+ function isBundlePartOfRoute(bundle, routeAndLayoutPaths) {
1517
+ if (!bundle.origins) {
1518
+ return false;
1519
+ }
1520
+ for (const bundleOrigin of bundle.origins) {
1521
+ const originPath = removeExtension(bundleOrigin);
1522
+ return routeAndLayoutPaths.some((path) => path.endsWith(originPath));
1523
+ }
1524
+ }
1219
1525
  function getRouteImports(routes, manifest) {
1220
1526
  const result = {};
1221
1527
  routes.forEach((route) => {
1222
1528
  const routePath = removeExtension(route.filePath);
1223
1529
  const layoutPaths = route.layouts ? route.layouts.map((layout) => removeExtension(layout.filePath)) : [];
1224
- const routeAndLayoutPaths = [routePath, ...layoutPaths];
1530
+ const routeAndLayoutPaths = [
1531
+ routePath,
1532
+ ...layoutPaths
1533
+ ];
1225
1534
  const bundles = [];
1226
1535
  for (const [bundleName, bundle] of Object.entries(manifest.bundles)) {
1227
1536
  if (isBundlePartOfRoute(bundle, routeAndLayoutPaths)) {
@@ -1229,7 +1538,9 @@ function getRouteImports(routes, manifest) {
1229
1538
  }
1230
1539
  }
1231
1540
  if (bundles.length > 0) {
1232
- result[route.routeName] = { dynamicImports: bundles };
1541
+ result[route.routeName] = {
1542
+ dynamicImports: bundles
1543
+ };
1233
1544
  }
1234
1545
  });
1235
1546
  for (const bundleName of Object.keys(manifest.bundles)) {
@@ -1237,71 +1548,235 @@ function getRouteImports(routes, manifest) {
1237
1548
  if (bundle.origins?.some((s) => s.endsWith(QWIK_ROUTER_CONFIG_ID))) {
1238
1549
  result[bundleName] = {
1239
1550
  ...bundle,
1240
- dynamicImports: bundle.dynamicImports?.filter(
1241
- (d) => manifest.bundles[d].origins?.some((s) => s.endsWith("menu.md"))
1242
- )
1551
+ dynamicImports: bundle.dynamicImports?.filter((d) => manifest.bundles[d].origins?.some((s) => s.endsWith("menu.md")))
1243
1552
  };
1244
1553
  break;
1245
1554
  }
1246
1555
  }
1247
1556
  return result;
1248
1557
  }
1249
- function isBundlePartOfRoute(bundle, routeAndLayoutPaths) {
1250
- if (!bundle.origins) {
1251
- return false;
1558
+
1559
+ const safeParseInt = (nu) => {
1560
+ try {
1561
+ return parseInt(nu, 10);
1562
+ } catch {
1563
+ return void 0;
1252
1564
  }
1253
- for (const bundleOrigin of bundle.origins) {
1254
- const originPath = removeExtension(bundleOrigin);
1255
- return routeAndLayoutPaths.some((path) => path.endsWith(originPath));
1565
+ };
1566
+ const findLocation = (e) => {
1567
+ const stack = e.stack;
1568
+ if (typeof stack === "string") {
1569
+ const lines = stack.split("\n").filter((l) => !l.includes("/node_modules/") && !l.includes("(node:"));
1570
+ for (let i = 1; i < lines.length; i++) {
1571
+ const line = lines[i].replace("file:///", "/");
1572
+ if (/^\s+at/.test(line)) {
1573
+ const start = line.indexOf("/");
1574
+ const end = line.lastIndexOf(")", start);
1575
+ if (start > 0) {
1576
+ const path = line.slice(start, end);
1577
+ const parts = path.split(":");
1578
+ const nu0 = safeParseInt(parts[parts.length - 1]);
1579
+ const nu1 = safeParseInt(parts[parts.length - 2]);
1580
+ if (typeof nu0 === "number" && typeof nu1 === "number") {
1581
+ parts.length -= 2;
1582
+ return {
1583
+ file: parts.join(":"),
1584
+ line: nu1,
1585
+ column: nu0
1586
+ };
1587
+ } else if (typeof nu0 === "number") {
1588
+ parts.length -= 1;
1589
+ return {
1590
+ file: parts.join(":"),
1591
+ line: nu0,
1592
+ column: void 0
1593
+ };
1594
+ } else {
1595
+ return {
1596
+ file: parts.join(":"),
1597
+ line: void 0,
1598
+ column: void 0
1599
+ };
1600
+ }
1601
+ }
1602
+ }
1603
+ }
1604
+ }
1605
+ return void 0;
1606
+ };
1607
+ const splitRE = /\r?\n/;
1608
+ const range = 2;
1609
+ function posToNumber(source, pos) {
1610
+ if (typeof pos === "number") {
1611
+ return pos;
1612
+ }
1613
+ if (pos.lo != null) {
1614
+ return pos.lo;
1615
+ }
1616
+ const lines = source.split(splitRE);
1617
+ const { line, column } = pos;
1618
+ let start = 0;
1619
+ for (let i = 0; i < line - 1 && i < lines.length; i++) {
1620
+ start += lines[i].length + 1;
1621
+ }
1622
+ return start + column;
1623
+ }
1624
+ function generateCodeFrame(source, start = 0, end) {
1625
+ start = posToNumber(source, start);
1626
+ end = end || start;
1627
+ const lines = source.split(splitRE);
1628
+ let count = 0;
1629
+ const res = [];
1630
+ for (let i = 0; i < lines.length; i++) {
1631
+ count += lines[i].length + 1;
1632
+ if (count >= start) {
1633
+ for (let j = i - range; j <= i + range || end > count; j++) {
1634
+ if (j < 0 || j >= lines.length) {
1635
+ continue;
1636
+ }
1637
+ const line = j + 1;
1638
+ res.push(`${line}${" ".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`);
1639
+ const lineLength = lines[j].length;
1640
+ if (j === i) {
1641
+ const pad = Math.max(start - (count - lineLength) + 1, 0);
1642
+ const length = Math.max(1, end > count ? lineLength - pad : end - start);
1643
+ res.push(` | ` + " ".repeat(pad) + "^".repeat(length));
1644
+ } else if (j > i) {
1645
+ if (end > count) {
1646
+ const length = Math.max(Math.min(end - count, lineLength), 1);
1647
+ res.push(` | ` + "^".repeat(length));
1648
+ }
1649
+ count += lineLength + 1;
1650
+ }
1651
+ }
1652
+ break;
1653
+ }
1256
1654
  }
1655
+ return res.join("\n");
1656
+ }
1657
+ function parseId(originalId) {
1658
+ const [pathId, query] = originalId.split("?");
1659
+ const queryStr = query || "";
1660
+ return {
1661
+ originalId,
1662
+ pathId,
1663
+ query: queryStr ? `?${query}` : "",
1664
+ params: new URLSearchParams(queryStr)
1665
+ };
1257
1666
  }
1258
1667
 
1259
- function imagePlugin(userOpts) {
1260
- const supportedExtensions = [".jpg", ".jpeg", ".png", ".webp", ".gif", ".avif", ".tiff"];
1261
- return [
1262
- import('vite-imagetools').then(
1263
- ({ imagetools }) => imagetools({
1264
- exclude: [],
1265
- extendOutputFormats(builtins) {
1266
- const jsx = () => (metadatas) => {
1267
- const srcSet = metadatas.map((meta) => `${meta.src} ${meta.width}w`).join(", ");
1268
- let largestImage;
1269
- let largestImageSize = 0;
1270
- for (let i = 0; i < metadatas.length; i++) {
1271
- const m = metadatas[i];
1272
- if (m.width > largestImageSize) {
1273
- largestImage = m;
1274
- largestImageSize = m.width;
1668
+ function optimizeSvg({ code, path: path2 }, userOpts) {
1669
+ const svgAttributes = {};
1670
+ const prefixIdsConfiguration = userOpts?.imageOptimization?.svgo?.prefixIds;
1671
+ const maybePrefixIdsPlugin = prefixIdsConfiguration !== false ? [
1672
+ {
1673
+ name: "prefixIds",
1674
+ params: prefixIdsConfiguration
1675
+ }
1676
+ ] : [];
1677
+ const userPlugins = userOpts?.imageOptimization?.svgo?.plugins?.filter((plugin) => {
1678
+ if (plugin === "preset-default" || typeof plugin === "object" && plugin.name === "preset-default") {
1679
+ 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.`);
1680
+ return false;
1681
+ }
1682
+ if (plugin === "prefixIds" || typeof plugin === "object" && plugin.name === "prefixIds") {
1683
+ 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 prefixIds option.`);
1684
+ return false;
1685
+ }
1686
+ return true;
1687
+ }) || [];
1688
+ const data = optimize(code, {
1689
+ floatPrecision: userOpts?.imageOptimization?.svgo?.floatPrecision,
1690
+ multipass: userOpts?.imageOptimization?.svgo?.multipass,
1691
+ path: path2,
1692
+ plugins: [
1693
+ {
1694
+ name: "preset-default",
1695
+ params: {
1696
+ overrides: {
1697
+ removeViewBox: false,
1698
+ ...userOpts?.imageOptimization?.svgo?.defaultPresetOverrides
1699
+ }
1700
+ }
1701
+ },
1702
+ {
1703
+ name: "customPluginName",
1704
+ fn: () => {
1705
+ return {
1706
+ element: {
1707
+ exit: (node) => {
1708
+ if (node.name === "svg") {
1709
+ node.name = "g";
1710
+ Object.assign(svgAttributes, node.attributes);
1711
+ node.attributes = {};
1712
+ }
1275
1713
  }
1276
1714
  }
1277
- return {
1278
- srcSet,
1279
- width: largestImage === null || largestImage === void 0 ? void 0 : largestImage.width,
1280
- height: largestImage === null || largestImage === void 0 ? void 0 : largestImage.height
1281
- };
1282
1715
  };
1716
+ }
1717
+ },
1718
+ ...maybePrefixIdsPlugin,
1719
+ ...userPlugins
1720
+ ]
1721
+ }).data;
1722
+ svgAttributes.dangerouslySetInnerHTML = data.slice(3, -4);
1723
+ return {
1724
+ data,
1725
+ svgAttributes
1726
+ };
1727
+ }
1728
+ function imagePlugin(userOpts) {
1729
+ const supportedExtensions = [
1730
+ ".jpg",
1731
+ ".jpeg",
1732
+ ".png",
1733
+ ".webp",
1734
+ ".gif",
1735
+ ".avif",
1736
+ ".tiff"
1737
+ ];
1738
+ return [
1739
+ import('vite-imagetools').then(({ imagetools }) => imagetools({
1740
+ exclude: [],
1741
+ extendOutputFormats(builtins) {
1742
+ const jsx = () => (metadatas) => {
1743
+ const srcSet = metadatas.map((meta) => `${meta.src} ${meta.width}w`).join(", ");
1744
+ let largestImage;
1745
+ let largestImageSize = 0;
1746
+ for (let i = 0; i < metadatas.length; i++) {
1747
+ const m = metadatas[i];
1748
+ if (m.width > largestImageSize) {
1749
+ largestImage = m;
1750
+ largestImageSize = m.width;
1751
+ }
1752
+ }
1283
1753
  return {
1284
- ...builtins,
1285
- jsx
1754
+ srcSet,
1755
+ width: largestImage === null || largestImage === void 0 ? void 0 : largestImage.width,
1756
+ height: largestImage === null || largestImage === void 0 ? void 0 : largestImage.height
1286
1757
  };
1287
- },
1288
- defaultDirectives: (url) => {
1289
- if (url.searchParams.has("jsx")) {
1290
- const { jsx: _, ...params } = Object.fromEntries(url.searchParams.entries());
1291
- return new URLSearchParams({
1292
- format: "webp",
1293
- quality: "75",
1294
- w: "200;400;600;800;1200",
1295
- withoutEnlargement: "",
1296
- ...userOpts?.imageOptimization?.jsxDirectives,
1297
- ...params,
1298
- as: "jsx"
1299
- });
1300
- }
1301
- return new URLSearchParams();
1758
+ };
1759
+ return {
1760
+ ...builtins,
1761
+ jsx
1762
+ };
1763
+ },
1764
+ defaultDirectives: (url) => {
1765
+ if (url.searchParams.has("jsx")) {
1766
+ const { jsx: _, ...params } = Object.fromEntries(url.searchParams.entries());
1767
+ return new URLSearchParams({
1768
+ format: "webp",
1769
+ quality: "75",
1770
+ w: "200;400;600;800;1200",
1771
+ withoutEnlargement: "",
1772
+ ...userOpts?.imageOptimization?.jsxDirectives,
1773
+ ...params,
1774
+ as: "jsx"
1775
+ });
1302
1776
  }
1303
- })
1304
- ).catch((err) => {
1777
+ return new URLSearchParams();
1778
+ }
1779
+ })).catch((err) => {
1305
1780
  console.error("Error loading vite-imagetools, image imports are not available", err);
1306
1781
  return null;
1307
1782
  }),
@@ -1341,7 +1816,10 @@ function imagePlugin(userOpts) {
1341
1816
  map: null
1342
1817
  };
1343
1818
  } else if (extension === ".svg") {
1344
- const { svgAttributes } = optimizeSvg({ code, path: pathId }, userOpts);
1819
+ const { svgAttributes } = optimizeSvg({
1820
+ code,
1821
+ path: pathId
1822
+ }, userOpts);
1345
1823
  return {
1346
1824
  code: `
1347
1825
  import { _jsxSorted } from '@qwik.dev/core';
@@ -1358,89 +1836,50 @@ function imagePlugin(userOpts) {
1358
1836
  }
1359
1837
  ];
1360
1838
  }
1361
- function optimizeSvg({ code, path: path2 }, userOpts) {
1362
- const svgAttributes = {};
1363
- const prefixIdsConfiguration = userOpts?.imageOptimization?.svgo?.prefixIds;
1364
- const maybePrefixIdsPlugin = prefixIdsConfiguration !== false ? [{ name: "prefixIds", params: prefixIdsConfiguration }] : [];
1365
- const userPlugins = userOpts?.imageOptimization?.svgo?.plugins?.filter((plugin) => {
1366
- if (plugin === "preset-default" || typeof plugin === "object" && plugin.name === "preset-default") {
1367
- console.warn(
1368
- `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.`
1369
- );
1370
- return false;
1371
- }
1372
- if (plugin === "prefixIds" || typeof plugin === "object" && plugin.name === "prefixIds") {
1373
- console.warn(
1374
- `You are trying to use the preset-default SVGO plugin. This plugin is already included by default, you can customize it through the prefixIds option.`
1375
- );
1376
- return false;
1377
- }
1378
- return true;
1379
- }) || [];
1380
- const data = optimize(code, {
1381
- floatPrecision: userOpts?.imageOptimization?.svgo?.floatPrecision,
1382
- multipass: userOpts?.imageOptimization?.svgo?.multipass,
1383
- path: path2,
1384
- plugins: [
1385
- {
1386
- name: "preset-default",
1387
- params: {
1388
- overrides: {
1389
- removeViewBox: false,
1390
- ...userOpts?.imageOptimization?.svgo?.defaultPresetOverrides
1391
- }
1392
- }
1393
- },
1394
- {
1395
- name: "customPluginName",
1396
- fn: () => {
1397
- return {
1398
- element: {
1399
- exit: (node) => {
1400
- if (node.name === "svg") {
1401
- node.name = "g";
1402
- Object.assign(svgAttributes, node.attributes);
1403
- node.attributes = {};
1404
- }
1405
- }
1406
- }
1407
- };
1408
- }
1409
- },
1410
- ...maybePrefixIdsPlugin,
1411
- ...userPlugins
1412
- ]
1413
- }).data;
1414
- svgAttributes.dangerouslySetInnerHTML = data.slice(3, -4);
1415
- return {
1416
- data,
1417
- svgAttributes
1418
- };
1419
- }
1420
1839
 
1421
1840
  async function validatePlugin(opts) {
1422
1841
  if (typeof opts.routesDir !== "string") {
1423
1842
  throw new Error(`qwikRouter plugin "routesDir" option missing`);
1424
1843
  }
1425
1844
  if (!isAbsolute(opts.routesDir)) {
1426
- throw new Error(
1427
- `qwikRouter plugin "routesDir" option must be an absolute path: ${opts.routesDir}`
1428
- );
1845
+ throw new Error(`qwikRouter plugin "routesDir" option must be an absolute path: ${opts.routesDir}`);
1429
1846
  }
1430
1847
  try {
1431
1848
  const s = await fs.promises.stat(opts.routesDir);
1432
1849
  if (!s.isDirectory()) {
1433
- throw new Error(
1434
- `qwikRouter plugin "routesDir" option must be a directory: ${opts.routesDir}`
1435
- );
1850
+ throw new Error(`qwikRouter plugin "routesDir" option must be a directory: ${opts.routesDir}`);
1436
1851
  }
1437
1852
  } catch (e) {
1438
1853
  throw new Error(`qwikRouter plugin "routesDir" not found: ${e}`);
1439
1854
  }
1440
1855
  }
1441
1856
 
1857
+ function formatError(e) {
1858
+ if (e instanceof Error) {
1859
+ const err = e;
1860
+ let loc = err.loc;
1861
+ if (!err.frame && !err.plugin) {
1862
+ if (!loc) {
1863
+ loc = findLocation(err);
1864
+ }
1865
+ if (loc) {
1866
+ err.loc = loc;
1867
+ if (loc.file) {
1868
+ err.id = normalizePath(err.loc.file);
1869
+ try {
1870
+ const code = fs.readFileSync(err.loc.file, "utf-8");
1871
+ err.frame = generateCodeFrame(code, err.loc);
1872
+ } catch {
1873
+ }
1874
+ }
1875
+ }
1876
+ }
1877
+ }
1878
+ return e;
1879
+ }
1880
+
1442
1881
  class HtmlTransformPatcher {
1443
- state = 0 /* BUFFERING */;
1882
+ state = 0;
1444
1883
  buffer = "";
1445
1884
  headInnerIndex = -1;
1446
1885
  bodyInnerIndex = -1;
@@ -1495,7 +1934,7 @@ class HtmlTransformPatcher {
1495
1934
  };
1496
1935
  }
1497
1936
  handleWrite(chunk, encoding, callback) {
1498
- if (!this.isHtmlResponse || this.state === 3 /* PASSTHROUGH */) {
1937
+ if (!this.isHtmlResponse || this.state === 3) {
1499
1938
  return this.origWrite(chunk, encoding, callback);
1500
1939
  }
1501
1940
  if (typeof encoding === "function") {
@@ -1514,7 +1953,7 @@ class HtmlTransformPatcher {
1514
1953
  }
1515
1954
  this.buffer += data;
1516
1955
  switch (this.state) {
1517
- case 0 /* BUFFERING */:
1956
+ case 0:
1518
1957
  if (this.headInnerIndex === -1) {
1519
1958
  const headMatch = this.buffer.match(/<head[^>]*>/i);
1520
1959
  if (headMatch) {
@@ -1525,16 +1964,16 @@ class HtmlTransformPatcher {
1525
1964
  if (this.headInnerIndex !== -1) {
1526
1965
  const bodyMatch = this.buffer.slice(this.headInnerIndex).match(/<body[^>]*>/i);
1527
1966
  if (bodyMatch) {
1528
- this.state = 1 /* PROCESSING_HEAD */;
1967
+ this.state = 1;
1529
1968
  const bodyOuterIndex = this.buffer.indexOf(bodyMatch[0]);
1530
1969
  this.bodyInnerIndex = bodyOuterIndex + bodyMatch[0].length;
1531
1970
  this.processingPromise = this.processHead();
1532
1971
  }
1533
1972
  }
1534
1973
  break;
1535
- case 1 /* PROCESSING_HEAD */:
1974
+ case 1:
1536
1975
  break;
1537
- case 2 /* STREAMING_BODY */:
1976
+ case 2:
1538
1977
  this.handleStreamingBodyState();
1539
1978
  break;
1540
1979
  default:
@@ -1546,10 +1985,7 @@ class HtmlTransformPatcher {
1546
1985
  async processHead() {
1547
1986
  try {
1548
1987
  const fakeHtml = `<html><head>[FAKE_HEAD]</head><body>[FAKE_BODY]</body></html>`;
1549
- const transformedHtml = await this.server.transformIndexHtml(
1550
- this.request.url || "/",
1551
- fakeHtml
1552
- );
1988
+ const transformedHtml = await this.server.transformIndexHtml(this.request.url || "/", fakeHtml);
1553
1989
  const hmrBridge = this.server.hot ? `<script type="module" src="/@id/@qwik-hmr-bridge"><\/script>` : "";
1554
1990
  const fakeHeadIndex = transformedHtml.indexOf("[FAKE_HEAD]");
1555
1991
  const fakeHeadCloseIndex = transformedHtml.indexOf("</head>", fakeHeadIndex);
@@ -1564,21 +2000,15 @@ class HtmlTransformPatcher {
1564
2000
  if (fakeBodyIndex === -1 || fakeBodyEndIndex === -1) {
1565
2001
  throw new Error("Transformed HTML does not contain [FAKE_BODY]...</body>");
1566
2002
  }
1567
- const bodyPreContent = transformedHtml.slice(
1568
- fakeBodyStartIndex + "<body>".length,
1569
- fakeBodyIndex
1570
- );
1571
- this.bodyPostContent = transformedHtml.slice(
1572
- fakeBodyIndex + "[FAKE_BODY]".length,
1573
- fakeBodyEndIndex
1574
- );
2003
+ const bodyPreContent = transformedHtml.slice(fakeBodyStartIndex + "<body>".length, fakeBodyIndex);
2004
+ this.bodyPostContent = transformedHtml.slice(fakeBodyIndex + "[FAKE_BODY]".length, fakeBodyEndIndex);
1575
2005
  const headCloseIndex = this.buffer.indexOf("</head>", this.headInnerIndex);
1576
2006
  if (headCloseIndex === -1) {
1577
2007
  throw new Error("Buffered HTML does not contain </head>");
1578
2008
  }
1579
2009
  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);
1580
2010
  if (this.bodyPostContent.length > 0) {
1581
- this.state = 2 /* STREAMING_BODY */;
2011
+ this.state = 2;
1582
2012
  this.handleStreamingBodyState();
1583
2013
  return;
1584
2014
  }
@@ -1601,7 +2031,7 @@ class HtmlTransformPatcher {
1601
2031
  this.flushBuffer(6);
1602
2032
  }
1603
2033
  transitionToPassthrough() {
1604
- this.state = 3 /* PASSTHROUGH */;
2034
+ this.state = 3;
1605
2035
  this.flushBuffer();
1606
2036
  }
1607
2037
  flushBuffer(keep = 0) {
@@ -1646,9 +2076,7 @@ const makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
1646
2076
  }
1647
2077
  const entry = ctx.entries.find((e) => req.url === `${server.config.base}${e.chunkFileName}`);
1648
2078
  if (entry) {
1649
- const entryContents = await server.transformRequest(
1650
- `/@fs${entry.filePath.startsWith("/") ? "" : "/"}${entry.filePath}`
1651
- );
2079
+ const entryContents = await server.transformRequest(`/@fs${entry.filePath.startsWith("/") ? "" : "/"}${entry.filePath}`);
1652
2080
  if (entryContents) {
1653
2081
  res.setHeader("Content-Type", "text/javascript");
1654
2082
  res.end(entryContents.code);
@@ -1659,19 +2087,15 @@ const makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
1659
2087
  }
1660
2088
  if (req.url === `${server.config.base}service-worker.js`) {
1661
2089
  res.setHeader("Content-Type", "text/javascript");
1662
- res.end(
1663
- `/* Qwik Router Dev Service Worker */self.addEventListener('install', () => self.skipWaiting());self.addEventListener('activate', (ev) => ev.waitUntil(self.clients.claim()));`
1664
- );
2090
+ res.end(`/* Qwik Router Dev Service Worker */self.addEventListener('install', () => self.skipWaiting());self.addEventListener('activate', (ev) => ev.waitUntil(self.clients.claim()));`);
1665
2091
  return;
1666
2092
  }
1667
2093
  globalThis.__qwik = void 0;
1668
- const { createQwikRouter } = await server.ssrLoadModule(
1669
- "@qwik.dev/router/middleware/node"
1670
- );
2094
+ const { createQwikRouter } = await server.ssrLoadModule("@qwik.dev/router/middleware/node");
1671
2095
  try {
1672
- const render = (async (opts) => {
2096
+ const render = async (opts) => {
1673
2097
  return await renderer(opts);
1674
- });
2098
+ };
1675
2099
  const { router, staticFile, notFound } = createQwikRouter({
1676
2100
  render,
1677
2101
  // inject the platform from dev middleware options
@@ -1692,43 +2116,59 @@ const makeRouterDevMiddleware = (server, ctx) => async (req, res, next) => {
1692
2116
  return;
1693
2117
  }
1694
2118
  };
1695
- const CSS_EXTENSIONS = [".css", ".scss", ".sass", ".less", ".styl", ".stylus"];
2119
+ const CSS_EXTENSIONS = [
2120
+ ".css",
2121
+ ".scss",
2122
+ ".sass",
2123
+ ".less",
2124
+ ".styl",
2125
+ ".stylus"
2126
+ ];
1696
2127
  const JS_EXTENSIONS = /\.[mc]?[tj]sx?$/;
1697
2128
  const isCssPath = (url) => CSS_EXTENSIONS.some((ext) => url.endsWith(ext));
1698
2129
  const getCssUrls = (server) => {
1699
- const graph = server.environments.client.moduleGraph;
2130
+ const clientGraph = server.environments.client.moduleGraph;
2131
+ const ssrGraph = server.environments.ssr.moduleGraph;
1700
2132
  const cssModules = /* @__PURE__ */ new Set();
1701
2133
  const cssImportedByCSS = /* @__PURE__ */ new Set();
1702
- for (const mod of graph.idToModuleMap.values()) {
1703
- const [pathId, query] = mod.url.split("?");
1704
- if (!query && isCssPath(pathId)) {
1705
- const isEntryCSS = mod.importers.size === 0;
1706
- const hasCSSImporter = Array.from(mod.importers).some((importer) => {
1707
- const importerPath = importer.url || importer.file;
1708
- const isCSS = importerPath && isCssPath(importerPath);
1709
- if (isCSS && mod.url) {
1710
- cssImportedByCSS.add(mod.url);
2134
+ for (const graph of [
2135
+ clientGraph,
2136
+ ssrGraph
2137
+ ]) {
2138
+ for (const mod of graph.idToModuleMap.values()) {
2139
+ const [pathId, query] = mod.url.split("?");
2140
+ if (!query && isCssPath(pathId)) {
2141
+ const isEntryCSS = mod.importers.size === 0;
2142
+ const hasCSSImporter = Array.from(mod.importers).some((importer) => {
2143
+ const importerPath = importer.url || importer.file;
2144
+ const isCSS = importerPath && isCssPath(importerPath);
2145
+ if (isCSS && mod.url) {
2146
+ cssImportedByCSS.add(mod.url);
2147
+ }
2148
+ return isCSS;
2149
+ });
2150
+ const hasJSImporter = Array.from(mod.importers).some((importer) => {
2151
+ const importerPath = importer.url || importer.file;
2152
+ return importerPath && JS_EXTENSIONS.test(importerPath);
2153
+ });
2154
+ if ((isEntryCSS || hasJSImporter) && !hasCSSImporter && !cssImportedByCSS.has(mod.url)) {
2155
+ cssModules.add(`${mod.url}${mod.lastHMRTimestamp ? `?t=${mod.lastHMRTimestamp}` : ""}`);
1711
2156
  }
1712
- return isCSS;
1713
- });
1714
- const hasJSImporter = Array.from(mod.importers).some((importer) => {
1715
- const importerPath = importer.url || importer.file;
1716
- return importerPath && JS_EXTENSIONS.test(importerPath);
1717
- });
1718
- if ((isEntryCSS || hasJSImporter) && !hasCSSImporter && !cssImportedByCSS.has(mod.url)) {
1719
- cssModules.add(mod);
1720
2157
  }
1721
2158
  }
1722
2159
  }
1723
- return [...cssModules].map(
1724
- ({ url, lastHMRTimestamp }) => `${url}${lastHMRTimestamp ? `?t=${lastHMRTimestamp}` : ""}`
1725
- );
2160
+ return [
2161
+ ...cssModules
2162
+ ];
1726
2163
  };
1727
2164
  const getRouterIndexTags = (server) => {
1728
2165
  const cssUrls = getCssUrls(server);
1729
2166
  return cssUrls.map((url) => ({
1730
2167
  tag: "link",
1731
- attrs: { rel: "stylesheet", href: url }
2168
+ attrs: {
2169
+ rel: "stylesheet",
2170
+ href: url
2171
+ }
1732
2172
  }));
1733
2173
  };
1734
2174
 
@@ -1736,11 +2176,25 @@ const QWIK_ROUTER_CONFIG_ID = "@qwik-router-config";
1736
2176
  const QWIK_ROUTER_ENTRIES_ID = "@qwik-router-entries";
1737
2177
  const QWIK_ROUTER = "@qwik.dev/router";
1738
2178
  const QWIK_ROUTER_SW_REGISTER = "@qwik-router-sw-register";
1739
- function qwikCity(userOpts) {
1740
- return qwikRouter(userOpts);
1741
- }
1742
- function qwikRouter(userOpts) {
1743
- return [qwikRouterPlugin(userOpts), ...imagePlugin(userOpts)];
2179
+ async function generateServerPackageJson(outDir) {
2180
+ await fs.promises.mkdir(outDir, {
2181
+ recursive: true
2182
+ });
2183
+ const serverPackageJsonPath = join(outDir, "package.json");
2184
+ let packageJson = {};
2185
+ if (fs.existsSync(serverPackageJsonPath)) {
2186
+ const content = await fs.promises.readFile(serverPackageJsonPath, "utf-8");
2187
+ const contentAsJson = JSON.parse(content);
2188
+ packageJson = {
2189
+ ...contentAsJson
2190
+ };
2191
+ }
2192
+ packageJson = {
2193
+ ...packageJson,
2194
+ type: "module"
2195
+ };
2196
+ const serverPackageJsonCode = JSON.stringify(packageJson, null, 2);
2197
+ await fs.promises.writeFile(serverPackageJsonPath, serverPackageJsonCode);
1744
2198
  }
1745
2199
  function qwikRouterPlugin(userOpts) {
1746
2200
  let ctx = null;
@@ -1770,20 +2224,37 @@ function qwikRouterPlugin(userOpts) {
1770
2224
  viteCommand = viteEnv.command;
1771
2225
  const updatedViteConfig = {
1772
2226
  define: {
1773
- "globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__": JSON.stringify(
1774
- userOpts?.defaultLoadersSerializationStrategy || "never"
1775
- ),
1776
- "globalThis.__NO_TRAILING_SLASH__": JSON.stringify(userOpts?.trailingSlash === false)
2227
+ "globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__": JSON.stringify(userOpts?.defaultLoadersSerializationStrategy || "never"),
2228
+ "globalThis.__NO_TRAILING_SLASH__": JSON.stringify(userOpts?.trailingSlash === false),
2229
+ "globalThis.__SSR_CACHE_SIZE__": JSON.stringify(viteEnv.command === "serve" ? 0 : userOpts?.ssrCacheSize ?? 50)
1777
2230
  },
1778
2231
  appType: "custom",
1779
2232
  resolve: {
1780
- dedupe: [QWIK_ROUTER, "@builder.io/qwik-city"],
2233
+ dedupe: [
2234
+ QWIK_ROUTER,
2235
+ "@builder.io/qwik-city"
2236
+ ],
1781
2237
  alias: [
1782
- { find: "@builder.io/qwik-city", replacement: "@qwik.dev/router" },
1783
- { find: /^@builder\.io\/qwik-city\/(.*)/, replacement: "@qwik.dev/router/$1" },
1784
- { find: "@qwik-city-plan", replacement: QWIK_ROUTER_CONFIG_ID },
1785
- { find: "@qwik-city-entries", replacement: QWIK_ROUTER_ENTRIES_ID },
1786
- { find: "@qwik-city-sw-register", replacement: QWIK_ROUTER_SW_REGISTER }
2238
+ {
2239
+ find: "@builder.io/qwik-city",
2240
+ replacement: "@qwik.dev/router"
2241
+ },
2242
+ {
2243
+ find: /^@builder\.io\/qwik-city\/(.*)/,
2244
+ replacement: "@qwik.dev/router/$1"
2245
+ },
2246
+ {
2247
+ find: "@qwik-city-plan",
2248
+ replacement: QWIK_ROUTER_CONFIG_ID
2249
+ },
2250
+ {
2251
+ find: "@qwik-city-entries",
2252
+ replacement: QWIK_ROUTER_ENTRIES_ID
2253
+ },
2254
+ {
2255
+ find: "@qwik-city-sw-register",
2256
+ replacement: QWIK_ROUTER_SW_REGISTER
2257
+ }
1787
2258
  ]
1788
2259
  },
1789
2260
  optimizeDeps: {
@@ -1803,7 +2274,9 @@ function qwikRouterPlugin(userOpts) {
1803
2274
  },
1804
2275
  // Duplicated from configEnvironment to support legacy vite build --ssr compatibility
1805
2276
  ssr: {
1806
- external: ["node:async_hooks"],
2277
+ external: [
2278
+ "node:async_hooks"
2279
+ ],
1807
2280
  noExternal: [
1808
2281
  QWIK_ROUTER,
1809
2282
  QWIK_ROUTER_CONFIG_ID,
@@ -1826,7 +2299,9 @@ function qwikRouterPlugin(userOpts) {
1826
2299
  if (name === "ssr") {
1827
2300
  return {
1828
2301
  resolve: {
1829
- external: ["node:async_hooks"],
2302
+ external: [
2303
+ "node:async_hooks"
2304
+ ],
1830
2305
  noExternal: [
1831
2306
  QWIK_ROUTER,
1832
2307
  QWIK_ROUTER_CONFIG_ID,
@@ -1843,18 +2318,10 @@ function qwikRouterPlugin(userOpts) {
1843
2318
  Object.assign(process.env, loadEnv(config.mode, process.cwd(), ""));
1844
2319
  rootDir = resolve(config.root);
1845
2320
  const target = config.build?.ssr || config.mode === "ssr" ? "ssr" : "client";
1846
- ctx = createBuildContext(
1847
- rootDir,
1848
- config.base,
1849
- userOpts,
1850
- target,
1851
- !userOpts?.staticImportRoutes
1852
- );
2321
+ ctx = createBuildContext(rootDir, config.base, userOpts, target, !userOpts?.staticImportRoutes);
1853
2322
  await validatePlugin(ctx.opts);
1854
2323
  mdxTransform = await createMdxTransformer(ctx);
1855
- qwikPlugin = config.plugins.find(
1856
- (p) => p.name === "vite-plugin-qwik"
1857
- );
2324
+ qwikPlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik");
1858
2325
  if (!qwikPlugin) {
1859
2326
  throw new Error("Missing vite-plugin-qwik");
1860
2327
  }
@@ -1868,10 +2335,7 @@ function qwikRouterPlugin(userOpts) {
1868
2335
  },
1869
2336
  async configureServer(server) {
1870
2337
  devServer = server;
1871
- const toWatch = resolve(
1872
- rootDir,
1873
- "src/routes/**/{index,layout,entry,service-worker}{.,@,-}*"
1874
- );
2338
+ const toWatch = resolve(rootDir, "src/routes/**/{index,layout,entry,service-worker}{.,@,-}*");
1875
2339
  server.watcher.add(toWatch);
1876
2340
  await new Promise((resolve2) => setTimeout(resolve2, 1e3));
1877
2341
  server.watcher.on("change", (path) => {
@@ -1933,11 +2397,7 @@ function qwikRouterPlugin(userOpts) {
1933
2397
  });
1934
2398
  }
1935
2399
  if (isRouterConfig) {
1936
- return generateQwikRouterConfig(
1937
- ctx,
1938
- qwikPlugin,
1939
- this.environment.config.consumer === "server"
1940
- );
2400
+ return generateQwikRouterConfig(ctx, qwikPlugin, this.environment.config.consumer === "server");
1941
2401
  }
1942
2402
  if (isSwRegister) {
1943
2403
  return generateServiceWorkerRegister(ctx, swRegister);
@@ -1957,7 +2417,10 @@ function qwikRouterPlugin(userOpts) {
1957
2417
  const fileName = basename(id);
1958
2418
  if (isMenuFileName(fileName)) {
1959
2419
  const menuCode = await transformMenu(ctx.opts, id, code);
1960
- return { code: menuCode, map: null };
2420
+ return {
2421
+ code: menuCode,
2422
+ map: null
2423
+ };
1961
2424
  }
1962
2425
  if (mdxTransform) {
1963
2426
  try {
@@ -1989,7 +2452,10 @@ function qwikRouterPlugin(userOpts) {
1989
2452
  },
1990
2453
  generateBundle(_, bundles) {
1991
2454
  if (this.environment.config.consumer === "client") {
1992
- const entries = [...ctx.entries, ...ctx.serviceWorkers].map((entry) => {
2455
+ const entries = [
2456
+ ...ctx.entries,
2457
+ ...ctx.serviceWorkers
2458
+ ].map((entry) => {
1993
2459
  return {
1994
2460
  chunkFileName: entry.chunkFileName,
1995
2461
  extensionlessFilePath: removeExtension(entry.filePath)
@@ -2020,23 +2486,14 @@ function qwikRouterPlugin(userOpts) {
2020
2486
  };
2021
2487
  return plugin;
2022
2488
  }
2023
- async function generateServerPackageJson(outDir) {
2024
- await fs.promises.mkdir(outDir, { recursive: true });
2025
- const serverPackageJsonPath = join(outDir, "package.json");
2026
- let packageJson = {};
2027
- if (fs.existsSync(serverPackageJsonPath)) {
2028
- const content = await fs.promises.readFile(serverPackageJsonPath, "utf-8");
2029
- const contentAsJson = JSON.parse(content);
2030
- packageJson = {
2031
- ...contentAsJson
2032
- };
2033
- }
2034
- packageJson = {
2035
- ...packageJson,
2036
- type: "module"
2037
- };
2038
- const serverPackageJsonCode = JSON.stringify(packageJson, null, 2);
2039
- await fs.promises.writeFile(serverPackageJsonPath, serverPackageJsonCode);
2489
+ function qwikRouter(userOpts) {
2490
+ return [
2491
+ qwikRouterPlugin(userOpts),
2492
+ ...imagePlugin(userOpts)
2493
+ ];
2494
+ }
2495
+ function qwikCity(userOpts) {
2496
+ return qwikRouter(userOpts);
2040
2497
  }
2041
2498
 
2042
2499
  export { extendConfig, qwikCity, qwikRouter };