@webtypen/webframez-react 0.0.49 → 0.0.50
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/README.md +61 -0
- package/defaults/webpack.client.cjs +6 -2
- package/dist/http.cjs +70 -39
- package/dist/http.d.ts +3 -0
- package/dist/http.js +67 -38
- package/dist/index.cjs +142 -46
- package/dist/index.d.ts +2 -0
- package/dist/index.js +162 -46
- package/dist/navigation.cjs +80 -15
- package/dist/navigation.d.ts +1 -1
- package/dist/navigation.js +92 -15
- package/dist/paths.cjs +102 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +92 -0
- package/dist/router.cjs +1 -2
- package/dist/router.js +1 -2
- package/dist/webframez-core.cjs +121 -46
- package/dist/webframez-core.d.ts +2 -8
- package/dist/webframez-core.js +141 -46
- package/package.json +18 -4
package/README.md
CHANGED
|
@@ -491,3 +491,64 @@ Watch mode for package development:
|
|
|
491
491
|
```bash
|
|
492
492
|
npm run build:watch
|
|
493
493
|
```
|
|
494
|
+
|
|
495
|
+
## Persistent navigation in consuming applications
|
|
496
|
+
|
|
497
|
+
Use the host router's Link component for URLs. Keep the Suite renderer mounted
|
|
498
|
+
across paths inside one authorized project; do not add `key={path}` or conditionally
|
|
499
|
+
unmount it while reloading project context. Revalidate/reset the context when the
|
|
500
|
+
project changes, and continue enforcing authorization on every server request.
|
|
501
|
+
Only the page content resets for a new screen. The renderer retains its layout and
|
|
502
|
+
prior page while a same-project request is pending, with stale interactions disabled.
|
|
503
|
+
|
|
504
|
+
For webframez-react, configure the DOM link adapter at the host boundary:
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
import React from "react";
|
|
508
|
+
import { Link } from "@webtypen/webframez-react/navigation";
|
|
509
|
+
|
|
510
|
+
const SuiteLink = React.forwardRef<HTMLAnchorElement,
|
|
511
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
512
|
+
>(function SuiteLink({ href, ...props }, ref) {
|
|
513
|
+
return <Link {...props} ref={ref} to={href || "#"} basename="" />;
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Inside an already authorized project context; paths are fully qualified.
|
|
517
|
+
<NativeDesignProvider
|
|
518
|
+
key={projectId}
|
|
519
|
+
suite={{ endpoint: "/manager", navigation: {
|
|
520
|
+
pathname, linkComponent: SuiteLink,
|
|
521
|
+
onNavigate: to => router.push(to),
|
|
522
|
+
} }}
|
|
523
|
+
>
|
|
524
|
+
<WebframezSuiteRenderer />
|
|
525
|
+
</NativeDesignProvider>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Screen definitions remain JSON-serializable: links use `to`/`path`; React Link
|
|
529
|
+
components belong in the consuming application's adapter, never in server schemas.
|
|
530
|
+
See `AGENTS.md` for the navigation invariants and regression-test requirements.
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
## Core router basename
|
|
534
|
+
|
|
535
|
+
With the updated Core router, set `application.router.basename` in the Core
|
|
536
|
+
configuration. `initWebframezReact(Route).renderReact("/", options)` inherits it;
|
|
537
|
+
no duplicate `basePath`, `assetsPrefix`, `rscPath`, `clientScriptUrl`, or
|
|
538
|
+
`Head.basename` is needed. Nested render routes and `Route.group` prefixes are
|
|
539
|
+
included in the runtime mount while build target names and directories stay
|
|
540
|
+
stable. Explicit external asset URLs remain unchanged. Without Core, the Node
|
|
541
|
+
handler still supports `basePath` and explicit transport URLs.
|
|
542
|
+
|
|
543
|
+
For API calls, form actions, raw links and redirects in shared/client code:
|
|
544
|
+
|
|
545
|
+
```ts
|
|
546
|
+
import { appPath, appRelativePath, getBasename } from "@webtypen/webframez-react/paths";
|
|
547
|
+
fetch(appPath("/api/items"));
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
These browser-safe helpers bundle Core's URL logic and read the runtime mount;
|
|
551
|
+
no server dependencies are included. `Link` and `Redirect` inherit it
|
|
552
|
+
implicitly. Server requests use an async-local context, and HTML rendering and
|
|
553
|
+
client navigation receive the same basename through the Flight head and HTML
|
|
554
|
+
shell. External URLs and already-prefixed URLs are preserved.
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
|
-
const
|
|
3
|
+
const { createRequire } = require("node:module");
|
|
4
4
|
const { fileURLToPath, pathToFileURL } = require("url");
|
|
5
5
|
|
|
6
6
|
const projectRoot = process.cwd();
|
|
7
|
+
const projectRequire = createRequire(path.join(projectRoot, "package.json"));
|
|
8
|
+
const ReactFlightWebpackPlugin = projectRequire("react-server-dom-webpack/plugin");
|
|
9
|
+
const reactDomRequire = createRequire(projectRequire.resolve("react-dom/package.json"));
|
|
7
10
|
const frameworkDistDir = path.resolve(__dirname, "..", "dist");
|
|
8
11
|
const clientEntry = process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY
|
|
9
12
|
? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY)
|
|
@@ -266,7 +269,8 @@ module.exports = {
|
|
|
266
269
|
"react-dom": path.resolve(projectRoot, "node_modules", "react-dom"),
|
|
267
270
|
"react/jsx-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-runtime.js"),
|
|
268
271
|
"react/jsx-dev-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-dev-runtime.js"),
|
|
269
|
-
|
|
272
|
+
// Resolve React DOM's own scheduler, including pnpm's isolated layout.
|
|
273
|
+
scheduler: path.dirname(reactDomRequire.resolve("scheduler/package.json")),
|
|
270
274
|
},
|
|
271
275
|
},
|
|
272
276
|
watchOptions: {
|
package/dist/http.cjs
CHANGED
|
@@ -29,9 +29,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
// src/http.ts
|
|
30
30
|
var http_exports = {};
|
|
31
31
|
__export(http_exports, {
|
|
32
|
-
createNodeRequestHandler: () => createNodeRequestHandler
|
|
32
|
+
createNodeRequestHandler: () => createNodeRequestHandler,
|
|
33
|
+
disposeReactHtmlRenderer: () => disposeReactHtmlRenderer,
|
|
34
|
+
renderReactToHtml: () => renderReactToHtml
|
|
33
35
|
});
|
|
34
36
|
module.exports = __toCommonJS(http_exports);
|
|
37
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
35
38
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
36
39
|
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
37
40
|
var import_node_url = require("node:url");
|
|
@@ -341,8 +344,7 @@ var FORCED_PACKAGE_REQUESTS = [
|
|
|
341
344
|
"react-server-dom-webpack",
|
|
342
345
|
"react-server-dom-webpack/server",
|
|
343
346
|
"react-server-dom-webpack/client",
|
|
344
|
-
"react-server-dom-webpack/client.node"
|
|
345
|
-
"scheduler"
|
|
347
|
+
"react-server-dom-webpack/client.node"
|
|
346
348
|
];
|
|
347
349
|
var forcedPackageResolutionInstalled = false;
|
|
348
350
|
function normalizePathname(pathname) {
|
|
@@ -993,6 +995,7 @@ const rootParent = {
|
|
|
993
995
|
path: process.cwd(),
|
|
994
996
|
paths: Module._nodeModulePaths(process.cwd()),
|
|
995
997
|
};
|
|
998
|
+
// Transitive dependencies (e.g. scheduler) must resolve from their importer.
|
|
996
999
|
const forcedPackageRequests = [
|
|
997
1000
|
"@webtypen/webframez-core",
|
|
998
1001
|
"@webtypen/webframez-react",
|
|
@@ -1007,7 +1010,6 @@ const forcedPackageRequests = [
|
|
|
1007
1010
|
"react-server-dom-webpack/server",
|
|
1008
1011
|
"react-server-dom-webpack/client",
|
|
1009
1012
|
"react-server-dom-webpack/client.node",
|
|
1010
|
-
"scheduler"
|
|
1011
1013
|
];
|
|
1012
1014
|
|
|
1013
1015
|
function shouldForcePackageResolution(request) {
|
|
@@ -1199,13 +1201,17 @@ async function renderHtmlFromFlightData(flightData, moduleMap) {
|
|
|
1199
1201
|
? payload.head.basename
|
|
1200
1202
|
: "";
|
|
1201
1203
|
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1204
|
+
const routingContext = globalThis.__WEBFRAMEZ_ROUTING_CONTEXT__ ??=
|
|
1205
|
+
new (require("node:async_hooks").AsyncLocalStorage)();
|
|
1206
|
+
return routingContext.run(basename, async () => {
|
|
1207
|
+
const previousBasename = globalThis.__RSC_BASENAME;
|
|
1208
|
+
globalThis.__RSC_BASENAME = basename;
|
|
1209
|
+
try {
|
|
1210
|
+
return await renderHtml(model);
|
|
1211
|
+
} finally {
|
|
1212
|
+
globalThis.__RSC_BASENAME = previousBasename;
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1209
1215
|
}
|
|
1210
1216
|
|
|
1211
1217
|
process.on("message", async (message) => {
|
|
@@ -1441,24 +1447,10 @@ ${stderrBuffer.trim()}` : "";
|
|
|
1441
1447
|
}
|
|
1442
1448
|
};
|
|
1443
1449
|
}
|
|
1450
|
+
var routingRuntime = globalThis;
|
|
1451
|
+
var basenameContext = routingRuntime.__WEBFRAMEZ_ROUTING_CONTEXT__ ??= new import_node_async_hooks.AsyncLocalStorage();
|
|
1444
1452
|
function withRequestBasename(basename, fn) {
|
|
1445
|
-
|
|
1446
|
-
const previous = target.__RSC_BASENAME;
|
|
1447
|
-
target.__RSC_BASENAME = basename;
|
|
1448
|
-
const finish = () => {
|
|
1449
|
-
target.__RSC_BASENAME = previous;
|
|
1450
|
-
};
|
|
1451
|
-
try {
|
|
1452
|
-
const result = fn();
|
|
1453
|
-
if (result && typeof result.then === "function") {
|
|
1454
|
-
return result.finally(finish);
|
|
1455
|
-
}
|
|
1456
|
-
finish();
|
|
1457
|
-
return result;
|
|
1458
|
-
} catch (error) {
|
|
1459
|
-
finish();
|
|
1460
|
-
throw error;
|
|
1461
|
-
}
|
|
1453
|
+
return basenameContext.run(basename, fn);
|
|
1462
1454
|
}
|
|
1463
1455
|
function parseCookies(rawCookieHeader) {
|
|
1464
1456
|
const raw = Array.isArray(rawCookieHeader) ? rawCookieHeader.join("; ") : rawCookieHeader ?? "";
|
|
@@ -1493,12 +1485,27 @@ function normalizeClientManifest(manifest, options) {
|
|
|
1493
1485
|
}
|
|
1494
1486
|
};
|
|
1495
1487
|
for (const [key, value] of Object.entries(manifest)) {
|
|
1488
|
+
const hashIndex = key.indexOf("#");
|
|
1489
|
+
const moduleKey = hashIndex < 0 ? key : key.slice(0, hashIndex);
|
|
1490
|
+
const exportSuffix = hashIndex < 0 ? "" : key.slice(hashIndex);
|
|
1491
|
+
if (!import_node_path3.default.isAbsolute(moduleKey) && !moduleKey.includes(":") && !moduleKey.startsWith("file://")) {
|
|
1492
|
+
const runtimePath = import_node_path3.default.resolve(options.cwd, moduleKey);
|
|
1493
|
+
const allowedRoots = [options.distRootDir, ...candidateNodeModulesDirs];
|
|
1494
|
+
const insideArtifact = allowedRoots.some((root) => {
|
|
1495
|
+
const relative = import_node_path3.default.relative(import_node_path3.default.resolve(root), runtimePath);
|
|
1496
|
+
return relative !== "" && relative !== ".." && !relative.startsWith(`..${import_node_path3.default.sep}`) && !import_node_path3.default.isAbsolute(relative);
|
|
1497
|
+
});
|
|
1498
|
+
if (insideArtifact) {
|
|
1499
|
+
addAlias(`${runtimePath}${exportSuffix}`, value);
|
|
1500
|
+
addAlias(`${(0, import_node_url.pathToFileURL)(runtimePath).href}${exportSuffix}`, value);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1496
1503
|
if (!key.startsWith("file://")) {
|
|
1497
1504
|
continue;
|
|
1498
1505
|
}
|
|
1499
1506
|
let absolutePath = "";
|
|
1500
1507
|
try {
|
|
1501
|
-
absolutePath = (0, import_node_url.fileURLToPath)(
|
|
1508
|
+
absolutePath = (0, import_node_url.fileURLToPath)(moduleKey);
|
|
1502
1509
|
} catch {
|
|
1503
1510
|
continue;
|
|
1504
1511
|
}
|
|
@@ -1509,13 +1516,13 @@ function normalizeClientManifest(manifest, options) {
|
|
|
1509
1516
|
}
|
|
1510
1517
|
const relativeModulePath = absolutePath.slice(markerIndex + marker.length);
|
|
1511
1518
|
const relativeModulePathPosix = relativeModulePath.split(import_node_path3.default.sep).join("/");
|
|
1512
|
-
addAlias(`./node_modules/${relativeModulePathPosix}`, value);
|
|
1513
|
-
addAlias(`node_modules/${relativeModulePathPosix}`, value);
|
|
1514
|
-
addAlias(absolutePath
|
|
1519
|
+
addAlias(`./node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
|
|
1520
|
+
addAlias(`node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
|
|
1521
|
+
addAlias(`${absolutePath}${exportSuffix}`, value);
|
|
1515
1522
|
for (const nodeModulesDir of candidateNodeModulesDirs) {
|
|
1516
1523
|
const aliasPath = import_node_path3.default.join(nodeModulesDir, relativeModulePath);
|
|
1517
|
-
addAlias(aliasPath
|
|
1518
|
-
addAlias((0, import_node_url.pathToFileURL)(aliasPath).href
|
|
1524
|
+
addAlias(`${aliasPath}${exportSuffix}`, value);
|
|
1525
|
+
addAlias(`${(0, import_node_url.pathToFileURL)(aliasPath).href}${exportSuffix}`, value);
|
|
1519
1526
|
}
|
|
1520
1527
|
}
|
|
1521
1528
|
return normalized;
|
|
@@ -1660,10 +1667,10 @@ function createNodeRequestHandler(options) {
|
|
|
1660
1667
|
const manifestPath = import_node_path3.default.resolve(
|
|
1661
1668
|
options.manifestPath ?? import_node_path3.default.join(distRootDir, "react-client-manifest.json")
|
|
1662
1669
|
);
|
|
1663
|
-
const assetsPrefix = options.assetsPrefix ?? "/assets/";
|
|
1664
|
-
const rscPath = options.rscPath ?? "/rsc";
|
|
1665
|
-
const clientScriptUrl = options.clientScriptUrl ?? "/assets/client.js";
|
|
1666
1670
|
const basePath = normalizeBasePath(options.basePath);
|
|
1671
|
+
const assetsPrefix = options.assetsPrefix ?? `${basePath}/assets/`;
|
|
1672
|
+
const rscPath = options.rscPath ?? `${basePath}/rsc`;
|
|
1673
|
+
const clientScriptUrl = options.clientScriptUrl ?? `${basePath}/assets/client.js`;
|
|
1667
1674
|
const nodeEnv = process.env.NODE_ENV || "";
|
|
1668
1675
|
const runningInWatchMode = Array.isArray(process.execArgv) && process.execArgv.includes("--watch");
|
|
1669
1676
|
const liveReloadEnabled = options.liveReloadPath !== false && (nodeEnv === "development" || runningInWatchMode);
|
|
@@ -1682,7 +1689,7 @@ function createNodeRequestHandler(options) {
|
|
|
1682
1689
|
process.once("exit", disposeInitialHtmlWorker);
|
|
1683
1690
|
process.once("SIGINT", disposeInitialHtmlWorker);
|
|
1684
1691
|
process.once("SIGTERM", disposeInitialHtmlWorker);
|
|
1685
|
-
|
|
1692
|
+
const handleRequest = async (req, res) => {
|
|
1686
1693
|
if (!req.url) {
|
|
1687
1694
|
res.statusCode = 400;
|
|
1688
1695
|
res.end("Bad request");
|
|
@@ -1746,6 +1753,7 @@ function createNodeRequestHandler(options) {
|
|
|
1746
1753
|
request: requestContext
|
|
1747
1754
|
})
|
|
1748
1755
|
);
|
|
1756
|
+
resolved2.head = { ...resolved2.head, basename: resolved2.head.basename ?? basePath };
|
|
1749
1757
|
attachResolvedContextToCoreRequest(req, resolved2.context);
|
|
1750
1758
|
const payload = {
|
|
1751
1759
|
model: resolved2.model,
|
|
@@ -1821,6 +1829,7 @@ function createNodeRequestHandler(options) {
|
|
|
1821
1829
|
)
|
|
1822
1830
|
})
|
|
1823
1831
|
);
|
|
1832
|
+
resolved.head = { ...resolved.head, basename: resolved.head.basename ?? basePath };
|
|
1824
1833
|
attachResolvedContextToCoreRequest(req, resolved.context);
|
|
1825
1834
|
const initialPayload = {
|
|
1826
1835
|
model: resolved.model,
|
|
@@ -1906,8 +1915,30 @@ function createNodeRequestHandler(options) {
|
|
|
1906
1915
|
}
|
|
1907
1916
|
);
|
|
1908
1917
|
};
|
|
1918
|
+
return (req, res) => withRequestBasename(basePath, () => handleRequest(req, res));
|
|
1919
|
+
}
|
|
1920
|
+
var standaloneHtmlWorker;
|
|
1921
|
+
async function renderReactToHtml(element) {
|
|
1922
|
+
if (!standaloneHtmlWorker) {
|
|
1923
|
+
standaloneHtmlWorker = createInitialHtmlWorker(process.cwd());
|
|
1924
|
+
process.once("exit", disposeReactHtmlRenderer);
|
|
1925
|
+
}
|
|
1926
|
+
const flightData = await renderRSCToString({ model: element }, {
|
|
1927
|
+
moduleMap: {},
|
|
1928
|
+
onError: (error) => {
|
|
1929
|
+
console.error("[webframez-react] HTML render failed", error);
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
return standaloneHtmlWorker.renderFromFlightData({ flightData, moduleMap: {} });
|
|
1933
|
+
}
|
|
1934
|
+
function disposeReactHtmlRenderer() {
|
|
1935
|
+
process.removeListener("exit", disposeReactHtmlRenderer);
|
|
1936
|
+
standaloneHtmlWorker?.dispose();
|
|
1937
|
+
standaloneHtmlWorker = void 0;
|
|
1909
1938
|
}
|
|
1910
1939
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1911
1940
|
0 && (module.exports = {
|
|
1912
|
-
createNodeRequestHandler
|
|
1941
|
+
createNodeRequestHandler,
|
|
1942
|
+
disposeReactHtmlRenderer,
|
|
1943
|
+
renderReactToHtml
|
|
1913
1944
|
});
|
package/dist/http.d.ts
CHANGED
|
@@ -27,3 +27,6 @@ export interface CreateNodeHandlerOptions
|
|
|
27
27
|
export function createNodeRequestHandler(
|
|
28
28
|
options: CreateNodeHandlerOptions
|
|
29
29
|
): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
30
|
+
|
|
31
|
+
export function renderReactToHtml(element: unknown): Promise<string>;
|
|
32
|
+
export function disposeReactHtmlRenderer(): void;
|
package/dist/http.js
CHANGED
|
@@ -7,6 +7,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// src/http.ts
|
|
10
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
11
|
import fs2 from "node:fs";
|
|
11
12
|
import path3 from "node:path";
|
|
12
13
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -321,8 +322,7 @@ var FORCED_PACKAGE_REQUESTS = [
|
|
|
321
322
|
"react-server-dom-webpack",
|
|
322
323
|
"react-server-dom-webpack/server",
|
|
323
324
|
"react-server-dom-webpack/client",
|
|
324
|
-
"react-server-dom-webpack/client.node"
|
|
325
|
-
"scheduler"
|
|
325
|
+
"react-server-dom-webpack/client.node"
|
|
326
326
|
];
|
|
327
327
|
var forcedPackageResolutionInstalled = false;
|
|
328
328
|
function normalizePathname(pathname) {
|
|
@@ -973,6 +973,7 @@ const rootParent = {
|
|
|
973
973
|
path: process.cwd(),
|
|
974
974
|
paths: Module._nodeModulePaths(process.cwd()),
|
|
975
975
|
};
|
|
976
|
+
// Transitive dependencies (e.g. scheduler) must resolve from their importer.
|
|
976
977
|
const forcedPackageRequests = [
|
|
977
978
|
"@webtypen/webframez-core",
|
|
978
979
|
"@webtypen/webframez-react",
|
|
@@ -987,7 +988,6 @@ const forcedPackageRequests = [
|
|
|
987
988
|
"react-server-dom-webpack/server",
|
|
988
989
|
"react-server-dom-webpack/client",
|
|
989
990
|
"react-server-dom-webpack/client.node",
|
|
990
|
-
"scheduler"
|
|
991
991
|
];
|
|
992
992
|
|
|
993
993
|
function shouldForcePackageResolution(request) {
|
|
@@ -1179,13 +1179,17 @@ async function renderHtmlFromFlightData(flightData, moduleMap) {
|
|
|
1179
1179
|
? payload.head.basename
|
|
1180
1180
|
: "";
|
|
1181
1181
|
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1182
|
+
const routingContext = globalThis.__WEBFRAMEZ_ROUTING_CONTEXT__ ??=
|
|
1183
|
+
new (require("node:async_hooks").AsyncLocalStorage)();
|
|
1184
|
+
return routingContext.run(basename, async () => {
|
|
1185
|
+
const previousBasename = globalThis.__RSC_BASENAME;
|
|
1186
|
+
globalThis.__RSC_BASENAME = basename;
|
|
1187
|
+
try {
|
|
1188
|
+
return await renderHtml(model);
|
|
1189
|
+
} finally {
|
|
1190
|
+
globalThis.__RSC_BASENAME = previousBasename;
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1189
1193
|
}
|
|
1190
1194
|
|
|
1191
1195
|
process.on("message", async (message) => {
|
|
@@ -1421,24 +1425,10 @@ ${stderrBuffer.trim()}` : "";
|
|
|
1421
1425
|
}
|
|
1422
1426
|
};
|
|
1423
1427
|
}
|
|
1428
|
+
var routingRuntime = globalThis;
|
|
1429
|
+
var basenameContext = routingRuntime.__WEBFRAMEZ_ROUTING_CONTEXT__ ??= new AsyncLocalStorage();
|
|
1424
1430
|
function withRequestBasename(basename, fn) {
|
|
1425
|
-
|
|
1426
|
-
const previous = target.__RSC_BASENAME;
|
|
1427
|
-
target.__RSC_BASENAME = basename;
|
|
1428
|
-
const finish = () => {
|
|
1429
|
-
target.__RSC_BASENAME = previous;
|
|
1430
|
-
};
|
|
1431
|
-
try {
|
|
1432
|
-
const result = fn();
|
|
1433
|
-
if (result && typeof result.then === "function") {
|
|
1434
|
-
return result.finally(finish);
|
|
1435
|
-
}
|
|
1436
|
-
finish();
|
|
1437
|
-
return result;
|
|
1438
|
-
} catch (error) {
|
|
1439
|
-
finish();
|
|
1440
|
-
throw error;
|
|
1441
|
-
}
|
|
1431
|
+
return basenameContext.run(basename, fn);
|
|
1442
1432
|
}
|
|
1443
1433
|
function parseCookies(rawCookieHeader) {
|
|
1444
1434
|
const raw = Array.isArray(rawCookieHeader) ? rawCookieHeader.join("; ") : rawCookieHeader ?? "";
|
|
@@ -1473,12 +1463,27 @@ function normalizeClientManifest(manifest, options) {
|
|
|
1473
1463
|
}
|
|
1474
1464
|
};
|
|
1475
1465
|
for (const [key, value] of Object.entries(manifest)) {
|
|
1466
|
+
const hashIndex = key.indexOf("#");
|
|
1467
|
+
const moduleKey = hashIndex < 0 ? key : key.slice(0, hashIndex);
|
|
1468
|
+
const exportSuffix = hashIndex < 0 ? "" : key.slice(hashIndex);
|
|
1469
|
+
if (!path3.isAbsolute(moduleKey) && !moduleKey.includes(":") && !moduleKey.startsWith("file://")) {
|
|
1470
|
+
const runtimePath = path3.resolve(options.cwd, moduleKey);
|
|
1471
|
+
const allowedRoots = [options.distRootDir, ...candidateNodeModulesDirs];
|
|
1472
|
+
const insideArtifact = allowedRoots.some((root) => {
|
|
1473
|
+
const relative = path3.relative(path3.resolve(root), runtimePath);
|
|
1474
|
+
return relative !== "" && relative !== ".." && !relative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relative);
|
|
1475
|
+
});
|
|
1476
|
+
if (insideArtifact) {
|
|
1477
|
+
addAlias(`${runtimePath}${exportSuffix}`, value);
|
|
1478
|
+
addAlias(`${pathToFileURL(runtimePath).href}${exportSuffix}`, value);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1476
1481
|
if (!key.startsWith("file://")) {
|
|
1477
1482
|
continue;
|
|
1478
1483
|
}
|
|
1479
1484
|
let absolutePath = "";
|
|
1480
1485
|
try {
|
|
1481
|
-
absolutePath = fileURLToPath(
|
|
1486
|
+
absolutePath = fileURLToPath(moduleKey);
|
|
1482
1487
|
} catch {
|
|
1483
1488
|
continue;
|
|
1484
1489
|
}
|
|
@@ -1489,13 +1494,13 @@ function normalizeClientManifest(manifest, options) {
|
|
|
1489
1494
|
}
|
|
1490
1495
|
const relativeModulePath = absolutePath.slice(markerIndex + marker.length);
|
|
1491
1496
|
const relativeModulePathPosix = relativeModulePath.split(path3.sep).join("/");
|
|
1492
|
-
addAlias(`./node_modules/${relativeModulePathPosix}`, value);
|
|
1493
|
-
addAlias(`node_modules/${relativeModulePathPosix}`, value);
|
|
1494
|
-
addAlias(absolutePath
|
|
1497
|
+
addAlias(`./node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
|
|
1498
|
+
addAlias(`node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
|
|
1499
|
+
addAlias(`${absolutePath}${exportSuffix}`, value);
|
|
1495
1500
|
for (const nodeModulesDir of candidateNodeModulesDirs) {
|
|
1496
1501
|
const aliasPath = path3.join(nodeModulesDir, relativeModulePath);
|
|
1497
|
-
addAlias(aliasPath
|
|
1498
|
-
addAlias(pathToFileURL(aliasPath).href
|
|
1502
|
+
addAlias(`${aliasPath}${exportSuffix}`, value);
|
|
1503
|
+
addAlias(`${pathToFileURL(aliasPath).href}${exportSuffix}`, value);
|
|
1499
1504
|
}
|
|
1500
1505
|
}
|
|
1501
1506
|
return normalized;
|
|
@@ -1640,10 +1645,10 @@ function createNodeRequestHandler(options) {
|
|
|
1640
1645
|
const manifestPath = path3.resolve(
|
|
1641
1646
|
options.manifestPath ?? path3.join(distRootDir, "react-client-manifest.json")
|
|
1642
1647
|
);
|
|
1643
|
-
const assetsPrefix = options.assetsPrefix ?? "/assets/";
|
|
1644
|
-
const rscPath = options.rscPath ?? "/rsc";
|
|
1645
|
-
const clientScriptUrl = options.clientScriptUrl ?? "/assets/client.js";
|
|
1646
1648
|
const basePath = normalizeBasePath(options.basePath);
|
|
1649
|
+
const assetsPrefix = options.assetsPrefix ?? `${basePath}/assets/`;
|
|
1650
|
+
const rscPath = options.rscPath ?? `${basePath}/rsc`;
|
|
1651
|
+
const clientScriptUrl = options.clientScriptUrl ?? `${basePath}/assets/client.js`;
|
|
1647
1652
|
const nodeEnv = process.env.NODE_ENV || "";
|
|
1648
1653
|
const runningInWatchMode = Array.isArray(process.execArgv) && process.execArgv.includes("--watch");
|
|
1649
1654
|
const liveReloadEnabled = options.liveReloadPath !== false && (nodeEnv === "development" || runningInWatchMode);
|
|
@@ -1662,7 +1667,7 @@ function createNodeRequestHandler(options) {
|
|
|
1662
1667
|
process.once("exit", disposeInitialHtmlWorker);
|
|
1663
1668
|
process.once("SIGINT", disposeInitialHtmlWorker);
|
|
1664
1669
|
process.once("SIGTERM", disposeInitialHtmlWorker);
|
|
1665
|
-
|
|
1670
|
+
const handleRequest = async (req, res) => {
|
|
1666
1671
|
if (!req.url) {
|
|
1667
1672
|
res.statusCode = 400;
|
|
1668
1673
|
res.end("Bad request");
|
|
@@ -1726,6 +1731,7 @@ function createNodeRequestHandler(options) {
|
|
|
1726
1731
|
request: requestContext
|
|
1727
1732
|
})
|
|
1728
1733
|
);
|
|
1734
|
+
resolved2.head = { ...resolved2.head, basename: resolved2.head.basename ?? basePath };
|
|
1729
1735
|
attachResolvedContextToCoreRequest(req, resolved2.context);
|
|
1730
1736
|
const payload = {
|
|
1731
1737
|
model: resolved2.model,
|
|
@@ -1801,6 +1807,7 @@ function createNodeRequestHandler(options) {
|
|
|
1801
1807
|
)
|
|
1802
1808
|
})
|
|
1803
1809
|
);
|
|
1810
|
+
resolved.head = { ...resolved.head, basename: resolved.head.basename ?? basePath };
|
|
1804
1811
|
attachResolvedContextToCoreRequest(req, resolved.context);
|
|
1805
1812
|
const initialPayload = {
|
|
1806
1813
|
model: resolved.model,
|
|
@@ -1886,7 +1893,29 @@ function createNodeRequestHandler(options) {
|
|
|
1886
1893
|
}
|
|
1887
1894
|
);
|
|
1888
1895
|
};
|
|
1896
|
+
return (req, res) => withRequestBasename(basePath, () => handleRequest(req, res));
|
|
1897
|
+
}
|
|
1898
|
+
var standaloneHtmlWorker;
|
|
1899
|
+
async function renderReactToHtml(element) {
|
|
1900
|
+
if (!standaloneHtmlWorker) {
|
|
1901
|
+
standaloneHtmlWorker = createInitialHtmlWorker(process.cwd());
|
|
1902
|
+
process.once("exit", disposeReactHtmlRenderer);
|
|
1903
|
+
}
|
|
1904
|
+
const flightData = await renderRSCToString({ model: element }, {
|
|
1905
|
+
moduleMap: {},
|
|
1906
|
+
onError: (error) => {
|
|
1907
|
+
console.error("[webframez-react] HTML render failed", error);
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
return standaloneHtmlWorker.renderFromFlightData({ flightData, moduleMap: {} });
|
|
1911
|
+
}
|
|
1912
|
+
function disposeReactHtmlRenderer() {
|
|
1913
|
+
process.removeListener("exit", disposeReactHtmlRenderer);
|
|
1914
|
+
standaloneHtmlWorker?.dispose();
|
|
1915
|
+
standaloneHtmlWorker = void 0;
|
|
1889
1916
|
}
|
|
1890
1917
|
export {
|
|
1891
|
-
createNodeRequestHandler
|
|
1918
|
+
createNodeRequestHandler,
|
|
1919
|
+
disposeReactHtmlRenderer,
|
|
1920
|
+
renderReactToHtml
|
|
1892
1921
|
};
|