weifuwu 0.18.2 → 0.18.3
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/index.js +28 -19
- package/dist/router.d.ts +9 -9
- package/dist/ssr/index.d.ts +1 -1
- package/dist/ssr/index.js +372 -375
- package/dist/ssr/ssr.d.ts +2 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -306,6 +306,11 @@ var Router = class _Router {
|
|
|
306
306
|
return this;
|
|
307
307
|
}
|
|
308
308
|
route(method, path2, ...args) {
|
|
309
|
+
const last = args[args.length - 1];
|
|
310
|
+
if (last instanceof _Router) {
|
|
311
|
+
this._mountRouter(path2, last);
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
309
314
|
const handler = args.pop();
|
|
310
315
|
const middlewares = args;
|
|
311
316
|
const segments = this.splitPath(path2);
|
|
@@ -5330,9 +5335,19 @@ function streamResponse(reactStream, opts) {
|
|
|
5330
5335
|
var als = new AsyncLocalStorage();
|
|
5331
5336
|
__registerAls(() => als.getStore());
|
|
5332
5337
|
var isDev = process.env.NODE_ENV !== "production";
|
|
5338
|
+
var bundleCache = /* @__PURE__ */ new Map();
|
|
5333
5339
|
function id2(s) {
|
|
5334
5340
|
return createHash3("md5").update(s).digest("hex").slice(0, 8);
|
|
5335
5341
|
}
|
|
5342
|
+
function serializeLoaderData(ctx) {
|
|
5343
|
+
const data = {};
|
|
5344
|
+
for (const key of Object.keys(ctx)) {
|
|
5345
|
+
if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
|
|
5346
|
+
data[key] = ctx[key];
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
return data;
|
|
5350
|
+
}
|
|
5336
5351
|
async function buildClientBundle(entryPath, layoutPaths) {
|
|
5337
5352
|
try {
|
|
5338
5353
|
const absEntry = resolve4(entryPath);
|
|
@@ -5379,21 +5394,17 @@ async function buildClientBundle(entryPath, layoutPaths) {
|
|
|
5379
5394
|
return null;
|
|
5380
5395
|
}
|
|
5381
5396
|
}
|
|
5382
|
-
var bundleRegistry = /* @__PURE__ */ new Map();
|
|
5383
|
-
function serializeLoaderData(ctx) {
|
|
5384
|
-
const data = {};
|
|
5385
|
-
for (const key of Object.keys(ctx)) {
|
|
5386
|
-
if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
|
|
5387
|
-
data[key] = ctx[key];
|
|
5388
|
-
}
|
|
5389
|
-
}
|
|
5390
|
-
return data;
|
|
5391
|
-
}
|
|
5392
5397
|
function ssr(path2) {
|
|
5393
5398
|
const entryId = id2(resolve4(path2));
|
|
5394
5399
|
const bundleKey = `/__ssr/${entryId}.js`;
|
|
5395
|
-
|
|
5396
|
-
|
|
5400
|
+
const r = new Router();
|
|
5401
|
+
r.get("/__ssr/:path", (req, ctx) => {
|
|
5402
|
+
const buf = bundleCache.get("/__ssr/" + ctx.params.path);
|
|
5403
|
+
return buf ? new Response(buf, {
|
|
5404
|
+
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
5405
|
+
}) : new Response("", { status: 404 });
|
|
5406
|
+
});
|
|
5407
|
+
r.get("/", async (req, ctx) => {
|
|
5397
5408
|
const pageMod = await compileTsx(path2);
|
|
5398
5409
|
const Component = pageMod.default;
|
|
5399
5410
|
if (!Component) return new Response("", { status: 500 });
|
|
@@ -5441,14 +5452,11 @@ function ssr(path2) {
|
|
|
5441
5452
|
}
|
|
5442
5453
|
}
|
|
5443
5454
|
let bundle = null;
|
|
5444
|
-
if (!
|
|
5455
|
+
if (!bundleCache.has(bundleKey)) {
|
|
5445
5456
|
const buf = await buildClientBundle(path2, layoutPaths);
|
|
5446
|
-
if (buf)
|
|
5447
|
-
bundleRegistry.set(bundleKey, buf);
|
|
5448
|
-
bundleBuilt = true;
|
|
5449
|
-
}
|
|
5457
|
+
if (buf) bundleCache.set(bundleKey, buf);
|
|
5450
5458
|
}
|
|
5451
|
-
if (
|
|
5459
|
+
if (bundleCache.has(bundleKey)) {
|
|
5452
5460
|
bundle = { url: bundleKey };
|
|
5453
5461
|
}
|
|
5454
5462
|
const { renderToReadableStream } = await import("react-dom/server");
|
|
@@ -5461,7 +5469,8 @@ function ssr(path2) {
|
|
|
5461
5469
|
loaderData
|
|
5462
5470
|
});
|
|
5463
5471
|
});
|
|
5464
|
-
};
|
|
5472
|
+
});
|
|
5473
|
+
return r;
|
|
5465
5474
|
}
|
|
5466
5475
|
|
|
5467
5476
|
// ssr/layout.ts
|
package/dist/router.d.ts
CHANGED
|
@@ -19,16 +19,16 @@ export declare class Router {
|
|
|
19
19
|
use(router: Router): this;
|
|
20
20
|
use(path: string, router: Router): this;
|
|
21
21
|
use(path: string, mw: Middleware): this;
|
|
22
|
-
get(path: string, ...args: [...Middleware[], Handler]): this;
|
|
23
|
-
post(path: string, ...args: [...Middleware[], Handler]): this;
|
|
24
|
-
put(path: string, ...args: [...Middleware[], Handler]): this;
|
|
25
|
-
delete(path: string, ...args: [...Middleware[], Handler]): this;
|
|
26
|
-
patch(path: string, ...args: [...Middleware[], Handler]): this;
|
|
27
|
-
head(path: string, ...args: [...Middleware[], Handler]): this;
|
|
28
|
-
options(path: string, ...args: [...Middleware[], Handler]): this;
|
|
29
|
-
all(path: string, ...args: [...Middleware[], Handler]): this;
|
|
22
|
+
get(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
23
|
+
post(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
24
|
+
put(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
25
|
+
delete(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
26
|
+
patch(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
27
|
+
head(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
28
|
+
options(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
29
|
+
all(path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
30
30
|
onError(handler: ErrorHandler): this;
|
|
31
|
-
route(method: string, path: string, ...args: [...Middleware[], Handler]): this;
|
|
31
|
+
route(method: string, path: string, ...args: [...Middleware[], Handler | Router]): this;
|
|
32
32
|
ws(path: string, ...args: [...Middleware[], WebSocketHandler]): this;
|
|
33
33
|
handler(): Handler;
|
|
34
34
|
websocketHandler(): WsUpgradeHandler;
|
package/dist/ssr/index.d.ts
CHANGED
package/dist/ssr/index.js
CHANGED
|
@@ -231,279 +231,6 @@ function setCtx(value) {
|
|
|
231
231
|
}
|
|
232
232
|
var TsxContext = createContext(DEFAULT_CTX);
|
|
233
233
|
|
|
234
|
-
// ssr/ssr.ts
|
|
235
|
-
var als = new AsyncLocalStorage();
|
|
236
|
-
__registerAls(() => als.getStore());
|
|
237
|
-
var isDev = process.env.NODE_ENV !== "production";
|
|
238
|
-
function id2(s) {
|
|
239
|
-
return createHash2("md5").update(s).digest("hex").slice(0, 8);
|
|
240
|
-
}
|
|
241
|
-
async function buildClientBundle(entryPath, layoutPaths) {
|
|
242
|
-
try {
|
|
243
|
-
const absEntry = resolve2(entryPath);
|
|
244
|
-
const absLayouts = layoutPaths.map((p) => resolve2(p));
|
|
245
|
-
const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
|
|
246
|
-
const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
|
|
247
|
-
const code = [
|
|
248
|
-
layoutImports,
|
|
249
|
-
`import{hydrateRoot}from'react-dom/client';`,
|
|
250
|
-
`import{createElement,useState,useEffect}from'react';`,
|
|
251
|
-
`import{TsxContext}from'weifuwu/react';`,
|
|
252
|
-
`import P from${JSON.stringify(absEntry)};`,
|
|
253
|
-
`var setCtx=${_sc};`,
|
|
254
|
-
`const c=document.getElementById('__weifuwu_root');`,
|
|
255
|
-
`if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
|
|
256
|
-
`if(!window.__WFW_ROOT){`,
|
|
257
|
-
`function App(){`,
|
|
258
|
-
`const[p,setP]=useState({C:P});`,
|
|
259
|
-
`useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
|
|
260
|
-
`const ctx=window.__WEIFUWU_CTX||{};`,
|
|
261
|
-
`return createElement(TsxContext.Provider,{value:ctx},`,
|
|
262
|
-
`createElement(p.C,null))`,
|
|
263
|
-
`}`,
|
|
264
|
-
`window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
|
|
265
|
-
`}else{`,
|
|
266
|
-
`window.__WFW_SET_PAGE?.(P);`,
|
|
267
|
-
`}`
|
|
268
|
-
].join("");
|
|
269
|
-
const { default: esbuild2 } = await import("esbuild");
|
|
270
|
-
const result = await esbuild2.build({
|
|
271
|
-
stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
|
|
272
|
-
bundle: true,
|
|
273
|
-
format: "esm",
|
|
274
|
-
jsx: "automatic",
|
|
275
|
-
jsxImportSource: "react",
|
|
276
|
-
banner: { js: "self.process={env:{}};" },
|
|
277
|
-
loader: { ".node": "empty" },
|
|
278
|
-
write: false,
|
|
279
|
-
minify: true
|
|
280
|
-
});
|
|
281
|
-
return result.outputFiles[0].contents;
|
|
282
|
-
} catch (err) {
|
|
283
|
-
console.error("hydration bundle failed:", err);
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
var bundleRegistry = /* @__PURE__ */ new Map();
|
|
288
|
-
function serializeLoaderData(ctx) {
|
|
289
|
-
const data = {};
|
|
290
|
-
for (const key of Object.keys(ctx)) {
|
|
291
|
-
if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
|
|
292
|
-
data[key] = ctx[key];
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return data;
|
|
296
|
-
}
|
|
297
|
-
function ssr(path) {
|
|
298
|
-
const entryId = id2(resolve2(path));
|
|
299
|
-
const bundleKey = `/__ssr/${entryId}.js`;
|
|
300
|
-
let bundleBuilt = false;
|
|
301
|
-
return async (req, ctx) => {
|
|
302
|
-
const pageMod = await compileTsx(path);
|
|
303
|
-
const Component = pageMod.default;
|
|
304
|
-
if (!Component) return new Response("", { status: 500 });
|
|
305
|
-
const layouts = ctx.layoutStack || [];
|
|
306
|
-
const layoutComponents = layouts.map((l) => l.component);
|
|
307
|
-
const layoutPaths = layouts.map((l) => l.path);
|
|
308
|
-
const base = (ctx.mountPath || "").replace(/\/$/, "");
|
|
309
|
-
const loaderData = serializeLoaderData(ctx);
|
|
310
|
-
const ctxValue = {
|
|
311
|
-
params: ctx.params,
|
|
312
|
-
query: ctx.query,
|
|
313
|
-
user: ctx.user ?? {},
|
|
314
|
-
parsed: ctx.parsed ?? {},
|
|
315
|
-
prefs: ctx.prefs ?? {},
|
|
316
|
-
loaderData,
|
|
317
|
-
env: ctx.env ?? {}
|
|
318
|
-
};
|
|
319
|
-
return als.run(ctxValue, async () => {
|
|
320
|
-
setCtx(ctxValue);
|
|
321
|
-
let element = createElement(
|
|
322
|
-
TsxContext.Provider,
|
|
323
|
-
{ value: ctxValue },
|
|
324
|
-
createElement(
|
|
325
|
-
"div",
|
|
326
|
-
{ id: "__weifuwu_root" },
|
|
327
|
-
createElement(Component, null)
|
|
328
|
-
)
|
|
329
|
-
);
|
|
330
|
-
if (layoutComponents.length === 0) {
|
|
331
|
-
element = createElement(
|
|
332
|
-
"html",
|
|
333
|
-
{ lang: "en" },
|
|
334
|
-
createElement(
|
|
335
|
-
"head",
|
|
336
|
-
null,
|
|
337
|
-
createElement("meta", { charSet: "utf-8" }),
|
|
338
|
-
createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
339
|
-
createElement("title", null, "weifuwu")
|
|
340
|
-
),
|
|
341
|
-
createElement("body", null, element)
|
|
342
|
-
);
|
|
343
|
-
} else {
|
|
344
|
-
for (const L of layoutComponents.toReversed()) {
|
|
345
|
-
element = createElement(L, { children: element });
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
let bundle = null;
|
|
349
|
-
if (!bundleBuilt) {
|
|
350
|
-
const buf = await buildClientBundle(path, layoutPaths);
|
|
351
|
-
if (buf) {
|
|
352
|
-
bundleRegistry.set(bundleKey, buf);
|
|
353
|
-
bundleBuilt = true;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (bundleRegistry.has(bundleKey)) {
|
|
357
|
-
bundle = { url: bundleKey };
|
|
358
|
-
}
|
|
359
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
360
|
-
const stream = await renderToReadableStream(element);
|
|
361
|
-
return streamResponse(stream, {
|
|
362
|
-
ctx,
|
|
363
|
-
base,
|
|
364
|
-
isDev,
|
|
365
|
-
bundle,
|
|
366
|
-
loaderData
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
function ssrBundleHandler() {
|
|
372
|
-
return (req, ctx) => {
|
|
373
|
-
const url = new URL(req.url);
|
|
374
|
-
const buf = bundleRegistry.get(url.pathname);
|
|
375
|
-
return buf ? new Response(buf, {
|
|
376
|
-
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
377
|
-
}) : new Response("", { status: 404 });
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// ssr/layout.ts
|
|
382
|
-
function layout(path) {
|
|
383
|
-
return async (req, ctx, next) => {
|
|
384
|
-
const mod = await compileTsx(path);
|
|
385
|
-
const Component = mod.default;
|
|
386
|
-
if (!Component) throw new Error(`Layout ${path} has no default export`);
|
|
387
|
-
ctx.layoutStack = [...ctx.layoutStack || [], { path, component: Component }];
|
|
388
|
-
return next(req, ctx);
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// ssr/tailwind.ts
|
|
393
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
394
|
-
import { relative, resolve as resolve3 } from "node:path";
|
|
395
|
-
var isDev2 = process.env.NODE_ENV !== "production";
|
|
396
|
-
function tailwind(cssPath, scanDir) {
|
|
397
|
-
let compiledCss = "";
|
|
398
|
-
let twWatcher = null;
|
|
399
|
-
return async (req, ctx, next) => {
|
|
400
|
-
const url = new URL(req.url);
|
|
401
|
-
if (url.pathname === "/__wfw/style.css") {
|
|
402
|
-
if (!compiledCss) compiledCss = await compile(cssPath, scanDir);
|
|
403
|
-
return new Response(compiledCss || "", {
|
|
404
|
-
headers: { "content-type": "text/css; charset=utf-8" }
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
ctx.compiledTailwindCss = compiledCss;
|
|
408
|
-
if (isDev2 && !twWatcher) {
|
|
409
|
-
twWatcher = watchFile(cssPath, () => {
|
|
410
|
-
compiledCss = "";
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
return next(req, ctx);
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
async function compile(cssPath, scanDir) {
|
|
417
|
-
try {
|
|
418
|
-
const inputFile = resolve3(cssPath);
|
|
419
|
-
if (!existsSync2(inputFile)) {
|
|
420
|
-
mkdirSync2(dirname3(inputFile), { recursive: true });
|
|
421
|
-
writeFileSync(inputFile, '@import "tailwindcss"\n', "utf-8");
|
|
422
|
-
}
|
|
423
|
-
const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
|
|
424
|
-
const { default: postcss } = await import("postcss");
|
|
425
|
-
let src = readFileSync2(inputFile, "utf-8");
|
|
426
|
-
const scanSource = scanDir ? relative(dirname3(inputFile), scanDir) || "." : ".";
|
|
427
|
-
const sourcePath = scanSource === "." ? "./" : `./${scanSource}/`;
|
|
428
|
-
src = `@source "${sourcePath}";
|
|
429
|
-
${src}`;
|
|
430
|
-
const result = await postcss([tailwindPlugin()]).process(src, { from: inputFile });
|
|
431
|
-
return result.css;
|
|
432
|
-
} catch (err) {
|
|
433
|
-
console.warn("Tailwind CSS processing failed:", err.message);
|
|
434
|
-
return "";
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
function dirname3(p) {
|
|
438
|
-
return p.substring(0, p.lastIndexOf("/")) || "/";
|
|
439
|
-
}
|
|
440
|
-
function watchFile(path, onChange) {
|
|
441
|
-
let watcher = null;
|
|
442
|
-
import("chokidar").then((chokidar2) => {
|
|
443
|
-
watcher = chokidar2.default.watch(resolve3(path), { persistent: false });
|
|
444
|
-
watcher.on("change", onChange);
|
|
445
|
-
});
|
|
446
|
-
return watcher;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// ssr/not-found.ts
|
|
450
|
-
function notFound(path) {
|
|
451
|
-
return async (req, ctx) => {
|
|
452
|
-
if (!path) return new Response("Not Found", { status: 404 });
|
|
453
|
-
const mod = await compileTsx(path);
|
|
454
|
-
const Component = mod?.default;
|
|
455
|
-
const body = Component ? "404 - Not Found" : "404 - Not Found";
|
|
456
|
-
return new Response(body, {
|
|
457
|
-
status: 404,
|
|
458
|
-
headers: { "content-type": "text/html; charset=utf-8" }
|
|
459
|
-
});
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// ssr/error-boundary.ts
|
|
464
|
-
import { createElement as createElement2 } from "react";
|
|
465
|
-
import { TextEncoder as TextEncoder2 } from "node:util";
|
|
466
|
-
function errorBoundary(errorPath) {
|
|
467
|
-
return async (req, ctx, next) => {
|
|
468
|
-
try {
|
|
469
|
-
return await next(req, ctx);
|
|
470
|
-
} catch (err) {
|
|
471
|
-
const mod = await compileTsx(errorPath);
|
|
472
|
-
const ErrorComponent = mod.default;
|
|
473
|
-
if (!ErrorComponent) throw err;
|
|
474
|
-
const layouts = (ctx.layoutStack || []).map((l) => l.component);
|
|
475
|
-
const stream = await import("react-dom/server").then((m) => m.renderToReadableStream(
|
|
476
|
-
createElement2(ErrorComponent, {
|
|
477
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
478
|
-
reset: () => {
|
|
479
|
-
}
|
|
480
|
-
})
|
|
481
|
-
));
|
|
482
|
-
const reader = stream.getReader();
|
|
483
|
-
const chunks = [];
|
|
484
|
-
while (true) {
|
|
485
|
-
const { done, value } = await reader.read();
|
|
486
|
-
if (done) break;
|
|
487
|
-
chunks.push(value);
|
|
488
|
-
}
|
|
489
|
-
const encoder = new TextEncoder2();
|
|
490
|
-
const body = chunks.reduce((acc, c) => {
|
|
491
|
-
const merged = new Uint8Array(acc.length + c.length);
|
|
492
|
-
merged.set(acc);
|
|
493
|
-
merged.set(c, acc.length);
|
|
494
|
-
return merged;
|
|
495
|
-
}, new Uint8Array(0));
|
|
496
|
-
return new Response(body, {
|
|
497
|
-
status: 500,
|
|
498
|
-
headers: { "content-type": "text/html; charset=utf-8" }
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// ssr/live.ts
|
|
505
|
-
import chokidar from "chokidar";
|
|
506
|
-
|
|
507
234
|
// router.ts
|
|
508
235
|
import { WebSocketServer } from "ws";
|
|
509
236
|
var createTrieNode = () => ({
|
|
@@ -632,6 +359,11 @@ var Router = class _Router {
|
|
|
632
359
|
return this;
|
|
633
360
|
}
|
|
634
361
|
route(method, path, ...args) {
|
|
362
|
+
const last = args[args.length - 1];
|
|
363
|
+
if (last instanceof _Router) {
|
|
364
|
+
this._mountRouter(path, last);
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
635
367
|
const handler = args.pop();
|
|
636
368
|
const middlewares = args;
|
|
637
369
|
const segments = this.splitPath(path);
|
|
@@ -779,117 +511,383 @@ var Router = class _Router {
|
|
|
779
511
|
wildcardIdx = i;
|
|
780
512
|
}
|
|
781
513
|
}
|
|
782
|
-
const segment = segments[i];
|
|
783
|
-
if (!segment) break;
|
|
784
|
-
const next = matchTrieNode(node, segment, params);
|
|
785
|
-
if (!next) {
|
|
786
|
-
if (wildcardHandler) {
|
|
787
|
-
params["*"] = segments.slice(wildcardIdx).join("/");
|
|
788
|
-
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
789
|
-
}
|
|
790
|
-
return null;
|
|
514
|
+
const segment = segments[i];
|
|
515
|
+
if (!segment) break;
|
|
516
|
+
const next = matchTrieNode(node, segment, params);
|
|
517
|
+
if (!next) {
|
|
518
|
+
if (wildcardHandler) {
|
|
519
|
+
params["*"] = segments.slice(wildcardIdx).join("/");
|
|
520
|
+
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
521
|
+
}
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
node = next;
|
|
525
|
+
}
|
|
526
|
+
pathMws.push(...node.pathMws);
|
|
527
|
+
const handler = node.handlers.get(method) || node.handlers.get("*");
|
|
528
|
+
if (handler) {
|
|
529
|
+
if (node.wildcard) params["*"] = segments.slice(segments.length).join("/");
|
|
530
|
+
return {
|
|
531
|
+
handler,
|
|
532
|
+
middlewares: node.middlewares.get(method) || node.middlewares.get("*") || [],
|
|
533
|
+
pathMws,
|
|
534
|
+
params
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
if (wildcardHandler) {
|
|
538
|
+
params["*"] = segments.slice(wildcardIdx).join("/");
|
|
539
|
+
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
540
|
+
}
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
matchWsTrie(root, segments) {
|
|
544
|
+
let node = root;
|
|
545
|
+
const params = {};
|
|
546
|
+
for (const segment of segments) {
|
|
547
|
+
const next = matchWsNode(node, segment, params);
|
|
548
|
+
if (!next) return null;
|
|
549
|
+
node = next;
|
|
550
|
+
}
|
|
551
|
+
return node.handler ? { handler: node.handler, middlewares: node.middlewares, params } : null;
|
|
552
|
+
}
|
|
553
|
+
async handle(req, ctx, segments, query) {
|
|
554
|
+
const match = this.matchTrie(req.method, segments);
|
|
555
|
+
if (match?.handler) {
|
|
556
|
+
const { handler, middlewares: routeMws, pathMws, params } = match;
|
|
557
|
+
const allMws = this.globalMws.length + pathMws.length + routeMws.length === 0 ? [] : [...this.globalMws, ...pathMws, ...routeMws];
|
|
558
|
+
const ctxWithMatch = { ...ctx, params: { ...ctx.params, ...params } };
|
|
559
|
+
try {
|
|
560
|
+
return await this.runChain(allMws, handler, req, ctxWithMatch);
|
|
561
|
+
} catch (e) {
|
|
562
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
563
|
+
return this.errorHandler ? this.errorHandler(err, req, ctxWithMatch) : new Response("Internal Server Error", { status: 500 });
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (this.globalMws.length > 0) {
|
|
567
|
+
try {
|
|
568
|
+
const delegate = () => new Response("Not Found", { status: 404 });
|
|
569
|
+
return await this.runChain(this.globalMws, delegate, req, ctx);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
572
|
+
return this.errorHandler ? this.errorHandler(err, req, ctx) : new Response("Internal Server Error", { status: 500 });
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return new Response("Not Found", { status: 404 });
|
|
576
|
+
}
|
|
577
|
+
async runChain(middlewares, finalHandler, req, ctx) {
|
|
578
|
+
let index = 0;
|
|
579
|
+
const dispatch = async (req2, ctx2) => {
|
|
580
|
+
if (index < middlewares.length) {
|
|
581
|
+
const mw = middlewares[index++];
|
|
582
|
+
return mw ? await mw(req2, ctx2, dispatch) : new Response("Middleware error", { status: 500 });
|
|
583
|
+
}
|
|
584
|
+
return await finalHandler(req2, ctx2);
|
|
585
|
+
};
|
|
586
|
+
return dispatch(req, ctx);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
function upgradeSocket(wss, req, socket, head, handler, ctx) {
|
|
590
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
591
|
+
if (handler.open) {
|
|
592
|
+
handler.open(ws, ctx);
|
|
593
|
+
}
|
|
594
|
+
ws.on("message", (data) => {
|
|
595
|
+
handler.message?.(ws, ctx, data);
|
|
596
|
+
});
|
|
597
|
+
ws.on("close", () => {
|
|
598
|
+
handler.close?.(ws, ctx);
|
|
599
|
+
});
|
|
600
|
+
ws.on("error", (err) => {
|
|
601
|
+
handler.error?.(ws, ctx, err);
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
function sendHttpResponseOnSocket(socket, response) {
|
|
606
|
+
const statusLine = `HTTP/1.1 ${response.status} ${response.statusText}`;
|
|
607
|
+
const headerLines = [statusLine];
|
|
608
|
+
response.headers.forEach((value, key) => {
|
|
609
|
+
headerLines.push(`${key}: ${value}`);
|
|
610
|
+
});
|
|
611
|
+
headerLines.push("Connection: close");
|
|
612
|
+
headerLines.push("");
|
|
613
|
+
const headerStr = headerLines.join("\r\n");
|
|
614
|
+
response.arrayBuffer().then((buf) => {
|
|
615
|
+
const body = Buffer.from(buf);
|
|
616
|
+
socket.write(headerStr + "\r\n" + body.toString());
|
|
617
|
+
socket.end();
|
|
618
|
+
}).catch(() => {
|
|
619
|
+
socket.write(headerStr + "\r\n");
|
|
620
|
+
socket.end();
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// ssr/ssr.ts
|
|
625
|
+
var als = new AsyncLocalStorage();
|
|
626
|
+
__registerAls(() => als.getStore());
|
|
627
|
+
var isDev = process.env.NODE_ENV !== "production";
|
|
628
|
+
var bundleCache = /* @__PURE__ */ new Map();
|
|
629
|
+
function id2(s) {
|
|
630
|
+
return createHash2("md5").update(s).digest("hex").slice(0, 8);
|
|
631
|
+
}
|
|
632
|
+
function serializeLoaderData(ctx) {
|
|
633
|
+
const data = {};
|
|
634
|
+
for (const key of Object.keys(ctx)) {
|
|
635
|
+
if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
|
|
636
|
+
data[key] = ctx[key];
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return data;
|
|
640
|
+
}
|
|
641
|
+
async function buildClientBundle(entryPath, layoutPaths) {
|
|
642
|
+
try {
|
|
643
|
+
const absEntry = resolve2(entryPath);
|
|
644
|
+
const absLayouts = layoutPaths.map((p) => resolve2(p));
|
|
645
|
+
const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
|
|
646
|
+
const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
|
|
647
|
+
const code = [
|
|
648
|
+
layoutImports,
|
|
649
|
+
`import{hydrateRoot}from'react-dom/client';`,
|
|
650
|
+
`import{createElement,useState,useEffect}from'react';`,
|
|
651
|
+
`import{TsxContext}from'weifuwu/react';`,
|
|
652
|
+
`import P from${JSON.stringify(absEntry)};`,
|
|
653
|
+
`var setCtx=${_sc};`,
|
|
654
|
+
`const c=document.getElementById('__weifuwu_root');`,
|
|
655
|
+
`if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
|
|
656
|
+
`if(!window.__WFW_ROOT){`,
|
|
657
|
+
`function App(){`,
|
|
658
|
+
`const[p,setP]=useState({C:P});`,
|
|
659
|
+
`useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
|
|
660
|
+
`const ctx=window.__WEIFUWU_CTX||{};`,
|
|
661
|
+
`return createElement(TsxContext.Provider,{value:ctx},`,
|
|
662
|
+
`createElement(p.C,null))`,
|
|
663
|
+
`}`,
|
|
664
|
+
`window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
|
|
665
|
+
`}else{`,
|
|
666
|
+
`window.__WFW_SET_PAGE?.(P);`,
|
|
667
|
+
`}`
|
|
668
|
+
].join("");
|
|
669
|
+
const { default: esbuild2 } = await import("esbuild");
|
|
670
|
+
const result = await esbuild2.build({
|
|
671
|
+
stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
|
|
672
|
+
bundle: true,
|
|
673
|
+
format: "esm",
|
|
674
|
+
jsx: "automatic",
|
|
675
|
+
jsxImportSource: "react",
|
|
676
|
+
banner: { js: "self.process={env:{}};" },
|
|
677
|
+
loader: { ".node": "empty" },
|
|
678
|
+
write: false,
|
|
679
|
+
minify: true
|
|
680
|
+
});
|
|
681
|
+
return result.outputFiles[0].contents;
|
|
682
|
+
} catch (err) {
|
|
683
|
+
console.error("hydration bundle failed:", err);
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function ssr(path) {
|
|
688
|
+
const entryId = id2(resolve2(path));
|
|
689
|
+
const bundleKey = `/__ssr/${entryId}.js`;
|
|
690
|
+
const r = new Router();
|
|
691
|
+
r.get("/__ssr/:path", (req, ctx) => {
|
|
692
|
+
const buf = bundleCache.get("/__ssr/" + ctx.params.path);
|
|
693
|
+
return buf ? new Response(buf, {
|
|
694
|
+
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
695
|
+
}) : new Response("", { status: 404 });
|
|
696
|
+
});
|
|
697
|
+
r.get("/", async (req, ctx) => {
|
|
698
|
+
const pageMod = await compileTsx(path);
|
|
699
|
+
const Component = pageMod.default;
|
|
700
|
+
if (!Component) return new Response("", { status: 500 });
|
|
701
|
+
const layouts = ctx.layoutStack || [];
|
|
702
|
+
const layoutComponents = layouts.map((l) => l.component);
|
|
703
|
+
const layoutPaths = layouts.map((l) => l.path);
|
|
704
|
+
const base = (ctx.mountPath || "").replace(/\/$/, "");
|
|
705
|
+
const loaderData = serializeLoaderData(ctx);
|
|
706
|
+
const ctxValue = {
|
|
707
|
+
params: ctx.params,
|
|
708
|
+
query: ctx.query,
|
|
709
|
+
user: ctx.user ?? {},
|
|
710
|
+
parsed: ctx.parsed ?? {},
|
|
711
|
+
prefs: ctx.prefs ?? {},
|
|
712
|
+
loaderData,
|
|
713
|
+
env: ctx.env ?? {}
|
|
714
|
+
};
|
|
715
|
+
return als.run(ctxValue, async () => {
|
|
716
|
+
setCtx(ctxValue);
|
|
717
|
+
let element = createElement(
|
|
718
|
+
TsxContext.Provider,
|
|
719
|
+
{ value: ctxValue },
|
|
720
|
+
createElement(
|
|
721
|
+
"div",
|
|
722
|
+
{ id: "__weifuwu_root" },
|
|
723
|
+
createElement(Component, null)
|
|
724
|
+
)
|
|
725
|
+
);
|
|
726
|
+
if (layoutComponents.length === 0) {
|
|
727
|
+
element = createElement(
|
|
728
|
+
"html",
|
|
729
|
+
{ lang: "en" },
|
|
730
|
+
createElement(
|
|
731
|
+
"head",
|
|
732
|
+
null,
|
|
733
|
+
createElement("meta", { charSet: "utf-8" }),
|
|
734
|
+
createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
735
|
+
createElement("title", null, "weifuwu")
|
|
736
|
+
),
|
|
737
|
+
createElement("body", null, element)
|
|
738
|
+
);
|
|
739
|
+
} else {
|
|
740
|
+
for (const L of layoutComponents.toReversed()) {
|
|
741
|
+
element = createElement(L, { children: element });
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
let bundle = null;
|
|
745
|
+
if (!bundleCache.has(bundleKey)) {
|
|
746
|
+
const buf = await buildClientBundle(path, layoutPaths);
|
|
747
|
+
if (buf) bundleCache.set(bundleKey, buf);
|
|
791
748
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
pathMws.push(...node.pathMws);
|
|
795
|
-
const handler = node.handlers.get(method) || node.handlers.get("*");
|
|
796
|
-
if (handler) {
|
|
797
|
-
if (node.wildcard) params["*"] = segments.slice(segments.length).join("/");
|
|
798
|
-
return {
|
|
799
|
-
handler,
|
|
800
|
-
middlewares: node.middlewares.get(method) || node.middlewares.get("*") || [],
|
|
801
|
-
pathMws,
|
|
802
|
-
params
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
if (wildcardHandler) {
|
|
806
|
-
params["*"] = segments.slice(wildcardIdx).join("/");
|
|
807
|
-
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
808
|
-
}
|
|
809
|
-
return null;
|
|
810
|
-
}
|
|
811
|
-
matchWsTrie(root, segments) {
|
|
812
|
-
let node = root;
|
|
813
|
-
const params = {};
|
|
814
|
-
for (const segment of segments) {
|
|
815
|
-
const next = matchWsNode(node, segment, params);
|
|
816
|
-
if (!next) return null;
|
|
817
|
-
node = next;
|
|
818
|
-
}
|
|
819
|
-
return node.handler ? { handler: node.handler, middlewares: node.middlewares, params } : null;
|
|
820
|
-
}
|
|
821
|
-
async handle(req, ctx, segments, query) {
|
|
822
|
-
const match = this.matchTrie(req.method, segments);
|
|
823
|
-
if (match?.handler) {
|
|
824
|
-
const { handler, middlewares: routeMws, pathMws, params } = match;
|
|
825
|
-
const allMws = this.globalMws.length + pathMws.length + routeMws.length === 0 ? [] : [...this.globalMws, ...pathMws, ...routeMws];
|
|
826
|
-
const ctxWithMatch = { ...ctx, params: { ...ctx.params, ...params } };
|
|
827
|
-
try {
|
|
828
|
-
return await this.runChain(allMws, handler, req, ctxWithMatch);
|
|
829
|
-
} catch (e) {
|
|
830
|
-
const err = e instanceof Error ? e : new Error(String(e));
|
|
831
|
-
return this.errorHandler ? this.errorHandler(err, req, ctxWithMatch) : new Response("Internal Server Error", { status: 500 });
|
|
749
|
+
if (bundleCache.has(bundleKey)) {
|
|
750
|
+
bundle = { url: bundleKey };
|
|
832
751
|
}
|
|
752
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
753
|
+
const stream = await renderToReadableStream(element);
|
|
754
|
+
return streamResponse(stream, {
|
|
755
|
+
ctx,
|
|
756
|
+
base,
|
|
757
|
+
isDev,
|
|
758
|
+
bundle,
|
|
759
|
+
loaderData
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
});
|
|
763
|
+
return r;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// ssr/layout.ts
|
|
767
|
+
function layout(path) {
|
|
768
|
+
return async (req, ctx, next) => {
|
|
769
|
+
const mod = await compileTsx(path);
|
|
770
|
+
const Component = mod.default;
|
|
771
|
+
if (!Component) throw new Error(`Layout ${path} has no default export`);
|
|
772
|
+
ctx.layoutStack = [...ctx.layoutStack || [], { path, component: Component }];
|
|
773
|
+
return next(req, ctx);
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// ssr/tailwind.ts
|
|
778
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
779
|
+
import { relative, resolve as resolve3 } from "node:path";
|
|
780
|
+
var isDev2 = process.env.NODE_ENV !== "production";
|
|
781
|
+
function tailwind(cssPath, scanDir) {
|
|
782
|
+
let compiledCss = "";
|
|
783
|
+
let twWatcher = null;
|
|
784
|
+
return async (req, ctx, next) => {
|
|
785
|
+
const url = new URL(req.url);
|
|
786
|
+
if (url.pathname === "/__wfw/style.css") {
|
|
787
|
+
if (!compiledCss) compiledCss = await compile(cssPath, scanDir);
|
|
788
|
+
return new Response(compiledCss || "", {
|
|
789
|
+
headers: { "content-type": "text/css; charset=utf-8" }
|
|
790
|
+
});
|
|
833
791
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
}
|
|
839
|
-
const err = e instanceof Error ? e : new Error(String(e));
|
|
840
|
-
return this.errorHandler ? this.errorHandler(err, req, ctx) : new Response("Internal Server Error", { status: 500 });
|
|
841
|
-
}
|
|
792
|
+
ctx.compiledTailwindCss = compiledCss;
|
|
793
|
+
if (isDev2 && !twWatcher) {
|
|
794
|
+
twWatcher = watchFile(cssPath, () => {
|
|
795
|
+
compiledCss = "";
|
|
796
|
+
});
|
|
842
797
|
}
|
|
843
|
-
return
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
return await finalHandler(req2, ctx2);
|
|
853
|
-
};
|
|
854
|
-
return dispatch(req, ctx);
|
|
855
|
-
}
|
|
856
|
-
};
|
|
857
|
-
function upgradeSocket(wss, req, socket, head, handler, ctx) {
|
|
858
|
-
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
859
|
-
if (handler.open) {
|
|
860
|
-
handler.open(ws, ctx);
|
|
798
|
+
return next(req, ctx);
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
async function compile(cssPath, scanDir) {
|
|
802
|
+
try {
|
|
803
|
+
const inputFile = resolve3(cssPath);
|
|
804
|
+
if (!existsSync2(inputFile)) {
|
|
805
|
+
mkdirSync2(dirname3(inputFile), { recursive: true });
|
|
806
|
+
writeFileSync(inputFile, '@import "tailwindcss"\n', "utf-8");
|
|
861
807
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
})
|
|
808
|
+
const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
|
|
809
|
+
const { default: postcss } = await import("postcss");
|
|
810
|
+
let src = readFileSync2(inputFile, "utf-8");
|
|
811
|
+
const scanSource = scanDir ? relative(dirname3(inputFile), scanDir) || "." : ".";
|
|
812
|
+
const sourcePath = scanSource === "." ? "./" : `./${scanSource}/`;
|
|
813
|
+
src = `@source "${sourcePath}";
|
|
814
|
+
${src}`;
|
|
815
|
+
const result = await postcss([tailwindPlugin()]).process(src, { from: inputFile });
|
|
816
|
+
return result.css;
|
|
817
|
+
} catch (err) {
|
|
818
|
+
console.warn("Tailwind CSS processing failed:", err.message);
|
|
819
|
+
return "";
|
|
820
|
+
}
|
|
872
821
|
}
|
|
873
|
-
function
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
const headerStr = headerLines.join("\r\n");
|
|
882
|
-
response.arrayBuffer().then((buf) => {
|
|
883
|
-
const body = Buffer.from(buf);
|
|
884
|
-
socket.write(headerStr + "\r\n" + body.toString());
|
|
885
|
-
socket.end();
|
|
886
|
-
}).catch(() => {
|
|
887
|
-
socket.write(headerStr + "\r\n");
|
|
888
|
-
socket.end();
|
|
822
|
+
function dirname3(p) {
|
|
823
|
+
return p.substring(0, p.lastIndexOf("/")) || "/";
|
|
824
|
+
}
|
|
825
|
+
function watchFile(path, onChange) {
|
|
826
|
+
let watcher = null;
|
|
827
|
+
import("chokidar").then((chokidar2) => {
|
|
828
|
+
watcher = chokidar2.default.watch(resolve3(path), { persistent: false });
|
|
829
|
+
watcher.on("change", onChange);
|
|
889
830
|
});
|
|
831
|
+
return watcher;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// ssr/not-found.ts
|
|
835
|
+
function notFound(path) {
|
|
836
|
+
return async (req, ctx) => {
|
|
837
|
+
if (!path) return new Response("Not Found", { status: 404 });
|
|
838
|
+
const mod = await compileTsx(path);
|
|
839
|
+
const Component = mod?.default;
|
|
840
|
+
const body = Component ? "404 - Not Found" : "404 - Not Found";
|
|
841
|
+
return new Response(body, {
|
|
842
|
+
status: 404,
|
|
843
|
+
headers: { "content-type": "text/html; charset=utf-8" }
|
|
844
|
+
});
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// ssr/error-boundary.ts
|
|
849
|
+
import { createElement as createElement2 } from "react";
|
|
850
|
+
import { TextEncoder as TextEncoder2 } from "node:util";
|
|
851
|
+
function errorBoundary(errorPath) {
|
|
852
|
+
return async (req, ctx, next) => {
|
|
853
|
+
try {
|
|
854
|
+
return await next(req, ctx);
|
|
855
|
+
} catch (err) {
|
|
856
|
+
const mod = await compileTsx(errorPath);
|
|
857
|
+
const ErrorComponent = mod.default;
|
|
858
|
+
if (!ErrorComponent) throw err;
|
|
859
|
+
const layouts = (ctx.layoutStack || []).map((l) => l.component);
|
|
860
|
+
const stream = await import("react-dom/server").then((m) => m.renderToReadableStream(
|
|
861
|
+
createElement2(ErrorComponent, {
|
|
862
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
863
|
+
reset: () => {
|
|
864
|
+
}
|
|
865
|
+
})
|
|
866
|
+
));
|
|
867
|
+
const reader = stream.getReader();
|
|
868
|
+
const chunks = [];
|
|
869
|
+
while (true) {
|
|
870
|
+
const { done, value } = await reader.read();
|
|
871
|
+
if (done) break;
|
|
872
|
+
chunks.push(value);
|
|
873
|
+
}
|
|
874
|
+
const encoder = new TextEncoder2();
|
|
875
|
+
const body = chunks.reduce((acc, c) => {
|
|
876
|
+
const merged = new Uint8Array(acc.length + c.length);
|
|
877
|
+
merged.set(acc);
|
|
878
|
+
merged.set(c, acc.length);
|
|
879
|
+
return merged;
|
|
880
|
+
}, new Uint8Array(0));
|
|
881
|
+
return new Response(body, {
|
|
882
|
+
status: 500,
|
|
883
|
+
headers: { "content-type": "text/html; charset=utf-8" }
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
};
|
|
890
887
|
}
|
|
891
888
|
|
|
892
889
|
// ssr/live.ts
|
|
890
|
+
import chokidar from "chokidar";
|
|
893
891
|
var clients = /* @__PURE__ */ new Set();
|
|
894
892
|
function broadcastReload() {
|
|
895
893
|
for (const ws of clients) {
|
|
@@ -931,6 +929,5 @@ export {
|
|
|
931
929
|
liveReload,
|
|
932
930
|
notFound,
|
|
933
931
|
ssr,
|
|
934
|
-
ssrBundleHandler,
|
|
935
932
|
tailwind
|
|
936
933
|
};
|
package/dist/ssr/ssr.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare function ssr(path: string):
|
|
3
|
-
export declare function ssrBundleHandler(): Handler;
|
|
1
|
+
import { Router } from '../router.ts';
|
|
2
|
+
export declare function ssr(path: string): Router;
|