@qwik.dev/router 2.0.0-beta.29 → 2.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/adapters/shared/vite/index.d.ts +1 -1
- package/lib/adapters/shared/vite/index.mjs +32 -3
- package/lib/chunks/deepFreeze.qwik.mjs +18 -0
- package/lib/chunks/http-error.qwik.mjs +14 -6
- package/lib/chunks/redirect-handler.mjs +6 -0
- package/lib/chunks/routing.qwik.mjs +52 -41
- package/lib/chunks/system.mjs +13 -8
- package/lib/chunks/worker-thread.qwik.mjs +2572 -0
- package/lib/index.qwik.mjs +70 -32
- package/lib/middleware/bun/index.mjs +3 -3
- package/lib/middleware/cloudflare-pages/index.mjs +3 -3
- package/lib/middleware/deno/index.mjs +3 -3
- package/lib/middleware/netlify-edge/index.mjs +3 -3
- package/lib/middleware/request-handler/index.d.ts +4 -15
- package/lib/middleware/request-handler/index.mjs +1190 -1049
- package/lib/middleware/vercel-edge/index.mjs +3 -3
- package/lib/ssg/index.d.ts +2 -2
- package/lib/ssg/index.mjs +32 -23
- package/lib/vite/index.mjs +162 -2
- package/package.json +4 -4
- package/lib/chunks/worker-thread.mjs +0 -271
|
@@ -68,9 +68,9 @@ function createQwikRouter(opts) {
|
|
|
68
68
|
};
|
|
69
69
|
const handledResponse = await requestHandler(serverRequestEv, opts);
|
|
70
70
|
if (handledResponse) {
|
|
71
|
-
handledResponse.completion.then((
|
|
72
|
-
if (
|
|
73
|
-
console.error(
|
|
71
|
+
handledResponse.completion.then((completion) => {
|
|
72
|
+
if (completion) {
|
|
73
|
+
console.error(completion);
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
const response = await handledResponse.response;
|
package/lib/ssg/index.d.ts
CHANGED
|
@@ -75,8 +75,8 @@ export declare interface SsgRenderOptions extends RenderOptions {
|
|
|
75
75
|
* root of the `outDir`. Setting to `null` will prevent the sitemap from being created.
|
|
76
76
|
*/
|
|
77
77
|
sitemapOutFile?: string | null;
|
|
78
|
-
/** Log level. */
|
|
79
|
-
log?: 'debug';
|
|
78
|
+
/** Log level. `'quiet'` suppresses per-page output, `'debug'` enables verbose logging. */
|
|
79
|
+
log?: 'debug' | 'quiet';
|
|
80
80
|
/**
|
|
81
81
|
* Set to `false` if the generated static HTML files should not be written to disk. Setting to
|
|
82
82
|
* `false` is useful if the SSG should only write the `q-data.json` files to disk. Defaults to
|
package/lib/ssg/index.mjs
CHANGED
|
@@ -78,6 +78,7 @@ async function mainThread(sys) {
|
|
|
78
78
|
const log = await sys.createLogger();
|
|
79
79
|
log.info("\n" + bold(green("Starting Qwik Router SSG...")));
|
|
80
80
|
const qwikRouterConfig = opts.qwikRouterConfig;
|
|
81
|
+
const renderTimeout = 3e4;
|
|
81
82
|
const queue = [];
|
|
82
83
|
const active = /* @__PURE__ */ new Set();
|
|
83
84
|
const routes = qwikRouterConfig.routes;
|
|
@@ -143,11 +144,16 @@ ${green("SSG results")}`);
|
|
|
143
144
|
const render = async (staticRoute) => {
|
|
144
145
|
try {
|
|
145
146
|
active.add(staticRoute.pathname);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
log.debug(`render start: ${staticRoute.pathname}`);
|
|
148
|
+
const result = await Promise.race([
|
|
149
|
+
main.render({
|
|
150
|
+
type: "render",
|
|
151
|
+
...staticRoute
|
|
152
|
+
}),
|
|
153
|
+
new Promise((_, reject2) => setTimeout(() => reject2(new Error(`SSG render timed out after ${renderTimeout}ms`)), renderTimeout))
|
|
154
|
+
]);
|
|
150
155
|
active.delete(staticRoute.pathname);
|
|
156
|
+
log.debug(`render done: ${staticRoute.pathname}`);
|
|
151
157
|
if (result.error) {
|
|
152
158
|
const err = new Error(result.error.message);
|
|
153
159
|
err.stack = result.error.stack;
|
|
@@ -216,26 +222,28 @@ ${bold(red(`!!! ${result.pathname}: Error during SSG`))}`);
|
|
|
216
222
|
const joinedParts = pathParts.join("/");
|
|
217
223
|
const originalPathname = basePathname + (joinedParts ? joinedParts + "/" : "");
|
|
218
224
|
const paramNames = pathParts.filter((p) => p.startsWith("[") && p.endsWith("]")).map((p) => p.startsWith("[...") ? p.slice(4, -1) : p.slice(1, -1));
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
if (paramNames.length === 0) {
|
|
226
|
+
addToQueue(originalPathname, void 0);
|
|
227
|
+
} else {
|
|
228
|
+
const pageLoader = pageLoaders[pageLoaders.length - 1];
|
|
229
|
+
if (typeof pageLoader === "function") {
|
|
230
|
+
const pageModule = await pageLoader();
|
|
231
|
+
if (typeof pageModule.onStaticGenerate === "function") {
|
|
232
|
+
const staticGenerate = await pageModule.onStaticGenerate({
|
|
233
|
+
env: {
|
|
234
|
+
get(key) {
|
|
235
|
+
return sys.getEnv(key);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
if (Array.isArray(staticGenerate.params)) {
|
|
240
|
+
for (const params of staticGenerate.params) {
|
|
241
|
+
const pathname = getPathnameForDynamicRoute(originalPathname, paramNames, params);
|
|
242
|
+
addToQueue(pathname, params);
|
|
227
243
|
}
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
if (Array.isArray(staticGenerate.params)) {
|
|
231
|
-
for (const params of staticGenerate.params) {
|
|
232
|
-
const pathname = getPathnameForDynamicRoute(originalPathname, paramNames, params);
|
|
233
|
-
addToQueue(pathname, params);
|
|
234
244
|
}
|
|
235
245
|
}
|
|
236
246
|
}
|
|
237
|
-
} else {
|
|
238
|
-
addToQueue(originalPathname, void 0);
|
|
239
247
|
}
|
|
240
248
|
}
|
|
241
249
|
if (node._M) {
|
|
@@ -273,8 +281,9 @@ ${bold(red(`!!! ${result.pathname}: Error during SSG`))}`);
|
|
|
273
281
|
}
|
|
274
282
|
};
|
|
275
283
|
const loadStaticRoutes = async () => {
|
|
276
|
-
|
|
277
|
-
await traverseRouteTree(routes, [],
|
|
284
|
+
log.debug("traversing route tree...");
|
|
285
|
+
await traverseRouteTree(routes, [], "/", []);
|
|
286
|
+
log.debug(`route tree traversed, ${queue.length} routes queued, ${active.size} active`);
|
|
278
287
|
isRoutesLoaded = true;
|
|
279
288
|
flushQueue();
|
|
280
289
|
};
|
|
@@ -319,7 +328,7 @@ async function startWorker(opts) {
|
|
|
319
328
|
qwikRouterConfig: opts.qwikRouterConfig
|
|
320
329
|
};
|
|
321
330
|
const { createSystem } = await import('../chunks/system.mjs');
|
|
322
|
-
const { workerThread } = await import('../chunks/worker-thread.mjs');
|
|
331
|
+
const { workerThread } = await import('../chunks/worker-thread.qwik.mjs');
|
|
323
332
|
const sys = await createSystem(mergedOpts, workerData?.threadId);
|
|
324
333
|
await workerThread(sys);
|
|
325
334
|
}
|
package/lib/vite/index.mjs
CHANGED
|
@@ -638,9 +638,97 @@ function rewriteRoutes(ctx, routes) {
|
|
|
638
638
|
});
|
|
639
639
|
return translatedRoutes.sort(routeSortCompare);
|
|
640
640
|
}
|
|
641
|
+
function applyRewriteRoutes(root, rewriteConfigs) {
|
|
642
|
+
const routables = [];
|
|
643
|
+
function walk(node, steps) {
|
|
644
|
+
const hasRoute = node._files.some((f) => f.type === "route" && f.extlessName !== "error" && f.extlessName !== "404");
|
|
645
|
+
if (hasRoute) {
|
|
646
|
+
routables.push({
|
|
647
|
+
steps: [
|
|
648
|
+
...steps
|
|
649
|
+
],
|
|
650
|
+
node
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
for (const [key, child] of node.children) {
|
|
654
|
+
const isGroup = key.startsWith("(") && key.endsWith(")");
|
|
655
|
+
if (isGroup) {
|
|
656
|
+
walk(child, steps);
|
|
657
|
+
} else {
|
|
658
|
+
walk(child, [
|
|
659
|
+
...steps,
|
|
660
|
+
{
|
|
661
|
+
key,
|
|
662
|
+
paramName: child._P,
|
|
663
|
+
prefix: child._0,
|
|
664
|
+
suffix: child._9
|
|
665
|
+
}
|
|
666
|
+
]);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
walk(root, []);
|
|
671
|
+
for (const config of rewriteConfigs) {
|
|
672
|
+
const translations = config.paths || {};
|
|
673
|
+
const translatable = new Set(Object.keys(translations).map((k) => k.toLowerCase()));
|
|
674
|
+
for (const { steps } of routables) {
|
|
675
|
+
const hasTranslatable = steps.some((s) => translatable.has(s.key));
|
|
676
|
+
if (!hasTranslatable && !config.prefix) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if (steps.length === 0 && !config.prefix) {
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
const originalKeyPath = steps.map((s) => s.key).join("/");
|
|
683
|
+
const translatedSteps = [];
|
|
684
|
+
if (config.prefix) {
|
|
685
|
+
translatedSteps.push({
|
|
686
|
+
key: config.prefix.toLowerCase()
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
for (const step of steps) {
|
|
690
|
+
const translated = translations[step.key];
|
|
691
|
+
translatedSteps.push({
|
|
692
|
+
...step,
|
|
693
|
+
key: translated ? translated.toLowerCase() : step.key
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
const translatedKeyPath = translatedSteps.map((s) => s.key).join("/");
|
|
697
|
+
if (translatedKeyPath === originalKeyPath) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
let current = root;
|
|
701
|
+
for (const step of translatedSteps) {
|
|
702
|
+
let child = current.children.get(step.key);
|
|
703
|
+
if (!child) {
|
|
704
|
+
child = {
|
|
705
|
+
_files: [],
|
|
706
|
+
_dirPath: "",
|
|
707
|
+
children: /* @__PURE__ */ new Map()
|
|
708
|
+
};
|
|
709
|
+
if (step.paramName) {
|
|
710
|
+
child._P = step.paramName;
|
|
711
|
+
}
|
|
712
|
+
if (step.prefix) {
|
|
713
|
+
child._0 = step.prefix;
|
|
714
|
+
}
|
|
715
|
+
if (step.suffix) {
|
|
716
|
+
child._9 = step.suffix;
|
|
717
|
+
}
|
|
718
|
+
current.children.set(step.key, child);
|
|
719
|
+
}
|
|
720
|
+
current = child;
|
|
721
|
+
}
|
|
722
|
+
current._G = originalKeyPath;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
641
726
|
async function _updateRoutingContext(ctx) {
|
|
642
727
|
const serverPlugins = await walkServerPlugins(ctx.opts);
|
|
643
728
|
const routeTrie = await walkRoutes(ctx.opts.routesDir);
|
|
729
|
+
if (ctx.opts.rewriteRoutes) {
|
|
730
|
+
applyRewriteRoutes(routeTrie, ctx.opts.rewriteRoutes);
|
|
731
|
+
}
|
|
644
732
|
ctx.routeTrie = routeTrie;
|
|
645
733
|
ctx.serverPlugins = serverPlugins;
|
|
646
734
|
const derived = deriveFromTrie(ctx.opts, routeTrie);
|
|
@@ -1486,6 +1574,9 @@ function generateQwikRouterConfig(ctx, qwikPlugin, isSSR) {
|
|
|
1486
1574
|
/** Qwik Router Config */`);
|
|
1487
1575
|
c.push(`
|
|
1488
1576
|
import { isDev } from '@qwik.dev/core/build';`);
|
|
1577
|
+
if (isSSR) {
|
|
1578
|
+
esmImports.push(`import 'virtual:qwik-router-server-fns';`);
|
|
1579
|
+
}
|
|
1489
1580
|
createServerPlugins(ctx, qwikPlugin, c, esmImports, isSSR);
|
|
1490
1581
|
createRoutes(ctx, qwikPlugin, c, esmImports, isSSR);
|
|
1491
1582
|
createEntries(ctx, c);
|
|
@@ -1736,7 +1827,7 @@ function imagePlugin(userOpts) {
|
|
|
1736
1827
|
".tiff"
|
|
1737
1828
|
];
|
|
1738
1829
|
return [
|
|
1739
|
-
import('vite-imagetools').then((
|
|
1830
|
+
import('vite-imagetools').then((_rawProps) => _rawProps.imagetools({
|
|
1740
1831
|
exclude: [],
|
|
1741
1832
|
extendOutputFormats(builtins) {
|
|
1742
1833
|
const jsx = () => (metadatas) => {
|
|
@@ -2176,6 +2267,7 @@ const QWIK_ROUTER_CONFIG_ID = "@qwik-router-config";
|
|
|
2176
2267
|
const QWIK_ROUTER_ENTRIES_ID = "@qwik-router-entries";
|
|
2177
2268
|
const QWIK_ROUTER = "@qwik.dev/router";
|
|
2178
2269
|
const QWIK_ROUTER_SW_REGISTER = "@qwik-router-sw-register";
|
|
2270
|
+
const VIRTUAL_SERVER_FNS = "virtual:qwik-router-server-fns";
|
|
2179
2271
|
async function generateServerPackageJson(outDir) {
|
|
2180
2272
|
await fs.promises.mkdir(outDir, {
|
|
2181
2273
|
recursive: true
|
|
@@ -2381,7 +2473,7 @@ function qwikRouterPlugin(userOpts) {
|
|
|
2381
2473
|
}
|
|
2382
2474
|
return null;
|
|
2383
2475
|
},
|
|
2384
|
-
async load(id
|
|
2476
|
+
async load(id) {
|
|
2385
2477
|
if (ctx) {
|
|
2386
2478
|
if (id.endsWith(QWIK_ROUTER_ENTRIES_ID)) {
|
|
2387
2479
|
return generateQwikRouterEntries(ctx);
|
|
@@ -2486,9 +2578,77 @@ function qwikRouterPlugin(userOpts) {
|
|
|
2486
2578
|
};
|
|
2487
2579
|
return plugin;
|
|
2488
2580
|
}
|
|
2581
|
+
function serverFnsPlugin() {
|
|
2582
|
+
const RESOLVED_ID = "\0" + VIRTUAL_SERVER_FNS;
|
|
2583
|
+
const serverFnModules = /* @__PURE__ */ new Set();
|
|
2584
|
+
let pendingModules = 0;
|
|
2585
|
+
let resolveServerFns = null;
|
|
2586
|
+
let serverFnsReady;
|
|
2587
|
+
function reset() {
|
|
2588
|
+
serverFnModules.clear();
|
|
2589
|
+
pendingModules = 0;
|
|
2590
|
+
serverFnsReady = new Promise((r) => {
|
|
2591
|
+
resolveServerFns = r;
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
reset();
|
|
2595
|
+
return {
|
|
2596
|
+
name: "vite-plugin-qwik-router-server-fns",
|
|
2597
|
+
buildStart() {
|
|
2598
|
+
reset();
|
|
2599
|
+
},
|
|
2600
|
+
resolveId(id) {
|
|
2601
|
+
if (id === VIRTUAL_SERVER_FNS) {
|
|
2602
|
+
return {
|
|
2603
|
+
id: RESOLVED_ID,
|
|
2604
|
+
moduleSideEffects: "no-treeshake"
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
},
|
|
2608
|
+
load: {
|
|
2609
|
+
order: "pre",
|
|
2610
|
+
async handler(id) {
|
|
2611
|
+
const isServerBuild = this.environment.config.consumer === "server" && this.environment.mode === "build";
|
|
2612
|
+
if (id === RESOLVED_ID) {
|
|
2613
|
+
if (isServerBuild) {
|
|
2614
|
+
await serverFnsReady;
|
|
2615
|
+
}
|
|
2616
|
+
if (!isServerBuild || serverFnModules.size === 0) {
|
|
2617
|
+
return "// No server$ functions";
|
|
2618
|
+
}
|
|
2619
|
+
return [
|
|
2620
|
+
...serverFnModules
|
|
2621
|
+
].map((mod) => `import ${JSON.stringify(mod)};`).join("\n");
|
|
2622
|
+
}
|
|
2623
|
+
if (isServerBuild && id !== RESOLVED_ID) {
|
|
2624
|
+
pendingModules++;
|
|
2625
|
+
this.load({
|
|
2626
|
+
id
|
|
2627
|
+
}).then((result) => {
|
|
2628
|
+
if (typeof result.code === "string" && result.code.includes("serverQrl(")) {
|
|
2629
|
+
serverFnModules.add(id);
|
|
2630
|
+
}
|
|
2631
|
+
}).finally(() => {
|
|
2632
|
+
pendingModules--;
|
|
2633
|
+
if (pendingModules <= 0 && resolveServerFns) {
|
|
2634
|
+
setTimeout(() => {
|
|
2635
|
+
if (pendingModules <= 0 && resolveServerFns) {
|
|
2636
|
+
resolveServerFns();
|
|
2637
|
+
resolveServerFns = null;
|
|
2638
|
+
}
|
|
2639
|
+
}, 50);
|
|
2640
|
+
}
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
return null;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2489
2648
|
function qwikRouter(userOpts) {
|
|
2490
2649
|
return [
|
|
2491
2650
|
qwikRouterPlugin(userOpts),
|
|
2651
|
+
serverFnsPlugin(),
|
|
2492
2652
|
...imagePlugin(userOpts)
|
|
2493
2653
|
];
|
|
2494
2654
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qwik.dev/router",
|
|
3
3
|
"description": "The router for Qwik.",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.30",
|
|
5
5
|
"bugs": "https://github.com/QwikDev/qwik/issues",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@azure/functions": "3.5.1",
|
|
8
8
|
"@mdx-js/mdx": "^3.1.1",
|
|
9
|
-
"@netlify/edge-functions": "^
|
|
9
|
+
"@netlify/edge-functions": "^3.0.6",
|
|
10
10
|
"@types/mdx": "^2.0.13",
|
|
11
11
|
"estree-util-value-to-estree": "^3.5.0",
|
|
12
12
|
"github-slugger": "^2.0.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"tsm": "2.3.0",
|
|
41
41
|
"typescript": "5.9.3",
|
|
42
42
|
"uvu": "0.5.6",
|
|
43
|
-
"@qwik.dev/core": "2.0.0-beta.
|
|
43
|
+
"@qwik.dev/core": "2.0.0-beta.30"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"main": "./lib/index.qwik.mjs",
|
|
170
170
|
"peerDependencies": {
|
|
171
171
|
"vite": ">=6 <9",
|
|
172
|
-
"@qwik.dev/core": "^2.0.0-beta.
|
|
172
|
+
"@qwik.dev/core": "^2.0.0-beta.30"
|
|
173
173
|
},
|
|
174
174
|
"publishConfig": {
|
|
175
175
|
"access": "public"
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { _serialize } from '@qwik.dev/core/internal';
|
|
2
|
-
import { RequestEvShareQData, requestHandler, RedirectMessage } from '@qwik.dev/router/middleware/request-handler';
|
|
3
|
-
import { parentPort } from 'node:worker_threads';
|
|
4
|
-
|
|
5
|
-
const createNoopWritableStream = () => new WritableStream();
|
|
6
|
-
async function workerRender(sys, opts, staticRoute, pendingPromises, callback) {
|
|
7
|
-
const url = new URL(staticRoute.pathname, opts.origin);
|
|
8
|
-
const result = {
|
|
9
|
-
type: "render",
|
|
10
|
-
pathname: staticRoute.pathname,
|
|
11
|
-
url: url.href,
|
|
12
|
-
ok: false,
|
|
13
|
-
error: null,
|
|
14
|
-
filePath: null,
|
|
15
|
-
contentType: null,
|
|
16
|
-
resourceType: null
|
|
17
|
-
};
|
|
18
|
-
try {
|
|
19
|
-
let routeWriter = null;
|
|
20
|
-
let closeResolved;
|
|
21
|
-
const closePromise = new Promise((closePromiseResolve) => {
|
|
22
|
-
closeResolved = closePromiseResolve;
|
|
23
|
-
});
|
|
24
|
-
const request = new Request(url);
|
|
25
|
-
const requestCtx = {
|
|
26
|
-
mode: "static",
|
|
27
|
-
locale: void 0,
|
|
28
|
-
url,
|
|
29
|
-
request,
|
|
30
|
-
env: {
|
|
31
|
-
get(key) {
|
|
32
|
-
return sys.getEnv(key);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
platform: sys.platform,
|
|
36
|
-
getClientConn: () => {
|
|
37
|
-
return {};
|
|
38
|
-
},
|
|
39
|
-
getWritableStream: (status, headers, _, _r, requestEv) => {
|
|
40
|
-
result.ok = status >= 200 && status < 300;
|
|
41
|
-
if (!result.ok) {
|
|
42
|
-
return createNoopWritableStream();
|
|
43
|
-
}
|
|
44
|
-
result.contentType = (headers.get("Content-Type") || "").toLowerCase();
|
|
45
|
-
const isHtml = result.contentType.includes("text/html");
|
|
46
|
-
const is404ErrorPage = url.pathname.endsWith("/404.html");
|
|
47
|
-
const routeFilePath = sys.getRouteFilePath(url.pathname, isHtml);
|
|
48
|
-
if (is404ErrorPage) {
|
|
49
|
-
result.resourceType = "404";
|
|
50
|
-
} else if (isHtml) {
|
|
51
|
-
result.resourceType = "page";
|
|
52
|
-
}
|
|
53
|
-
const hasRouteWriter = isHtml ? opts.emitHtml !== false : true;
|
|
54
|
-
const writeQDataEnabled = isHtml && opts.emitData !== false;
|
|
55
|
-
const stream = new WritableStream({
|
|
56
|
-
async start() {
|
|
57
|
-
try {
|
|
58
|
-
if (hasRouteWriter || writeQDataEnabled) {
|
|
59
|
-
await sys.ensureDir(routeFilePath);
|
|
60
|
-
}
|
|
61
|
-
if (hasRouteWriter) {
|
|
62
|
-
routeWriter = sys.createWriteStream(routeFilePath);
|
|
63
|
-
routeWriter.on("error", (e) => {
|
|
64
|
-
console.error(e);
|
|
65
|
-
routeWriter = null;
|
|
66
|
-
result.error = {
|
|
67
|
-
message: e.message,
|
|
68
|
-
stack: e.stack
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
} catch (e) {
|
|
73
|
-
console.error("Error during stream start", staticRoute.pathname, e);
|
|
74
|
-
routeWriter = null;
|
|
75
|
-
result.error = {
|
|
76
|
-
message: String(e),
|
|
77
|
-
stack: e.stack || ""
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
write(chunk) {
|
|
82
|
-
try {
|
|
83
|
-
if (routeWriter) {
|
|
84
|
-
routeWriter.write(Buffer.from(chunk.buffer));
|
|
85
|
-
}
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.error("Error during stream write", staticRoute.pathname, e);
|
|
88
|
-
routeWriter = null;
|
|
89
|
-
result.error = {
|
|
90
|
-
message: String(e),
|
|
91
|
-
stack: e.stack || ""
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
async close() {
|
|
96
|
-
const writePromises = [];
|
|
97
|
-
try {
|
|
98
|
-
if (writeQDataEnabled) {
|
|
99
|
-
const qData = requestEv.sharedMap.get(RequestEvShareQData);
|
|
100
|
-
if (qData && !is404ErrorPage) {
|
|
101
|
-
const qDataFilePath = sys.getDataFilePath(url.pathname);
|
|
102
|
-
const dataWriter = sys.createWriteStream(qDataFilePath);
|
|
103
|
-
dataWriter.on("error", (e) => {
|
|
104
|
-
console.error(e);
|
|
105
|
-
result.error = {
|
|
106
|
-
message: e.message,
|
|
107
|
-
stack: e.stack
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
const serialized = await _serialize(qData);
|
|
111
|
-
dataWriter.write(serialized);
|
|
112
|
-
writePromises.push(new Promise((resolve) => {
|
|
113
|
-
result.filePath = routeFilePath;
|
|
114
|
-
dataWriter.end(resolve);
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (routeWriter) {
|
|
119
|
-
writePromises.push(new Promise((resolve) => {
|
|
120
|
-
result.filePath = routeFilePath;
|
|
121
|
-
routeWriter.end(resolve);
|
|
122
|
-
}).finally(closeResolved));
|
|
123
|
-
}
|
|
124
|
-
if (writePromises.length > 0) {
|
|
125
|
-
await Promise.all(writePromises);
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
console.error("Error during stream close", staticRoute.pathname, e);
|
|
129
|
-
routeWriter = null;
|
|
130
|
-
result.error = {
|
|
131
|
-
message: String(e),
|
|
132
|
-
stack: e.stack || ""
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
return stream;
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const promise = requestHandler(requestCtx, opts).then((rsp) => {
|
|
141
|
-
if (rsp != null) {
|
|
142
|
-
return rsp.completion.then((r) => {
|
|
143
|
-
if (routeWriter) {
|
|
144
|
-
return closePromise.then(() => r);
|
|
145
|
-
}
|
|
146
|
-
return r;
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}).then((e) => {
|
|
150
|
-
if (e !== void 0) {
|
|
151
|
-
if (e instanceof RedirectMessage) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
if (e instanceof Error) {
|
|
155
|
-
result.error = {
|
|
156
|
-
message: e.message,
|
|
157
|
-
stack: e.stack
|
|
158
|
-
};
|
|
159
|
-
} else {
|
|
160
|
-
result.error = {
|
|
161
|
-
message: String(e),
|
|
162
|
-
stack: void 0
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
console.error("Error during request handling", staticRoute.pathname, e);
|
|
166
|
-
}
|
|
167
|
-
}).catch((e) => {
|
|
168
|
-
console.error("Unhandled error during request handling", staticRoute.pathname, e);
|
|
169
|
-
result.error = {
|
|
170
|
-
message: String(e),
|
|
171
|
-
stack: e.stack || ""
|
|
172
|
-
};
|
|
173
|
-
}).finally(() => {
|
|
174
|
-
pendingPromises.delete(promise);
|
|
175
|
-
callback(result);
|
|
176
|
-
});
|
|
177
|
-
pendingPromises.add(promise);
|
|
178
|
-
} catch (e) {
|
|
179
|
-
console.error("Error during render", staticRoute.pathname, e);
|
|
180
|
-
if (e instanceof Error) {
|
|
181
|
-
result.error = {
|
|
182
|
-
message: e.message,
|
|
183
|
-
stack: e.stack
|
|
184
|
-
};
|
|
185
|
-
} else {
|
|
186
|
-
result.error = {
|
|
187
|
-
message: String(e),
|
|
188
|
-
stack: void 0
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
callback(result);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async function workerThread(sys) {
|
|
195
|
-
delete globalThis.__qwik;
|
|
196
|
-
const opts = sys.getOptions();
|
|
197
|
-
const pendingPromises = /* @__PURE__ */ new Set();
|
|
198
|
-
const log = await sys.createLogger();
|
|
199
|
-
process.on("uncaughtException", (e) => {
|
|
200
|
-
console.error("Worker uncaught exception (suppressed):", e.message);
|
|
201
|
-
});
|
|
202
|
-
process.on("unhandledRejection", (e) => {
|
|
203
|
-
console.error("Worker unhandled rejection (suppressed):", e instanceof Error ? e.message : e);
|
|
204
|
-
});
|
|
205
|
-
const onMessage = async (msg) => {
|
|
206
|
-
switch (msg.type) {
|
|
207
|
-
case "render": {
|
|
208
|
-
log.debug(`Worker thread rendering: ${msg.pathname}`);
|
|
209
|
-
return new Promise((resolve) => {
|
|
210
|
-
workerRender(sys, opts, msg, pendingPromises, resolve).catch((e) => {
|
|
211
|
-
console.error("Error during render", msg.pathname, e);
|
|
212
|
-
resolve({
|
|
213
|
-
type: "render",
|
|
214
|
-
pathname: msg.pathname,
|
|
215
|
-
url: "",
|
|
216
|
-
ok: false,
|
|
217
|
-
error: {
|
|
218
|
-
message: e instanceof Error ? e.message : String(e),
|
|
219
|
-
stack: e instanceof Error ? e.stack : void 0
|
|
220
|
-
},
|
|
221
|
-
filePath: null,
|
|
222
|
-
contentType: null,
|
|
223
|
-
resourceType: null
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
case "close": {
|
|
229
|
-
if (pendingPromises.size) {
|
|
230
|
-
log.debug(`Worker thread closing, waiting for ${pendingPromises.size} pending renders`);
|
|
231
|
-
const promises = Array.from(pendingPromises);
|
|
232
|
-
pendingPromises.clear();
|
|
233
|
-
await Promise.all(promises);
|
|
234
|
-
}
|
|
235
|
-
log.debug(`Worker thread closed`);
|
|
236
|
-
return {
|
|
237
|
-
type: "close"
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
parentPort?.on("message", async (msg) => {
|
|
243
|
-
try {
|
|
244
|
-
parentPort?.postMessage(await onMessage(msg));
|
|
245
|
-
} catch (e) {
|
|
246
|
-
if (msg.type === "render") {
|
|
247
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
248
|
-
parentPort?.postMessage({
|
|
249
|
-
type: "render",
|
|
250
|
-
pathname: msg.pathname,
|
|
251
|
-
url: "",
|
|
252
|
-
ok: false,
|
|
253
|
-
error: {
|
|
254
|
-
message: error.message,
|
|
255
|
-
stack: error.stack
|
|
256
|
-
},
|
|
257
|
-
filePath: null,
|
|
258
|
-
contentType: null,
|
|
259
|
-
resourceType: null
|
|
260
|
-
});
|
|
261
|
-
} else {
|
|
262
|
-
console.error("Worker message handler error", e);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (msg.type === "close") {
|
|
266
|
-
parentPort?.close();
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export { workerThread };
|