@qwik.dev/router 2.0.0-beta.36 → 2.0.0-beta.38

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 (41) hide show
  1. package/lib/adapters/cloudflare-pages/vite/index.mjs +3 -5
  2. package/lib/adapters/shared/vite/index.d.ts +3 -4
  3. package/lib/adapters/shared/vite/index.mjs +167 -155
  4. package/lib/chunks/dev-preloaded-route-loader.mjs +3 -0
  5. package/lib/chunks/format.mjs +31 -0
  6. package/lib/chunks/fs.mjs +10 -8
  7. package/lib/chunks/head.qwik.mjs +1425 -0
  8. package/lib/chunks/http-error.qwik.mjs +2 -2
  9. package/lib/chunks/pathname.mjs +3 -32
  10. package/lib/chunks/request-body-limit.mjs +37 -0
  11. package/lib/chunks/request-path.mjs +60 -0
  12. package/lib/chunks/routes.mjs +47 -0
  13. package/lib/chunks/server-error.mjs +19 -0
  14. package/lib/chunks/system.mjs +8 -8
  15. package/lib/chunks/use-functions.qwik.mjs +3 -12
  16. package/lib/chunks/user-response.mjs +1875 -0
  17. package/lib/chunks/worker-thread.mjs +317 -0
  18. package/lib/index.d.ts +251 -44
  19. package/lib/index.qwik.mjs +734 -485
  20. package/lib/middleware/aws-lambda/index.mjs +2 -1
  21. package/lib/middleware/azure-swa/index.mjs +13 -9
  22. package/lib/middleware/cloudflare-pages/index.mjs +2 -2
  23. package/lib/middleware/deno/index.d.ts +2 -0
  24. package/lib/middleware/deno/index.mjs +2 -1
  25. package/lib/middleware/netlify-edge/index.mjs +2 -2
  26. package/lib/middleware/node/index.d.ts +9 -1
  27. package/lib/middleware/node/index.mjs +28 -3
  28. package/lib/middleware/request-handler/index.d.ts +65 -26
  29. package/lib/middleware/request-handler/index.mjs +38 -1679
  30. package/lib/middleware/vercel-edge/index.mjs +2 -2
  31. package/lib/ssg/index.d.ts +5 -13
  32. package/lib/ssg/index.mjs +14 -53
  33. package/lib/vite/index.d.ts +23 -0
  34. package/lib/vite/index.mjs +533 -122
  35. package/package.json +4 -3
  36. package/lib/chunks/deepFreeze.qwik.mjs +0 -18
  37. package/lib/chunks/error-handler.mjs +0 -57
  38. package/lib/chunks/not-found-wrapper.qwik.mjs +0 -25
  39. package/lib/chunks/redirect-handler.mjs +0 -6
  40. package/lib/chunks/routing.qwik.mjs +0 -821
  41. package/lib/chunks/worker-thread.qwik.mjs +0 -2585
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import { join, relative } from 'node:path';
3
3
  import { n as normalizePathSlash } from '../../../chunks/fs.mjs';
4
+ import { e as ensureSlash } from '../../../chunks/pathname.mjs';
4
5
  import { viteAdapter } from '../../shared/vite/index.mjs';
5
6
 
6
7
  function cloudflarePagesAdapter(opts = {}) {
@@ -38,14 +39,11 @@ function cloudflarePagesAdapter(opts = {}) {
38
39
  publicDir: false
39
40
  };
40
41
  },
41
- async generate({ clientOutDir, serverOutDir, basePathname, assetsDir }) {
42
+ async generate({ clientOutDir, serverOutDir, basePathname }) {
42
43
  const routesJsonPath = join(clientOutDir, "_routes.json");
43
44
  const hasRoutesJson = fs.existsSync(routesJsonPath);
44
45
  if (!hasRoutesJson && opts.functionRoutes !== false) {
45
- let pathName = assetsDir ? join(basePathname, assetsDir) : basePathname;
46
- if (!pathName.endsWith("/")) {
47
- pathName += "/";
48
- }
46
+ const pathName = ensureSlash(basePathname);
49
47
  const routesJson = {
50
48
  version: 1,
51
49
  include: [
@@ -1,6 +1,6 @@
1
- import type { Plugin as Plugin_2 } from 'vite';
1
+ import { Plugin as Plugin_2 } from 'vite';
2
2
  import type { SsgRenderOptions } from 'packages/qwik-router/src/ssg';
3
- import type { UserConfig } from 'vite';
3
+ import { UserConfig } from 'vite';
4
4
 
5
5
  /** @public */
6
6
  export declare interface AdapterSSGOptions extends Omit<SsgRenderOptions, 'outDir' | 'origin'> {
@@ -75,7 +75,7 @@ export declare interface ServerAdapterOptions {
75
75
  }
76
76
 
77
77
  /** @public */
78
- export declare function viteAdapter(opts: ViteAdapterPluginOptions): Plugin_2<any>[];
78
+ export declare function viteAdapter(opts: ViteAdapterPluginOptions): Plugin_2<never>[];
79
79
 
80
80
  /** @public */
81
81
  declare interface ViteAdapterPluginOptions {
@@ -93,7 +93,6 @@ declare interface ViteAdapterPluginOptions {
93
93
  serverOutDir: string;
94
94
  basePathname: string;
95
95
  routes: BuiltRoute[];
96
- assetsDir?: string;
97
96
  warn: (message: string) => void;
98
97
  error: (message: string) => void;
99
98
  }) => Promise<void>;
@@ -1,71 +1,21 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readFile, unlink, rm } from 'node:fs/promises';
1
3
  import { join, resolve, dirname, basename } from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
4
  import fs from 'node:fs';
4
- import { g as getErrorHtml } from '../../../chunks/error-handler.mjs';
5
+ import { L as LOADER_REGEX } from '../../../chunks/request-path.mjs';
6
+ import { e as ensureSlash } from '../../../chunks/pathname.mjs';
5
7
 
6
- const SSG_WORKER_IMPORT_PREFIX = "@qwik-router-ssg-worker/";
7
- function ssgWorkerImportPlugin() {
8
- return {
9
- name: "qwik-router-ssg-worker-imports",
10
- enforce: "pre",
11
- async resolveId(id, importer) {
12
- if (!id.startsWith(SSG_WORKER_IMPORT_PREFIX)) {
13
- return null;
14
- }
15
- const subpath = id.slice(SSG_WORKER_IMPORT_PREFIX.length);
16
- const sourceId = fileURLToPath(new URL(`../../${subpath}`, import.meta.url));
17
- const resolved = await this.resolve(sourceId, importer, {
18
- skipSelf: true
19
- });
20
- return `${(resolved ?? {
21
- id: sourceId
22
- }).id}?ssg-worker`;
23
- }
24
- };
25
- }
26
-
27
- function normalizeTrailingSlash(pathname) {
28
- if (!pathname.endsWith("/")) {
29
- return pathname + "/";
30
- }
31
- return pathname;
32
- }
33
- function createNotFoundPathsCode(basePathname, notFounds) {
34
- notFounds.sort((a, b) => {
35
- if (a[0].length > b[0].length) {
36
- return -1;
37
- }
38
- if (a[0].length < b[0].length) {
39
- return 1;
40
- }
41
- if (a[0] < b[0]) {
42
- return -1;
43
- }
44
- if (a[0] > b[0]) {
45
- return 1;
46
- }
47
- return 0;
48
- });
49
- if (!notFounds.some((r) => r[0] === basePathname)) {
50
- const html = getErrorHtml(404, "Resource Not Found");
51
- notFounds.push([
52
- basePathname,
53
- html
54
- ]);
55
- }
56
- return JSON.stringify(notFounds, null, 2).slice(1, -1);
57
- }
58
8
  function createStaticPathsCode(staticPaths) {
59
9
  return JSON.stringify(Array.from(new Set(staticPaths)).sort()).slice(1, -1);
60
10
  }
61
- const injectStatics = async (staticPathsCode, notFoundPathsCode, outDir) => {
11
+ const injectStatics = async (staticPathsCode, outDir) => {
62
12
  const promises = /* @__PURE__ */ new Set();
63
13
  const doReplace = async (path) => {
64
14
  const code = await fs.promises.readFile(path, "utf-8");
65
15
  let replaced = false;
66
- const newCode = code.replace(/(['"])__QWIK_ROUTER_(STATIC_PATHS|NOT_FOUND)_ARRAY__\1/g, (_, _quote, type) => {
16
+ const newCode = code.replace(/(['"])__QWIK_ROUTER_STATIC_PATHS_ARRAY__\1/g, () => {
67
17
  replaced = true;
68
- return type === "STATIC_PATHS" ? staticPathsCode : notFoundPathsCode;
18
+ return staticPathsCode;
69
19
  });
70
20
  if (replaced) {
71
21
  await fs.promises.writeFile(path, newCode);
@@ -91,37 +41,37 @@ const injectStatics = async (staticPathsCode, notFoundPathsCode, outDir) => {
91
41
  };
92
42
  async function postBuild(clientOutDir, serverOutDir, pathName, userStaticPaths, cleanStatic) {
93
43
  if (pathName && !pathName.endsWith("/")) {
94
- pathName += "/";
44
+ pathName = ensureSlash(pathName);
95
45
  }
46
+ const pathNameBase = pathName || "/";
96
47
  const ignorePathnames = /* @__PURE__ */ new Set([
97
- pathName + "/" + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/",
98
- pathName + "/" + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/"
48
+ pathNameBase + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/",
49
+ pathNameBase + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/"
99
50
  ]);
100
- const staticPaths = new Set(userStaticPaths.map(normalizeTrailingSlash));
101
- const notFounds = [];
51
+ const staticPaths = new Set(userStaticPaths.map(ensureSlash));
102
52
  const loadItem = async (fsDir, fsName, pathname) => {
103
- pathname = normalizeTrailingSlash(pathname);
53
+ pathname = ensureSlash(pathname);
104
54
  if (ignorePathnames.has(pathname)) {
105
55
  return;
106
56
  }
107
57
  const fsPath = join(fsDir, fsName);
108
- if (fsName === "index.html" || fsName === "q-data.json") {
58
+ if (fsName === "index.html") {
109
59
  if (!staticPaths.has(pathname) && cleanStatic) {
110
60
  await fs.promises.unlink(fsPath);
111
61
  }
112
62
  return;
113
63
  }
114
- if (fsName === "404.html") {
115
- const notFoundHtml = await fs.promises.readFile(fsPath, "utf-8");
116
- notFounds.push([
117
- pathname,
118
- notFoundHtml
119
- ]);
64
+ if (LOADER_REGEX.test("/" + fsName)) {
65
+ if (staticPaths.has(pathname)) {
66
+ staticPaths.add(pathname + fsName);
67
+ } else if (cleanStatic) {
68
+ await fs.promises.unlink(fsPath);
69
+ }
120
70
  return;
121
71
  }
122
72
  const stat = await fs.promises.stat(fsPath);
123
73
  if (stat.isDirectory()) {
124
- await loadDir(fsPath, pathname + fsName + "/");
74
+ await loadDir(fsPath, ensureSlash(pathname + fsName));
125
75
  } else if (stat.isFile()) {
126
76
  staticPaths.add(pathname + fsName);
127
77
  }
@@ -133,19 +83,21 @@ async function postBuild(clientOutDir, serverOutDir, pathName, userStaticPaths,
133
83
  if (fs.existsSync(clientOutDir)) {
134
84
  await loadDir(clientOutDir, pathName);
135
85
  }
136
- const notFoundPathsCode = createNotFoundPathsCode(pathName, notFounds);
137
86
  const staticPathsCode = createStaticPathsCode(staticPaths);
138
- await injectStatics(staticPathsCode, notFoundPathsCode, serverOutDir);
87
+ await injectStatics(staticPathsCode, serverOutDir);
139
88
  }
140
89
 
141
90
  const QWIK_SSG_ENTRY_ID = "@qwik-ssg-entry";
142
91
  const QWIK_SSG_ENTRY_RESOLVED = "\0@qwik-ssg-entry";
92
+ const QWIK_SSG_WORKER_ENTRY_ID = "@qwik-ssg-worker-entry";
93
+ const QWIK_SSG_WORKER_ENTRY_RESOLVED = "\0@qwik-ssg-worker-entry";
143
94
  function viteAdapter(opts) {
144
95
  let qwikRouterPlugin = null;
145
96
  let qwikVitePlugin = null;
146
- let serverOutDir = null;
147
97
  let viteCommand;
98
+ let buildAppRan = false;
148
99
  const outputEntries = [];
100
+ const ssgOutDirFor = (root) => join(resolve(root), "node_modules", ".cache", `qwik-router-ssg-${process.pid}`);
149
101
  const plugin = {
150
102
  name: `vite-plugin-qwik-router-ssg-${opts.name}`,
151
103
  enforce: "post",
@@ -158,30 +110,78 @@ function viteAdapter(opts) {
158
110
  "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production"),
159
111
  ...config.define
160
112
  };
113
+ config.builder ??= {};
114
+ if (opts.ssg !== null) {
115
+ config.environments = {
116
+ ...config.environments,
117
+ // Same server externalization as `ssr` (via the router/qwik `configEnvironment` hooks);
118
+ // only the build graph and outDir differ. run-ssg externalizes node_modules deps and
119
+ // resolves them at render time, so native/CJS packages (e.g. a database client) are not
120
+ // force-bundled.
121
+ ssg: {
122
+ consumer: "server",
123
+ build: {
124
+ ssr: true,
125
+ outDir: ssgOutDirFor(config.root ?? process.cwd()),
126
+ emptyOutDir: true,
127
+ // Throwaway output, executed once and deleted — skip minify/sourcemap work.
128
+ minify: false,
129
+ sourcemap: false
130
+ }
131
+ }
132
+ };
133
+ }
161
134
  return config;
162
135
  },
136
+ configEnvironment(name, environmentOptions) {
137
+ if (name === "ssg") {
138
+ environmentOptions.build = {
139
+ ...environmentOptions.build,
140
+ rollupOptions: {
141
+ ...environmentOptions.build?.rollupOptions,
142
+ input: {}
143
+ }
144
+ };
145
+ }
146
+ },
163
147
  configResolved(config) {
164
148
  viteCommand = config.command;
165
149
  qwikRouterPlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik-router");
166
150
  if (!qwikRouterPlugin) {
167
151
  throw new Error("Missing vite-plugin-qwik-router");
168
152
  }
153
+ qwikRouterPlugin.api?._setSsgRoutes?.(opts.ssg?.include, opts.ssg?.exclude);
169
154
  qwikVitePlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik");
170
155
  if (!qwikVitePlugin) {
171
156
  throw new Error("Missing vite-plugin-qwik");
172
157
  }
173
- serverOutDir = config.build.outDir;
174
158
  },
175
159
  resolveId(id) {
176
160
  if (id === QWIK_SSG_ENTRY_ID) {
177
161
  return QWIK_SSG_ENTRY_RESOLVED;
178
162
  }
163
+ if (id === QWIK_SSG_WORKER_ENTRY_ID) {
164
+ return QWIK_SSG_WORKER_ENTRY_RESOLVED;
165
+ }
179
166
  },
180
167
  load(id) {
168
+ if (id === QWIK_SSG_WORKER_ENTRY_RESOLVED) {
169
+ const { srcDir } = qwikVitePlugin.api.getOptions();
170
+ return [
171
+ `import render from '${srcDir}/entry.ssr';`,
172
+ `import qwikRouterConfig from '@qwik-router-config';`,
173
+ `import { startWorker } from '@qwik.dev/router/ssg';`,
174
+ // Fire-and-forget (no top-level await): avoids a Rollup inlined-dynamic-import init-order
175
+ // bug on the SSR target. See rollup/rollup#4166.
176
+ `startWorker({ render, qwikRouterConfig }).catch((err) => {`,
177
+ ` console.error(err);`,
178
+ ` process.exit(1);`,
179
+ `});`
180
+ ].join("\n");
181
+ }
181
182
  if (id !== QWIK_SSG_ENTRY_RESOLVED) {
182
183
  return;
183
184
  }
184
- const { srcDir } = qwikVitePlugin.api.getOptions();
185
185
  const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
186
186
  const basePathname = qwikRouterPlugin.api.getBasePathname();
187
187
  const rootDir = qwikVitePlugin.api.getRootDir() ?? void 0;
@@ -215,47 +215,43 @@ function viteAdapter(opts) {
215
215
  }
216
216
  }
217
217
  return [
218
- `import { isMainThread } from 'node:worker_threads';`,
219
- `import render from '${srcDir}/entry.ssr';`,
220
218
  `import qwikRouterConfig from '@qwik-router-config';`,
221
- `import { runSsg, startWorker } from '@qwik.dev/router/ssg';`,
219
+ `import { runSsg } from '@qwik.dev/router/ssg';`,
222
220
  ``,
223
221
  `const ssgOpts = ${JSON.stringify(ssgOpts)};`,
224
222
  ``,
225
223
  `// Parse --quiet / --debug CLI flags`,
226
- `const args = isMainThread ? process.argv.slice(2) : [];`,
224
+ `const args = process.argv.slice(2);`,
227
225
  `if (args.includes('--quiet')) ssgOpts.log = 'quiet';`,
228
226
  `if (args.includes('--debug')) ssgOpts.log = 'debug';`,
229
227
  ``,
230
- // Fire-and-forget instead of top-level await. On the worker/edge SSR target Vite
231
- // inlines dynamic imports, and Rollup then reads the inlined `./system` namespace
232
- // before it is initialized across a top-level await. See rollup/rollup#4166.
233
- // runSsg/startWorker keep the process alive (worker handles) and call process.exit.
234
- `const ssgRun = isMainThread`,
235
- ` ? runSsg({`,
236
- ` render,`,
237
- ` qwikRouterConfig,`,
238
- ` workerFilePath: new URL(import.meta.url).href,`,
239
- ` ...ssgOpts,`,
240
- ` })`,
241
- ` : startWorker({ render, qwikRouterConfig });`,
242
- `ssgRun.catch((err) => {`,
228
+ // Fire-and-forget; see rollup/rollup#4166 above. The worker entry is a sibling file.
229
+ `runSsg({`,
230
+ ` qwikRouterConfig,`,
231
+ ` workerFilePath: new URL('./run-ssg-worker.js', import.meta.url).href,`,
232
+ ` ...ssgOpts,`,
233
+ `}).catch((err) => {`,
243
234
  ` console.error(err);`,
244
235
  ` process.exit(1);`,
245
236
  `});`
246
237
  ].join("\n");
247
238
  },
248
239
  buildStart() {
249
- if (this.environment.config.consumer === "server" && opts.ssg !== null && viteCommand === "build" && serverOutDir) {
240
+ if (this.environment.name === "ssg" && viteCommand === "build") {
250
241
  this.emitFile({
251
242
  id: QWIK_SSG_ENTRY_ID,
252
243
  type: "chunk",
253
244
  fileName: "run-ssg.js"
254
245
  });
246
+ this.emitFile({
247
+ id: QWIK_SSG_WORKER_ENTRY_ID,
248
+ type: "chunk",
249
+ fileName: "run-ssg-worker.js"
250
+ });
255
251
  }
256
252
  },
257
253
  generateBundle(_, bundles) {
258
- if (this.environment.config.consumer === "server") {
254
+ if (this.environment.name === "ssr") {
259
255
  outputEntries.length = 0;
260
256
  for (const fileName in bundles) {
261
257
  const chunk = bundles[fileName];
@@ -263,77 +259,93 @@ function viteAdapter(opts) {
263
259
  outputEntries.push(fileName);
264
260
  }
265
261
  }
262
+ if (opts.ssg !== null && viteCommand === "build" && !buildAppRan) {
263
+ this.warn("Qwik Router SSG was skipped: the `ssr` environment was built directly instead of through the Vite app builder, so no pages were prerendered. Build with the Qwik CLI or `createBuilder(config).buildApp()` (a plain `vite build` does this automatically).");
264
+ }
266
265
  }
267
266
  },
268
- closeBundle: {
269
- sequential: true,
270
- async handler() {
271
- if (this.environment.config.consumer === "server" && serverOutDir && qwikRouterPlugin?.api && qwikVitePlugin?.api) {
272
- const staticPaths = opts.staticPaths || [];
273
- const routes = qwikRouterPlugin.api.getRoutes();
274
- const basePathname = qwikRouterPlugin.api.getBasePathname();
275
- const clientOutDir = qwikVitePlugin.api.getClientOutDir();
276
- const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
277
- const assetsDir = qwikVitePlugin.api.getAssetsDir();
278
- if (opts.ssg !== null && clientOutDir && clientPublicOutDir) {
279
- const runSsgPath = join(serverOutDir, "run-ssg.js");
280
- const { spawn } = await import('node:child_process');
281
- const ssgExitCode = await new Promise((resolve2, reject) => {
282
- const child = spawn(process.execPath, [
283
- runSsgPath
284
- ], {
285
- stdio: [
286
- "ignore",
287
- "inherit",
288
- "inherit"
289
- ],
290
- env: {
291
- ...process.env,
292
- NODE_ENV: process.env.NODE_ENV || "production"
293
- }
294
- });
295
- child.on("close", resolve2);
296
- child.on("error", reject);
297
- });
298
- if (ssgExitCode !== 0) {
299
- const err = new Error(`Error while running SSG from "${opts.name}" adapter. At least one path failed to render.`);
300
- err.stack = void 0;
301
- this.error(err);
302
- }
303
- const fs = await import('node:fs');
304
- const staticPathsFile = join(clientPublicOutDir, "_static-paths.json");
305
- try {
306
- const content = await fs.promises.readFile(staticPathsFile, "utf-8");
307
- staticPaths.push(...JSON.parse(content));
308
- await fs.promises.unlink(staticPathsFile);
309
- } catch {
267
+ // Build the deployed server (`ssr`) and the separate `ssg` graph (run-ssg) — two graphs, so
268
+ // prerendered route code never reaches the `ssr` bundle — then render the pages and post-build.
269
+ // (The client builds in its own `vite build`.)
270
+ async buildApp(builder) {
271
+ buildAppRan = true;
272
+ const ssr = builder.environments.ssr;
273
+ if (ssr) {
274
+ await builder.build(ssr);
275
+ }
276
+ const serverOutDir = ssr?.config.build.outDir;
277
+ if (!serverOutDir || !qwikRouterPlugin?.api || !qwikVitePlugin?.api) {
278
+ return;
279
+ }
280
+ const log = builder.config.logger;
281
+ const staticPaths = opts.staticPaths || [];
282
+ const routes = qwikRouterPlugin.api.getRoutes();
283
+ const basePathname = qwikRouterPlugin.api.getBasePathname();
284
+ const clientOutDir = qwikVitePlugin.api.getClientOutDir();
285
+ const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
286
+ const ssgEnv = builder.environments.ssg;
287
+ const ssgOutDir = ssgOutDirFor(builder.config.root);
288
+ if (ssgEnv && clientOutDir && clientPublicOutDir) {
289
+ await builder.build(ssgEnv);
290
+ const runSsgPath = join(ssgOutDir, "run-ssg.js");
291
+ const ssgExitCode = await new Promise((res, reject) => {
292
+ const child = spawn(process.execPath, [
293
+ runSsgPath
294
+ ], {
295
+ stdio: [
296
+ "ignore",
297
+ "inherit",
298
+ "inherit"
299
+ ],
300
+ env: {
301
+ ...process.env,
302
+ NODE_ENV: process.env.NODE_ENV || "production"
310
303
  }
304
+ });
305
+ child.on("close", res);
306
+ child.on("error", reject);
307
+ });
308
+ if (ssgExitCode !== 0) {
309
+ throw new Error(`Error while running SSG from "${opts.name}" adapter. At least one path failed to render.`);
310
+ }
311
+ const staticPathsFile = join(clientPublicOutDir, "_static-paths.json");
312
+ try {
313
+ staticPaths.push(...JSON.parse(await readFile(staticPathsFile, "utf-8")));
314
+ await unlink(staticPathsFile);
315
+ } catch {
316
+ }
317
+ if (process.env.QWIK_ROUTER_KEEP_SSG_BUILD) {
318
+ log.warn(`SSG build kept at ${ssgOutDir}`);
319
+ } else {
320
+ await rm(ssgOutDir, {
321
+ recursive: true,
322
+ force: true
323
+ });
324
+ }
325
+ }
326
+ await postBuild(clientPublicOutDir, serverOutDir, basePathname, staticPaths, !!opts.cleanStaticGenerated);
327
+ if (typeof opts.generate === "function") {
328
+ await opts.generate({
329
+ outputEntries,
330
+ serverOutDir,
331
+ clientOutDir,
332
+ clientPublicOutDir,
333
+ basePathname,
334
+ routes,
335
+ warn: (message) => log.warn(message),
336
+ error: (message) => {
337
+ throw new Error(message);
311
338
  }
312
- await postBuild(clientPublicOutDir, serverOutDir, assetsDir ? join(basePathname, assetsDir) : basePathname, staticPaths, !!opts.cleanStaticGenerated);
313
- if (typeof opts.generate === "function") {
314
- await opts.generate({
315
- outputEntries,
316
- serverOutDir,
317
- clientOutDir,
318
- clientPublicOutDir,
319
- basePathname,
320
- routes,
321
- assetsDir,
322
- warn: (message) => this.warn(message),
323
- error: (message) => this.error(message)
324
- });
325
- }
326
- this.warn(`
339
+ });
340
+ }
341
+ log.warn(`
327
342
  ==============================================
328
343
  Note: Make sure that you are serving the built files with proper cache headers.
329
344
  See https://qwik.dev/docs/deployments/#cache-headers for more information.
330
345
  ==============================================`);
331
- }
332
- }
333
346
  }
334
347
  };
335
348
  return [
336
- ssgWorkerImportPlugin(),
337
349
  plugin
338
350
  ];
339
351
  }
@@ -0,0 +1,3 @@
1
+ const devPreloadedRouteLoaders = globalThis[/* @__PURE__ */ Symbol.for("devPreloadedRouteLoaders")] ??= /* @__PURE__ */ new WeakMap();
2
+
3
+ export { devPreloadedRouteLoaders as d };
@@ -0,0 +1,31 @@
1
+ function toTitleCase(str) {
2
+ return str.replace(/\w\S*/g, (txt) => {
3
+ return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
4
+ });
5
+ }
6
+ function addError(ctx, e) {
7
+ ctx.diagnostics.push({
8
+ type: "error",
9
+ message: e ? String(e.stack || e) : "Error"
10
+ });
11
+ }
12
+ function addWarning(ctx, message) {
13
+ ctx.diagnostics.push({
14
+ type: "warn",
15
+ message: String(message)
16
+ });
17
+ }
18
+ function msToString(ms) {
19
+ if (ms < 1) {
20
+ return ms.toFixed(2) + " ms";
21
+ }
22
+ if (ms < 1e3) {
23
+ return ms.toFixed(1) + " ms";
24
+ }
25
+ if (ms < 6e4) {
26
+ return (ms / 1e3).toFixed(1) + " s";
27
+ }
28
+ return (ms / 6e4).toFixed(1) + " m";
29
+ }
30
+
31
+ export { addError as a, addWarning as b, msToString as m, toTitleCase as t };
package/lib/chunks/fs.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { normalize, basename, dirname, relative } from 'node:path';
2
- import { t as toTitleCase, n as normalizePathname } from './pathname.mjs';
2
+ import { t as toTitleCase } from './format.mjs';
3
+ import { n as normalizePathname, e as ensureSlash } from './pathname.mjs';
3
4
 
4
5
  function parseRouteIndexName(extlessName) {
5
6
  let layoutName = "";
@@ -56,11 +57,8 @@ function normalizePath(path) {
56
57
  function getMenuPathname(opts, filePath) {
57
58
  let pathname = normalizePath(relative(opts.routesDir, filePath));
58
59
  pathname = `/` + normalizePath(dirname(pathname));
59
- let result = normalizePathname(pathname, opts.basePathname);
60
- if (!result.endsWith("/")) {
61
- result += "/";
62
- }
63
- return result;
60
+ const result = normalizePathname(pathname, opts.basePathname);
61
+ return ensureSlash(result);
64
62
  }
65
63
  function createFileId(routesDir, fsPath, explicitFileType) {
66
64
  const ids = [];
@@ -125,8 +123,12 @@ function isServiceWorkerName(extlessName) {
125
123
  function isEntryName(extlessName) {
126
124
  return extlessName === "entry";
127
125
  }
126
+ function errorBoundaryName(extlessName) {
127
+ const match = /^(error|404)(?:|!|@.+)$/.exec(extlessName);
128
+ return match ? match[1] : void 0;
129
+ }
128
130
  function isErrorName(extlessName) {
129
- return extlessName === "error" || extlessName === "404";
131
+ return errorBoundaryName(extlessName) !== void 0;
130
132
  }
131
133
  function isGroupedLayoutName(dirName, warn = true) {
132
134
  return dirName.startsWith("(") && dirName.endsWith(")");
@@ -141,4 +143,4 @@ function getPathnameFromDirPath(opts, dirPath) {
141
143
  return pathname;
142
144
  }
143
145
 
144
- export { isErrorName as a, isLayoutModule as b, isEntryName as c, isMenuFileName as d, isServiceWorkerName as e, isPageModuleExt as f, getExtension as g, isModuleExt as h, isIndexModule as i, isMarkdownExt as j, normalizePath as k, getPathnameFromDirPath as l, getMenuPathname as m, normalizePathSlash as n, createFileId as o, parseRouteIndexName as p, isPluginModule as q, removeExtension as r, isPageExt as s };
146
+ export { isErrorName as a, isPageModuleExt as b, isModuleExt as c, isMarkdownExt as d, isLayoutModule as e, isEntryName as f, getExtension as g, isMenuFileName as h, isIndexModule as i, isServiceWorkerName as j, normalizePath as k, getPathnameFromDirPath as l, getMenuPathname as m, normalizePathSlash as n, createFileId as o, parseRouteIndexName as p, errorBoundaryName as q, removeExtension as r, isPluginModule as s, isPageExt as t };