@qwik.dev/router 2.0.0-beta.10 → 2.0.0-beta.13

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 (140) hide show
  1. package/lib/adapters/azure-swa/vite/index.cjs +61 -5
  2. package/lib/adapters/azure-swa/vite/index.mjs +26 -201
  3. package/lib/adapters/bun-server/vite/index.cjs +27 -5
  4. package/lib/adapters/bun-server/vite/index.mjs +14 -196
  5. package/lib/adapters/cloud-run/vite/index.cjs +24 -5
  6. package/lib/adapters/cloud-run/vite/index.mjs +13 -195
  7. package/lib/adapters/cloudflare-pages/vite/index.cjs +65 -1
  8. package/lib/adapters/cloudflare-pages/vite/index.mjs +63 -4
  9. package/lib/adapters/deno-server/vite/index.cjs +39 -5
  10. package/lib/adapters/deno-server/vite/index.mjs +16 -198
  11. package/lib/adapters/netlify-edge/vite/index.cjs +88 -6
  12. package/lib/adapters/netlify-edge/vite/index.mjs +56 -240
  13. package/lib/adapters/node-server/vite/index.cjs +27 -5
  14. package/lib/adapters/node-server/vite/index.mjs +14 -196
  15. package/lib/adapters/shared/vite/index.cjs +303 -2
  16. package/lib/adapters/shared/vite/index.d.ts +4 -4
  17. package/lib/adapters/shared/vite/index.mjs +248 -143
  18. package/lib/adapters/ssg/vite/index.cjs +19 -5
  19. package/lib/adapters/ssg/vite/index.mjs +11 -193
  20. package/lib/adapters/vercel-edge/vite/index.cjs +81 -5
  21. package/lib/adapters/vercel-edge/vite/index.d.ts +1 -1
  22. package/lib/adapters/vercel-edge/vite/index.mjs +48 -229
  23. package/lib/chunks/error-handler.cjs +58 -0
  24. package/lib/chunks/error-handler.mjs +59 -0
  25. package/lib/chunks/format-error.cjs +136 -0
  26. package/lib/chunks/format-error.mjs +137 -0
  27. package/lib/chunks/fs.cjs +274 -0
  28. package/lib/chunks/fs.mjs +275 -0
  29. package/lib/chunks/index.cjs +877 -0
  30. package/lib/chunks/index.mjs +876 -0
  31. package/lib/chunks/mime-types.cjs +52 -0
  32. package/lib/chunks/mime-types.mjs +53 -0
  33. package/lib/chunks/routing.qwik.cjs +452 -0
  34. package/lib/chunks/routing.qwik.mjs +453 -0
  35. package/lib/chunks/types.qwik.cjs +24 -0
  36. package/lib/chunks/types.qwik.mjs +25 -0
  37. package/lib/index.d.ts +9 -3
  38. package/lib/index.qwik.cjs +543 -1001
  39. package/lib/index.qwik.mjs +512 -972
  40. package/lib/middleware/aws-lambda/index.cjs +52 -1
  41. package/lib/middleware/aws-lambda/index.mjs +37 -26
  42. package/lib/middleware/azure-swa/index.cjs +92 -1
  43. package/lib/middleware/azure-swa/index.mjs +64 -46
  44. package/lib/middleware/bun/index.cjs +143 -1
  45. package/lib/middleware/bun/index.mjs +103 -117
  46. package/lib/middleware/cloudflare-pages/index.cjs +96 -1
  47. package/lib/middleware/cloudflare-pages/index.mjs +68 -47
  48. package/lib/middleware/deno/index.cjs +130 -1
  49. package/lib/middleware/deno/index.mjs +93 -112
  50. package/lib/middleware/firebase/index.cjs +33 -1
  51. package/lib/middleware/firebase/index.mjs +25 -16
  52. package/lib/middleware/netlify-edge/index.cjs +71 -1
  53. package/lib/middleware/netlify-edge/index.mjs +52 -36
  54. package/lib/middleware/node/index.cjs +219 -1
  55. package/lib/middleware/node/index.mjs +178 -165
  56. package/lib/middleware/request-handler/index.cjs +1488 -18
  57. package/lib/middleware/request-handler/index.d.ts +20 -2
  58. package/lib/middleware/request-handler/index.mjs +1225 -873
  59. package/lib/middleware/vercel-edge/index.cjs +98 -1
  60. package/lib/middleware/vercel-edge/index.mjs +71 -47
  61. package/lib/service-worker/index.cjs +5 -0
  62. package/lib/service-worker/index.mjs +5 -0
  63. package/lib/ssg/index.cjs +15 -1
  64. package/lib/ssg/index.mjs +12 -19
  65. package/lib/vite/index.cjs +2006 -27
  66. package/lib/vite/index.d.ts +9 -9
  67. package/lib/vite/index.mjs +1597 -1216
  68. package/package.json +9 -8
  69. package/lib/adapters/azure-swa/vite/index-BqUeglYs.cjs +0 -1
  70. package/lib/adapters/azure-swa/vite/index-CBIchDYq.js +0 -651
  71. package/lib/adapters/azure-swa/vite/index-ClHGw5z1.js +0 -6
  72. package/lib/adapters/azure-swa/vite/index-CrwlB95_.js +0 -22
  73. package/lib/adapters/azure-swa/vite/index-DTIOTwZo.cjs +0 -11
  74. package/lib/adapters/azure-swa/vite/index-vQuPcef3.cjs +0 -1
  75. package/lib/adapters/bun-server/vite/index-BqUeglYs.cjs +0 -1
  76. package/lib/adapters/bun-server/vite/index-CBIchDYq.js +0 -651
  77. package/lib/adapters/bun-server/vite/index-ClHGw5z1.js +0 -6
  78. package/lib/adapters/bun-server/vite/index-CrwlB95_.js +0 -22
  79. package/lib/adapters/bun-server/vite/index-DTIOTwZo.cjs +0 -11
  80. package/lib/adapters/bun-server/vite/index-vQuPcef3.cjs +0 -1
  81. package/lib/adapters/cloud-run/vite/index-BqUeglYs.cjs +0 -1
  82. package/lib/adapters/cloud-run/vite/index-CBIchDYq.js +0 -651
  83. package/lib/adapters/cloud-run/vite/index-ClHGw5z1.js +0 -6
  84. package/lib/adapters/cloud-run/vite/index-CrwlB95_.js +0 -22
  85. package/lib/adapters/cloud-run/vite/index-DTIOTwZo.cjs +0 -11
  86. package/lib/adapters/cloud-run/vite/index-vQuPcef3.cjs +0 -1
  87. package/lib/adapters/cloudflare-pages/vite/index-BIeHg2Cj.cjs +0 -5
  88. package/lib/adapters/cloudflare-pages/vite/index-C455V8_A.cjs +0 -1
  89. package/lib/adapters/cloudflare-pages/vite/index-ClHGw5z1.js +0 -6
  90. package/lib/adapters/cloudflare-pages/vite/index-D3HITboM.js +0 -645
  91. package/lib/adapters/cloudflare-pages/vite/index-DKcVHRBy.cjs +0 -11
  92. package/lib/adapters/cloudflare-pages/vite/index-DwovcBp3.js +0 -22
  93. package/lib/adapters/cloudflare-pages/vite/index-bogwy7wh.js +0 -250
  94. package/lib/adapters/cloudflare-pages/vite/index-vQuPcef3.cjs +0 -1
  95. package/lib/adapters/deno-server/vite/index-BqUeglYs.cjs +0 -1
  96. package/lib/adapters/deno-server/vite/index-CBIchDYq.js +0 -651
  97. package/lib/adapters/deno-server/vite/index-ClHGw5z1.js +0 -6
  98. package/lib/adapters/deno-server/vite/index-CrwlB95_.js +0 -22
  99. package/lib/adapters/deno-server/vite/index-DTIOTwZo.cjs +0 -11
  100. package/lib/adapters/deno-server/vite/index-vQuPcef3.cjs +0 -1
  101. package/lib/adapters/netlify-edge/vite/index-BqUeglYs.cjs +0 -1
  102. package/lib/adapters/netlify-edge/vite/index-CBIchDYq.js +0 -651
  103. package/lib/adapters/netlify-edge/vite/index-ClHGw5z1.js +0 -6
  104. package/lib/adapters/netlify-edge/vite/index-CrwlB95_.js +0 -22
  105. package/lib/adapters/netlify-edge/vite/index-DTIOTwZo.cjs +0 -11
  106. package/lib/adapters/netlify-edge/vite/index-vQuPcef3.cjs +0 -1
  107. package/lib/adapters/node-server/vite/index-BqUeglYs.cjs +0 -1
  108. package/lib/adapters/node-server/vite/index-CBIchDYq.js +0 -651
  109. package/lib/adapters/node-server/vite/index-ClHGw5z1.js +0 -6
  110. package/lib/adapters/node-server/vite/index-CrwlB95_.js +0 -22
  111. package/lib/adapters/node-server/vite/index-DTIOTwZo.cjs +0 -11
  112. package/lib/adapters/node-server/vite/index-vQuPcef3.cjs +0 -1
  113. package/lib/adapters/shared/vite/index-BqUeglYs.cjs +0 -1
  114. package/lib/adapters/shared/vite/index-CBIchDYq.js +0 -651
  115. package/lib/adapters/shared/vite/index-ClHGw5z1.js +0 -6
  116. package/lib/adapters/shared/vite/index-CrwlB95_.js +0 -22
  117. package/lib/adapters/shared/vite/index-DTIOTwZo.cjs +0 -11
  118. package/lib/adapters/shared/vite/index-vQuPcef3.cjs +0 -1
  119. package/lib/adapters/ssg/vite/index-BqUeglYs.cjs +0 -1
  120. package/lib/adapters/ssg/vite/index-CBIchDYq.js +0 -651
  121. package/lib/adapters/ssg/vite/index-ClHGw5z1.js +0 -6
  122. package/lib/adapters/ssg/vite/index-CrwlB95_.js +0 -22
  123. package/lib/adapters/ssg/vite/index-DTIOTwZo.cjs +0 -11
  124. package/lib/adapters/ssg/vite/index-vQuPcef3.cjs +0 -1
  125. package/lib/adapters/vercel-edge/vite/index-BqUeglYs.cjs +0 -1
  126. package/lib/adapters/vercel-edge/vite/index-CBIchDYq.js +0 -651
  127. package/lib/adapters/vercel-edge/vite/index-ClHGw5z1.js +0 -6
  128. package/lib/adapters/vercel-edge/vite/index-CrwlB95_.js +0 -22
  129. package/lib/adapters/vercel-edge/vite/index-DTIOTwZo.cjs +0 -11
  130. package/lib/adapters/vercel-edge/vite/index-vQuPcef3.cjs +0 -1
  131. package/lib/service-worker.cjs +0 -1
  132. package/lib/service-worker.mjs +0 -5
  133. package/lib/ssg/deno.cjs +0 -1
  134. package/lib/ssg/deno.mjs +0 -6
  135. package/lib/ssg/index-CBIchDYq.js +0 -651
  136. package/lib/ssg/index-ClHGw5z1.js +0 -6
  137. package/lib/ssg/index-DTIOTwZo.cjs +0 -11
  138. package/lib/ssg/index-vQuPcef3.cjs +0 -1
  139. package/lib/ssg/node.cjs +0 -11
  140. package/lib/ssg/node.mjs +0 -651
@@ -0,0 +1,876 @@
1
+ import fs from "node:fs";
2
+ import { isAbsolute, resolve, extname, join, dirname, relative } from "node:path";
3
+ import { cpus } from "node:os";
4
+ import { Worker, parentPort, isMainThread, workerData, threadId } from "node:worker_threads";
5
+ import { l as normalizePath, w as msToString, x as getPathnameForDynamicRoute } from "./fs.mjs";
6
+ import { bold, green, dim, red, magenta } from "kleur/colors";
7
+ import { pathToFileURL } from "node:url";
8
+ import { buildErrorMessage } from "vite";
9
+ import { f as formatError } from "./format-error.mjs";
10
+ import { getErrorHtml, RequestEvShareQData, requestHandler, RedirectMessage } from "@qwik.dev/router/middleware/request-handler";
11
+ import { R as RouteDataProp } from "./types.qwik.mjs";
12
+ import { _serialize } from "@qwik.dev/core/internal";
13
+ import { WritableStream } from "node:stream/web";
14
+ async function createNodeMainProcess(sys, opts) {
15
+ const ssgWorkers = [];
16
+ const sitemapBuffer = [];
17
+ let sitemapPromise = null;
18
+ opts = { ...opts };
19
+ let outDir = opts.outDir;
20
+ if (typeof outDir !== "string") {
21
+ throw new Error(`Missing "outDir" option`);
22
+ }
23
+ if (!isAbsolute(outDir)) {
24
+ throw new Error(`"outDir" must be an absolute file path, received: ${outDir}`);
25
+ }
26
+ outDir = normalizePath(outDir);
27
+ let maxWorkers = cpus().length;
28
+ if (typeof opts.maxWorkers === "number") {
29
+ maxWorkers = Math.max(1, Math.min(opts.maxWorkers, maxWorkers));
30
+ }
31
+ let maxTasksPerWorker = 20;
32
+ if (typeof opts.maxTasksPerWorker === "number") {
33
+ maxTasksPerWorker = Math.max(1, Math.min(opts.maxTasksPerWorker, 50));
34
+ }
35
+ let sitemapOutFile = opts.sitemapOutFile;
36
+ if (sitemapOutFile !== null) {
37
+ if (typeof sitemapOutFile !== "string") {
38
+ sitemapOutFile = "sitemap.xml";
39
+ }
40
+ if (!isAbsolute(sitemapOutFile)) {
41
+ sitemapOutFile = resolve(outDir, sitemapOutFile);
42
+ }
43
+ }
44
+ const createWorker = () => {
45
+ let terminateResolve = null;
46
+ const mainTasks = /* @__PURE__ */ new Map();
47
+ let workerFilePath;
48
+ let terminateTimeout = null;
49
+ if (typeof __filename === "string") {
50
+ const ext = extname(__filename) || ".js";
51
+ workerFilePath = join(dirname(__filename), `index${ext}`);
52
+ } else {
53
+ const thisUrl = new URL(import.meta.url);
54
+ const pathname = thisUrl.pathname || "";
55
+ let ext = ".js";
56
+ if (pathname.endsWith(".ts")) {
57
+ ext = ".ts";
58
+ } else if (pathname.endsWith(".mjs")) {
59
+ ext = ".mjs";
60
+ }
61
+ workerFilePath = new URL(`./index${ext}`, thisUrl);
62
+ }
63
+ const nodeWorker = new Worker(workerFilePath, { workerData: opts });
64
+ nodeWorker.unref();
65
+ const ssgWorker = {
66
+ activeTasks: 0,
67
+ totalTasks: 0,
68
+ render: (staticRoute) => {
69
+ return new Promise((resolve2, reject) => {
70
+ try {
71
+ ssgWorker.activeTasks++;
72
+ ssgWorker.totalTasks++;
73
+ mainTasks.set(staticRoute.pathname, resolve2);
74
+ nodeWorker.postMessage(staticRoute);
75
+ } catch (e) {
76
+ ssgWorker.activeTasks--;
77
+ mainTasks.delete(staticRoute.pathname);
78
+ reject(e);
79
+ }
80
+ });
81
+ },
82
+ terminate: async () => {
83
+ mainTasks.clear();
84
+ const msg = { type: "close" };
85
+ await new Promise((resolve2) => {
86
+ terminateResolve = resolve2;
87
+ nodeWorker.postMessage(msg);
88
+ });
89
+ terminateTimeout = setTimeout(async () => {
90
+ await nodeWorker.terminate();
91
+ }, 1e3);
92
+ }
93
+ };
94
+ nodeWorker.on("message", (msg) => {
95
+ switch (msg.type) {
96
+ case "render": {
97
+ const mainTask = mainTasks.get(msg.pathname);
98
+ if (mainTask) {
99
+ mainTasks.delete(msg.pathname);
100
+ ssgWorker.activeTasks--;
101
+ mainTask(msg);
102
+ }
103
+ break;
104
+ }
105
+ case "close": {
106
+ if (terminateResolve) {
107
+ terminateResolve();
108
+ terminateResolve = null;
109
+ }
110
+ break;
111
+ }
112
+ }
113
+ });
114
+ nodeWorker.on("error", (e) => {
115
+ console.error(`worker error`, e);
116
+ });
117
+ nodeWorker.on("exit", (code) => {
118
+ if (terminateTimeout) {
119
+ clearTimeout(terminateTimeout);
120
+ terminateTimeout = null;
121
+ }
122
+ if (code !== 0) {
123
+ console.error(`worker exit ${code}`);
124
+ }
125
+ });
126
+ return ssgWorker;
127
+ };
128
+ const getNextWorker = () => ssgWorkers.sort(ssgWorkerCompare)[0];
129
+ const hasAvailableWorker = () => {
130
+ const ssgWorker = getNextWorker();
131
+ return ssgWorker.activeTasks < maxTasksPerWorker;
132
+ };
133
+ const render = async (ssgRoute) => {
134
+ const ssgWorker = getNextWorker();
135
+ const result = await ssgWorker.render(ssgRoute);
136
+ if (sitemapOutFile && result.ok && result.resourceType === "page") {
137
+ sitemapBuffer.push(`<url><loc>${result.url}</loc></url>`);
138
+ if (sitemapBuffer.length > 50) {
139
+ if (sitemapPromise) {
140
+ await sitemapPromise;
141
+ }
142
+ const siteMapUrls = sitemapBuffer.join("\n") + "\n";
143
+ sitemapBuffer.length = 0;
144
+ sitemapPromise = fs.promises.appendFile(sitemapOutFile, siteMapUrls);
145
+ }
146
+ }
147
+ return result;
148
+ };
149
+ const close = async () => {
150
+ const promises = [];
151
+ if (sitemapOutFile) {
152
+ if (sitemapPromise) {
153
+ await sitemapPromise;
154
+ }
155
+ sitemapBuffer.push(`</urlset>`);
156
+ promises.push(fs.promises.appendFile(sitemapOutFile, sitemapBuffer.join("\n")));
157
+ sitemapBuffer.length = 0;
158
+ }
159
+ for (const ssgWorker of ssgWorkers) {
160
+ try {
161
+ promises.push(ssgWorker.terminate());
162
+ } catch (e) {
163
+ console.error(e);
164
+ }
165
+ }
166
+ await Promise.all(promises);
167
+ ssgWorkers.length = 0;
168
+ if (process.platform === "win32") {
169
+ await new Promise((resolve2) => setTimeout(resolve2, 300));
170
+ }
171
+ };
172
+ if (sitemapOutFile) {
173
+ await ensureDir(sitemapOutFile);
174
+ await fs.promises.writeFile(
175
+ sitemapOutFile,
176
+ `<?xml version="1.0" encoding="UTF-8"?>
177
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
178
+ `
179
+ );
180
+ }
181
+ for (let i = 0; i < maxWorkers; i++) {
182
+ ssgWorkers.push(createWorker());
183
+ if (process.platform === "win32" && i < maxWorkers - 1) {
184
+ await new Promise((resolve2) => setTimeout(resolve2, 100));
185
+ }
186
+ }
187
+ const mainCtx = {
188
+ hasAvailableWorker,
189
+ render,
190
+ close
191
+ };
192
+ return mainCtx;
193
+ }
194
+ function ssgWorkerCompare(a, b) {
195
+ if (a.activeTasks < b.activeTasks) {
196
+ return -1;
197
+ }
198
+ if (a.activeTasks > b.activeTasks) {
199
+ return 1;
200
+ }
201
+ return a.totalTasks < b.totalTasks ? -1 : 1;
202
+ }
203
+ async function createNodeWorkerProcess(onMessage) {
204
+ parentPort?.on("message", async (msg) => {
205
+ parentPort?.postMessage(await onMessage(msg));
206
+ if (msg.type === "close") {
207
+ parentPort?.close();
208
+ }
209
+ });
210
+ }
211
+ async function createSystem(opts, threadId2) {
212
+ const createWriteStream = (filePath) => {
213
+ return fs.createWriteStream(filePath, {
214
+ flags: "w"
215
+ });
216
+ };
217
+ const NS_PER_SEC = 1e9;
218
+ const MS_PER_NS = 1e-6;
219
+ const createTimer = () => {
220
+ const start = process.hrtime();
221
+ return () => {
222
+ const diff = process.hrtime(start);
223
+ return (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS;
224
+ };
225
+ };
226
+ const createLogger = async () => {
227
+ if (threadId2 !== void 0) {
228
+ return {
229
+ debug: opts.log === "debug" ? console.debug.bind(console, `[${threadId2}]`) : () => {
230
+ },
231
+ error: console.error.bind(console, `[${threadId2}]`),
232
+ info: console.info.bind(console, `[${threadId2}]`)
233
+ };
234
+ }
235
+ return {
236
+ debug: opts.log === "debug" ? console.debug.bind(console) : () => {
237
+ },
238
+ error: console.error.bind(console),
239
+ info: console.info.bind(console)
240
+ };
241
+ };
242
+ const outDir = normalizePath(opts.outDir);
243
+ const basePathname = opts.basePathname || "/";
244
+ const basenameLen = basePathname.length;
245
+ const getRouteFilePath = (pathname, isHtml) => {
246
+ pathname = pathname.slice(basenameLen);
247
+ if (isHtml) {
248
+ if (!pathname.endsWith(".html")) {
249
+ if (pathname.endsWith("/")) {
250
+ pathname += "index.html";
251
+ } else {
252
+ pathname += "/index.html";
253
+ }
254
+ }
255
+ } else {
256
+ if (pathname.endsWith("/")) {
257
+ pathname = pathname.slice(0, -1);
258
+ }
259
+ }
260
+ return join(outDir, pathname);
261
+ };
262
+ const getDataFilePath = (pathname) => {
263
+ pathname = pathname.slice(basenameLen);
264
+ if (pathname.endsWith("/")) {
265
+ pathname += "q-data.json";
266
+ } else {
267
+ pathname += "/q-data.json";
268
+ }
269
+ return join(outDir, pathname);
270
+ };
271
+ const sys = {
272
+ createMainProcess: null,
273
+ createWorkerProcess: createNodeWorkerProcess,
274
+ createLogger,
275
+ getOptions: () => opts,
276
+ ensureDir,
277
+ createWriteStream,
278
+ createTimer,
279
+ access,
280
+ getRouteFilePath,
281
+ getDataFilePath,
282
+ getEnv: (key) => process.env[key],
283
+ platform: {
284
+ static: true,
285
+ node: process.versions.node
286
+ }
287
+ };
288
+ sys.createMainProcess = () => createNodeMainProcess(sys, opts);
289
+ return sys;
290
+ }
291
+ const ensureDir = async (filePath) => {
292
+ await fs.promises.mkdir(dirname(filePath), { recursive: true });
293
+ };
294
+ const access = async (path) => {
295
+ try {
296
+ await fs.promises.access(path);
297
+ return true;
298
+ } catch {
299
+ return false;
300
+ }
301
+ };
302
+ function extractParamNames(routeName) {
303
+ const params = [];
304
+ let idx = 0;
305
+ while (idx < routeName.length) {
306
+ const start = routeName.indexOf("[", idx);
307
+ if (start !== -1) {
308
+ const end = routeName.indexOf("]", start);
309
+ const param = routeName.slice(start + 1, end);
310
+ params.push(param.startsWith("...") ? param.substring(3) : param);
311
+ idx = end + 1;
312
+ } else {
313
+ idx = routeName.length;
314
+ }
315
+ }
316
+ return params;
317
+ }
318
+ async function generateNotFoundPages(sys, opts, routes) {
319
+ if (opts.emit404Pages !== false) {
320
+ const basePathname = opts.basePathname || "/";
321
+ const rootNotFoundPathname = basePathname + "404.html";
322
+ const hasRootNotFound = routes.some(
323
+ (r) => r[RouteDataProp.OriginalPathname] === rootNotFoundPathname
324
+ );
325
+ if (!hasRootNotFound) {
326
+ const filePath = sys.getRouteFilePath(rootNotFoundPathname, true);
327
+ const html = getErrorHtml(404, "Resource Not Found");
328
+ await sys.ensureDir(filePath);
329
+ return new Promise((resolve2) => {
330
+ const writer = sys.createWriteStream(filePath);
331
+ writer.write(html);
332
+ writer.end(resolve2);
333
+ });
334
+ }
335
+ }
336
+ }
337
+ function createRouteTester(basePathname, includeRoutes, excludeRoutes) {
338
+ const includes = routesToRegExps(includeRoutes);
339
+ const excludes = routesToRegExps(excludeRoutes);
340
+ return (pathname) => {
341
+ if (pathname.endsWith("404.html")) {
342
+ return true;
343
+ }
344
+ if (basePathname !== "/") {
345
+ pathname = pathname.slice(basePathname.length - 1);
346
+ }
347
+ for (const exclude of excludes) {
348
+ if (exclude.test(pathname)) {
349
+ return false;
350
+ }
351
+ }
352
+ for (const include of includes) {
353
+ if (include.test(pathname)) {
354
+ return true;
355
+ }
356
+ }
357
+ return false;
358
+ };
359
+ }
360
+ function routesToRegExps(routes) {
361
+ if (!Array.isArray(routes)) {
362
+ return [];
363
+ }
364
+ return routes.filter((r) => typeof r === "string").map(routeToRegExp);
365
+ }
366
+ function routeToRegExp(rule) {
367
+ let transformedRule;
368
+ if (rule === "/" || rule === "/*") {
369
+ transformedRule = rule;
370
+ } else if (rule.endsWith("/*")) {
371
+ transformedRule = `${rule.substring(0, rule.length - 2)}(/*)?`;
372
+ } else if (rule.endsWith("/")) {
373
+ transformedRule = `${rule.substring(0, rule.length - 1)}(/)?`;
374
+ } else if (rule.endsWith("*")) {
375
+ transformedRule = rule;
376
+ } else {
377
+ transformedRule = `${rule}(/)?`;
378
+ }
379
+ transformedRule = `^${transformedRule.replace(/\*/g, ".*")}$`;
380
+ return new RegExp(transformedRule);
381
+ }
382
+ async function mainThread(sys) {
383
+ const opts = sys.getOptions();
384
+ validateOptions(opts);
385
+ const main = await sys.createMainProcess();
386
+ const log = await sys.createLogger();
387
+ log.info("\n" + bold(green("Starting Qwik Router SSG...")));
388
+ const qwikRouterConfig = (await import(pathToFileURL(opts.qwikRouterConfigModulePath).href)).default;
389
+ const queue = [];
390
+ const active = /* @__PURE__ */ new Set();
391
+ const routes = qwikRouterConfig.routes || [];
392
+ const trailingSlash = !!qwikRouterConfig.trailingSlash;
393
+ const includeRoute = createRouteTester(opts.basePathname || "/", opts.include, opts.exclude);
394
+ return new Promise((resolve2, reject) => {
395
+ try {
396
+ const timer = sys.createTimer();
397
+ const generatorResult = {
398
+ duration: 0,
399
+ rendered: 0,
400
+ errors: 0,
401
+ staticPaths: []
402
+ };
403
+ let isCompleted = false;
404
+ let isRoutesLoaded = false;
405
+ const completed = async () => {
406
+ const closePromise = main.close();
407
+ await generateNotFoundPages(sys, opts, routes);
408
+ generatorResult.duration = timer();
409
+ if (generatorResult.errors === 0) {
410
+ log.info(`
411
+ ${green("SSG results")}`);
412
+ if (generatorResult.rendered > 0) {
413
+ log.info(
414
+ `- Generated: ${dim(
415
+ `${generatorResult.rendered} page${generatorResult.rendered === 1 ? "" : "s"}`
416
+ )}`
417
+ );
418
+ }
419
+ log.info(`- Duration: ${dim(msToString(generatorResult.duration))}`);
420
+ const total = generatorResult.rendered + generatorResult.errors;
421
+ if (total > 0) {
422
+ log.info(
423
+ `- Average: ${dim(msToString(generatorResult.duration / total) + " per page")}`
424
+ );
425
+ }
426
+ log.info(``);
427
+ }
428
+ closePromise.then(() => {
429
+ setTimeout(() => resolve2(generatorResult));
430
+ }).catch(reject);
431
+ };
432
+ const next = () => {
433
+ while (!isCompleted && main.hasAvailableWorker() && queue.length > 0) {
434
+ const staticRoute = queue.shift();
435
+ if (staticRoute) {
436
+ render(staticRoute).catch((e) => {
437
+ console.error(`render failed for ${staticRoute.pathname}`, e);
438
+ });
439
+ }
440
+ }
441
+ if (!isCompleted && isRoutesLoaded && queue.length === 0 && active.size === 0) {
442
+ isCompleted = true;
443
+ completed().catch((e) => {
444
+ console.error("SSG completion failed", e);
445
+ });
446
+ }
447
+ };
448
+ let isPendingDrain = false;
449
+ const flushQueue = () => {
450
+ if (!isPendingDrain) {
451
+ isPendingDrain = true;
452
+ setTimeout(() => {
453
+ isPendingDrain = false;
454
+ next();
455
+ });
456
+ }
457
+ };
458
+ const render = async (staticRoute) => {
459
+ try {
460
+ active.add(staticRoute.pathname);
461
+ const result = await main.render({ type: "render", ...staticRoute });
462
+ active.delete(staticRoute.pathname);
463
+ if (result.error) {
464
+ const err = new Error(result.error.message);
465
+ err.stack = result.error.stack;
466
+ log.error(`
467
+ ${bold(red(`!!! ${result.pathname}: Error during SSG`))}`);
468
+ log.error(red(err.message));
469
+ log.error(` Pathname: ${magenta(staticRoute.pathname)}`);
470
+ Object.assign(formatError(err), {
471
+ plugin: "qwik-ssg"
472
+ });
473
+ log.error(buildErrorMessage(err));
474
+ generatorResult.errors++;
475
+ }
476
+ if (result.filePath != null) {
477
+ generatorResult.rendered++;
478
+ generatorResult.staticPaths.push(result.pathname);
479
+ const base = opts.rootDir ?? opts.outDir;
480
+ const path = relative(base, result.filePath);
481
+ const lastSlash = path.lastIndexOf("/");
482
+ log.info(`${dim(path.slice(0, lastSlash + 1))}${path.slice(lastSlash + 1)}`);
483
+ }
484
+ flushQueue();
485
+ } catch (e) {
486
+ console.error(`render failed for ${staticRoute.pathname}`, e);
487
+ isCompleted = true;
488
+ reject(e);
489
+ }
490
+ };
491
+ const addToQueue = (pathname, params) => {
492
+ if (pathname) {
493
+ pathname = new URL(pathname, `https://qwik.dev`).pathname;
494
+ if (pathname !== opts.basePathname) {
495
+ if (trailingSlash) {
496
+ if (!pathname.endsWith("/")) {
497
+ const segments = pathname.split("/");
498
+ const lastSegment = segments[segments.length - 1];
499
+ if (!lastSegment.includes(".")) {
500
+ pathname += "/";
501
+ }
502
+ }
503
+ } else {
504
+ if (pathname.endsWith("/")) {
505
+ pathname = pathname.slice(0, pathname.length - 1);
506
+ }
507
+ }
508
+ }
509
+ if (includeRoute(pathname) && !queue.some((s) => s.pathname === pathname)) {
510
+ queue.push({
511
+ pathname,
512
+ params
513
+ });
514
+ flushQueue();
515
+ }
516
+ }
517
+ };
518
+ const loadStaticRoute = async (route) => {
519
+ const [routeName, loaders, originalPathname] = route;
520
+ const modules = await Promise.all(loaders.map((loader) => loader()));
521
+ const pageModule = modules[modules.length - 1];
522
+ const paramNames = extractParamNames(routeName);
523
+ const isValidStaticModule = pageModule && (pageModule.default || pageModule.onRequest || pageModule.onGet);
524
+ if (isValidStaticModule) {
525
+ if (Array.isArray(paramNames) && paramNames.length > 0) {
526
+ if (typeof pageModule.onStaticGenerate === "function" && paramNames.length > 0) {
527
+ const staticGenerate = await pageModule.onStaticGenerate({
528
+ env: {
529
+ get(key) {
530
+ return sys.getEnv(key);
531
+ }
532
+ }
533
+ });
534
+ if (Array.isArray(staticGenerate.params)) {
535
+ for (const params of staticGenerate.params) {
536
+ const pathname = getPathnameForDynamicRoute(
537
+ originalPathname,
538
+ paramNames,
539
+ params
540
+ );
541
+ addToQueue(pathname, params);
542
+ }
543
+ }
544
+ }
545
+ } else {
546
+ addToQueue(originalPathname, void 0);
547
+ }
548
+ }
549
+ };
550
+ const loadStaticRoutes = async () => {
551
+ await Promise.all(routes.map(loadStaticRoute));
552
+ isRoutesLoaded = true;
553
+ flushQueue();
554
+ };
555
+ loadStaticRoutes().catch((e) => {
556
+ console.error("SSG route loading failed", e);
557
+ reject(e);
558
+ });
559
+ } catch (e) {
560
+ console.error("SSG main thread failed", e);
561
+ reject(e);
562
+ }
563
+ });
564
+ }
565
+ function validateOptions(opts) {
566
+ if (!opts.qwikRouterConfigModulePath) {
567
+ if (!opts.qwikCityPlanModulePath) {
568
+ throw new Error(`Missing "qwikRouterConfigModulePath" option`);
569
+ } else {
570
+ console.warn(
571
+ "`qwikCityPlanModulePath` is deprecated. Use `qwikRouterConfigModulePath` instead."
572
+ );
573
+ }
574
+ }
575
+ if (!opts.renderModulePath) {
576
+ throw new Error(`Missing "renderModulePath" option`);
577
+ }
578
+ let siteOrigin = opts.origin;
579
+ if (typeof siteOrigin !== "string" || siteOrigin.trim().length === 0) {
580
+ throw new Error(`Missing "origin" option`);
581
+ }
582
+ siteOrigin = siteOrigin.trim();
583
+ if (!/:\/\//.test(siteOrigin) || siteOrigin.startsWith("://")) {
584
+ throw new Error(
585
+ `"origin" must start with a valid protocol, such as "https://" or "http://", received "${siteOrigin}"`
586
+ );
587
+ }
588
+ try {
589
+ new URL(siteOrigin);
590
+ } catch (e) {
591
+ throw new Error(`Invalid "origin"`, { cause: e });
592
+ }
593
+ }
594
+ async function workerThread(sys) {
595
+ delete globalThis.__qwik;
596
+ const ssgOpts = sys.getOptions();
597
+ const pendingPromises = /* @__PURE__ */ new Set();
598
+ const log = await sys.createLogger();
599
+ const opts = {
600
+ ...ssgOpts,
601
+ // TODO export this from server
602
+ render: (await import(pathToFileURL(ssgOpts.renderModulePath).href)).default,
603
+ // TODO this should be built-in
604
+ qwikRouterConfig: (await import(pathToFileURL(ssgOpts.qwikRouterConfigModulePath).href)).default
605
+ };
606
+ sys.createWorkerProcess(async (msg) => {
607
+ switch (msg.type) {
608
+ case "render": {
609
+ log.debug(`Worker thread rendering: ${msg.pathname}`);
610
+ return new Promise((resolve2) => {
611
+ workerRender(sys, opts, msg, pendingPromises, resolve2).catch((e) => {
612
+ console.error("Error during render", msg.pathname, e);
613
+ });
614
+ });
615
+ }
616
+ case "close": {
617
+ if (pendingPromises.size) {
618
+ log.debug(`Worker thread closing, waiting for ${pendingPromises.size} pending renders`);
619
+ const promises = Array.from(pendingPromises);
620
+ pendingPromises.clear();
621
+ await Promise.all(promises);
622
+ }
623
+ log.debug(`Worker thread closed`);
624
+ return { type: "close" };
625
+ }
626
+ }
627
+ })?.catch((e) => {
628
+ console.error("Worker process creation failed", e);
629
+ });
630
+ }
631
+ async function workerRender(sys, opts, staticRoute, pendingPromises, callback) {
632
+ const url = new URL(staticRoute.pathname, opts.origin);
633
+ const result = {
634
+ type: "render",
635
+ pathname: staticRoute.pathname,
636
+ url: url.href,
637
+ ok: false,
638
+ error: null,
639
+ filePath: null,
640
+ contentType: null,
641
+ resourceType: null
642
+ };
643
+ try {
644
+ let routeWriter = null;
645
+ let closeResolved;
646
+ const closePromise = new Promise((closePromiseResolve) => {
647
+ closeResolved = closePromiseResolve;
648
+ });
649
+ const request = new Request(url);
650
+ const requestCtx = {
651
+ mode: "static",
652
+ locale: void 0,
653
+ url,
654
+ request,
655
+ env: {
656
+ get(key) {
657
+ return sys.getEnv(key);
658
+ }
659
+ },
660
+ platform: sys.platform,
661
+ getClientConn: () => {
662
+ return {};
663
+ },
664
+ getWritableStream: (status, headers, _, _r, requestEv) => {
665
+ result.ok = status >= 200 && status < 300;
666
+ if (!result.ok) {
667
+ return noopWritableStream;
668
+ }
669
+ result.contentType = (headers.get("Content-Type") || "").toLowerCase();
670
+ const isHtml = result.contentType.includes("text/html");
671
+ const is404ErrorPage = url.pathname.endsWith("/404.html");
672
+ const routeFilePath = sys.getRouteFilePath(url.pathname, isHtml);
673
+ if (is404ErrorPage) {
674
+ result.resourceType = "404";
675
+ } else if (isHtml) {
676
+ result.resourceType = "page";
677
+ }
678
+ const hasRouteWriter = isHtml ? opts.emitHtml !== false : true;
679
+ const writeQDataEnabled = isHtml && opts.emitData !== false;
680
+ const stream = new WritableStream({
681
+ async start() {
682
+ try {
683
+ if (hasRouteWriter || writeQDataEnabled) {
684
+ await sys.ensureDir(routeFilePath);
685
+ }
686
+ if (hasRouteWriter) {
687
+ routeWriter = sys.createWriteStream(routeFilePath);
688
+ routeWriter.on("error", (e) => {
689
+ console.error(e);
690
+ routeWriter = null;
691
+ result.error = {
692
+ message: e.message,
693
+ stack: e.stack
694
+ };
695
+ });
696
+ }
697
+ } catch (e) {
698
+ console.error("Error during stream start", staticRoute.pathname, e);
699
+ routeWriter = null;
700
+ result.error = {
701
+ message: String(e),
702
+ stack: e.stack || ""
703
+ };
704
+ }
705
+ },
706
+ write(chunk) {
707
+ try {
708
+ if (routeWriter) {
709
+ routeWriter.write(Buffer.from(chunk.buffer));
710
+ }
711
+ } catch (e) {
712
+ console.error("Error during stream write", staticRoute.pathname, e);
713
+ routeWriter = null;
714
+ result.error = {
715
+ message: String(e),
716
+ stack: e.stack || ""
717
+ };
718
+ }
719
+ },
720
+ async close() {
721
+ const writePromises = [];
722
+ try {
723
+ if (writeQDataEnabled) {
724
+ const qData = requestEv.sharedMap.get(RequestEvShareQData);
725
+ if (qData && !is404ErrorPage) {
726
+ const qDataFilePath = sys.getDataFilePath(url.pathname);
727
+ const dataWriter = sys.createWriteStream(qDataFilePath);
728
+ dataWriter.on("error", (e) => {
729
+ console.error(e);
730
+ result.error = {
731
+ message: e.message,
732
+ stack: e.stack
733
+ };
734
+ });
735
+ const serialized = await _serialize([qData]);
736
+ dataWriter.write(serialized);
737
+ writePromises.push(
738
+ new Promise((resolve2) => {
739
+ result.filePath = routeFilePath;
740
+ dataWriter.end(resolve2);
741
+ })
742
+ );
743
+ }
744
+ }
745
+ if (routeWriter) {
746
+ writePromises.push(
747
+ new Promise((resolve2) => {
748
+ result.filePath = routeFilePath;
749
+ routeWriter.end(resolve2);
750
+ }).finally(closeResolved)
751
+ );
752
+ }
753
+ if (writePromises.length > 0) {
754
+ await Promise.all(writePromises);
755
+ }
756
+ } catch (e) {
757
+ console.error("Error during stream close", staticRoute.pathname, e);
758
+ routeWriter = null;
759
+ result.error = {
760
+ message: String(e),
761
+ stack: e.stack || ""
762
+ };
763
+ }
764
+ }
765
+ });
766
+ return stream;
767
+ }
768
+ };
769
+ const promise = requestHandler(requestCtx, opts).then((rsp) => {
770
+ if (rsp != null) {
771
+ return rsp.completion.then((r) => {
772
+ if (routeWriter) {
773
+ return closePromise.then(() => r);
774
+ }
775
+ return r;
776
+ });
777
+ }
778
+ }).then((e) => {
779
+ if (e !== void 0) {
780
+ if (e instanceof RedirectMessage) {
781
+ return;
782
+ }
783
+ if (e instanceof Error) {
784
+ result.error = {
785
+ message: e.message,
786
+ stack: e.stack
787
+ };
788
+ } else {
789
+ result.error = {
790
+ message: String(e),
791
+ stack: void 0
792
+ };
793
+ }
794
+ console.error("Error during request handling", staticRoute.pathname, e);
795
+ }
796
+ }).catch((e) => {
797
+ console.error("Unhandled error during request handling", staticRoute.pathname, e);
798
+ result.error = {
799
+ message: String(e),
800
+ stack: e.stack || ""
801
+ };
802
+ }).finally(() => {
803
+ pendingPromises.delete(promise);
804
+ callback(result);
805
+ });
806
+ pendingPromises.add(promise);
807
+ } catch (e) {
808
+ console.error("Error during render", staticRoute.pathname, e);
809
+ if (e instanceof Error) {
810
+ result.error = {
811
+ message: e.message,
812
+ stack: e.stack
813
+ };
814
+ } else {
815
+ result.error = {
816
+ message: String(e),
817
+ stack: void 0
818
+ };
819
+ }
820
+ callback(result);
821
+ }
822
+ }
823
+ const noopWriter = {
824
+ closed: Promise.resolve(void 0),
825
+ ready: Promise.resolve(void 0),
826
+ desiredSize: 0,
827
+ async close() {
828
+ },
829
+ async abort() {
830
+ },
831
+ async write() {
832
+ },
833
+ releaseLock() {
834
+ }
835
+ };
836
+ const noopWritableStream = {
837
+ get locked() {
838
+ return false;
839
+ },
840
+ set locked(_) {
841
+ },
842
+ async abort() {
843
+ },
844
+ async close() {
845
+ },
846
+ getWriter() {
847
+ return noopWriter;
848
+ }
849
+ };
850
+ async function generate(opts) {
851
+ if (isMainThread) {
852
+ const sys = await createSystem(opts);
853
+ const result = await mainThread(sys);
854
+ return result;
855
+ }
856
+ throw new Error(`generate() cannot be called from a worker thread`);
857
+ }
858
+ if (!isMainThread && workerData) {
859
+ const opts = workerData;
860
+ (async () => {
861
+ try {
862
+ if (opts.log === "debug") {
863
+ console.debug(`Worker thread starting (ID: ${threadId})`);
864
+ }
865
+ const sys = await createSystem(opts, threadId);
866
+ await workerThread(sys);
867
+ } catch (error) {
868
+ console.error(`Error occurred in worker thread (ID: ${threadId}): ${error}`);
869
+ }
870
+ })().catch((e) => {
871
+ console.error(e);
872
+ });
873
+ }
874
+ export {
875
+ generate
876
+ };