@qwik.dev/router 2.0.0-beta.39 → 2.0.0-beta.40

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 (40) hide show
  1. package/lib/adapters/azure-swa/vite/index.mjs +45 -54
  2. package/lib/adapters/bun-server/vite/index.mjs +16 -22
  3. package/lib/adapters/cloud-run/vite/index.mjs +15 -19
  4. package/lib/adapters/cloudflare-pages/vite/index.mjs +46 -67
  5. package/lib/adapters/deno-server/vite/index.mjs +25 -39
  6. package/lib/adapters/netlify-edge/vite/index.mjs +50 -76
  7. package/lib/adapters/node-server/vite/index.mjs +16 -22
  8. package/lib/adapters/shared/vite/index.mjs +271 -360
  9. package/lib/adapters/ssg/vite/index.mjs +11 -15
  10. package/lib/adapters/vercel-edge/vite/index.mjs +74 -95
  11. package/lib/chunks/dev-preloaded-route-loader.mjs +2 -3
  12. package/lib/chunks/format.mjs +16 -23
  13. package/lib/chunks/fs.mjs +93 -106
  14. package/lib/chunks/head.qwik.mjs +1174 -1382
  15. package/lib/chunks/http-error.qwik.mjs +20 -28
  16. package/lib/chunks/pathname.mjs +50 -69
  17. package/lib/chunks/request-body-limit.mjs +25 -35
  18. package/lib/chunks/request-path.mjs +44 -55
  19. package/lib/chunks/routes.mjs +20 -41
  20. package/lib/chunks/server-error.mjs +15 -18
  21. package/lib/chunks/system.mjs +258 -326
  22. package/lib/chunks/url.mjs +56 -58
  23. package/lib/chunks/user-response.mjs +1616 -1804
  24. package/lib/chunks/worker-thread.mjs +254 -307
  25. package/lib/index.qwik.mjs +1637 -1918
  26. package/lib/middleware/aws-lambda/index.mjs +44 -52
  27. package/lib/middleware/azure-swa/index.mjs +85 -94
  28. package/lib/middleware/bun/index.mjs +118 -138
  29. package/lib/middleware/cloudflare-pages/index.mjs +83 -96
  30. package/lib/middleware/deno/index.mjs +104 -125
  31. package/lib/middleware/firebase/index.mjs +21 -25
  32. package/lib/middleware/netlify-edge/index.mjs +63 -71
  33. package/lib/middleware/node/index.mjs +297 -357
  34. package/lib/middleware/request-handler/index.mjs +110 -133
  35. package/lib/middleware/vercel-edge/index.mjs +82 -98
  36. package/lib/service-worker/index.mjs +12 -3
  37. package/lib/ssg/index.mjs +249 -289
  38. package/lib/vite/index.mjs +2344 -3030
  39. package/package.json +5 -5
  40. package/lib/chunks/use-functions.qwik.mjs +0 -23
@@ -1,367 +1,278 @@
1
- import { spawn } from 'node:child_process';
2
- import { readFile, unlink, rm } from 'node:fs/promises';
3
- import { join, resolve, dirname, basename } from 'node:path';
4
- import fs from 'node:fs';
5
- import { L as LOADER_REGEX } from '../../../chunks/request-path.mjs';
6
- import { e as ensureSlash } from '../../../chunks/pathname.mjs';
7
-
1
+ import { t as ensureSlash } from "../../../chunks/pathname.mjs";
2
+ import { r as LOADER_REGEX } from "../../../chunks/request-path.mjs";
3
+ import fs from "node:fs";
4
+ import { basename, dirname, join, resolve } from "node:path";
5
+ import { spawn } from "node:child_process";
6
+ import { readFile, rm, unlink } from "node:fs/promises";
8
7
  function createStaticPathsCode(staticPaths) {
9
- return JSON.stringify(Array.from(new Set(staticPaths)).sort()).slice(1, -1);
8
+ return JSON.stringify(Array.from(new Set(staticPaths)).sort()).slice(1, -1);
10
9
  }
11
- const injectStatics = async (staticPathsCode, outDir) => {
12
- const promises = /* @__PURE__ */ new Set();
13
- const doReplace = async (path) => {
14
- const code = await fs.promises.readFile(path, "utf-8");
15
- let replaced = false;
16
- const newCode = code.replace(/(['"])__QWIK_ROUTER_STATIC_PATHS_ARRAY__\1/g, () => {
17
- replaced = true;
18
- return staticPathsCode;
19
- });
20
- if (replaced) {
21
- await fs.promises.writeFile(path, newCode);
22
- }
23
- };
24
- const walk = async (dir) => {
25
- const entries = await fs.promises.readdir(dir, {
26
- withFileTypes: true
27
- });
28
- for (const entry of entries) {
29
- if (entry.isDirectory()) {
30
- await walk(join(dir, entry.name));
31
- } else if (entry.name.endsWith("js")) {
32
- const p = doReplace(join(dir, entry.name)).finally(() => {
33
- promises.delete(p);
34
- });
35
- promises.add(p);
36
- }
37
- }
38
- };
39
- await walk(outDir);
40
- await Promise.all(promises);
10
+ var injectStatics = async (staticPathsCode, outDir) => {
11
+ const promises = /* @__PURE__ */ new Set();
12
+ const doReplace = async (path) => {
13
+ const code = await fs.promises.readFile(path, "utf-8");
14
+ let replaced = false;
15
+ const newCode = code.replace(/(['"`])__QWIK_ROUTER_STATIC_PATHS_ARRAY__\1/g, () => {
16
+ replaced = true;
17
+ return staticPathsCode;
18
+ });
19
+ if (replaced) await fs.promises.writeFile(path, newCode);
20
+ };
21
+ const walk = async (dir) => {
22
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
23
+ for (const entry of entries) if (entry.isDirectory()) await walk(join(dir, entry.name));
24
+ else if (entry.name.endsWith("js")) {
25
+ const p = doReplace(join(dir, entry.name)).finally(() => {
26
+ promises.delete(p);
27
+ });
28
+ promises.add(p);
29
+ }
30
+ };
31
+ await walk(outDir);
32
+ await Promise.all(promises);
41
33
  };
42
- async function postBuild(clientOutDir, serverOutDir, pathName, userStaticPaths, cleanStatic) {
43
- if (pathName && !pathName.endsWith("/")) {
44
- pathName = ensureSlash(pathName);
45
- }
46
- const pathNameBase = pathName || "/";
47
- const ignorePathnames = /* @__PURE__ */ new Set([
48
- pathNameBase + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/",
49
- pathNameBase + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/"
50
- ]);
51
- const staticPaths = new Set(userStaticPaths.map(ensureSlash));
52
- const loadItem = async (fsDir, fsName, pathname) => {
53
- pathname = ensureSlash(pathname);
54
- if (ignorePathnames.has(pathname)) {
55
- return;
56
- }
57
- const fsPath = join(fsDir, fsName);
58
- if (fsName === "index.html") {
59
- if (!staticPaths.has(pathname) && cleanStatic) {
60
- await fs.promises.unlink(fsPath);
61
- }
62
- return;
63
- }
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
- }
70
- return;
71
- }
72
- const stat = await fs.promises.stat(fsPath);
73
- if (stat.isDirectory()) {
74
- await loadDir(fsPath, ensureSlash(pathname + fsName));
75
- } else if (stat.isFile()) {
76
- staticPaths.add(pathname + fsName);
77
- }
78
- };
79
- const loadDir = async (fsDir, pathname) => {
80
- const itemNames = await fs.promises.readdir(fsDir);
81
- await Promise.all(itemNames.map((i) => loadItem(fsDir, i, pathname)));
82
- };
83
- if (fs.existsSync(clientOutDir)) {
84
- await loadDir(clientOutDir, pathName);
85
- }
86
- const staticPathsCode = createStaticPathsCode(staticPaths);
87
- await injectStatics(staticPathsCode, serverOutDir);
34
+ /** Cleans the client output SSG results if needed and injects the SSG metadata into the build output */ async function postBuild(clientOutDir, serverOutDir, pathName, userStaticPaths, cleanStatic) {
35
+ if (pathName && !pathName.endsWith("/")) pathName = ensureSlash(pathName);
36
+ const pathNameBase = pathName || "/";
37
+ const ignorePathnames = /* @__PURE__ */ new Set([pathNameBase + (globalThis.__QWIK_BUILD_DIR__ || "build") + "/", pathNameBase + (globalThis.__QWIK_ASSETS_DIR__ || "assets") + "/"]);
38
+ const staticPaths = new Set(userStaticPaths.map(ensureSlash));
39
+ const loadItem = async (fsDir, fsName, pathname) => {
40
+ pathname = ensureSlash(pathname);
41
+ if (ignorePathnames.has(pathname)) return;
42
+ const fsPath = join(fsDir, fsName);
43
+ if (fsName === "index.html") {
44
+ if (!staticPaths.has(pathname) && cleanStatic) await fs.promises.unlink(fsPath);
45
+ return;
46
+ }
47
+ if (LOADER_REGEX.test("/" + fsName)) {
48
+ if (staticPaths.has(pathname)) staticPaths.add(pathname + fsName);
49
+ else if (cleanStatic) await fs.promises.unlink(fsPath);
50
+ return;
51
+ }
52
+ const stat = await fs.promises.stat(fsPath);
53
+ if (stat.isDirectory()) await loadDir(fsPath, ensureSlash(pathname + fsName));
54
+ else if (stat.isFile()) staticPaths.add(pathname + fsName);
55
+ };
56
+ const loadDir = async (fsDir, pathname) => {
57
+ const itemNames = await fs.promises.readdir(fsDir);
58
+ await Promise.all(itemNames.map((i) => loadItem(fsDir, i, pathname)));
59
+ };
60
+ if (fs.existsSync(clientOutDir)) await loadDir(clientOutDir, pathName);
61
+ await injectStatics(createStaticPathsCode(staticPaths), serverOutDir);
88
62
  }
89
-
90
- const QWIK_SSG_ENTRY_ID = "@qwik-ssg-entry";
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";
94
- function viteAdapter(opts) {
95
- let qwikRouterPlugin = null;
96
- let qwikVitePlugin = null;
97
- let viteCommand;
98
- let buildAppRan = false;
99
- const outputEntries = [];
100
- const ssgOutDirFor = (root) => join(resolve(root), "node_modules", ".cache", `qwik-router-ssg-${process.pid}`);
101
- const plugin = {
102
- name: `vite-plugin-qwik-router-ssg-${opts.name}`,
103
- enforce: "post",
104
- apply: "build",
105
- config(config) {
106
- if (typeof opts.config === "function") {
107
- config = opts.config(config);
108
- }
109
- config.define = {
110
- "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production"),
111
- ...config.define
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
- }
134
- return config;
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
- },
147
- configResolved(config) {
148
- viteCommand = config.command;
149
- qwikRouterPlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik-router");
150
- if (!qwikRouterPlugin) {
151
- throw new Error("Missing vite-plugin-qwik-router");
152
- }
153
- qwikRouterPlugin.api?._setSsgRoutes?.(opts.ssg?.include, opts.ssg?.exclude);
154
- qwikVitePlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik");
155
- if (!qwikVitePlugin) {
156
- throw new Error("Missing vite-plugin-qwik");
157
- }
158
- },
159
- resolveId(id) {
160
- if (id === QWIK_SSG_ENTRY_ID) {
161
- return QWIK_SSG_ENTRY_RESOLVED;
162
- }
163
- if (id === QWIK_SSG_WORKER_ENTRY_ID) {
164
- return QWIK_SSG_WORKER_ENTRY_RESOLVED;
165
- }
166
- },
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
- }
182
- if (id !== QWIK_SSG_ENTRY_RESOLVED) {
183
- return;
184
- }
185
- const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
186
- const basePathname = qwikRouterPlugin.api.getBasePathname();
187
- const rootDir = qwikVitePlugin.api.getRootDir() ?? void 0;
188
- let ssgOrigin = opts.ssg?.origin ?? opts.origin;
189
- if (!ssgOrigin) {
190
- ssgOrigin = `https://yoursite.qwik.dev`;
191
- }
192
- if (ssgOrigin.length > 0 && !/:\/\//.test(ssgOrigin)) {
193
- ssgOrigin = `https://${ssgOrigin}`;
194
- }
195
- if (ssgOrigin.startsWith("//")) {
196
- ssgOrigin = `https:${ssgOrigin}`;
197
- }
198
- try {
199
- ssgOrigin = new URL(ssgOrigin).origin;
200
- } catch {
201
- this.warn(`Invalid "origin" option: "${ssgOrigin}". Using default origin: "https://yoursite.qwik.dev"`);
202
- ssgOrigin = `https://yoursite.qwik.dev`;
203
- }
204
- const ssgOpts = {
205
- origin: ssgOrigin,
206
- outDir: clientPublicOutDir,
207
- basePathname,
208
- rootDir,
209
- ...opts.ssg,
210
- maxWorkers: opts.maxWorkers
211
- };
212
- for (const key of Object.keys(ssgOpts)) {
213
- if (ssgOpts[key] === void 0) {
214
- delete ssgOpts[key];
215
- }
216
- }
217
- return [
218
- `import qwikRouterConfig from '@qwik-router-config';`,
219
- `import { runSsg } from '@qwik.dev/router/ssg';`,
220
- ``,
221
- `const ssgOpts = ${JSON.stringify(ssgOpts)};`,
222
- ``,
223
- `// Parse --quiet / --debug CLI flags`,
224
- `const args = process.argv.slice(2);`,
225
- `if (args.includes('--quiet')) ssgOpts.log = 'quiet';`,
226
- `if (args.includes('--debug')) ssgOpts.log = 'debug';`,
227
- ``,
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) => {`,
234
- ` console.error(err);`,
235
- ` process.exit(1);`,
236
- `});`
237
- ].join("\n");
238
- },
239
- buildStart() {
240
- if (this.environment.name === "ssg" && viteCommand === "build") {
241
- this.emitFile({
242
- id: QWIK_SSG_ENTRY_ID,
243
- type: "chunk",
244
- fileName: "run-ssg.js"
245
- });
246
- this.emitFile({
247
- id: QWIK_SSG_WORKER_ENTRY_ID,
248
- type: "chunk",
249
- fileName: "run-ssg-worker.js"
250
- });
251
- }
252
- },
253
- generateBundle(_, bundles) {
254
- if (this.environment.name === "ssr") {
255
- outputEntries.length = 0;
256
- for (const fileName in bundles) {
257
- const chunk = bundles[fileName];
258
- if (chunk.type === "chunk" && chunk.isEntry) {
259
- outputEntries.push(fileName);
260
- }
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
- }
265
- }
266
- },
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"
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);
338
- }
339
- });
340
- }
341
- log.warn(`
342
- ==============================================
343
- Note: Make sure that you are serving the built files with proper cache headers.
344
- See https://qwik.dev/docs/deployments/#cache-headers for more information.
345
- ==============================================`);
346
- }
347
- };
348
- return [
349
- plugin
350
- ];
63
+ /**
64
+ * Implements the SSG after the build is complete. Also provides a `generate(...)` callback that is
65
+ * called after the SSG is complete, which allows for custom post-processing of the complete build
66
+ * results.
67
+ *
68
+ * @public
69
+ */ var QWIK_SSG_ENTRY_ID = "@qwik-ssg-entry";
70
+ var QWIK_SSG_ENTRY_RESOLVED = "\0@qwik-ssg-entry";
71
+ var QWIK_SSG_WORKER_ENTRY_ID = "@qwik-ssg-worker-entry";
72
+ var QWIK_SSG_WORKER_ENTRY_RESOLVED = "\0@qwik-ssg-worker-entry";
73
+ /** @public */ function viteAdapter(opts) {
74
+ let qwikRouterPlugin = null;
75
+ let qwikVitePlugin = null;
76
+ let viteCommand;
77
+ let buildAppRan = false;
78
+ const outputEntries = [];
79
+ const ssgOutDirFor = (root) => join(resolve(root), "node_modules", ".cache", `qwik-router-ssg-${process.pid}`);
80
+ return [{
81
+ name: `vite-plugin-qwik-router-ssg-${opts.name}`,
82
+ enforce: "post",
83
+ apply: "build",
84
+ config(config) {
85
+ if (typeof opts.config === "function") config = opts.config(config);
86
+ config.define = {
87
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production"),
88
+ ...config.define
89
+ };
90
+ config.builder ??= {};
91
+ if (opts.ssg !== null) config.environments = {
92
+ ...config.environments,
93
+ ssg: {
94
+ consumer: "server",
95
+ build: {
96
+ ssr: true,
97
+ outDir: ssgOutDirFor(config.root ?? process.cwd()),
98
+ emptyOutDir: true,
99
+ minify: false,
100
+ sourcemap: false
101
+ }
102
+ }
103
+ };
104
+ return config;
105
+ },
106
+ configEnvironment(name, environmentOptions) {
107
+ if (name === "ssg") environmentOptions.build = {
108
+ ...environmentOptions.build,
109
+ rolldownOptions: {
110
+ ...environmentOptions.build?.rolldownOptions,
111
+ input: {}
112
+ }
113
+ };
114
+ },
115
+ configResolved(config) {
116
+ viteCommand = config.command;
117
+ qwikRouterPlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik-router");
118
+ if (!qwikRouterPlugin) throw new Error("Missing vite-plugin-qwik-router");
119
+ qwikRouterPlugin.api?._setSsgRoutes?.(opts.ssg?.include, opts.ssg?.exclude);
120
+ qwikVitePlugin = config.plugins.find((p) => p.name === "vite-plugin-qwik");
121
+ if (!qwikVitePlugin) throw new Error("Missing vite-plugin-qwik");
122
+ },
123
+ resolveId(id) {
124
+ if (id === QWIK_SSG_ENTRY_ID) return QWIK_SSG_ENTRY_RESOLVED;
125
+ if (id === QWIK_SSG_WORKER_ENTRY_ID) return QWIK_SSG_WORKER_ENTRY_RESOLVED;
126
+ },
127
+ load(id) {
128
+ if (id === QWIK_SSG_WORKER_ENTRY_RESOLVED) {
129
+ const { srcDir } = qwikVitePlugin.api.getOptions();
130
+ return [
131
+ `import render from '${srcDir}/entry.ssr';`,
132
+ `import qwikRouterConfig from '@qwik-router-config';`,
133
+ `import { startWorker } from '@qwik.dev/router/ssg';`,
134
+ `startWorker({ render, qwikRouterConfig }).catch((err) => {`,
135
+ ` console.error(err);`,
136
+ ` process.exit(1);`,
137
+ `});`
138
+ ].join("\n");
139
+ }
140
+ if (id !== QWIK_SSG_ENTRY_RESOLVED) return;
141
+ const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
142
+ const basePathname = qwikRouterPlugin.api.getBasePathname();
143
+ const rootDir = qwikVitePlugin.api.getRootDir() ?? void 0;
144
+ let ssgOrigin = opts.ssg?.origin ?? opts.origin;
145
+ if (!ssgOrigin) ssgOrigin = `https://yoursite.qwik.dev`;
146
+ if (ssgOrigin.length > 0 && !/:\/\//.test(ssgOrigin)) ssgOrigin = `https://${ssgOrigin}`;
147
+ if (ssgOrigin.startsWith("//")) ssgOrigin = `https:${ssgOrigin}`;
148
+ try {
149
+ ssgOrigin = new URL(ssgOrigin).origin;
150
+ } catch {
151
+ this.warn(`Invalid "origin" option: "${ssgOrigin}". Using default origin: "https://yoursite.qwik.dev"`);
152
+ ssgOrigin = `https://yoursite.qwik.dev`;
153
+ }
154
+ const ssgOpts = {
155
+ origin: ssgOrigin,
156
+ outDir: clientPublicOutDir,
157
+ basePathname,
158
+ rootDir,
159
+ ...opts.ssg,
160
+ maxWorkers: opts.maxWorkers
161
+ };
162
+ for (const key of Object.keys(ssgOpts)) if (ssgOpts[key] === void 0) delete ssgOpts[key];
163
+ return [
164
+ `import qwikRouterConfig from '@qwik-router-config';`,
165
+ `import { runSsg } from '@qwik.dev/router/ssg';`,
166
+ ``,
167
+ `const ssgOpts = ${JSON.stringify(ssgOpts)};`,
168
+ ``,
169
+ `// Parse --quiet / --debug CLI flags`,
170
+ `const args = process.argv.slice(2);`,
171
+ `if (args.includes('--quiet')) ssgOpts.log = 'quiet';`,
172
+ `if (args.includes('--debug')) ssgOpts.log = 'debug';`,
173
+ ``,
174
+ `runSsg({`,
175
+ ` qwikRouterConfig,`,
176
+ ` workerFilePath: new URL('./run-ssg-worker.js', import.meta.url).href,`,
177
+ ` ...ssgOpts,`,
178
+ `}).catch((err) => {`,
179
+ ` console.error(err);`,
180
+ ` process.exit(1);`,
181
+ `});`
182
+ ].join("\n");
183
+ },
184
+ buildStart() {
185
+ if (this.environment.name === "ssg" && viteCommand === "build") {
186
+ this.emitFile({
187
+ id: QWIK_SSG_ENTRY_ID,
188
+ type: "chunk",
189
+ fileName: "run-ssg.js"
190
+ });
191
+ this.emitFile({
192
+ id: QWIK_SSG_WORKER_ENTRY_ID,
193
+ type: "chunk",
194
+ fileName: "run-ssg-worker.js"
195
+ });
196
+ }
197
+ },
198
+ generateBundle(_, bundles) {
199
+ if (this.environment.name === "ssr") {
200
+ outputEntries.length = 0;
201
+ for (const fileName in bundles) {
202
+ const chunk = bundles[fileName];
203
+ if (chunk.type === "chunk" && chunk.isEntry) outputEntries.push(fileName);
204
+ }
205
+ if (opts.ssg !== null && viteCommand === "build" && !buildAppRan) 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).");
206
+ }
207
+ },
208
+ async buildApp(builder) {
209
+ buildAppRan = true;
210
+ const ssr = builder.environments.ssr;
211
+ if (ssr) await builder.build(ssr);
212
+ const serverOutDir = ssr?.config.build.outDir;
213
+ if (!serverOutDir || !qwikRouterPlugin?.api || !qwikVitePlugin?.api) return;
214
+ const log = builder.config.logger;
215
+ const staticPaths = opts.staticPaths || [];
216
+ const routes = qwikRouterPlugin.api.getRoutes();
217
+ const basePathname = qwikRouterPlugin.api.getBasePathname();
218
+ const clientOutDir = qwikVitePlugin.api.getClientOutDir();
219
+ const clientPublicOutDir = qwikVitePlugin.api.getClientPublicOutDir();
220
+ const ssgEnv = builder.environments.ssg;
221
+ const ssgOutDir = ssgOutDirFor(builder.config.root);
222
+ if (ssgEnv && clientOutDir && clientPublicOutDir) {
223
+ await builder.build(ssgEnv);
224
+ const runSsgPath = join(ssgOutDir, "run-ssg.js");
225
+ if (await new Promise((res, reject) => {
226
+ const child = spawn(process.execPath, [runSsgPath], {
227
+ stdio: [
228
+ "ignore",
229
+ "inherit",
230
+ "inherit"
231
+ ],
232
+ env: {
233
+ ...process.env,
234
+ NODE_ENV: process.env.NODE_ENV || "production"
235
+ }
236
+ });
237
+ child.on("close", res);
238
+ child.on("error", reject);
239
+ }) !== 0) throw new Error(`Error while running SSG from "${opts.name}" adapter. At least one path failed to render.`);
240
+ const staticPathsFile = join(clientPublicOutDir, "_static-paths.json");
241
+ try {
242
+ staticPaths.push(...JSON.parse(await readFile(staticPathsFile, "utf-8")));
243
+ await unlink(staticPathsFile);
244
+ } catch {}
245
+ if (process.env.QWIK_ROUTER_KEEP_SSG_BUILD) log.warn(`SSG build kept at ${ssgOutDir}`);
246
+ else await rm(ssgOutDir, {
247
+ recursive: true,
248
+ force: true
249
+ });
250
+ }
251
+ await postBuild(clientPublicOutDir, serverOutDir, basePathname, staticPaths, !!opts.cleanStaticGenerated);
252
+ if (typeof opts.generate === "function") await opts.generate({
253
+ outputEntries,
254
+ serverOutDir,
255
+ clientOutDir,
256
+ clientPublicOutDir,
257
+ basePathname,
258
+ routes,
259
+ warn: (message) => log.warn(message),
260
+ error: (message) => {
261
+ throw new Error(message);
262
+ }
263
+ });
264
+ log.warn("\n==============================================\nNote: Make sure that you are serving the built files with proper cache headers.\nSee https://qwik.dev/docs/deployments/#cache-headers for more information.\n==============================================");
265
+ }
266
+ }];
351
267
  }
352
- function getParentDir(startDir, dirName) {
353
- const root = resolve("/");
354
- let dir = startDir;
355
- for (let i = 0; i < 20; i++) {
356
- dir = dirname(dir);
357
- if (basename(dir) === dirName) {
358
- return dir;
359
- }
360
- if (dir === root) {
361
- break;
362
- }
363
- }
364
- throw new Error(`Unable to find "${dirName}" directory from "${startDir}"`);
268
+ /** @public */ function getParentDir(startDir, dirName) {
269
+ const root = resolve("/");
270
+ let dir = startDir;
271
+ for (let i = 0; i < 20; i++) {
272
+ dir = dirname(dir);
273
+ if (basename(dir) === dirName) return dir;
274
+ if (dir === root) break;
275
+ }
276
+ throw new Error(`Unable to find "${dirName}" directory from "${startDir}"`);
365
277
  }
366
-
367
278
  export { getParentDir, viteAdapter };