@webtypen/webframez-react 0.0.4 → 0.0.5
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/dist/http.cjs +171 -67
- package/dist/http.js +172 -68
- package/dist/index.cjs +171 -67
- package/dist/index.js +172 -68
- package/dist/webframez-core.cjs +171 -67
- package/dist/webframez-core.js +172 -68
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -515,57 +515,16 @@ function parseSearchParams(query) {
|
|
|
515
515
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
516
516
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
517
517
|
var import_node_child_process = require("node:child_process");
|
|
518
|
-
|
|
519
|
-
if (!basePath || basePath === "/") {
|
|
520
|
-
return "";
|
|
521
|
-
}
|
|
522
|
-
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
523
|
-
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
524
|
-
}
|
|
525
|
-
function stripBasePath(pathname, basePath) {
|
|
526
|
-
if (!basePath) {
|
|
527
|
-
return pathname;
|
|
528
|
-
}
|
|
529
|
-
if (pathname === basePath) {
|
|
530
|
-
return "/";
|
|
531
|
-
}
|
|
532
|
-
if (pathname.startsWith(`${basePath}/`)) {
|
|
533
|
-
return pathname.slice(basePath.length) || "/";
|
|
534
|
-
}
|
|
535
|
-
return pathname;
|
|
536
|
-
}
|
|
537
|
-
function runNodeCommand(args) {
|
|
538
|
-
return new Promise((resolve, reject) => {
|
|
539
|
-
const execArgs = [
|
|
540
|
-
"--conditions",
|
|
541
|
-
"react-server",
|
|
542
|
-
"-r",
|
|
543
|
-
"@webtypen/webframez-react/register",
|
|
544
|
-
...args
|
|
545
|
-
];
|
|
546
|
-
(0, import_node_child_process.execFile)(
|
|
547
|
-
process.execPath,
|
|
548
|
-
execArgs,
|
|
549
|
-
{ timeout: 1e4, maxBuffer: 1024 * 1024 * 5 },
|
|
550
|
-
(error, stdout, stderr) => {
|
|
551
|
-
if (error) {
|
|
552
|
-
const out = stderr && stderr.trim() !== "" ? stderr : stdout;
|
|
553
|
-
reject(new Error(out || error.message));
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
resolve({ stdout, stderr });
|
|
557
|
-
}
|
|
558
|
-
);
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
async function renderInitialHtmlInWorker(options) {
|
|
562
|
-
const payload = Buffer.from(JSON.stringify(options), "utf8").toString("base64url");
|
|
563
|
-
const script = `
|
|
518
|
+
var INITIAL_HTML_WORKER_SCRIPT = `
|
|
564
519
|
const path = require("node:path");
|
|
565
520
|
const Module = require("node:module");
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
521
|
+
|
|
522
|
+
const pagesDir = process.env.WEBFRAMEZ_REACT_PAGES_DIR || "";
|
|
523
|
+
if (!pagesDir) {
|
|
524
|
+
throw new Error("Missing WEBFRAMEZ_REACT_PAGES_DIR");
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const appRequire = Module.createRequire(path.join(pagesDir, "__webframez_react_worker__.js"));
|
|
569
528
|
const originalResolveFilename = Module._resolveFilename;
|
|
570
529
|
const forcedResolutions = new Map([
|
|
571
530
|
["react", appRequire.resolve("react")],
|
|
@@ -573,35 +532,174 @@ const forcedResolutions = new Map([
|
|
|
573
532
|
["react/jsx-dev-runtime", appRequire.resolve("react/jsx-dev-runtime")],
|
|
574
533
|
["react-dom/client", appRequire.resolve("react-dom/client")]
|
|
575
534
|
]);
|
|
535
|
+
|
|
576
536
|
Module._resolveFilename = function(request, parent, isMain, options) {
|
|
577
537
|
if (forcedResolutions.has(request)) {
|
|
578
538
|
return forcedResolutions.get(request);
|
|
579
539
|
}
|
|
580
540
|
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
581
541
|
};
|
|
542
|
+
|
|
582
543
|
const { createFileRouter } = require("@webtypen/webframez-react/router");
|
|
583
544
|
const reactDomPkg = require.resolve("react-dom/package.json", {
|
|
584
|
-
paths: [process.cwd(),
|
|
545
|
+
paths: [process.cwd(), pagesDir]
|
|
585
546
|
});
|
|
586
547
|
const reactDomServer = require(path.join(path.dirname(reactDomPkg), "server.node.js"));
|
|
548
|
+
const router = createFileRouter({ pagesDir });
|
|
587
549
|
|
|
588
|
-
(async () => {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
550
|
+
process.on("message", async (message) => {
|
|
551
|
+
if (!message || message.type !== "render") {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const previousBasename = globalThis.__RSC_BASENAME;
|
|
556
|
+
globalThis.__RSC_BASENAME = message.payload.basename || "";
|
|
557
|
+
|
|
558
|
+
try {
|
|
559
|
+
const resolved = await router.resolve({
|
|
560
|
+
pathname: message.payload.pathname,
|
|
561
|
+
searchParams: message.payload.searchParams || {},
|
|
562
|
+
cookies: message.payload.cookies || {},
|
|
563
|
+
});
|
|
564
|
+
const html = reactDomServer.renderToString(resolved.model);
|
|
565
|
+
if (typeof process.send === "function") {
|
|
566
|
+
process.send({ id: message.id, ok: true, html });
|
|
567
|
+
}
|
|
568
|
+
} catch (error) {
|
|
569
|
+
const formatted = error && (error.stack || String(error))
|
|
570
|
+
? (error.stack || String(error))
|
|
571
|
+
: "Unknown SSR worker error";
|
|
572
|
+
if (typeof process.send === "function") {
|
|
573
|
+
process.send({ id: message.id, ok: false, error: formatted });
|
|
574
|
+
}
|
|
575
|
+
} finally {
|
|
576
|
+
globalThis.__RSC_BASENAME = previousBasename;
|
|
577
|
+
}
|
|
600
578
|
});
|
|
601
579
|
`;
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
580
|
+
function normalizeBasePath(basePath) {
|
|
581
|
+
if (!basePath || basePath === "/") {
|
|
582
|
+
return "";
|
|
583
|
+
}
|
|
584
|
+
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
585
|
+
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
586
|
+
}
|
|
587
|
+
function stripBasePath(pathname, basePath) {
|
|
588
|
+
if (!basePath) {
|
|
589
|
+
return pathname;
|
|
590
|
+
}
|
|
591
|
+
if (pathname === basePath) {
|
|
592
|
+
return "/";
|
|
593
|
+
}
|
|
594
|
+
if (pathname.startsWith(`${basePath}/`)) {
|
|
595
|
+
return pathname.slice(basePath.length) || "/";
|
|
596
|
+
}
|
|
597
|
+
return pathname;
|
|
598
|
+
}
|
|
599
|
+
function createInitialHtmlWorker(pagesDir) {
|
|
600
|
+
let child = null;
|
|
601
|
+
let nextRequestId = 1;
|
|
602
|
+
let stderrBuffer = "";
|
|
603
|
+
const pending = /* @__PURE__ */ new Map();
|
|
604
|
+
const rejectPending = (error) => {
|
|
605
|
+
for (const entry of pending.values()) {
|
|
606
|
+
clearTimeout(entry.timeout);
|
|
607
|
+
entry.reject(error);
|
|
608
|
+
}
|
|
609
|
+
pending.clear();
|
|
610
|
+
};
|
|
611
|
+
const stopWorker = () => {
|
|
612
|
+
if (!child) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
child.removeAllListeners();
|
|
616
|
+
if (!child.killed) {
|
|
617
|
+
child.kill();
|
|
618
|
+
}
|
|
619
|
+
child = null;
|
|
620
|
+
};
|
|
621
|
+
const startWorker = () => {
|
|
622
|
+
if (child && child.connected && !child.killed) {
|
|
623
|
+
return child;
|
|
624
|
+
}
|
|
625
|
+
stderrBuffer = "";
|
|
626
|
+
child = (0, import_node_child_process.spawn)(process.execPath, ["-e", INITIAL_HTML_WORKER_SCRIPT], {
|
|
627
|
+
cwd: process.cwd(),
|
|
628
|
+
env: {
|
|
629
|
+
...process.env,
|
|
630
|
+
WEBFRAMEZ_REACT_PAGES_DIR: pagesDir
|
|
631
|
+
},
|
|
632
|
+
stdio: ["ignore", "ignore", "pipe", "ipc"]
|
|
633
|
+
});
|
|
634
|
+
child.on("message", (message) => {
|
|
635
|
+
if (!message || typeof message.id !== "number") {
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const entry = pending.get(message.id);
|
|
639
|
+
if (!entry) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
pending.delete(message.id);
|
|
643
|
+
clearTimeout(entry.timeout);
|
|
644
|
+
if (message.ok) {
|
|
645
|
+
entry.resolve(message.html);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
entry.reject(new Error(message.error));
|
|
649
|
+
});
|
|
650
|
+
child.stderr?.on("data", (chunk) => {
|
|
651
|
+
stderrBuffer = `${stderrBuffer}${chunk.toString("utf8")}`.slice(-8192);
|
|
652
|
+
});
|
|
653
|
+
child.on("exit", (code, signal) => {
|
|
654
|
+
const suffix = stderrBuffer.trim() !== "" ? `
|
|
655
|
+
${stderrBuffer.trim()}` : "";
|
|
656
|
+
rejectPending(
|
|
657
|
+
new Error(
|
|
658
|
+
`[webframez-react] Initial HTML worker exited (${signal ?? code ?? "unknown"})${suffix}`
|
|
659
|
+
)
|
|
660
|
+
);
|
|
661
|
+
child = null;
|
|
662
|
+
});
|
|
663
|
+
child.on("error", (error) => {
|
|
664
|
+
rejectPending(error instanceof Error ? error : new Error(String(error)));
|
|
665
|
+
child = null;
|
|
666
|
+
});
|
|
667
|
+
return child;
|
|
668
|
+
};
|
|
669
|
+
return {
|
|
670
|
+
render(payload) {
|
|
671
|
+
const activeChild = startWorker();
|
|
672
|
+
const requestId = nextRequestId++;
|
|
673
|
+
return new Promise((resolve, reject) => {
|
|
674
|
+
const timeout = setTimeout(() => {
|
|
675
|
+
rejectPending(new Error("[webframez-react] Initial HTML worker timed out"));
|
|
676
|
+
stopWorker();
|
|
677
|
+
}, 1e4);
|
|
678
|
+
pending.set(requestId, { resolve, reject, timeout });
|
|
679
|
+
const request = {
|
|
680
|
+
id: requestId,
|
|
681
|
+
type: "render",
|
|
682
|
+
payload
|
|
683
|
+
};
|
|
684
|
+
activeChild.send(request, (error) => {
|
|
685
|
+
if (!error) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const entry = pending.get(requestId);
|
|
689
|
+
if (!entry) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
pending.delete(requestId);
|
|
693
|
+
clearTimeout(entry.timeout);
|
|
694
|
+
entry.reject(error instanceof Error ? error : new Error(String(error)));
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
},
|
|
698
|
+
dispose() {
|
|
699
|
+
rejectPending(new Error("[webframez-react] Initial HTML worker disposed"));
|
|
700
|
+
stopWorker();
|
|
701
|
+
}
|
|
702
|
+
};
|
|
605
703
|
}
|
|
606
704
|
function withRequestBasename(basename, fn) {
|
|
607
705
|
const target = globalThis;
|
|
@@ -661,6 +759,13 @@ function createNodeRequestHandler(options) {
|
|
|
661
759
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
662
760
|
const router = createFileRouter({ pagesDir });
|
|
663
761
|
const moduleMap = JSON.parse(import_node_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
762
|
+
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
763
|
+
const disposeInitialHtmlWorker = () => {
|
|
764
|
+
initialHtmlWorker.dispose();
|
|
765
|
+
};
|
|
766
|
+
process.once("exit", disposeInitialHtmlWorker);
|
|
767
|
+
process.once("SIGINT", disposeInitialHtmlWorker);
|
|
768
|
+
process.once("SIGTERM", disposeInitialHtmlWorker);
|
|
664
769
|
return async function handleRequest(req, res) {
|
|
665
770
|
if (!req.url) {
|
|
666
771
|
res.statusCode = 400;
|
|
@@ -760,8 +865,7 @@ function createNodeRequestHandler(options) {
|
|
|
760
865
|
);
|
|
761
866
|
let rootHtml = "";
|
|
762
867
|
try {
|
|
763
|
-
rootHtml = await
|
|
764
|
-
pagesDir,
|
|
868
|
+
rootHtml = await initialHtmlWorker.render({
|
|
765
869
|
pathname: stripBasePath(url.pathname, basePath),
|
|
766
870
|
searchParams: parseSearchParams(url.searchParams),
|
|
767
871
|
cookies: requestCookies,
|
package/dist/index.js
CHANGED
|
@@ -478,58 +478,17 @@ function parseSearchParams(query) {
|
|
|
478
478
|
// src/http.ts
|
|
479
479
|
import fs2 from "node:fs";
|
|
480
480
|
import path2 from "node:path";
|
|
481
|
-
import {
|
|
482
|
-
|
|
483
|
-
if (!basePath || basePath === "/") {
|
|
484
|
-
return "";
|
|
485
|
-
}
|
|
486
|
-
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
487
|
-
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
488
|
-
}
|
|
489
|
-
function stripBasePath(pathname, basePath) {
|
|
490
|
-
if (!basePath) {
|
|
491
|
-
return pathname;
|
|
492
|
-
}
|
|
493
|
-
if (pathname === basePath) {
|
|
494
|
-
return "/";
|
|
495
|
-
}
|
|
496
|
-
if (pathname.startsWith(`${basePath}/`)) {
|
|
497
|
-
return pathname.slice(basePath.length) || "/";
|
|
498
|
-
}
|
|
499
|
-
return pathname;
|
|
500
|
-
}
|
|
501
|
-
function runNodeCommand(args) {
|
|
502
|
-
return new Promise((resolve, reject) => {
|
|
503
|
-
const execArgs = [
|
|
504
|
-
"--conditions",
|
|
505
|
-
"react-server",
|
|
506
|
-
"-r",
|
|
507
|
-
"@webtypen/webframez-react/register",
|
|
508
|
-
...args
|
|
509
|
-
];
|
|
510
|
-
execFile(
|
|
511
|
-
process.execPath,
|
|
512
|
-
execArgs,
|
|
513
|
-
{ timeout: 1e4, maxBuffer: 1024 * 1024 * 5 },
|
|
514
|
-
(error, stdout, stderr) => {
|
|
515
|
-
if (error) {
|
|
516
|
-
const out = stderr && stderr.trim() !== "" ? stderr : stdout;
|
|
517
|
-
reject(new Error(out || error.message));
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
resolve({ stdout, stderr });
|
|
521
|
-
}
|
|
522
|
-
);
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
async function renderInitialHtmlInWorker(options) {
|
|
526
|
-
const payload = Buffer.from(JSON.stringify(options), "utf8").toString("base64url");
|
|
527
|
-
const script = `
|
|
481
|
+
import { spawn } from "node:child_process";
|
|
482
|
+
var INITIAL_HTML_WORKER_SCRIPT = `
|
|
528
483
|
const path = require("node:path");
|
|
529
484
|
const Module = require("node:module");
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
485
|
+
|
|
486
|
+
const pagesDir = process.env.WEBFRAMEZ_REACT_PAGES_DIR || "";
|
|
487
|
+
if (!pagesDir) {
|
|
488
|
+
throw new Error("Missing WEBFRAMEZ_REACT_PAGES_DIR");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const appRequire = Module.createRequire(path.join(pagesDir, "__webframez_react_worker__.js"));
|
|
533
492
|
const originalResolveFilename = Module._resolveFilename;
|
|
534
493
|
const forcedResolutions = new Map([
|
|
535
494
|
["react", appRequire.resolve("react")],
|
|
@@ -537,35 +496,174 @@ const forcedResolutions = new Map([
|
|
|
537
496
|
["react/jsx-dev-runtime", appRequire.resolve("react/jsx-dev-runtime")],
|
|
538
497
|
["react-dom/client", appRequire.resolve("react-dom/client")]
|
|
539
498
|
]);
|
|
499
|
+
|
|
540
500
|
Module._resolveFilename = function(request, parent, isMain, options) {
|
|
541
501
|
if (forcedResolutions.has(request)) {
|
|
542
502
|
return forcedResolutions.get(request);
|
|
543
503
|
}
|
|
544
504
|
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
545
505
|
};
|
|
506
|
+
|
|
546
507
|
const { createFileRouter } = require("@webtypen/webframez-react/router");
|
|
547
508
|
const reactDomPkg = require.resolve("react-dom/package.json", {
|
|
548
|
-
paths: [process.cwd(),
|
|
509
|
+
paths: [process.cwd(), pagesDir]
|
|
549
510
|
});
|
|
550
511
|
const reactDomServer = require(path.join(path.dirname(reactDomPkg), "server.node.js"));
|
|
512
|
+
const router = createFileRouter({ pagesDir });
|
|
551
513
|
|
|
552
|
-
(async () => {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
514
|
+
process.on("message", async (message) => {
|
|
515
|
+
if (!message || message.type !== "render") {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const previousBasename = globalThis.__RSC_BASENAME;
|
|
520
|
+
globalThis.__RSC_BASENAME = message.payload.basename || "";
|
|
521
|
+
|
|
522
|
+
try {
|
|
523
|
+
const resolved = await router.resolve({
|
|
524
|
+
pathname: message.payload.pathname,
|
|
525
|
+
searchParams: message.payload.searchParams || {},
|
|
526
|
+
cookies: message.payload.cookies || {},
|
|
527
|
+
});
|
|
528
|
+
const html = reactDomServer.renderToString(resolved.model);
|
|
529
|
+
if (typeof process.send === "function") {
|
|
530
|
+
process.send({ id: message.id, ok: true, html });
|
|
531
|
+
}
|
|
532
|
+
} catch (error) {
|
|
533
|
+
const formatted = error && (error.stack || String(error))
|
|
534
|
+
? (error.stack || String(error))
|
|
535
|
+
: "Unknown SSR worker error";
|
|
536
|
+
if (typeof process.send === "function") {
|
|
537
|
+
process.send({ id: message.id, ok: false, error: formatted });
|
|
538
|
+
}
|
|
539
|
+
} finally {
|
|
540
|
+
globalThis.__RSC_BASENAME = previousBasename;
|
|
541
|
+
}
|
|
564
542
|
});
|
|
565
543
|
`;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
544
|
+
function normalizeBasePath(basePath) {
|
|
545
|
+
if (!basePath || basePath === "/") {
|
|
546
|
+
return "";
|
|
547
|
+
}
|
|
548
|
+
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
549
|
+
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
550
|
+
}
|
|
551
|
+
function stripBasePath(pathname, basePath) {
|
|
552
|
+
if (!basePath) {
|
|
553
|
+
return pathname;
|
|
554
|
+
}
|
|
555
|
+
if (pathname === basePath) {
|
|
556
|
+
return "/";
|
|
557
|
+
}
|
|
558
|
+
if (pathname.startsWith(`${basePath}/`)) {
|
|
559
|
+
return pathname.slice(basePath.length) || "/";
|
|
560
|
+
}
|
|
561
|
+
return pathname;
|
|
562
|
+
}
|
|
563
|
+
function createInitialHtmlWorker(pagesDir) {
|
|
564
|
+
let child = null;
|
|
565
|
+
let nextRequestId = 1;
|
|
566
|
+
let stderrBuffer = "";
|
|
567
|
+
const pending = /* @__PURE__ */ new Map();
|
|
568
|
+
const rejectPending = (error) => {
|
|
569
|
+
for (const entry of pending.values()) {
|
|
570
|
+
clearTimeout(entry.timeout);
|
|
571
|
+
entry.reject(error);
|
|
572
|
+
}
|
|
573
|
+
pending.clear();
|
|
574
|
+
};
|
|
575
|
+
const stopWorker = () => {
|
|
576
|
+
if (!child) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
child.removeAllListeners();
|
|
580
|
+
if (!child.killed) {
|
|
581
|
+
child.kill();
|
|
582
|
+
}
|
|
583
|
+
child = null;
|
|
584
|
+
};
|
|
585
|
+
const startWorker = () => {
|
|
586
|
+
if (child && child.connected && !child.killed) {
|
|
587
|
+
return child;
|
|
588
|
+
}
|
|
589
|
+
stderrBuffer = "";
|
|
590
|
+
child = spawn(process.execPath, ["-e", INITIAL_HTML_WORKER_SCRIPT], {
|
|
591
|
+
cwd: process.cwd(),
|
|
592
|
+
env: {
|
|
593
|
+
...process.env,
|
|
594
|
+
WEBFRAMEZ_REACT_PAGES_DIR: pagesDir
|
|
595
|
+
},
|
|
596
|
+
stdio: ["ignore", "ignore", "pipe", "ipc"]
|
|
597
|
+
});
|
|
598
|
+
child.on("message", (message) => {
|
|
599
|
+
if (!message || typeof message.id !== "number") {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const entry = pending.get(message.id);
|
|
603
|
+
if (!entry) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
pending.delete(message.id);
|
|
607
|
+
clearTimeout(entry.timeout);
|
|
608
|
+
if (message.ok) {
|
|
609
|
+
entry.resolve(message.html);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
entry.reject(new Error(message.error));
|
|
613
|
+
});
|
|
614
|
+
child.stderr?.on("data", (chunk) => {
|
|
615
|
+
stderrBuffer = `${stderrBuffer}${chunk.toString("utf8")}`.slice(-8192);
|
|
616
|
+
});
|
|
617
|
+
child.on("exit", (code, signal) => {
|
|
618
|
+
const suffix = stderrBuffer.trim() !== "" ? `
|
|
619
|
+
${stderrBuffer.trim()}` : "";
|
|
620
|
+
rejectPending(
|
|
621
|
+
new Error(
|
|
622
|
+
`[webframez-react] Initial HTML worker exited (${signal ?? code ?? "unknown"})${suffix}`
|
|
623
|
+
)
|
|
624
|
+
);
|
|
625
|
+
child = null;
|
|
626
|
+
});
|
|
627
|
+
child.on("error", (error) => {
|
|
628
|
+
rejectPending(error instanceof Error ? error : new Error(String(error)));
|
|
629
|
+
child = null;
|
|
630
|
+
});
|
|
631
|
+
return child;
|
|
632
|
+
};
|
|
633
|
+
return {
|
|
634
|
+
render(payload) {
|
|
635
|
+
const activeChild = startWorker();
|
|
636
|
+
const requestId = nextRequestId++;
|
|
637
|
+
return new Promise((resolve, reject) => {
|
|
638
|
+
const timeout = setTimeout(() => {
|
|
639
|
+
rejectPending(new Error("[webframez-react] Initial HTML worker timed out"));
|
|
640
|
+
stopWorker();
|
|
641
|
+
}, 1e4);
|
|
642
|
+
pending.set(requestId, { resolve, reject, timeout });
|
|
643
|
+
const request = {
|
|
644
|
+
id: requestId,
|
|
645
|
+
type: "render",
|
|
646
|
+
payload
|
|
647
|
+
};
|
|
648
|
+
activeChild.send(request, (error) => {
|
|
649
|
+
if (!error) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const entry = pending.get(requestId);
|
|
653
|
+
if (!entry) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
pending.delete(requestId);
|
|
657
|
+
clearTimeout(entry.timeout);
|
|
658
|
+
entry.reject(error instanceof Error ? error : new Error(String(error)));
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
},
|
|
662
|
+
dispose() {
|
|
663
|
+
rejectPending(new Error("[webframez-react] Initial HTML worker disposed"));
|
|
664
|
+
stopWorker();
|
|
665
|
+
}
|
|
666
|
+
};
|
|
569
667
|
}
|
|
570
668
|
function withRequestBasename(basename, fn) {
|
|
571
669
|
const target = globalThis;
|
|
@@ -625,6 +723,13 @@ function createNodeRequestHandler(options) {
|
|
|
625
723
|
const liveReloadClients = /* @__PURE__ */ new Set();
|
|
626
724
|
const router = createFileRouter({ pagesDir });
|
|
627
725
|
const moduleMap = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
726
|
+
const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
|
|
727
|
+
const disposeInitialHtmlWorker = () => {
|
|
728
|
+
initialHtmlWorker.dispose();
|
|
729
|
+
};
|
|
730
|
+
process.once("exit", disposeInitialHtmlWorker);
|
|
731
|
+
process.once("SIGINT", disposeInitialHtmlWorker);
|
|
732
|
+
process.once("SIGTERM", disposeInitialHtmlWorker);
|
|
628
733
|
return async function handleRequest(req, res) {
|
|
629
734
|
if (!req.url) {
|
|
630
735
|
res.statusCode = 400;
|
|
@@ -724,8 +829,7 @@ function createNodeRequestHandler(options) {
|
|
|
724
829
|
);
|
|
725
830
|
let rootHtml = "";
|
|
726
831
|
try {
|
|
727
|
-
rootHtml = await
|
|
728
|
-
pagesDir,
|
|
832
|
+
rootHtml = await initialHtmlWorker.render({
|
|
729
833
|
pathname: stripBasePath(url.pathname, basePath),
|
|
730
834
|
searchParams: parseSearchParams(url.searchParams),
|
|
731
835
|
cookies: requestCookies,
|