weifuwu 0.33.0 → 0.33.1
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 +145 -144
- package/dist/index.d.ts +0 -3
- package/dist/index.js +22 -470
- package/dist/middleware/esbuild-dev.d.ts +1 -15
- package/dist/middleware/esbuild-dev.js +17 -86
- package/dist/types.d.ts +0 -1
- package/package.json +1 -21
- package/dist/react/client.d.ts +0 -76
- package/dist/react/client.js +0 -182
- package/dist/react/compile.d.ts +0 -17
- package/dist/react/context.d.ts +0 -2
- package/dist/react/error-boundary.d.ts +0 -30
- package/dist/react/hooks.d.ts +0 -6
- package/dist/react/index.d.ts +0 -92
- package/dist/react/index.js +0 -910
- package/dist/react/types.d.ts +0 -146
package/dist/index.js
CHANGED
|
@@ -225,14 +225,14 @@ function serve(router, options) {
|
|
|
225
225
|
if (!server.listening) return;
|
|
226
226
|
server.close();
|
|
227
227
|
server.closeIdleConnections();
|
|
228
|
-
return new Promise((
|
|
228
|
+
return new Promise((resolve5) => {
|
|
229
229
|
const timer = setTimeout(() => {
|
|
230
230
|
server.closeAllConnections();
|
|
231
|
-
|
|
231
|
+
resolve5();
|
|
232
232
|
}, timeoutMs);
|
|
233
233
|
server.on("close", () => {
|
|
234
234
|
clearTimeout(timer);
|
|
235
|
-
|
|
235
|
+
resolve5();
|
|
236
236
|
});
|
|
237
237
|
});
|
|
238
238
|
}
|
|
@@ -277,7 +277,7 @@ function createHub(opts) {
|
|
|
277
277
|
}
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
|
-
function
|
|
280
|
+
function join3(key, ws) {
|
|
281
281
|
if (!channels.has(key)) {
|
|
282
282
|
channels.set(key, /* @__PURE__ */ new Set());
|
|
283
283
|
redisSub?.subscribe(`${prefix}${key}`);
|
|
@@ -339,7 +339,7 @@ function createHub(opts) {
|
|
|
339
339
|
redisPub = void 0;
|
|
340
340
|
redisSub = null;
|
|
341
341
|
}
|
|
342
|
-
return { join:
|
|
342
|
+
return { join: join3, leave, broadcast, close };
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
// src/core/ws.ts
|
|
@@ -1296,90 +1296,22 @@ ${String(err)}`;
|
|
|
1296
1296
|
}
|
|
1297
1297
|
async function compile(entry) {
|
|
1298
1298
|
const esbuild = await getEsbuild();
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
${entries2.join("\n")}
|
|
1316
|
-
}`;
|
|
1317
|
-
} else if (cr.routes) {
|
|
1318
|
-
routesCode = `import { routes } from '${cr.routes}'`;
|
|
1319
|
-
} else {
|
|
1320
|
-
routesCode = "const routes = {}";
|
|
1321
|
-
}
|
|
1322
|
-
const fallbackLine = cr.fallback ? `const fallback = () => import('${cr.fallback}')` : "";
|
|
1323
|
-
const fallbackOpt = cr.fallback ? " fallback," : "";
|
|
1324
|
-
const generatedCode = [
|
|
1325
|
-
`import { createBrowserRouter } from 'weifuwu/react/client'`,
|
|
1326
|
-
layoutImport,
|
|
1327
|
-
routesCode,
|
|
1328
|
-
fallbackLine,
|
|
1329
|
-
"",
|
|
1330
|
-
"createBrowserRouter({",
|
|
1331
|
-
" layout: Layout,",
|
|
1332
|
-
" routes,",
|
|
1333
|
-
fallbackOpt,
|
|
1334
|
-
"})"
|
|
1335
|
-
].filter(Boolean).join("\n");
|
|
1336
|
-
buildOpts = {
|
|
1337
|
-
entryPoints: [virtualModule],
|
|
1338
|
-
bundle: entry.bundle ?? true,
|
|
1339
|
-
external: entry.external ?? [],
|
|
1340
|
-
minify: entry.minify ?? true,
|
|
1341
|
-
platform: entry.platform ?? "browser",
|
|
1342
|
-
format: entry.format ?? "esm",
|
|
1343
|
-
sourcemap: entry.sourcemap ?? false,
|
|
1344
|
-
splitting: entry.splitting ?? false,
|
|
1345
|
-
...entry.splitting ? { outdir: resolve3(".weifuwu-esbuild-out") } : {},
|
|
1346
|
-
define: entry.define,
|
|
1347
|
-
loader: entry.loader,
|
|
1348
|
-
write: false,
|
|
1349
|
-
logLevel: "silent",
|
|
1350
|
-
plugins: [{
|
|
1351
|
-
name: "weifuwu-client-router",
|
|
1352
|
-
setup(build) {
|
|
1353
|
-
build.onResolve({ filter: new RegExp(`^${virtualModule.replace(/:/g, "\\:")}$`) }, () => ({
|
|
1354
|
-
path: virtualModule,
|
|
1355
|
-
namespace: "weifuwu-client"
|
|
1356
|
-
}));
|
|
1357
|
-
build.onLoad({ filter: /.*/, namespace: "weifuwu-client" }, () => ({
|
|
1358
|
-
contents: generatedCode,
|
|
1359
|
-
loader: "ts",
|
|
1360
|
-
resolveDir: process.cwd()
|
|
1361
|
-
}));
|
|
1362
|
-
}
|
|
1363
|
-
}]
|
|
1364
|
-
};
|
|
1365
|
-
} else {
|
|
1366
|
-
entryAbs = resolve3(entry.entry);
|
|
1367
|
-
buildOpts = {
|
|
1368
|
-
entryPoints: [entryAbs],
|
|
1369
|
-
bundle: entry.bundle ?? true,
|
|
1370
|
-
external: entry.external ?? [],
|
|
1371
|
-
minify: entry.minify ?? true,
|
|
1372
|
-
platform: entry.platform ?? "browser",
|
|
1373
|
-
format: entry.format ?? "esm",
|
|
1374
|
-
sourcemap: entry.sourcemap ?? false,
|
|
1375
|
-
splitting: entry.splitting ?? false,
|
|
1376
|
-
...entry.splitting ? { outdir: dirname(entryAbs) } : {},
|
|
1377
|
-
define: entry.define,
|
|
1378
|
-
loader: entry.loader,
|
|
1379
|
-
write: false,
|
|
1380
|
-
logLevel: "silent"
|
|
1381
|
-
};
|
|
1382
|
-
}
|
|
1299
|
+
const entryAbs = resolve3(entry.entry);
|
|
1300
|
+
const buildOpts = {
|
|
1301
|
+
entryPoints: [entryAbs],
|
|
1302
|
+
bundle: entry.bundle ?? true,
|
|
1303
|
+
external: entry.external ?? [],
|
|
1304
|
+
minify: entry.minify ?? true,
|
|
1305
|
+
platform: entry.platform ?? "browser",
|
|
1306
|
+
format: entry.format ?? "esm",
|
|
1307
|
+
sourcemap: entry.sourcemap ?? false,
|
|
1308
|
+
splitting: entry.splitting ?? false,
|
|
1309
|
+
...entry.splitting ? { outdir: dirname(entryAbs) } : {},
|
|
1310
|
+
define: entry.define,
|
|
1311
|
+
loader: entry.loader,
|
|
1312
|
+
write: false,
|
|
1313
|
+
logLevel: "silent"
|
|
1314
|
+
};
|
|
1383
1315
|
const result = await esbuild.build(buildOpts);
|
|
1384
1316
|
const msgs = [];
|
|
1385
1317
|
for (const w of result.warnings) {
|
|
@@ -1479,8 +1411,7 @@ ${entries2.join("\n")}
|
|
|
1479
1411
|
}
|
|
1480
1412
|
}
|
|
1481
1413
|
const { code, etag, chunks } = await compile(config);
|
|
1482
|
-
const
|
|
1483
|
-
const deps = await collectDeps(resolve3(depEntry));
|
|
1414
|
+
const deps = await collectDeps(resolve3(config.entry));
|
|
1484
1415
|
if (cache === "memory") {
|
|
1485
1416
|
cacheStore.set(pathname, { code, etag, files: deps, chunks });
|
|
1486
1417
|
if (chunks) {
|
|
@@ -2490,379 +2421,6 @@ function queue(opts) {
|
|
|
2490
2421
|
return q2;
|
|
2491
2422
|
}
|
|
2492
2423
|
|
|
2493
|
-
// src/react/index.ts
|
|
2494
|
-
import { createElement as createElement2 } from "react";
|
|
2495
|
-
import { renderToReadableStream } from "react-dom/server";
|
|
2496
|
-
|
|
2497
|
-
// src/react/compile.ts
|
|
2498
|
-
import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile4 } from "node:fs/promises";
|
|
2499
|
-
import { resolve as resolve5, join as join3, dirname as dirname2 } from "node:path";
|
|
2500
|
-
import { createHash } from "node:crypto";
|
|
2501
|
-
import { existsSync } from "node:fs";
|
|
2502
|
-
var EXTERNAL_PKGS = [
|
|
2503
|
-
"react",
|
|
2504
|
-
"react/jsx-runtime",
|
|
2505
|
-
"react-dom",
|
|
2506
|
-
"react-dom/server",
|
|
2507
|
-
"react-dom/client",
|
|
2508
|
-
"weifuwu",
|
|
2509
|
-
"weifuwu/react"
|
|
2510
|
-
];
|
|
2511
|
-
var FRAMEWORK_IMPORTS = [
|
|
2512
|
-
"react",
|
|
2513
|
-
"react/jsx-runtime",
|
|
2514
|
-
"react-dom",
|
|
2515
|
-
"react-dom/server",
|
|
2516
|
-
"react-dom/client",
|
|
2517
|
-
"weifuwu",
|
|
2518
|
-
"weifuwu/react"
|
|
2519
|
-
];
|
|
2520
|
-
var memCache = /* @__PURE__ */ new Map();
|
|
2521
|
-
function buildResolveMap() {
|
|
2522
|
-
const map = {};
|
|
2523
|
-
for (const spec of FRAMEWORK_IMPORTS) {
|
|
2524
|
-
try {
|
|
2525
|
-
map[spec] = import.meta.resolve(spec);
|
|
2526
|
-
} catch {
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
return map;
|
|
2530
|
-
}
|
|
2531
|
-
var _resolveMap = null;
|
|
2532
|
-
function resolveMap() {
|
|
2533
|
-
if (!_resolveMap) _resolveMap = buildResolveMap();
|
|
2534
|
-
return _resolveMap;
|
|
2535
|
-
}
|
|
2536
|
-
function rewriteImports(code) {
|
|
2537
|
-
const map = resolveMap();
|
|
2538
|
-
let result = code;
|
|
2539
|
-
for (const [spec, url] of Object.entries(map)) {
|
|
2540
|
-
const quoted = JSON.stringify(spec);
|
|
2541
|
-
const escaped = quoted.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2542
|
-
result = result.replace(new RegExp(`(from\\s+)${escaped}`, "g"), `$1${JSON.stringify(url)}`).replace(new RegExp(`(import\\s+)${escaped}(\\s*;)`, "g"), `$1${JSON.stringify(url)}$2`).replace(new RegExp(`(export\\s+.*?from\\s+)${escaped}`, "g"), `$1${JSON.stringify(url)}`);
|
|
2543
|
-
}
|
|
2544
|
-
return result;
|
|
2545
|
-
}
|
|
2546
|
-
var _cacheDir = null;
|
|
2547
|
-
function setReactCacheDir(dir) {
|
|
2548
|
-
_cacheDir = dir;
|
|
2549
|
-
}
|
|
2550
|
-
function getCacheDir() {
|
|
2551
|
-
if (_cacheDir) return _cacheDir;
|
|
2552
|
-
_cacheDir = join3(process.cwd(), "node_modules", ".weifuwu", "react");
|
|
2553
|
-
return _cacheDir;
|
|
2554
|
-
}
|
|
2555
|
-
async function loadTsxModule(entryPath) {
|
|
2556
|
-
const abs = resolve5(entryPath);
|
|
2557
|
-
let source;
|
|
2558
|
-
try {
|
|
2559
|
-
source = await readFile4(abs, "utf-8");
|
|
2560
|
-
} catch {
|
|
2561
|
-
throw new Error(`Cannot read file: ${entryPath}`);
|
|
2562
|
-
}
|
|
2563
|
-
const sourceHash = createHash("sha256").update(source).digest("hex").slice(0, 16);
|
|
2564
|
-
const memCached = memCache.get(abs);
|
|
2565
|
-
if (memCached && memCached.sourceHash === sourceHash) {
|
|
2566
|
-
return memCached.mod;
|
|
2567
|
-
}
|
|
2568
|
-
const tmpDir = getCacheDir();
|
|
2569
|
-
const tmpFile = join3(tmpDir, `${sourceHash}.mjs`);
|
|
2570
|
-
if (existsSync(tmpFile)) {
|
|
2571
|
-
try {
|
|
2572
|
-
const mod2 = await import(tmpFile + "?" + sourceHash);
|
|
2573
|
-
memCache.set(abs, { sourceHash, mod: mod2 });
|
|
2574
|
-
return mod2;
|
|
2575
|
-
} catch {
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
const esbuild = await import("esbuild");
|
|
2579
|
-
const result = await esbuild.build({
|
|
2580
|
-
entryPoints: [abs],
|
|
2581
|
-
bundle: true,
|
|
2582
|
-
write: false,
|
|
2583
|
-
format: "esm",
|
|
2584
|
-
platform: "node",
|
|
2585
|
-
jsx: "automatic",
|
|
2586
|
-
external: EXTERNAL_PKGS,
|
|
2587
|
-
logLevel: "silent"
|
|
2588
|
-
});
|
|
2589
|
-
let code = result.outputFiles[0]?.text ?? "";
|
|
2590
|
-
if (!code) throw new Error(`esbuild produced empty output for ${entryPath}`);
|
|
2591
|
-
code = rewriteImports(code);
|
|
2592
|
-
await mkdir3(dirname2(tmpFile), { recursive: true });
|
|
2593
|
-
await writeFile3(tmpFile, code);
|
|
2594
|
-
const mod = await import(tmpFile + "?" + sourceHash);
|
|
2595
|
-
memCache.set(abs, { sourceHash, mod });
|
|
2596
|
-
return mod;
|
|
2597
|
-
}
|
|
2598
|
-
async function loadTsxComponent(entryPath) {
|
|
2599
|
-
const mod = await loadTsxModule(entryPath);
|
|
2600
|
-
if (mod.default && typeof mod.default === "function") return mod.default;
|
|
2601
|
-
for (const [, val] of Object.entries(mod)) {
|
|
2602
|
-
if (typeof val === "function") return val;
|
|
2603
|
-
}
|
|
2604
|
-
throw new Error(`No component export found in ${entryPath}. Export a default or named component function.`);
|
|
2605
|
-
}
|
|
2606
|
-
|
|
2607
|
-
// src/react/context.ts
|
|
2608
|
-
import { createContext } from "react";
|
|
2609
|
-
var CTX_KEY = /* @__PURE__ */ Symbol.for("weifuwu.react.ServerDataContext");
|
|
2610
|
-
function getServerDataContext() {
|
|
2611
|
-
const globalStore = globalThis;
|
|
2612
|
-
if (globalStore[CTX_KEY]) return globalStore[CTX_KEY];
|
|
2613
|
-
const ctx = createContext({});
|
|
2614
|
-
ctx.displayName = "ServerData";
|
|
2615
|
-
globalStore[CTX_KEY] = ctx;
|
|
2616
|
-
return ctx;
|
|
2617
|
-
}
|
|
2618
|
-
var ServerDataContext = getServerDataContext();
|
|
2619
|
-
|
|
2620
|
-
// src/react/error-boundary.ts
|
|
2621
|
-
import { createElement, Component } from "react";
|
|
2622
|
-
var ErrorBoundary = class extends Component {
|
|
2623
|
-
state = { hasError: false, error: null };
|
|
2624
|
-
static getDerivedStateFromError(error) {
|
|
2625
|
-
return { hasError: true, error };
|
|
2626
|
-
}
|
|
2627
|
-
componentDidCatch(error) {
|
|
2628
|
-
this.props.onError?.(error);
|
|
2629
|
-
}
|
|
2630
|
-
render() {
|
|
2631
|
-
if (this.state.hasError) {
|
|
2632
|
-
if (this.props.fallback) return this.props.fallback;
|
|
2633
|
-
return createElement(
|
|
2634
|
-
"div",
|
|
2635
|
-
{ style: { padding: "2rem", textAlign: "center" } },
|
|
2636
|
-
createElement("h1", null, "Something went wrong"),
|
|
2637
|
-
createElement("p", null, this.state.error?.message ?? "Unknown error")
|
|
2638
|
-
);
|
|
2639
|
-
}
|
|
2640
|
-
return this.props.children;
|
|
2641
|
-
}
|
|
2642
|
-
};
|
|
2643
|
-
|
|
2644
|
-
// src/react/hooks.ts
|
|
2645
|
-
import { useContext } from "react";
|
|
2646
|
-
function useServerData() {
|
|
2647
|
-
return useContext(ServerDataContext);
|
|
2648
|
-
}
|
|
2649
|
-
|
|
2650
|
-
// src/react/index.ts
|
|
2651
|
-
function HtmlShell({ children, importMap, stylesheets, data }) {
|
|
2652
|
-
const headChildren = [
|
|
2653
|
-
createElement2("meta", { charSet: "utf-8", key: "charset" }),
|
|
2654
|
-
createElement2("meta", { name: "viewport", content: "width=device-width, initial-scale=1", key: "viewport" })
|
|
2655
|
-
];
|
|
2656
|
-
if (stylesheets) {
|
|
2657
|
-
for (const href of stylesheets) {
|
|
2658
|
-
headChildren.push(
|
|
2659
|
-
createElement2("link", { rel: "stylesheet", href, key: `css-${href}` })
|
|
2660
|
-
);
|
|
2661
|
-
}
|
|
2662
|
-
}
|
|
2663
|
-
if (importMap) {
|
|
2664
|
-
headChildren.push(
|
|
2665
|
-
createElement2("script", {
|
|
2666
|
-
type: "importmap",
|
|
2667
|
-
key: "importmap",
|
|
2668
|
-
dangerouslySetInnerHTML: { __html: JSON.stringify(importMap) }
|
|
2669
|
-
})
|
|
2670
|
-
);
|
|
2671
|
-
}
|
|
2672
|
-
const bodyChildren = [
|
|
2673
|
-
createElement2("div", { id: "root", key: "root" }, children)
|
|
2674
|
-
];
|
|
2675
|
-
if (data && Object.keys(data).length > 0) {
|
|
2676
|
-
bodyChildren.push(
|
|
2677
|
-
createElement2("script", {
|
|
2678
|
-
id: "__WEIFUWU_DATA__",
|
|
2679
|
-
type: "application/json",
|
|
2680
|
-
key: "weifuwu-data",
|
|
2681
|
-
dangerouslySetInnerHTML: { __html: JSON.stringify(data).replace(/</g, "\\u003c") }
|
|
2682
|
-
})
|
|
2683
|
-
);
|
|
2684
|
-
}
|
|
2685
|
-
return createElement2(
|
|
2686
|
-
"html",
|
|
2687
|
-
{ lang: "en" },
|
|
2688
|
-
createElement2("head", null, ...headChildren),
|
|
2689
|
-
createElement2("body", null, ...bodyChildren)
|
|
2690
|
-
);
|
|
2691
|
-
}
|
|
2692
|
-
async function renderComponent(Component2, data, layout, renderOpts) {
|
|
2693
|
-
let element = createElement2(Component2, renderOpts.props ?? {});
|
|
2694
|
-
if (layout) {
|
|
2695
|
-
element = createElement2(layout, { children: element });
|
|
2696
|
-
}
|
|
2697
|
-
element = createElement2(ServerDataContext.Provider, { value: data }, element);
|
|
2698
|
-
const page = createElement2(HtmlShell, {
|
|
2699
|
-
children: element,
|
|
2700
|
-
importMap: renderOpts.importMap,
|
|
2701
|
-
stylesheets: renderOpts.stylesheets,
|
|
2702
|
-
data: Object.keys(data).length > 0 ? data : void 0
|
|
2703
|
-
});
|
|
2704
|
-
const rstream = await renderToReadableStream(page, {
|
|
2705
|
-
bootstrapScripts: renderOpts.bootstrapScripts,
|
|
2706
|
-
bootstrapModules: renderOpts.bootstrapModules
|
|
2707
|
-
});
|
|
2708
|
-
if (renderOpts.stream === false) {
|
|
2709
|
-
await rstream.allReady;
|
|
2710
|
-
}
|
|
2711
|
-
return new Response(rstream, {
|
|
2712
|
-
status: renderOpts.status ?? 200,
|
|
2713
|
-
headers: { "content-type": "text/html; charset=utf-8", ...renderOpts.headers }
|
|
2714
|
-
});
|
|
2715
|
-
}
|
|
2716
|
-
function react(opts) {
|
|
2717
|
-
if (opts && "pages" in opts) {
|
|
2718
|
-
return (app) => createFullReactApp(app, opts);
|
|
2719
|
-
}
|
|
2720
|
-
if (opts?.cacheDir) setReactCacheDir(opts.cacheDir);
|
|
2721
|
-
let LayoutComponent = null;
|
|
2722
|
-
let layoutLoaded = false;
|
|
2723
|
-
let layoutLoadError = null;
|
|
2724
|
-
async function getLayout() {
|
|
2725
|
-
if (!opts?.layout) return null;
|
|
2726
|
-
if (layoutLoaded) {
|
|
2727
|
-
if (layoutLoadError) throw layoutLoadError;
|
|
2728
|
-
return LayoutComponent;
|
|
2729
|
-
}
|
|
2730
|
-
try {
|
|
2731
|
-
LayoutComponent = await loadTsxComponent(opts.layout);
|
|
2732
|
-
layoutLoaded = true;
|
|
2733
|
-
return LayoutComponent;
|
|
2734
|
-
} catch (err) {
|
|
2735
|
-
layoutLoadError = err instanceof Error ? err : new Error(String(err));
|
|
2736
|
-
layoutLoaded = true;
|
|
2737
|
-
throw layoutLoadError;
|
|
2738
|
-
}
|
|
2739
|
-
}
|
|
2740
|
-
return async (_req, ctx, next) => {
|
|
2741
|
-
ctx.render = async (path, renderOpts) => {
|
|
2742
|
-
let data = renderOpts?.data ?? {};
|
|
2743
|
-
if (renderOpts?.loader) {
|
|
2744
|
-
const loaderData = await renderOpts.loader(ctx);
|
|
2745
|
-
data = { ...data, ...loaderData };
|
|
2746
|
-
}
|
|
2747
|
-
const Component2 = await loadTsxComponent(path);
|
|
2748
|
-
const layout = await getLayout();
|
|
2749
|
-
return renderComponent(Component2, data, layout, renderOpts ?? {});
|
|
2750
|
-
};
|
|
2751
|
-
return next(_req, ctx);
|
|
2752
|
-
};
|
|
2753
|
-
}
|
|
2754
|
-
async function resolveLoader(modulePath) {
|
|
2755
|
-
const mod = await loadTsxModule(modulePath);
|
|
2756
|
-
return typeof mod.loader === "function" ? mod.loader : null;
|
|
2757
|
-
}
|
|
2758
|
-
async function callLoader(loader, ctx, data, rethrow = true) {
|
|
2759
|
-
if (!loader) return data;
|
|
2760
|
-
try {
|
|
2761
|
-
return { ...data, ...await loader(ctx) };
|
|
2762
|
-
} catch (err) {
|
|
2763
|
-
if (rethrow) throw err;
|
|
2764
|
-
return data;
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
function createFullReactApp(app, opts) {
|
|
2768
|
-
const stylesheets = [...opts.stylesheets ?? []];
|
|
2769
|
-
if (opts.tailwind) {
|
|
2770
|
-
const twPath = opts.tailwind.path ?? "/assets/tailwind.css";
|
|
2771
|
-
const twEntry = opts.tailwind.entry ?? "./styles/input.css";
|
|
2772
|
-
app.use(tailwindDev({ entries: { [twPath]: { entry: twEntry } } }));
|
|
2773
|
-
if (!stylesheets.includes(twPath)) stylesheets.push(twPath);
|
|
2774
|
-
}
|
|
2775
|
-
app.use(react({ layout: opts.layout, cacheDir: opts.cacheDir }));
|
|
2776
|
-
const layoutLoaderP = resolveLoader(opts.layout);
|
|
2777
|
-
const notFoundLoaderP = opts.notFound ? resolveLoader(opts.notFound) : Promise.resolve(null);
|
|
2778
|
-
const clientCfg = typeof opts.client === "object" ? opts.client : {};
|
|
2779
|
-
const clientPath = clientCfg.path ?? "/assets/client.js";
|
|
2780
|
-
const bootstrapModules = [...opts.bootstrapModules ?? []];
|
|
2781
|
-
if (opts.client !== false && !bootstrapModules.includes(clientPath)) {
|
|
2782
|
-
bootstrapModules.push(clientPath);
|
|
2783
|
-
}
|
|
2784
|
-
const renderOpts = {
|
|
2785
|
-
stylesheets: stylesheets.length > 0 ? stylesheets : void 0,
|
|
2786
|
-
bootstrapModules: bootstrapModules.length > 0 ? bootstrapModules : void 0,
|
|
2787
|
-
stream: opts.stream
|
|
2788
|
-
};
|
|
2789
|
-
for (const [path, component] of Object.entries(opts.pages)) {
|
|
2790
|
-
app.get(path, async (_req, ctx) => {
|
|
2791
|
-
let data = {};
|
|
2792
|
-
data = await callLoader(await layoutLoaderP, ctx, data);
|
|
2793
|
-
const pageLoader = opts.loaders?.[path] ?? await resolveLoader(component);
|
|
2794
|
-
data = await callLoader(pageLoader, ctx, data);
|
|
2795
|
-
return ctx.render(component, { ...renderOpts, data });
|
|
2796
|
-
});
|
|
2797
|
-
}
|
|
2798
|
-
if (opts.notFound) {
|
|
2799
|
-
const notFoundPath = opts.notFound;
|
|
2800
|
-
app.onError(async (err, _req, ctx) => {
|
|
2801
|
-
const status = typeof err === "object" && err !== null && "status" in err ? err.status : 500;
|
|
2802
|
-
if (ctx.render) {
|
|
2803
|
-
let data = { error: String(err) };
|
|
2804
|
-
data = await callLoader(await layoutLoaderP, ctx, data, false);
|
|
2805
|
-
data = await callLoader(await notFoundLoaderP, ctx, data, false);
|
|
2806
|
-
return ctx.render(notFoundPath, { ...renderOpts, status, data });
|
|
2807
|
-
}
|
|
2808
|
-
return new Response("Internal Server Error", { status });
|
|
2809
|
-
});
|
|
2810
|
-
}
|
|
2811
|
-
if (opts.client !== false) {
|
|
2812
|
-
app.use(esbuildDev({
|
|
2813
|
-
entries: {
|
|
2814
|
-
[clientPath]: {
|
|
2815
|
-
clientRouter: {
|
|
2816
|
-
pages: opts.pages,
|
|
2817
|
-
layout: opts.layout,
|
|
2818
|
-
fallback: opts.notFound
|
|
2819
|
-
},
|
|
2820
|
-
bundle: true,
|
|
2821
|
-
splitting: clientCfg.splitting ?? true,
|
|
2822
|
-
minify: clientCfg.minify ?? false
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
}));
|
|
2826
|
-
}
|
|
2827
|
-
}
|
|
2828
|
-
function extractImportPath(fn) {
|
|
2829
|
-
const src = fn.toString();
|
|
2830
|
-
const m = src.match(/import\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
2831
|
-
if (!m) throw new Error(`Cannot extract import path from: ${src}`);
|
|
2832
|
-
return m[1];
|
|
2833
|
-
}
|
|
2834
|
-
function reactRouter(app, routes, opts = {}) {
|
|
2835
|
-
let LayoutComponent = null;
|
|
2836
|
-
let layoutPromise = null;
|
|
2837
|
-
async function getLayout() {
|
|
2838
|
-
if (!opts.layout) return null;
|
|
2839
|
-
if (LayoutComponent) return LayoutComponent;
|
|
2840
|
-
if (!layoutPromise) {
|
|
2841
|
-
layoutPromise = loadTsxComponent(opts.layout).then((c) => {
|
|
2842
|
-
LayoutComponent = c;
|
|
2843
|
-
return c;
|
|
2844
|
-
});
|
|
2845
|
-
}
|
|
2846
|
-
return layoutPromise;
|
|
2847
|
-
}
|
|
2848
|
-
for (const [path, importer] of Object.entries(routes)) {
|
|
2849
|
-
app.get(path, async (_req, ctx) => {
|
|
2850
|
-
const cmpPath = extractImportPath(importer);
|
|
2851
|
-
const Component2 = await loadTsxComponent(cmpPath);
|
|
2852
|
-
const layout = await getLayout();
|
|
2853
|
-
let data = {};
|
|
2854
|
-
const loader = opts.loaders?.[path];
|
|
2855
|
-
if (loader) {
|
|
2856
|
-
data = await loader(ctx);
|
|
2857
|
-
}
|
|
2858
|
-
return renderComponent(Component2, data, layout, opts);
|
|
2859
|
-
});
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
function Link({ href, children, ...props }) {
|
|
2863
|
-
return createElement2("a", { href, ...props }, children);
|
|
2864
|
-
}
|
|
2865
|
-
|
|
2866
2424
|
// src/ai/index.ts
|
|
2867
2425
|
function ai(opts) {
|
|
2868
2426
|
let aiModule = null;
|
|
@@ -5224,14 +4782,11 @@ export {
|
|
|
5224
4782
|
Base,
|
|
5225
4783
|
CMS,
|
|
5226
4784
|
DEFAULT_MAX_BODY,
|
|
5227
|
-
ErrorBoundary,
|
|
5228
4785
|
HttpError,
|
|
5229
4786
|
KB,
|
|
5230
|
-
Link,
|
|
5231
4787
|
MIGRATIONS_TABLE,
|
|
5232
4788
|
Messager,
|
|
5233
4789
|
Router,
|
|
5234
|
-
ServerDataContext,
|
|
5235
4790
|
UserModule,
|
|
5236
4791
|
agent,
|
|
5237
4792
|
ai,
|
|
@@ -5251,8 +4806,6 @@ export {
|
|
|
5251
4806
|
postgres,
|
|
5252
4807
|
queue,
|
|
5253
4808
|
rateLimit,
|
|
5254
|
-
react,
|
|
5255
|
-
reactRouter,
|
|
5256
4809
|
redis,
|
|
5257
4810
|
requireRole,
|
|
5258
4811
|
runWithTrace,
|
|
@@ -5263,6 +4816,5 @@ export {
|
|
|
5263
4816
|
trace,
|
|
5264
4817
|
traceElapsed,
|
|
5265
4818
|
upload,
|
|
5266
|
-
useServerData,
|
|
5267
4819
|
user
|
|
5268
4820
|
};
|
|
@@ -19,22 +19,8 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { Middleware, Context } from '../types.ts';
|
|
21
21
|
export interface EsbuildDevEntry {
|
|
22
|
-
/** Source entry point relative to cwd or absolute.
|
|
22
|
+
/** Source entry point relative to cwd or absolute. */
|
|
23
23
|
entry?: string;
|
|
24
|
-
/**
|
|
25
|
-
* Auto-generate a client entry from route config — eliminates client.ts.
|
|
26
|
-
* The generated entry imports routes + layout, calls createBrowserRouter().
|
|
27
|
-
*/
|
|
28
|
-
clientRouter?: {
|
|
29
|
-
/** Path to the shared routes file (relative to cwd). Overridden by `pages`. */
|
|
30
|
-
routes?: string;
|
|
31
|
-
/** Inline page definitions — alternative to a separate routes.ts file. */
|
|
32
|
-
pages?: Record<string, string>;
|
|
33
|
-
/** Layout component import path (relative to cwd). */
|
|
34
|
-
layout: string;
|
|
35
|
-
/** Fallback 404 component import path (relative to cwd). */
|
|
36
|
-
fallback?: string;
|
|
37
|
-
};
|
|
38
24
|
/** Bundle all dependencies (default: true). */
|
|
39
25
|
bundle?: boolean;
|
|
40
26
|
/** Packages to leave external (not bundled). */
|