@nestjs-ssr/react 0.3.4 → 0.3.6
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/client.d.mts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +50 -8
- package/dist/client.mjs +50 -8
- package/dist/{index-BzOLOiIZ.d.ts → index-CSvZfKpi.d.ts} +161 -8
- package/dist/{index-DdE--mA2.d.mts → index-ZpkYrPcK.d.mts} +161 -8
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +137 -35
- package/dist/index.mjs +138 -36
- package/dist/render/index.d.mts +3 -3
- package/dist/render/index.d.ts +3 -3
- package/dist/render/index.js +118 -35
- package/dist/render/index.mjs +119 -36
- package/dist/{render-response.interface-CxbuKGnV.d.mts → render-response.interface-ClWJXKL4.d.mts} +19 -10
- package/dist/{render-response.interface-CxbuKGnV.d.ts → render-response.interface-ClWJXKL4.d.ts} +19 -10
- package/dist/templates/entry-client.tsx +23 -4
- package/dist/templates/entry-server.tsx +25 -8
- package/dist/{use-page-context-CGT9woWe.d.mts → use-page-context-CVC9DHcL.d.mts} +2 -1
- package/dist/{use-page-context-05ODF4zW.d.ts → use-page-context-DChgHhL9.d.ts} +2 -1
- package/package.json +12 -1
- package/src/templates/entry-client.tsx +23 -4
- package/src/templates/entry-server.tsx +25 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { E as ErrorPageDevelopment, e as ErrorPageProduction, c as RenderConfig, b as RenderInterceptor, R as RenderModule, a as RenderService, d as SSRMode, S as StreamingErrorHandler, T as TemplateParserService } from './index-
|
|
1
|
+
export { C as ContextFactory, E as ErrorPageDevelopment, e as ErrorPageProduction, c as RenderConfig, b as RenderInterceptor, R as RenderModule, a as RenderService, d as SSRMode, S as StreamingErrorHandler, T as TemplateParserService } from './index-ZpkYrPcK.mjs';
|
|
2
2
|
import React, { ComponentType, ReactNode } from 'react';
|
|
3
|
-
import { P as PageProps } from './use-page-context-
|
|
4
|
-
export { a as PageContextProvider, c as createSSRHooks, i as useCookie, h as useCookies, g as useHeader, f as useHeaders, u as usePageContext, b as useParams, d as useQuery, e as useRequest } from './use-page-context-
|
|
5
|
-
import { R as RenderContext, H as HeadData, a as RenderResponse } from './render-response.interface-
|
|
3
|
+
import { P as PageProps } from './use-page-context-CVC9DHcL.mjs';
|
|
4
|
+
export { a as PageContextProvider, c as createSSRHooks, i as useCookie, h as useCookies, g as useHeader, f as useHeaders, u as usePageContext, b as useParams, d as useQuery, e as useRequest } from './use-page-context-CVC9DHcL.mjs';
|
|
5
|
+
import { R as RenderContext, H as HeadData, a as RenderResponse } from './render-response.interface-ClWJXKL4.mjs';
|
|
6
6
|
import '@nestjs/common';
|
|
7
|
+
import 'http';
|
|
7
8
|
import 'vite';
|
|
8
|
-
import 'express';
|
|
9
9
|
import '@nestjs/core';
|
|
10
10
|
import 'rxjs';
|
|
11
11
|
import 'react/jsx-runtime';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { E as ErrorPageDevelopment, e as ErrorPageProduction, c as RenderConfig, b as RenderInterceptor, R as RenderModule, a as RenderService, d as SSRMode, S as StreamingErrorHandler, T as TemplateParserService } from './index-
|
|
1
|
+
export { C as ContextFactory, E as ErrorPageDevelopment, e as ErrorPageProduction, c as RenderConfig, b as RenderInterceptor, R as RenderModule, a as RenderService, d as SSRMode, S as StreamingErrorHandler, T as TemplateParserService } from './index-CSvZfKpi.js';
|
|
2
2
|
import React, { ComponentType, ReactNode } from 'react';
|
|
3
|
-
import { P as PageProps } from './use-page-context-
|
|
4
|
-
export { a as PageContextProvider, c as createSSRHooks, i as useCookie, h as useCookies, g as useHeader, f as useHeaders, u as usePageContext, b as useParams, d as useQuery, e as useRequest } from './use-page-context-
|
|
5
|
-
import { R as RenderContext, H as HeadData, a as RenderResponse } from './render-response.interface-
|
|
3
|
+
import { P as PageProps } from './use-page-context-DChgHhL9.js';
|
|
4
|
+
export { a as PageContextProvider, c as createSSRHooks, i as useCookie, h as useCookies, g as useHeader, f as useHeaders, u as usePageContext, b as useParams, d as useQuery, e as useRequest } from './use-page-context-DChgHhL9.js';
|
|
5
|
+
import { R as RenderContext, H as HeadData, a as RenderResponse } from './render-response.interface-ClWJXKL4.js';
|
|
6
6
|
import '@nestjs/common';
|
|
7
|
+
import 'http';
|
|
7
8
|
import 'vite';
|
|
8
|
-
import 'express';
|
|
9
9
|
import '@nestjs/core';
|
|
10
10
|
import 'rxjs';
|
|
11
11
|
import 'react/jsx-runtime';
|
package/dist/index.js
CHANGED
|
@@ -315,9 +315,13 @@ var StringRenderer = class _StringRenderer {
|
|
|
315
315
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
-
const { data: pageData, __context: pageContext } = data;
|
|
318
|
+
const { data: pageData, __context: pageContext, __layouts: layouts } = data;
|
|
319
319
|
const html = await renderModule.renderSegment(viewComponent, data);
|
|
320
320
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
321
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
322
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
323
|
+
props: l.props
|
|
324
|
+
})) : [];
|
|
321
325
|
if (context.isDevelopment) {
|
|
322
326
|
const duration = Date.now() - startTime;
|
|
323
327
|
this.logger.log(`[SSR] ${componentName} segment rendered in ${duration}ms`);
|
|
@@ -328,7 +332,8 @@ var StringRenderer = class _StringRenderer {
|
|
|
328
332
|
props: pageData,
|
|
329
333
|
swapTarget,
|
|
330
334
|
componentName,
|
|
331
|
-
context: pageContext
|
|
335
|
+
context: pageContext,
|
|
336
|
+
layouts: layoutMetadata
|
|
332
337
|
};
|
|
333
338
|
}
|
|
334
339
|
};
|
|
@@ -457,6 +462,39 @@ function ErrorPageProduction() {
|
|
|
457
462
|
}
|
|
458
463
|
__name(ErrorPageProduction, "ErrorPageProduction");
|
|
459
464
|
|
|
465
|
+
// src/render/adapters/http-adapter-utils.ts
|
|
466
|
+
function detectAdapterType(httpAdapterHost) {
|
|
467
|
+
const adapter = httpAdapterHost?.httpAdapter;
|
|
468
|
+
if (!adapter) return "unknown";
|
|
469
|
+
const instance = adapter.getInstance();
|
|
470
|
+
if (instance && typeof instance.register === "function") {
|
|
471
|
+
return "fastify";
|
|
472
|
+
}
|
|
473
|
+
if (instance && typeof instance.use === "function" && typeof instance.get === "function") {
|
|
474
|
+
return "express";
|
|
475
|
+
}
|
|
476
|
+
return "unknown";
|
|
477
|
+
}
|
|
478
|
+
__name(detectAdapterType, "detectAdapterType");
|
|
479
|
+
function isFastifyLikeResponse(res) {
|
|
480
|
+
return res != null && typeof res === "object" && "raw" in res && res.raw != null && typeof res.raw.write === "function";
|
|
481
|
+
}
|
|
482
|
+
__name(isFastifyLikeResponse, "isFastifyLikeResponse");
|
|
483
|
+
function getRawResponse(res) {
|
|
484
|
+
if (isFastifyLikeResponse(res)) {
|
|
485
|
+
return res.raw;
|
|
486
|
+
}
|
|
487
|
+
return res;
|
|
488
|
+
}
|
|
489
|
+
__name(getRawResponse, "getRawResponse");
|
|
490
|
+
function isHeadersSent(res) {
|
|
491
|
+
if (typeof res.sent === "boolean") {
|
|
492
|
+
return res.sent;
|
|
493
|
+
}
|
|
494
|
+
return res.headersSent === true;
|
|
495
|
+
}
|
|
496
|
+
__name(isHeadersSent, "isHeadersSent");
|
|
497
|
+
|
|
460
498
|
// src/render/streaming-error-handler.ts
|
|
461
499
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
462
500
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -492,21 +530,19 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
|
|
|
492
530
|
*/
|
|
493
531
|
handleShellError(error, res, viewPath, isDevelopment) {
|
|
494
532
|
this.logger.error(`Shell error rendering ${viewPath}: ${error.message}`, error.stack);
|
|
495
|
-
|
|
533
|
+
const rawRes = getRawResponse(res);
|
|
534
|
+
if (isHeadersSent(res)) {
|
|
496
535
|
this.logger.error(`Cannot send error page for ${viewPath} - headers already sent (streaming started)`);
|
|
497
|
-
if (!
|
|
498
|
-
|
|
499
|
-
|
|
536
|
+
if (!rawRes.writableEnded) {
|
|
537
|
+
rawRes.write(this.renderInlineErrorOverlay(error, viewPath, isDevelopment));
|
|
538
|
+
rawRes.end();
|
|
500
539
|
}
|
|
501
540
|
return;
|
|
502
541
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
} else {
|
|
508
|
-
res.send(this.renderProductionErrorPage());
|
|
509
|
-
}
|
|
542
|
+
rawRes.statusCode = 500;
|
|
543
|
+
rawRes.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
544
|
+
const html = isDevelopment ? this.renderDevelopmentErrorPage(error, viewPath, "shell") : this.renderProductionErrorPage();
|
|
545
|
+
rawRes.end(html);
|
|
510
546
|
}
|
|
511
547
|
/**
|
|
512
548
|
* Handle error that occurred during streaming
|
|
@@ -662,7 +698,7 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
662
698
|
*
|
|
663
699
|
* @param viewComponent - The React component to render
|
|
664
700
|
* @param data - Data to pass to the component
|
|
665
|
-
* @param res -
|
|
701
|
+
* @param res - HTTP response object (Express or Fastify)
|
|
666
702
|
* @param context - Render context with Vite and manifest info
|
|
667
703
|
* @param head - Head data for SEO tags
|
|
668
704
|
*/
|
|
@@ -704,20 +740,21 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
704
740
|
const { PassThrough } = await import('stream');
|
|
705
741
|
const reactStream = new PassThrough();
|
|
706
742
|
let allReadyFired = false;
|
|
743
|
+
const rawRes = getRawResponse(res);
|
|
707
744
|
const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
|
|
708
745
|
onShellReady: /* @__PURE__ */ __name(() => {
|
|
709
746
|
shellReadyTime = Date.now();
|
|
710
|
-
if (!
|
|
711
|
-
|
|
712
|
-
|
|
747
|
+
if (!rawRes.headersSent) {
|
|
748
|
+
rawRes.statusCode = didError ? 500 : 200;
|
|
749
|
+
rawRes.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
713
750
|
}
|
|
714
751
|
let htmlStart = templateParts.htmlStart;
|
|
715
752
|
htmlStart = htmlStart.replace("<!--styles-->", stylesheetTags);
|
|
716
753
|
htmlStart = htmlStart.replace("<!--head-meta-->", headTags);
|
|
717
|
-
|
|
718
|
-
|
|
754
|
+
rawRes.write(htmlStart);
|
|
755
|
+
rawRes.write(templateParts.rootStart);
|
|
719
756
|
pipe(reactStream);
|
|
720
|
-
reactStream.pipe(
|
|
757
|
+
reactStream.pipe(rawRes, {
|
|
721
758
|
end: false
|
|
722
759
|
});
|
|
723
760
|
if (context.isDevelopment) {
|
|
@@ -742,11 +779,11 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
742
779
|
if (shellErrorOccurred) {
|
|
743
780
|
return;
|
|
744
781
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
782
|
+
rawRes.write(inlineScripts);
|
|
783
|
+
rawRes.write(clientScript);
|
|
784
|
+
rawRes.write(templateParts.rootEnd);
|
|
785
|
+
rawRes.write(templateParts.htmlEnd);
|
|
786
|
+
rawRes.end();
|
|
750
787
|
if (context.isDevelopment) {
|
|
751
788
|
const totalTime = Date.now() - startTime;
|
|
752
789
|
const streamTime = Date.now() - shellReadyTime;
|
|
@@ -758,7 +795,7 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
758
795
|
reactStream.on("error", (error) => {
|
|
759
796
|
reject(error);
|
|
760
797
|
});
|
|
761
|
-
|
|
798
|
+
rawRes.on("close", () => {
|
|
762
799
|
abort();
|
|
763
800
|
resolve();
|
|
764
801
|
});
|
|
@@ -1097,11 +1134,13 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
1097
1134
|
renderService;
|
|
1098
1135
|
allowedHeaders;
|
|
1099
1136
|
allowedCookies;
|
|
1100
|
-
|
|
1137
|
+
contextFactory;
|
|
1138
|
+
constructor(reflector, renderService, allowedHeaders, allowedCookies, contextFactory) {
|
|
1101
1139
|
this.reflector = reflector;
|
|
1102
1140
|
this.renderService = renderService;
|
|
1103
1141
|
this.allowedHeaders = allowedHeaders;
|
|
1104
1142
|
this.allowedCookies = allowedCookies;
|
|
1143
|
+
this.contextFactory = contextFactory;
|
|
1105
1144
|
}
|
|
1106
1145
|
/**
|
|
1107
1146
|
* Resolve the layout hierarchy for a given route
|
|
@@ -1241,6 +1280,14 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
1241
1280
|
renderContext.cookies = cookies;
|
|
1242
1281
|
}
|
|
1243
1282
|
}
|
|
1283
|
+
if (this.contextFactory) {
|
|
1284
|
+
const customContext = await this.contextFactory({
|
|
1285
|
+
req: request
|
|
1286
|
+
});
|
|
1287
|
+
if (customContext) {
|
|
1288
|
+
Object.assign(renderContext, customContext);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1244
1291
|
const renderResponse = isRenderResponse(data) ? data : {
|
|
1245
1292
|
props: data
|
|
1246
1293
|
};
|
|
@@ -1287,12 +1334,15 @@ exports.RenderInterceptor = _ts_decorate6([
|
|
|
1287
1334
|
_ts_param3(2, common.Inject("ALLOWED_HEADERS")),
|
|
1288
1335
|
_ts_param3(3, common.Optional()),
|
|
1289
1336
|
_ts_param3(3, common.Inject("ALLOWED_COOKIES")),
|
|
1337
|
+
_ts_param3(4, common.Optional()),
|
|
1338
|
+
_ts_param3(4, common.Inject("CONTEXT_FACTORY")),
|
|
1290
1339
|
_ts_metadata5("design:type", Function),
|
|
1291
1340
|
_ts_metadata5("design:paramtypes", [
|
|
1292
1341
|
typeof core.Reflector === "undefined" ? Object : core.Reflector,
|
|
1293
1342
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
1294
1343
|
Array,
|
|
1295
|
-
Array
|
|
1344
|
+
Array,
|
|
1345
|
+
typeof ContextFactory === "undefined" ? Object : ContextFactory
|
|
1296
1346
|
])
|
|
1297
1347
|
], exports.RenderInterceptor);
|
|
1298
1348
|
function _ts_decorate7(decorators, target, key, desc) {
|
|
@@ -1343,7 +1393,7 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1343
1393
|
if (isDevelopment) {
|
|
1344
1394
|
await this.setupDevelopmentMode();
|
|
1345
1395
|
} else {
|
|
1346
|
-
this.setupProductionMode();
|
|
1396
|
+
await this.setupProductionMode();
|
|
1347
1397
|
}
|
|
1348
1398
|
}
|
|
1349
1399
|
async setupDevelopmentMode() {
|
|
@@ -1385,18 +1435,38 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1385
1435
|
this.logger.warn(`Failed to setup Vite proxy: ${error.message}. Make sure http-proxy-middleware is installed.`);
|
|
1386
1436
|
}
|
|
1387
1437
|
}
|
|
1388
|
-
setupProductionMode() {
|
|
1438
|
+
async setupProductionMode() {
|
|
1389
1439
|
try {
|
|
1390
1440
|
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
1391
|
-
if (httpAdapter)
|
|
1392
|
-
|
|
1393
|
-
|
|
1441
|
+
if (!httpAdapter) return;
|
|
1442
|
+
const app = httpAdapter.getInstance();
|
|
1443
|
+
const { join: join2 } = __require("path");
|
|
1444
|
+
const staticPath = join2(process.cwd(), "dist/client");
|
|
1445
|
+
const adapterType = detectAdapterType(this.httpAdapterHost);
|
|
1446
|
+
if (adapterType === "fastify") {
|
|
1447
|
+
try {
|
|
1448
|
+
const fastifyStatic = await import('@fastify/static').catch(() => null);
|
|
1449
|
+
if (fastifyStatic) {
|
|
1450
|
+
await app.register(fastifyStatic.default, {
|
|
1451
|
+
root: staticPath,
|
|
1452
|
+
prefix: "/",
|
|
1453
|
+
index: false,
|
|
1454
|
+
maxAge: 31536e6
|
|
1455
|
+
});
|
|
1456
|
+
this.logger.log("\u2713 Static assets configured (dist/client) [Fastify]");
|
|
1457
|
+
} else {
|
|
1458
|
+
this.logger.warn("For Fastify static file serving, install @fastify/static: npm install @fastify/static");
|
|
1459
|
+
}
|
|
1460
|
+
} catch {
|
|
1461
|
+
this.logger.warn("For Fastify static file serving, install @fastify/static: npm install @fastify/static");
|
|
1462
|
+
}
|
|
1463
|
+
} else {
|
|
1394
1464
|
const express = __require("express");
|
|
1395
|
-
app.use(express.static(
|
|
1465
|
+
app.use(express.static(staticPath, {
|
|
1396
1466
|
index: false,
|
|
1397
1467
|
maxAge: "1y"
|
|
1398
1468
|
}));
|
|
1399
|
-
this.logger.log("\u2713 Static assets configured (dist/client)");
|
|
1469
|
+
this.logger.log("\u2713 Static assets configured (dist/client) [Express]");
|
|
1400
1470
|
}
|
|
1401
1471
|
} catch (error) {
|
|
1402
1472
|
this.logger.warn(`Failed to setup static assets: ${error.message}`);
|
|
@@ -1536,6 +1606,12 @@ exports.RenderModule = class _RenderModule {
|
|
|
1536
1606
|
provide: "ALLOWED_COOKIES",
|
|
1537
1607
|
useValue: config?.allowedCookies || []
|
|
1538
1608
|
});
|
|
1609
|
+
if (config?.context) {
|
|
1610
|
+
providers.push({
|
|
1611
|
+
provide: "CONTEXT_FACTORY",
|
|
1612
|
+
useValue: config.context
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1539
1615
|
return {
|
|
1540
1616
|
global: true,
|
|
1541
1617
|
module: _RenderModule,
|
|
@@ -1654,6 +1730,13 @@ exports.RenderModule = class _RenderModule {
|
|
|
1654
1730
|
inject: [
|
|
1655
1731
|
"RENDER_CONFIG"
|
|
1656
1732
|
]
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
provide: "CONTEXT_FACTORY",
|
|
1736
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.context, "useFactory"),
|
|
1737
|
+
inject: [
|
|
1738
|
+
"RENDER_CONFIG"
|
|
1739
|
+
]
|
|
1657
1740
|
}
|
|
1658
1741
|
];
|
|
1659
1742
|
return {
|
|
@@ -1716,9 +1799,28 @@ var PageContext = getOrCreateContext();
|
|
|
1716
1799
|
function registerPageContextState(setter) {
|
|
1717
1800
|
}
|
|
1718
1801
|
__name(registerPageContextState, "registerPageContextState");
|
|
1802
|
+
var segmentSetters = /* @__PURE__ */ new Set();
|
|
1803
|
+
function registerSegmentSetter(setter) {
|
|
1804
|
+
segmentSetters.add(setter);
|
|
1805
|
+
}
|
|
1806
|
+
__name(registerSegmentSetter, "registerSegmentSetter");
|
|
1807
|
+
function unregisterSegmentSetter(setter) {
|
|
1808
|
+
segmentSetters.delete(setter);
|
|
1809
|
+
}
|
|
1810
|
+
__name(unregisterSegmentSetter, "unregisterSegmentSetter");
|
|
1811
|
+
function broadcastToSegments(context) {
|
|
1812
|
+
segmentSetters.forEach((setter) => setter(context));
|
|
1813
|
+
}
|
|
1814
|
+
__name(broadcastToSegments, "broadcastToSegments");
|
|
1719
1815
|
function PageContextProvider({ context: initialContext, children, isSegment = false }) {
|
|
1720
1816
|
const [context, setContext] = React2.useState(initialContext);
|
|
1721
1817
|
React2.useEffect(() => {
|
|
1818
|
+
if (!isSegment) {
|
|
1819
|
+
return void 0;
|
|
1820
|
+
} else {
|
|
1821
|
+
registerSegmentSetter(setContext);
|
|
1822
|
+
return () => unregisterSegmentSetter(setContext);
|
|
1823
|
+
}
|
|
1722
1824
|
}, [
|
|
1723
1825
|
isSegment
|
|
1724
1826
|
]);
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Injectable, Logger, Optional, Inject, Global, Module, SetMetadata } from '@nestjs/common';
|
|
2
|
-
import { HttpAdapterHost, APP_INTERCEPTOR
|
|
2
|
+
import { Reflector, HttpAdapterHost, APP_INTERCEPTOR } from '@nestjs/core';
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { join, relative } from 'path';
|
|
5
5
|
import { uneval } from 'devalue';
|
|
@@ -308,9 +308,13 @@ var StringRenderer = class _StringRenderer {
|
|
|
308
308
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
const { data: pageData, __context: pageContext } = data;
|
|
311
|
+
const { data: pageData, __context: pageContext, __layouts: layouts } = data;
|
|
312
312
|
const html = await renderModule.renderSegment(viewComponent, data);
|
|
313
313
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
314
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
315
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
316
|
+
props: l.props
|
|
317
|
+
})) : [];
|
|
314
318
|
if (context.isDevelopment) {
|
|
315
319
|
const duration = Date.now() - startTime;
|
|
316
320
|
this.logger.log(`[SSR] ${componentName} segment rendered in ${duration}ms`);
|
|
@@ -321,7 +325,8 @@ var StringRenderer = class _StringRenderer {
|
|
|
321
325
|
props: pageData,
|
|
322
326
|
swapTarget,
|
|
323
327
|
componentName,
|
|
324
|
-
context: pageContext
|
|
328
|
+
context: pageContext,
|
|
329
|
+
layouts: layoutMetadata
|
|
325
330
|
};
|
|
326
331
|
}
|
|
327
332
|
};
|
|
@@ -450,6 +455,39 @@ function ErrorPageProduction() {
|
|
|
450
455
|
}
|
|
451
456
|
__name(ErrorPageProduction, "ErrorPageProduction");
|
|
452
457
|
|
|
458
|
+
// src/render/adapters/http-adapter-utils.ts
|
|
459
|
+
function detectAdapterType(httpAdapterHost) {
|
|
460
|
+
const adapter = httpAdapterHost?.httpAdapter;
|
|
461
|
+
if (!adapter) return "unknown";
|
|
462
|
+
const instance = adapter.getInstance();
|
|
463
|
+
if (instance && typeof instance.register === "function") {
|
|
464
|
+
return "fastify";
|
|
465
|
+
}
|
|
466
|
+
if (instance && typeof instance.use === "function" && typeof instance.get === "function") {
|
|
467
|
+
return "express";
|
|
468
|
+
}
|
|
469
|
+
return "unknown";
|
|
470
|
+
}
|
|
471
|
+
__name(detectAdapterType, "detectAdapterType");
|
|
472
|
+
function isFastifyLikeResponse(res) {
|
|
473
|
+
return res != null && typeof res === "object" && "raw" in res && res.raw != null && typeof res.raw.write === "function";
|
|
474
|
+
}
|
|
475
|
+
__name(isFastifyLikeResponse, "isFastifyLikeResponse");
|
|
476
|
+
function getRawResponse(res) {
|
|
477
|
+
if (isFastifyLikeResponse(res)) {
|
|
478
|
+
return res.raw;
|
|
479
|
+
}
|
|
480
|
+
return res;
|
|
481
|
+
}
|
|
482
|
+
__name(getRawResponse, "getRawResponse");
|
|
483
|
+
function isHeadersSent(res) {
|
|
484
|
+
if (typeof res.sent === "boolean") {
|
|
485
|
+
return res.sent;
|
|
486
|
+
}
|
|
487
|
+
return res.headersSent === true;
|
|
488
|
+
}
|
|
489
|
+
__name(isHeadersSent, "isHeadersSent");
|
|
490
|
+
|
|
453
491
|
// src/render/streaming-error-handler.ts
|
|
454
492
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
455
493
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -485,21 +523,19 @@ var StreamingErrorHandler = class _StreamingErrorHandler {
|
|
|
485
523
|
*/
|
|
486
524
|
handleShellError(error, res, viewPath, isDevelopment) {
|
|
487
525
|
this.logger.error(`Shell error rendering ${viewPath}: ${error.message}`, error.stack);
|
|
488
|
-
|
|
526
|
+
const rawRes = getRawResponse(res);
|
|
527
|
+
if (isHeadersSent(res)) {
|
|
489
528
|
this.logger.error(`Cannot send error page for ${viewPath} - headers already sent (streaming started)`);
|
|
490
|
-
if (!
|
|
491
|
-
|
|
492
|
-
|
|
529
|
+
if (!rawRes.writableEnded) {
|
|
530
|
+
rawRes.write(this.renderInlineErrorOverlay(error, viewPath, isDevelopment));
|
|
531
|
+
rawRes.end();
|
|
493
532
|
}
|
|
494
533
|
return;
|
|
495
534
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
} else {
|
|
501
|
-
res.send(this.renderProductionErrorPage());
|
|
502
|
-
}
|
|
535
|
+
rawRes.statusCode = 500;
|
|
536
|
+
rawRes.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
537
|
+
const html = isDevelopment ? this.renderDevelopmentErrorPage(error, viewPath, "shell") : this.renderProductionErrorPage();
|
|
538
|
+
rawRes.end(html);
|
|
503
539
|
}
|
|
504
540
|
/**
|
|
505
541
|
* Handle error that occurred during streaming
|
|
@@ -655,7 +691,7 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
655
691
|
*
|
|
656
692
|
* @param viewComponent - The React component to render
|
|
657
693
|
* @param data - Data to pass to the component
|
|
658
|
-
* @param res -
|
|
694
|
+
* @param res - HTTP response object (Express or Fastify)
|
|
659
695
|
* @param context - Render context with Vite and manifest info
|
|
660
696
|
* @param head - Head data for SEO tags
|
|
661
697
|
*/
|
|
@@ -697,20 +733,21 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
697
733
|
const { PassThrough } = await import('stream');
|
|
698
734
|
const reactStream = new PassThrough();
|
|
699
735
|
let allReadyFired = false;
|
|
736
|
+
const rawRes = getRawResponse(res);
|
|
700
737
|
const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
|
|
701
738
|
onShellReady: /* @__PURE__ */ __name(() => {
|
|
702
739
|
shellReadyTime = Date.now();
|
|
703
|
-
if (!
|
|
704
|
-
|
|
705
|
-
|
|
740
|
+
if (!rawRes.headersSent) {
|
|
741
|
+
rawRes.statusCode = didError ? 500 : 200;
|
|
742
|
+
rawRes.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
706
743
|
}
|
|
707
744
|
let htmlStart = templateParts.htmlStart;
|
|
708
745
|
htmlStart = htmlStart.replace("<!--styles-->", stylesheetTags);
|
|
709
746
|
htmlStart = htmlStart.replace("<!--head-meta-->", headTags);
|
|
710
|
-
|
|
711
|
-
|
|
747
|
+
rawRes.write(htmlStart);
|
|
748
|
+
rawRes.write(templateParts.rootStart);
|
|
712
749
|
pipe(reactStream);
|
|
713
|
-
reactStream.pipe(
|
|
750
|
+
reactStream.pipe(rawRes, {
|
|
714
751
|
end: false
|
|
715
752
|
});
|
|
716
753
|
if (context.isDevelopment) {
|
|
@@ -735,11 +772,11 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
735
772
|
if (shellErrorOccurred) {
|
|
736
773
|
return;
|
|
737
774
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
775
|
+
rawRes.write(inlineScripts);
|
|
776
|
+
rawRes.write(clientScript);
|
|
777
|
+
rawRes.write(templateParts.rootEnd);
|
|
778
|
+
rawRes.write(templateParts.htmlEnd);
|
|
779
|
+
rawRes.end();
|
|
743
780
|
if (context.isDevelopment) {
|
|
744
781
|
const totalTime = Date.now() - startTime;
|
|
745
782
|
const streamTime = Date.now() - shellReadyTime;
|
|
@@ -751,7 +788,7 @@ var StreamRenderer = class _StreamRenderer {
|
|
|
751
788
|
reactStream.on("error", (error) => {
|
|
752
789
|
reject(error);
|
|
753
790
|
});
|
|
754
|
-
|
|
791
|
+
rawRes.on("close", () => {
|
|
755
792
|
abort();
|
|
756
793
|
resolve();
|
|
757
794
|
});
|
|
@@ -1090,11 +1127,13 @@ var RenderInterceptor = class {
|
|
|
1090
1127
|
renderService;
|
|
1091
1128
|
allowedHeaders;
|
|
1092
1129
|
allowedCookies;
|
|
1093
|
-
|
|
1130
|
+
contextFactory;
|
|
1131
|
+
constructor(reflector, renderService, allowedHeaders, allowedCookies, contextFactory) {
|
|
1094
1132
|
this.reflector = reflector;
|
|
1095
1133
|
this.renderService = renderService;
|
|
1096
1134
|
this.allowedHeaders = allowedHeaders;
|
|
1097
1135
|
this.allowedCookies = allowedCookies;
|
|
1136
|
+
this.contextFactory = contextFactory;
|
|
1098
1137
|
}
|
|
1099
1138
|
/**
|
|
1100
1139
|
* Resolve the layout hierarchy for a given route
|
|
@@ -1234,6 +1273,14 @@ var RenderInterceptor = class {
|
|
|
1234
1273
|
renderContext.cookies = cookies;
|
|
1235
1274
|
}
|
|
1236
1275
|
}
|
|
1276
|
+
if (this.contextFactory) {
|
|
1277
|
+
const customContext = await this.contextFactory({
|
|
1278
|
+
req: request
|
|
1279
|
+
});
|
|
1280
|
+
if (customContext) {
|
|
1281
|
+
Object.assign(renderContext, customContext);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1237
1284
|
const renderResponse = isRenderResponse(data) ? data : {
|
|
1238
1285
|
props: data
|
|
1239
1286
|
};
|
|
@@ -1280,12 +1327,15 @@ RenderInterceptor = _ts_decorate6([
|
|
|
1280
1327
|
_ts_param3(2, Inject("ALLOWED_HEADERS")),
|
|
1281
1328
|
_ts_param3(3, Optional()),
|
|
1282
1329
|
_ts_param3(3, Inject("ALLOWED_COOKIES")),
|
|
1330
|
+
_ts_param3(4, Optional()),
|
|
1331
|
+
_ts_param3(4, Inject("CONTEXT_FACTORY")),
|
|
1283
1332
|
_ts_metadata5("design:type", Function),
|
|
1284
1333
|
_ts_metadata5("design:paramtypes", [
|
|
1285
1334
|
typeof Reflector === "undefined" ? Object : Reflector,
|
|
1286
1335
|
typeof RenderService === "undefined" ? Object : RenderService,
|
|
1287
1336
|
Array,
|
|
1288
|
-
Array
|
|
1337
|
+
Array,
|
|
1338
|
+
typeof ContextFactory === "undefined" ? Object : ContextFactory
|
|
1289
1339
|
])
|
|
1290
1340
|
], RenderInterceptor);
|
|
1291
1341
|
function _ts_decorate7(decorators, target, key, desc) {
|
|
@@ -1336,7 +1386,7 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1336
1386
|
if (isDevelopment) {
|
|
1337
1387
|
await this.setupDevelopmentMode();
|
|
1338
1388
|
} else {
|
|
1339
|
-
this.setupProductionMode();
|
|
1389
|
+
await this.setupProductionMode();
|
|
1340
1390
|
}
|
|
1341
1391
|
}
|
|
1342
1392
|
async setupDevelopmentMode() {
|
|
@@ -1378,18 +1428,38 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1378
1428
|
this.logger.warn(`Failed to setup Vite proxy: ${error.message}. Make sure http-proxy-middleware is installed.`);
|
|
1379
1429
|
}
|
|
1380
1430
|
}
|
|
1381
|
-
setupProductionMode() {
|
|
1431
|
+
async setupProductionMode() {
|
|
1382
1432
|
try {
|
|
1383
1433
|
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
1384
|
-
if (httpAdapter)
|
|
1385
|
-
|
|
1386
|
-
|
|
1434
|
+
if (!httpAdapter) return;
|
|
1435
|
+
const app = httpAdapter.getInstance();
|
|
1436
|
+
const { join: join2 } = __require("path");
|
|
1437
|
+
const staticPath = join2(process.cwd(), "dist/client");
|
|
1438
|
+
const adapterType = detectAdapterType(this.httpAdapterHost);
|
|
1439
|
+
if (adapterType === "fastify") {
|
|
1440
|
+
try {
|
|
1441
|
+
const fastifyStatic = await import('@fastify/static').catch(() => null);
|
|
1442
|
+
if (fastifyStatic) {
|
|
1443
|
+
await app.register(fastifyStatic.default, {
|
|
1444
|
+
root: staticPath,
|
|
1445
|
+
prefix: "/",
|
|
1446
|
+
index: false,
|
|
1447
|
+
maxAge: 31536e6
|
|
1448
|
+
});
|
|
1449
|
+
this.logger.log("\u2713 Static assets configured (dist/client) [Fastify]");
|
|
1450
|
+
} else {
|
|
1451
|
+
this.logger.warn("For Fastify static file serving, install @fastify/static: npm install @fastify/static");
|
|
1452
|
+
}
|
|
1453
|
+
} catch {
|
|
1454
|
+
this.logger.warn("For Fastify static file serving, install @fastify/static: npm install @fastify/static");
|
|
1455
|
+
}
|
|
1456
|
+
} else {
|
|
1387
1457
|
const express = __require("express");
|
|
1388
|
-
app.use(express.static(
|
|
1458
|
+
app.use(express.static(staticPath, {
|
|
1389
1459
|
index: false,
|
|
1390
1460
|
maxAge: "1y"
|
|
1391
1461
|
}));
|
|
1392
|
-
this.logger.log("\u2713 Static assets configured (dist/client)");
|
|
1462
|
+
this.logger.log("\u2713 Static assets configured (dist/client) [Express]");
|
|
1393
1463
|
}
|
|
1394
1464
|
} catch (error) {
|
|
1395
1465
|
this.logger.warn(`Failed to setup static assets: ${error.message}`);
|
|
@@ -1529,6 +1599,12 @@ var RenderModule = class _RenderModule {
|
|
|
1529
1599
|
provide: "ALLOWED_COOKIES",
|
|
1530
1600
|
useValue: config?.allowedCookies || []
|
|
1531
1601
|
});
|
|
1602
|
+
if (config?.context) {
|
|
1603
|
+
providers.push({
|
|
1604
|
+
provide: "CONTEXT_FACTORY",
|
|
1605
|
+
useValue: config.context
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1532
1608
|
return {
|
|
1533
1609
|
global: true,
|
|
1534
1610
|
module: _RenderModule,
|
|
@@ -1647,6 +1723,13 @@ var RenderModule = class _RenderModule {
|
|
|
1647
1723
|
inject: [
|
|
1648
1724
|
"RENDER_CONFIG"
|
|
1649
1725
|
]
|
|
1726
|
+
},
|
|
1727
|
+
{
|
|
1728
|
+
provide: "CONTEXT_FACTORY",
|
|
1729
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.context, "useFactory"),
|
|
1730
|
+
inject: [
|
|
1731
|
+
"RENDER_CONFIG"
|
|
1732
|
+
]
|
|
1650
1733
|
}
|
|
1651
1734
|
];
|
|
1652
1735
|
return {
|
|
@@ -1709,9 +1792,28 @@ var PageContext = getOrCreateContext();
|
|
|
1709
1792
|
function registerPageContextState(setter) {
|
|
1710
1793
|
}
|
|
1711
1794
|
__name(registerPageContextState, "registerPageContextState");
|
|
1795
|
+
var segmentSetters = /* @__PURE__ */ new Set();
|
|
1796
|
+
function registerSegmentSetter(setter) {
|
|
1797
|
+
segmentSetters.add(setter);
|
|
1798
|
+
}
|
|
1799
|
+
__name(registerSegmentSetter, "registerSegmentSetter");
|
|
1800
|
+
function unregisterSegmentSetter(setter) {
|
|
1801
|
+
segmentSetters.delete(setter);
|
|
1802
|
+
}
|
|
1803
|
+
__name(unregisterSegmentSetter, "unregisterSegmentSetter");
|
|
1804
|
+
function broadcastToSegments(context) {
|
|
1805
|
+
segmentSetters.forEach((setter) => setter(context));
|
|
1806
|
+
}
|
|
1807
|
+
__name(broadcastToSegments, "broadcastToSegments");
|
|
1712
1808
|
function PageContextProvider({ context: initialContext, children, isSegment = false }) {
|
|
1713
1809
|
const [context, setContext] = useState(initialContext);
|
|
1714
1810
|
useEffect(() => {
|
|
1811
|
+
if (!isSegment) {
|
|
1812
|
+
return void 0;
|
|
1813
|
+
} else {
|
|
1814
|
+
registerSegmentSetter(setContext);
|
|
1815
|
+
return () => unregisterSegmentSetter(setContext);
|
|
1816
|
+
}
|
|
1715
1817
|
}, [
|
|
1716
1818
|
isSegment
|
|
1717
1819
|
]);
|
package/dist/render/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { E as ErrorPageDevelopment, e as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-
|
|
1
|
+
export { E as ErrorPageDevelopment, e as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-ZpkYrPcK.mjs';
|
|
2
2
|
import '@nestjs/common';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../render-response.interface-
|
|
4
|
+
import '../render-response.interface-ClWJXKL4.mjs';
|
|
5
|
+
import 'http';
|
|
5
6
|
import 'vite';
|
|
6
|
-
import 'express';
|
|
7
7
|
import '@nestjs/core';
|
|
8
8
|
import 'rxjs';
|
|
9
9
|
import 'react/jsx-runtime';
|