@nestjs-ssr/react 0.2.5 → 0.3.0
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 +7 -7
- package/dist/cli/init.js +35 -72
- package/dist/cli/init.mjs +35 -72
- package/dist/client.d.mts +55 -304
- package/dist/client.d.ts +55 -304
- package/dist/client.js +360 -13
- package/dist/client.mjs +336 -5
- package/dist/{index-BMdluY1g.d.mts → index-BzOLOiIZ.d.ts} +207 -44
- package/dist/{index-rl0S5kqW.d.ts → index-DdE--mA2.d.mts} +207 -44
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +646 -317
- package/dist/index.mjs +640 -319
- package/dist/render/index.d.mts +2 -2
- package/dist/render/index.d.ts +2 -2
- package/dist/render/index.js +610 -315
- package/dist/render/index.mjs +610 -315
- package/dist/{render-response.interface-Dc-Kwb09.d.mts → render-response.interface-CxbuKGnV.d.mts} +57 -1
- package/dist/{render-response.interface-Dc-Kwb09.d.ts → render-response.interface-CxbuKGnV.d.ts} +57 -1
- package/dist/templates/entry-client.tsx +21 -5
- package/dist/templates/entry-server.tsx +28 -6
- package/dist/use-page-context-05ODF4zW.d.ts +281 -0
- package/dist/use-page-context-CGT9woWe.d.mts +281 -0
- package/package.json +1 -1
- package/src/global.d.ts +11 -0
- package/src/templates/entry-client.tsx +21 -5
- package/src/templates/entry-server.tsx +28 -6
package/dist/index.js
CHANGED
|
@@ -192,6 +192,153 @@ window.__LAYOUTS__ = ${devalue.uneval(layoutMetadata)};
|
|
|
192
192
|
exports.TemplateParserService = _ts_decorate([
|
|
193
193
|
common.Injectable()
|
|
194
194
|
], exports.TemplateParserService);
|
|
195
|
+
|
|
196
|
+
// src/render/renderers/string-renderer.ts
|
|
197
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
198
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
199
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
200
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
201
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
202
|
+
}
|
|
203
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
204
|
+
function _ts_metadata(k, v) {
|
|
205
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
206
|
+
}
|
|
207
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
208
|
+
var StringRenderer = class _StringRenderer {
|
|
209
|
+
static {
|
|
210
|
+
__name(this, "StringRenderer");
|
|
211
|
+
}
|
|
212
|
+
templateParser;
|
|
213
|
+
logger = new common.Logger(_StringRenderer.name);
|
|
214
|
+
constructor(templateParser) {
|
|
215
|
+
this.templateParser = templateParser;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Render a React component to a complete HTML string
|
|
219
|
+
*/
|
|
220
|
+
async render(viewComponent, data, context, head) {
|
|
221
|
+
const startTime = Date.now();
|
|
222
|
+
let template = context.template;
|
|
223
|
+
if (context.vite) {
|
|
224
|
+
template = await context.vite.transformIndexHtml("/", template);
|
|
225
|
+
}
|
|
226
|
+
let renderModule;
|
|
227
|
+
if (context.vite) {
|
|
228
|
+
renderModule = await context.vite.ssrLoadModule(context.entryServerPath);
|
|
229
|
+
} else {
|
|
230
|
+
if (context.serverManifest) {
|
|
231
|
+
const manifestEntry = Object.entries(context.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
|
|
232
|
+
if (manifestEntry) {
|
|
233
|
+
const [, entry] = manifestEntry;
|
|
234
|
+
const serverPath = `${process.cwd()}/dist/server/${entry.file}`;
|
|
235
|
+
renderModule = await import(serverPath);
|
|
236
|
+
} else {
|
|
237
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const { data: pageData, __context: pageContext, __layouts: layouts } = data;
|
|
244
|
+
const appHtml = await renderModule.renderComponent(viewComponent, data);
|
|
245
|
+
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
246
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
247
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
248
|
+
props: l.props
|
|
249
|
+
})) : [];
|
|
250
|
+
const initialStateScript = `
|
|
251
|
+
<script>
|
|
252
|
+
window.__INITIAL_STATE__ = ${devalue.uneval(pageData)};
|
|
253
|
+
window.__CONTEXT__ = ${devalue.uneval(pageContext)};
|
|
254
|
+
window.__COMPONENT_NAME__ = ${devalue.uneval(componentName)};
|
|
255
|
+
window.__LAYOUTS__ = ${devalue.uneval(layoutMetadata)};
|
|
256
|
+
</script>
|
|
257
|
+
`;
|
|
258
|
+
let clientScript = "";
|
|
259
|
+
let styles = "";
|
|
260
|
+
if (context.vite) {
|
|
261
|
+
clientScript = `<script type="module" src="/src/views/entry-client.tsx"></script>`;
|
|
262
|
+
} else {
|
|
263
|
+
if (context.manifest) {
|
|
264
|
+
const manifestEntry = Object.entries(context.manifest).find(([key, value]) => value.isEntry && key.includes("entry-client"));
|
|
265
|
+
if (manifestEntry) {
|
|
266
|
+
const [, entry] = manifestEntry;
|
|
267
|
+
const entryFile = entry.file;
|
|
268
|
+
clientScript = `<script type="module" src="/${entryFile}"></script>`;
|
|
269
|
+
if (entry.css) {
|
|
270
|
+
const cssFiles = entry.css;
|
|
271
|
+
styles = cssFiles.map((css) => `<link rel="stylesheet" href="/${css}" />`).join("\n ");
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
this.logger.error("\u26A0\uFE0F Client entry not found in manifest");
|
|
275
|
+
clientScript = `<script type="module" src="/assets/client.js"></script>`;
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
this.logger.error("\u26A0\uFE0F Client manifest not found");
|
|
279
|
+
clientScript = `<script type="module" src="/assets/client.js"></script>`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const headTags = this.templateParser.buildHeadTags(head);
|
|
283
|
+
let html = template.replace("<!--app-html-->", appHtml);
|
|
284
|
+
html = html.replace("<!--initial-state-->", initialStateScript);
|
|
285
|
+
html = html.replace("<!--client-scripts-->", clientScript);
|
|
286
|
+
html = html.replace("<!--styles-->", styles);
|
|
287
|
+
html = html.replace("<!--head-meta-->", headTags);
|
|
288
|
+
if (context.isDevelopment) {
|
|
289
|
+
const duration = Date.now() - startTime;
|
|
290
|
+
const name = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
|
|
291
|
+
this.logger.log(`[SSR] ${name} rendered in ${duration}ms (string mode)`);
|
|
292
|
+
}
|
|
293
|
+
return html;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Render a segment for client-side navigation.
|
|
297
|
+
* Returns just the HTML and metadata without the full page template.
|
|
298
|
+
*/
|
|
299
|
+
async renderSegment(viewComponent, data, context, swapTarget, head) {
|
|
300
|
+
const startTime = Date.now();
|
|
301
|
+
let renderModule;
|
|
302
|
+
if (context.vite) {
|
|
303
|
+
renderModule = await context.vite.ssrLoadModule(context.entryServerPath);
|
|
304
|
+
} else {
|
|
305
|
+
if (context.serverManifest) {
|
|
306
|
+
const manifestEntry = Object.entries(context.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
|
|
307
|
+
if (manifestEntry) {
|
|
308
|
+
const [, entry] = manifestEntry;
|
|
309
|
+
const serverPath = `${process.cwd()}/dist/server/${entry.file}`;
|
|
310
|
+
renderModule = await import(serverPath);
|
|
311
|
+
} else {
|
|
312
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const { data: pageData, __context: pageContext } = data;
|
|
319
|
+
const html = await renderModule.renderComponent(viewComponent, data);
|
|
320
|
+
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
321
|
+
if (context.isDevelopment) {
|
|
322
|
+
const duration = Date.now() - startTime;
|
|
323
|
+
this.logger.log(`[SSR] ${componentName} segment rendered in ${duration}ms`);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
html,
|
|
327
|
+
head,
|
|
328
|
+
props: pageData,
|
|
329
|
+
swapTarget,
|
|
330
|
+
componentName,
|
|
331
|
+
context: pageContext
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
StringRenderer = _ts_decorate2([
|
|
336
|
+
common.Injectable(),
|
|
337
|
+
_ts_metadata("design:type", Function),
|
|
338
|
+
_ts_metadata("design:paramtypes", [
|
|
339
|
+
typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService
|
|
340
|
+
])
|
|
341
|
+
], StringRenderer);
|
|
195
342
|
function ErrorPageDevelopment({ error, viewPath, phase }) {
|
|
196
343
|
const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
|
|
197
344
|
return /* @__PURE__ */ React__default.default.createElement("html", {
|
|
@@ -307,17 +454,17 @@ function ErrorPageProduction() {
|
|
|
307
454
|
__name(ErrorPageProduction, "ErrorPageProduction");
|
|
308
455
|
|
|
309
456
|
// src/render/streaming-error-handler.ts
|
|
310
|
-
function
|
|
457
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
311
458
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
312
459
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
313
460
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
314
461
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
315
462
|
}
|
|
316
|
-
__name(
|
|
317
|
-
function
|
|
463
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
464
|
+
function _ts_metadata2(k, v) {
|
|
318
465
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
319
466
|
}
|
|
320
|
-
__name(
|
|
467
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
321
468
|
function _ts_param(paramIndex, decorator) {
|
|
322
469
|
return function(target, key) {
|
|
323
470
|
decorator(target, key, paramIndex);
|
|
@@ -341,6 +488,14 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
|
|
|
341
488
|
*/
|
|
342
489
|
handleShellError(error, res, viewPath, isDevelopment) {
|
|
343
490
|
this.logger.error(`Shell error rendering ${viewPath}: ${error.message}`, error.stack);
|
|
491
|
+
if (res.headersSent) {
|
|
492
|
+
this.logger.error(`Cannot send error page for ${viewPath} - headers already sent (streaming started)`);
|
|
493
|
+
if (!res.writableEnded) {
|
|
494
|
+
res.write(this.renderInlineErrorOverlay(error, viewPath, isDevelopment));
|
|
495
|
+
res.end();
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
344
499
|
res.statusCode = 500;
|
|
345
500
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
346
501
|
if (isDevelopment) {
|
|
@@ -376,32 +531,263 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
|
|
|
376
531
|
const element = React.createElement(ErrorComponent);
|
|
377
532
|
return "<!DOCTYPE html>\n" + server.renderToStaticMarkup(element);
|
|
378
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Render inline error overlay for when headers are already sent
|
|
536
|
+
* This gets injected into the stream to show a visible error UI
|
|
537
|
+
*/
|
|
538
|
+
renderInlineErrorOverlay(error, viewPath, isDevelopment) {
|
|
539
|
+
const errorMessage = escapeHtml__default.default(error.message);
|
|
540
|
+
const errorStack = escapeHtml__default.default(error.stack || "");
|
|
541
|
+
const escapedViewPath = escapeHtml__default.default(viewPath);
|
|
542
|
+
if (isDevelopment) {
|
|
543
|
+
return `
|
|
544
|
+
<div id="ssr-error-overlay" style="
|
|
545
|
+
position: fixed;
|
|
546
|
+
inset: 0;
|
|
547
|
+
z-index: 99999;
|
|
548
|
+
background: rgba(0, 0, 0, 0.85);
|
|
549
|
+
color: #fff;
|
|
550
|
+
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
551
|
+
font-size: 14px;
|
|
552
|
+
padding: 32px;
|
|
553
|
+
overflow: auto;
|
|
554
|
+
">
|
|
555
|
+
<div style="max-width: 900px; margin: 0 auto;">
|
|
556
|
+
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 24px;">
|
|
557
|
+
<span style="font-size: 32px;">\u26A0\uFE0F</span>
|
|
558
|
+
<h1 style="margin: 0; font-size: 24px; font-weight: 600; color: #ff6b6b;">
|
|
559
|
+
SSR Streaming Error
|
|
560
|
+
</h1>
|
|
561
|
+
</div>
|
|
562
|
+
<p style="color: #aaa; margin-bottom: 16px;">
|
|
563
|
+
An error occurred after streaming started in <code style="background: #333; padding: 2px 6px; border-radius: 4px;">${escapedViewPath}</code>
|
|
564
|
+
</p>
|
|
565
|
+
<div style="background: #1a1a1a; border: 1px solid #333; border-radius: 8px; padding: 16px; margin-bottom: 16px;">
|
|
566
|
+
<div style="color: #ff6b6b; font-weight: 600; margin-bottom: 8px;">Error Message:</div>
|
|
567
|
+
<pre style="margin: 0; white-space: pre-wrap; word-break: break-word; color: #fff;">${errorMessage}</pre>
|
|
568
|
+
</div>
|
|
569
|
+
<div style="background: #1a1a1a; border: 1px solid #333; border-radius: 8px; padding: 16px;">
|
|
570
|
+
<div style="color: #888; font-weight: 600; margin-bottom: 8px;">Stack Trace:</div>
|
|
571
|
+
<pre style="margin: 0; white-space: pre-wrap; word-break: break-word; color: #888; font-size: 12px;">${errorStack}</pre>
|
|
572
|
+
</div>
|
|
573
|
+
<button onclick="document.getElementById('ssr-error-overlay').remove()" style="
|
|
574
|
+
margin-top: 24px;
|
|
575
|
+
background: #333;
|
|
576
|
+
color: #fff;
|
|
577
|
+
border: 1px solid #555;
|
|
578
|
+
padding: 8px 16px;
|
|
579
|
+
border-radius: 6px;
|
|
580
|
+
cursor: pointer;
|
|
581
|
+
font-family: inherit;
|
|
582
|
+
">Dismiss</button>
|
|
583
|
+
</div>
|
|
584
|
+
</div>
|
|
585
|
+
<script>console.error('SSR Streaming Error in ${escapedViewPath}:', ${devalue.uneval(error.message)});</script>
|
|
586
|
+
`;
|
|
587
|
+
} else {
|
|
588
|
+
return `
|
|
589
|
+
<div id="ssr-error-overlay" style="
|
|
590
|
+
position: fixed;
|
|
591
|
+
inset: 0;
|
|
592
|
+
z-index: 99999;
|
|
593
|
+
background: #fff;
|
|
594
|
+
color: #333;
|
|
595
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
596
|
+
display: flex;
|
|
597
|
+
align-items: center;
|
|
598
|
+
justify-content: center;
|
|
599
|
+
text-align: center;
|
|
600
|
+
">
|
|
601
|
+
<div>
|
|
602
|
+
<h1 style="font-size: 24px; font-weight: 600; margin-bottom: 16px;">Something went wrong</h1>
|
|
603
|
+
<p style="color: #666; margin-bottom: 24px;">We're sorry, but something went wrong. Please try refreshing the page.</p>
|
|
604
|
+
<button onclick="location.reload()" style="
|
|
605
|
+
background: #333;
|
|
606
|
+
color: #fff;
|
|
607
|
+
border: none;
|
|
608
|
+
padding: 12px 24px;
|
|
609
|
+
border-radius: 6px;
|
|
610
|
+
cursor: pointer;
|
|
611
|
+
font-family: inherit;
|
|
612
|
+
font-size: 16px;
|
|
613
|
+
">Refresh Page</button>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
`;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
379
619
|
};
|
|
380
|
-
exports.StreamingErrorHandler =
|
|
620
|
+
exports.StreamingErrorHandler = _ts_decorate3([
|
|
381
621
|
common.Injectable(),
|
|
382
622
|
_ts_param(0, common.Optional()),
|
|
383
623
|
_ts_param(0, common.Inject("ERROR_PAGE_DEVELOPMENT")),
|
|
384
624
|
_ts_param(1, common.Optional()),
|
|
385
625
|
_ts_param(1, common.Inject("ERROR_PAGE_PRODUCTION")),
|
|
386
|
-
|
|
387
|
-
|
|
626
|
+
_ts_metadata2("design:type", Function),
|
|
627
|
+
_ts_metadata2("design:paramtypes", [
|
|
388
628
|
typeof ComponentType === "undefined" ? Object : ComponentType,
|
|
389
629
|
typeof ComponentType === "undefined" ? Object : ComponentType
|
|
390
630
|
])
|
|
391
631
|
], exports.StreamingErrorHandler);
|
|
392
632
|
|
|
633
|
+
// src/render/renderers/stream-renderer.ts
|
|
634
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
635
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
636
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
637
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
638
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
639
|
+
}
|
|
640
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
641
|
+
function _ts_metadata3(k, v) {
|
|
642
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
643
|
+
}
|
|
644
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
645
|
+
var StreamRenderer = class _StreamRenderer {
|
|
646
|
+
static {
|
|
647
|
+
__name(this, "StreamRenderer");
|
|
648
|
+
}
|
|
649
|
+
templateParser;
|
|
650
|
+
streamingErrorHandler;
|
|
651
|
+
logger = new common.Logger(_StreamRenderer.name);
|
|
652
|
+
constructor(templateParser, streamingErrorHandler) {
|
|
653
|
+
this.templateParser = templateParser;
|
|
654
|
+
this.streamingErrorHandler = streamingErrorHandler;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Render a React component using streaming SSR
|
|
658
|
+
*
|
|
659
|
+
* @param viewComponent - The React component to render
|
|
660
|
+
* @param data - Data to pass to the component
|
|
661
|
+
* @param res - Express response object (required for streaming)
|
|
662
|
+
* @param context - Render context with Vite and manifest info
|
|
663
|
+
* @param head - Head data for SEO tags
|
|
664
|
+
*/
|
|
665
|
+
async render(viewComponent, data, res, context, head) {
|
|
666
|
+
const startTime = Date.now();
|
|
667
|
+
let shellReadyTime = 0;
|
|
668
|
+
return new Promise((resolve, reject) => {
|
|
669
|
+
const executeStream = /* @__PURE__ */ __name(async () => {
|
|
670
|
+
let template = context.template;
|
|
671
|
+
if (context.vite) {
|
|
672
|
+
template = await context.vite.transformIndexHtml("/", template);
|
|
673
|
+
}
|
|
674
|
+
const templateParts = this.templateParser.parseTemplate(template);
|
|
675
|
+
let renderModule;
|
|
676
|
+
if (context.vite) {
|
|
677
|
+
renderModule = await context.vite.ssrLoadModule(context.entryServerPath);
|
|
678
|
+
} else {
|
|
679
|
+
if (context.serverManifest) {
|
|
680
|
+
const manifestEntry = Object.entries(context.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
|
|
681
|
+
if (manifestEntry) {
|
|
682
|
+
const [, entry] = manifestEntry;
|
|
683
|
+
const serverPath = `${process.cwd()}/dist/server/${entry.file}`;
|
|
684
|
+
renderModule = await import(serverPath);
|
|
685
|
+
} else {
|
|
686
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
687
|
+
}
|
|
688
|
+
} else {
|
|
689
|
+
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const { data: pageData, __context: pageContext, __layouts: layouts } = data;
|
|
693
|
+
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
694
|
+
const inlineScripts = this.templateParser.buildInlineScripts(pageData, pageContext, componentName, layouts);
|
|
695
|
+
const clientScript = this.templateParser.getClientScriptTag(context.isDevelopment, context.manifest);
|
|
696
|
+
const stylesheetTags = this.templateParser.getStylesheetTags(context.isDevelopment, context.manifest);
|
|
697
|
+
const headTags = this.templateParser.buildHeadTags(head);
|
|
698
|
+
let didError = false;
|
|
699
|
+
let shellErrorOccurred = false;
|
|
700
|
+
const { PassThrough } = await import('stream');
|
|
701
|
+
const reactStream = new PassThrough();
|
|
702
|
+
let allReadyFired = false;
|
|
703
|
+
const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
|
|
704
|
+
onShellReady: /* @__PURE__ */ __name(() => {
|
|
705
|
+
shellReadyTime = Date.now();
|
|
706
|
+
if (!res.headersSent) {
|
|
707
|
+
res.statusCode = didError ? 500 : 200;
|
|
708
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
709
|
+
}
|
|
710
|
+
let htmlStart = templateParts.htmlStart;
|
|
711
|
+
htmlStart = htmlStart.replace("<!--styles-->", stylesheetTags);
|
|
712
|
+
htmlStart = htmlStart.replace("<!--head-meta-->", headTags);
|
|
713
|
+
res.write(htmlStart);
|
|
714
|
+
res.write(templateParts.rootStart);
|
|
715
|
+
pipe(reactStream);
|
|
716
|
+
reactStream.pipe(res, {
|
|
717
|
+
end: false
|
|
718
|
+
});
|
|
719
|
+
if (context.isDevelopment) {
|
|
720
|
+
const ttfb = shellReadyTime - startTime;
|
|
721
|
+
this.logger.log(`[SSR] ${componentName} shell ready in ${ttfb}ms (stream mode - TTFB)`);
|
|
722
|
+
}
|
|
723
|
+
}, "onShellReady"),
|
|
724
|
+
onShellError: /* @__PURE__ */ __name((error) => {
|
|
725
|
+
shellErrorOccurred = true;
|
|
726
|
+
this.streamingErrorHandler.handleShellError(error, res, componentName, context.isDevelopment);
|
|
727
|
+
resolve();
|
|
728
|
+
}, "onShellError"),
|
|
729
|
+
onError: /* @__PURE__ */ __name((error) => {
|
|
730
|
+
didError = true;
|
|
731
|
+
this.streamingErrorHandler.handleStreamError(error, componentName);
|
|
732
|
+
}, "onError"),
|
|
733
|
+
onAllReady: /* @__PURE__ */ __name(() => {
|
|
734
|
+
allReadyFired = true;
|
|
735
|
+
}, "onAllReady")
|
|
736
|
+
});
|
|
737
|
+
reactStream.on("end", () => {
|
|
738
|
+
if (shellErrorOccurred) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
res.write(inlineScripts);
|
|
742
|
+
res.write(clientScript);
|
|
743
|
+
res.write(templateParts.rootEnd);
|
|
744
|
+
res.write(templateParts.htmlEnd);
|
|
745
|
+
res.end();
|
|
746
|
+
if (context.isDevelopment) {
|
|
747
|
+
const totalTime = Date.now() - startTime;
|
|
748
|
+
const streamTime = Date.now() - shellReadyTime;
|
|
749
|
+
const viaAllReady = allReadyFired ? " (onAllReady fired)" : " (onAllReady never fired)";
|
|
750
|
+
this.logger.log(`[SSR] ${componentName} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)${viaAllReady}`);
|
|
751
|
+
}
|
|
752
|
+
resolve();
|
|
753
|
+
});
|
|
754
|
+
reactStream.on("error", (error) => {
|
|
755
|
+
reject(error);
|
|
756
|
+
});
|
|
757
|
+
res.on("close", () => {
|
|
758
|
+
abort();
|
|
759
|
+
resolve();
|
|
760
|
+
});
|
|
761
|
+
}, "executeStream");
|
|
762
|
+
executeStream().catch((error) => {
|
|
763
|
+
const componentName = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
|
|
764
|
+
this.streamingErrorHandler.handleShellError(error, res, componentName, context.isDevelopment);
|
|
765
|
+
resolve();
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
StreamRenderer = _ts_decorate4([
|
|
771
|
+
common.Injectable(),
|
|
772
|
+
_ts_metadata3("design:type", Function),
|
|
773
|
+
_ts_metadata3("design:paramtypes", [
|
|
774
|
+
typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService,
|
|
775
|
+
typeof exports.StreamingErrorHandler === "undefined" ? Object : exports.StreamingErrorHandler
|
|
776
|
+
])
|
|
777
|
+
], StreamRenderer);
|
|
778
|
+
|
|
393
779
|
// src/render/render.service.ts
|
|
394
|
-
function
|
|
780
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
395
781
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
396
782
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
397
783
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
398
784
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
399
785
|
}
|
|
400
|
-
__name(
|
|
401
|
-
function
|
|
786
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
787
|
+
function _ts_metadata4(k, v) {
|
|
402
788
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
403
789
|
}
|
|
404
|
-
__name(
|
|
790
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
405
791
|
function _ts_param2(paramIndex, decorator) {
|
|
406
792
|
return function(target, key) {
|
|
407
793
|
decorator(target, key, paramIndex);
|
|
@@ -412,8 +798,8 @@ exports.RenderService = class _RenderService {
|
|
|
412
798
|
static {
|
|
413
799
|
__name(this, "RenderService");
|
|
414
800
|
}
|
|
415
|
-
|
|
416
|
-
|
|
801
|
+
stringRenderer;
|
|
802
|
+
streamRenderer;
|
|
417
803
|
defaultHead;
|
|
418
804
|
logger = new common.Logger(_RenderService.name);
|
|
419
805
|
vite = null;
|
|
@@ -425,12 +811,12 @@ exports.RenderService = class _RenderService {
|
|
|
425
811
|
entryServerPath;
|
|
426
812
|
rootLayout = void 0;
|
|
427
813
|
rootLayoutChecked = false;
|
|
428
|
-
constructor(
|
|
429
|
-
this.
|
|
430
|
-
this.
|
|
814
|
+
constructor(stringRenderer, streamRenderer, ssrMode, defaultHead, customTemplate) {
|
|
815
|
+
this.stringRenderer = stringRenderer;
|
|
816
|
+
this.streamRenderer = streamRenderer;
|
|
431
817
|
this.defaultHead = defaultHead;
|
|
432
818
|
this.isDevelopment = process.env.NODE_ENV !== "production";
|
|
433
|
-
this.ssrMode = ssrMode || process.env.SSR_MODE || "
|
|
819
|
+
this.ssrMode = ssrMode || process.env.SSR_MODE || "string";
|
|
434
820
|
const absoluteServerPath = path.join(__dirname, "/templates/entry-server.tsx");
|
|
435
821
|
const relativeServerPath = path.relative(process.cwd(), absoluteServerPath);
|
|
436
822
|
if (relativeServerPath.startsWith("..")) {
|
|
@@ -438,67 +824,82 @@ exports.RenderService = class _RenderService {
|
|
|
438
824
|
} else {
|
|
439
825
|
this.entryServerPath = "/" + relativeServerPath.replace(/\\/g, "/");
|
|
440
826
|
}
|
|
827
|
+
this.template = this.loadTemplate(customTemplate);
|
|
828
|
+
if (!this.isDevelopment) {
|
|
829
|
+
this.loadManifests();
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Load HTML template from custom path, package, or local location
|
|
834
|
+
*/
|
|
835
|
+
loadTemplate(customTemplate) {
|
|
441
836
|
if (customTemplate) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
837
|
+
return this.loadCustomTemplate(customTemplate);
|
|
838
|
+
}
|
|
839
|
+
return this.loadDefaultTemplate();
|
|
840
|
+
}
|
|
841
|
+
loadCustomTemplate(customTemplate) {
|
|
842
|
+
if (customTemplate.includes("<!DOCTYPE") || customTemplate.includes("<html")) {
|
|
843
|
+
this.logger.log(`\u2713 Loaded custom template (inline)`);
|
|
844
|
+
return customTemplate;
|
|
845
|
+
}
|
|
846
|
+
const customTemplatePath = customTemplate.startsWith("/") ? customTemplate : path.join(process.cwd(), customTemplate);
|
|
847
|
+
if (!fs.existsSync(customTemplatePath)) {
|
|
848
|
+
throw new Error(`Custom template file not found at ${customTemplatePath}`);
|
|
849
|
+
}
|
|
850
|
+
try {
|
|
851
|
+
const template = fs.readFileSync(customTemplatePath, "utf-8");
|
|
852
|
+
this.logger.log(`\u2713 Loaded custom template from ${customTemplatePath}`);
|
|
853
|
+
return template;
|
|
854
|
+
} catch (error) {
|
|
855
|
+
throw new Error(`Failed to read custom template file at ${customTemplatePath}: ${error.message}`);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
loadDefaultTemplate() {
|
|
859
|
+
let templatePath;
|
|
860
|
+
if (this.isDevelopment) {
|
|
861
|
+
const packageTemplatePaths = [
|
|
862
|
+
path.join(__dirname, "../templates/index.html"),
|
|
863
|
+
path.join(__dirname, "../src/templates/index.html"),
|
|
864
|
+
path.join(__dirname, "../../src/templates/index.html")
|
|
865
|
+
];
|
|
866
|
+
const localTemplatePath = path.join(process.cwd(), "src/views/index.html");
|
|
867
|
+
const foundPackageTemplate = packageTemplatePaths.find((p) => fs.existsSync(p));
|
|
868
|
+
if (foundPackageTemplate) {
|
|
869
|
+
templatePath = foundPackageTemplate;
|
|
870
|
+
} else if (fs.existsSync(localTemplatePath)) {
|
|
871
|
+
templatePath = localTemplatePath;
|
|
445
872
|
} else {
|
|
446
|
-
|
|
447
|
-
if (!fs.existsSync(customTemplatePath)) {
|
|
448
|
-
throw new Error(`Custom template file not found at ${customTemplatePath}`);
|
|
449
|
-
}
|
|
450
|
-
try {
|
|
451
|
-
this.template = fs.readFileSync(customTemplatePath, "utf-8");
|
|
452
|
-
this.logger.log(`\u2713 Loaded custom template from ${customTemplatePath}`);
|
|
453
|
-
} catch (error) {
|
|
454
|
-
throw new Error(`Failed to read custom template file at ${customTemplatePath}: ${error.message}`);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
} else {
|
|
458
|
-
let templatePath;
|
|
459
|
-
if (this.isDevelopment) {
|
|
460
|
-
const packageTemplatePaths = [
|
|
461
|
-
path.join(__dirname, "../templates/index.html"),
|
|
462
|
-
path.join(__dirname, "../src/templates/index.html"),
|
|
463
|
-
path.join(__dirname, "../../src/templates/index.html")
|
|
464
|
-
];
|
|
465
|
-
const localTemplatePath = path.join(process.cwd(), "src/views/index.html");
|
|
466
|
-
const foundPackageTemplate = packageTemplatePaths.find((p) => fs.existsSync(p));
|
|
467
|
-
if (foundPackageTemplate) {
|
|
468
|
-
templatePath = foundPackageTemplate;
|
|
469
|
-
} else if (fs.existsSync(localTemplatePath)) {
|
|
470
|
-
templatePath = localTemplatePath;
|
|
471
|
-
} else {
|
|
472
|
-
throw new Error(`Template file not found. Tried:
|
|
873
|
+
throw new Error(`Template file not found. Tried:
|
|
473
874
|
` + packageTemplatePaths.map((p) => ` - ${p} (package template)`).join("\n") + `
|
|
474
875
|
- ${localTemplatePath} (local template)`);
|
|
475
|
-
}
|
|
476
|
-
} else {
|
|
477
|
-
templatePath = path.join(process.cwd(), "dist/client/index.html");
|
|
478
|
-
if (!fs.existsSync(templatePath)) {
|
|
479
|
-
throw new Error(`Template file not found at ${templatePath}. Make sure to run the build process first.`);
|
|
480
|
-
}
|
|
481
876
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
877
|
+
} else {
|
|
878
|
+
templatePath = path.join(process.cwd(), "dist/client/index.html");
|
|
879
|
+
if (!fs.existsSync(templatePath)) {
|
|
880
|
+
throw new Error(`Template file not found at ${templatePath}. Make sure to run the build process first.`);
|
|
487
881
|
}
|
|
488
882
|
}
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
883
|
+
try {
|
|
884
|
+
const template = fs.readFileSync(templatePath, "utf-8");
|
|
885
|
+
this.logger.log(`\u2713 Loaded template from ${templatePath}`);
|
|
886
|
+
return template;
|
|
887
|
+
} catch (error) {
|
|
888
|
+
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
loadManifests() {
|
|
892
|
+
const manifestPath = path.join(process.cwd(), "dist/client/.vite/manifest.json");
|
|
893
|
+
if (fs.existsSync(manifestPath)) {
|
|
894
|
+
this.manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
895
|
+
} else {
|
|
896
|
+
this.logger.warn("\u26A0\uFE0F Client manifest not found. Run `pnpm build:client` first.");
|
|
897
|
+
}
|
|
898
|
+
const serverManifestPath = path.join(process.cwd(), "dist/server/.vite/manifest.json");
|
|
899
|
+
if (fs.existsSync(serverManifestPath)) {
|
|
900
|
+
this.serverManifest = JSON.parse(fs.readFileSync(serverManifestPath, "utf-8"));
|
|
901
|
+
} else {
|
|
902
|
+
this.logger.warn("\u26A0\uFE0F Server manifest not found. Run `pnpm build:server` first.");
|
|
502
903
|
}
|
|
503
904
|
}
|
|
504
905
|
setViteServer(vite) {
|
|
@@ -552,16 +953,50 @@ exports.RenderService = class _RenderService {
|
|
|
552
953
|
}
|
|
553
954
|
/**
|
|
554
955
|
* Main render method that routes to string or stream mode
|
|
956
|
+
*
|
|
957
|
+
* String mode (default):
|
|
958
|
+
* - Returns complete HTML string
|
|
959
|
+
* - Atomic responses - works completely or fails completely
|
|
960
|
+
* - Proper HTTP status codes always
|
|
961
|
+
*
|
|
962
|
+
* Stream mode:
|
|
963
|
+
* - Writes directly to response
|
|
964
|
+
* - Better TTFB, progressive rendering
|
|
965
|
+
* - Requires response object
|
|
555
966
|
*/
|
|
556
967
|
async render(viewComponent, data = {}, res, head) {
|
|
557
968
|
const mergedHead = this.mergeHead(this.defaultHead, head);
|
|
969
|
+
const renderContext = {
|
|
970
|
+
template: this.template,
|
|
971
|
+
vite: this.vite,
|
|
972
|
+
manifest: this.manifest,
|
|
973
|
+
serverManifest: this.serverManifest,
|
|
974
|
+
entryServerPath: this.entryServerPath,
|
|
975
|
+
isDevelopment: this.isDevelopment
|
|
976
|
+
};
|
|
558
977
|
if (this.ssrMode === "stream") {
|
|
559
978
|
if (!res) {
|
|
560
979
|
throw new Error("Response object is required for streaming SSR mode. Pass res as third parameter.");
|
|
561
980
|
}
|
|
562
|
-
return this.
|
|
981
|
+
return this.streamRenderer.render(viewComponent, data, res, renderContext, mergedHead);
|
|
563
982
|
}
|
|
564
|
-
return this.
|
|
983
|
+
return this.stringRenderer.render(viewComponent, data, renderContext, mergedHead);
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Render a segment for client-side navigation.
|
|
987
|
+
* Always uses string mode (streaming not supported for segments).
|
|
988
|
+
*/
|
|
989
|
+
async renderSegment(viewComponent, data, swapTarget, head) {
|
|
990
|
+
const mergedHead = this.mergeHead(this.defaultHead, head);
|
|
991
|
+
const renderContext = {
|
|
992
|
+
template: this.template,
|
|
993
|
+
vite: this.vite,
|
|
994
|
+
manifest: this.manifest,
|
|
995
|
+
serverManifest: this.serverManifest,
|
|
996
|
+
entryServerPath: this.entryServerPath,
|
|
997
|
+
isDevelopment: this.isDevelopment
|
|
998
|
+
};
|
|
999
|
+
return this.stringRenderer.renderSegment(viewComponent, data, renderContext, swapTarget, mergedHead);
|
|
565
1000
|
}
|
|
566
1001
|
/**
|
|
567
1002
|
* Merge default head with page-specific head
|
|
@@ -574,7 +1009,6 @@ exports.RenderService = class _RenderService {
|
|
|
574
1009
|
return {
|
|
575
1010
|
...defaultHead,
|
|
576
1011
|
...pageHead,
|
|
577
|
-
// Merge arrays (links and meta) instead of replacing
|
|
578
1012
|
links: [
|
|
579
1013
|
...defaultHead?.links || [],
|
|
580
1014
|
...pageHead?.links || []
|
|
@@ -585,198 +1019,8 @@ exports.RenderService = class _RenderService {
|
|
|
585
1019
|
]
|
|
586
1020
|
};
|
|
587
1021
|
}
|
|
588
|
-
/**
|
|
589
|
-
* Traditional string-based SSR using renderToString
|
|
590
|
-
*/
|
|
591
|
-
async renderToString(viewComponent, data = {}, head) {
|
|
592
|
-
const startTime = Date.now();
|
|
593
|
-
try {
|
|
594
|
-
let template = this.template;
|
|
595
|
-
if (this.vite) {
|
|
596
|
-
template = await this.vite.transformIndexHtml("/", template);
|
|
597
|
-
}
|
|
598
|
-
let renderModule;
|
|
599
|
-
if (this.vite) {
|
|
600
|
-
renderModule = await this.vite.ssrLoadModule(this.entryServerPath);
|
|
601
|
-
} else {
|
|
602
|
-
if (this.serverManifest) {
|
|
603
|
-
const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
|
|
604
|
-
if (manifestEntry) {
|
|
605
|
-
const [, entry] = manifestEntry;
|
|
606
|
-
const serverPath = path.join(process.cwd(), "dist/server", entry.file);
|
|
607
|
-
renderModule = await import(serverPath);
|
|
608
|
-
} else {
|
|
609
|
-
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
610
|
-
}
|
|
611
|
-
} else {
|
|
612
|
-
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
616
|
-
const appHtml = await renderModule.renderComponent(viewComponent, data);
|
|
617
|
-
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
618
|
-
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
619
|
-
name: l.layout.displayName || l.layout.name || "default",
|
|
620
|
-
props: l.props
|
|
621
|
-
})) : [];
|
|
622
|
-
const initialStateScript = `
|
|
623
|
-
<script>
|
|
624
|
-
window.__INITIAL_STATE__ = ${devalue.uneval(pageData)};
|
|
625
|
-
window.__CONTEXT__ = ${devalue.uneval(context)};
|
|
626
|
-
window.__COMPONENT_NAME__ = ${devalue.uneval(componentName)};
|
|
627
|
-
window.__LAYOUTS__ = ${devalue.uneval(layoutMetadata)};
|
|
628
|
-
</script>
|
|
629
|
-
`;
|
|
630
|
-
let clientScript = "";
|
|
631
|
-
let styles = "";
|
|
632
|
-
if (this.vite) {
|
|
633
|
-
clientScript = `<script type="module" src="/src/views/entry-client.tsx"></script>`;
|
|
634
|
-
styles = "";
|
|
635
|
-
} else {
|
|
636
|
-
if (this.manifest) {
|
|
637
|
-
const manifestEntry = Object.entries(this.manifest).find(([key, value]) => value.isEntry && key.includes("entry-client"));
|
|
638
|
-
if (manifestEntry) {
|
|
639
|
-
const [, entry] = manifestEntry;
|
|
640
|
-
const entryFile = entry.file;
|
|
641
|
-
clientScript = `<script type="module" src="/${entryFile}"></script>`;
|
|
642
|
-
if (entry.css) {
|
|
643
|
-
const cssFiles = entry.css;
|
|
644
|
-
styles = cssFiles.map((css) => `<link rel="stylesheet" href="/${css}" />`).join("\n ");
|
|
645
|
-
}
|
|
646
|
-
} else {
|
|
647
|
-
this.logger.error("\u26A0\uFE0F Client entry not found in manifest");
|
|
648
|
-
clientScript = `<script type="module" src="/assets/client.js"></script>`;
|
|
649
|
-
}
|
|
650
|
-
} else {
|
|
651
|
-
this.logger.error("\u26A0\uFE0F Client manifest not found");
|
|
652
|
-
clientScript = `<script type="module" src="/assets/client.js"></script>`;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
const headTags = this.templateParser.buildHeadTags(head);
|
|
656
|
-
let html = template.replace("<!--app-html-->", appHtml);
|
|
657
|
-
html = html.replace("<!--initial-state-->", initialStateScript);
|
|
658
|
-
html = html.replace("<!--client-scripts-->", clientScript);
|
|
659
|
-
html = html.replace("<!--styles-->", styles);
|
|
660
|
-
html = html.replace("<!--head-meta-->", headTags);
|
|
661
|
-
if (this.isDevelopment) {
|
|
662
|
-
const duration = Date.now() - startTime;
|
|
663
|
-
const componentName2 = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
|
|
664
|
-
this.logger.log(`[SSR] ${componentName2} rendered in ${duration}ms (string mode)`);
|
|
665
|
-
}
|
|
666
|
-
return html;
|
|
667
|
-
} catch (error) {
|
|
668
|
-
throw error;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Modern streaming SSR using renderToPipeableStream
|
|
673
|
-
*/
|
|
674
|
-
async renderToStream(viewComponent, data = {}, res, head) {
|
|
675
|
-
const startTime = Date.now();
|
|
676
|
-
let shellReadyTime = 0;
|
|
677
|
-
return new Promise((resolve, reject) => {
|
|
678
|
-
const executeStream = /* @__PURE__ */ __name(async () => {
|
|
679
|
-
let template = this.template;
|
|
680
|
-
if (this.vite) {
|
|
681
|
-
template = await this.vite.transformIndexHtml("/", template);
|
|
682
|
-
}
|
|
683
|
-
const templateParts = this.templateParser.parseTemplate(template);
|
|
684
|
-
let renderModule;
|
|
685
|
-
if (this.vite) {
|
|
686
|
-
renderModule = await this.vite.ssrLoadModule(this.entryServerPath);
|
|
687
|
-
} else {
|
|
688
|
-
if (this.serverManifest) {
|
|
689
|
-
const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
|
|
690
|
-
if (manifestEntry) {
|
|
691
|
-
const [, entry] = manifestEntry;
|
|
692
|
-
const serverPath = path.join(process.cwd(), "dist/server", entry.file);
|
|
693
|
-
renderModule = await import(serverPath);
|
|
694
|
-
} else {
|
|
695
|
-
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
696
|
-
}
|
|
697
|
-
} else {
|
|
698
|
-
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
702
|
-
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
703
|
-
const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName, layouts);
|
|
704
|
-
const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
|
|
705
|
-
const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
|
|
706
|
-
const headTags = this.templateParser.buildHeadTags(head);
|
|
707
|
-
let didError = false;
|
|
708
|
-
let shellErrorOccurred = false;
|
|
709
|
-
const { PassThrough } = await import('stream');
|
|
710
|
-
const reactStream = new PassThrough();
|
|
711
|
-
let allReadyFired = false;
|
|
712
|
-
const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
|
|
713
|
-
onShellReady: /* @__PURE__ */ __name(() => {
|
|
714
|
-
shellReadyTime = Date.now();
|
|
715
|
-
if (!res.headersSent) {
|
|
716
|
-
res.statusCode = didError ? 500 : 200;
|
|
717
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
718
|
-
}
|
|
719
|
-
let htmlStart = templateParts.htmlStart;
|
|
720
|
-
htmlStart = htmlStart.replace("<!--styles-->", stylesheetTags);
|
|
721
|
-
htmlStart = htmlStart.replace("<!--head-meta-->", headTags);
|
|
722
|
-
res.write(htmlStart);
|
|
723
|
-
res.write(templateParts.rootStart);
|
|
724
|
-
pipe(reactStream);
|
|
725
|
-
reactStream.pipe(res, {
|
|
726
|
-
end: false
|
|
727
|
-
});
|
|
728
|
-
if (this.isDevelopment) {
|
|
729
|
-
const ttfb = shellReadyTime - startTime;
|
|
730
|
-
this.logger.log(`[SSR] ${componentName} shell ready in ${ttfb}ms (stream mode - TTFB)`);
|
|
731
|
-
}
|
|
732
|
-
}, "onShellReady"),
|
|
733
|
-
onShellError: /* @__PURE__ */ __name((error) => {
|
|
734
|
-
shellErrorOccurred = true;
|
|
735
|
-
this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
|
|
736
|
-
resolve();
|
|
737
|
-
}, "onShellError"),
|
|
738
|
-
onError: /* @__PURE__ */ __name((error) => {
|
|
739
|
-
didError = true;
|
|
740
|
-
this.streamingErrorHandler.handleStreamError(error, componentName);
|
|
741
|
-
}, "onError"),
|
|
742
|
-
onAllReady: /* @__PURE__ */ __name(() => {
|
|
743
|
-
allReadyFired = true;
|
|
744
|
-
}, "onAllReady")
|
|
745
|
-
});
|
|
746
|
-
reactStream.on("end", () => {
|
|
747
|
-
if (shellErrorOccurred) {
|
|
748
|
-
return;
|
|
749
|
-
}
|
|
750
|
-
res.write(inlineScripts);
|
|
751
|
-
res.write(clientScript);
|
|
752
|
-
res.write(templateParts.rootEnd);
|
|
753
|
-
res.write(templateParts.htmlEnd);
|
|
754
|
-
res.end();
|
|
755
|
-
if (this.isDevelopment) {
|
|
756
|
-
const totalTime = Date.now() - startTime;
|
|
757
|
-
const streamTime = Date.now() - shellReadyTime;
|
|
758
|
-
const viaAllReady = allReadyFired ? " (onAllReady fired)" : " (onAllReady never fired)";
|
|
759
|
-
this.logger.log(`[SSR] ${componentName} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)${viaAllReady}`);
|
|
760
|
-
}
|
|
761
|
-
resolve();
|
|
762
|
-
});
|
|
763
|
-
reactStream.on("error", (error) => {
|
|
764
|
-
reject(error);
|
|
765
|
-
});
|
|
766
|
-
res.on("close", () => {
|
|
767
|
-
abort();
|
|
768
|
-
resolve();
|
|
769
|
-
});
|
|
770
|
-
}, "executeStream");
|
|
771
|
-
executeStream().catch((error) => {
|
|
772
|
-
const componentName = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
|
|
773
|
-
this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
|
|
774
|
-
resolve();
|
|
775
|
-
});
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
1022
|
};
|
|
779
|
-
exports.RenderService =
|
|
1023
|
+
exports.RenderService = _ts_decorate5([
|
|
780
1024
|
common.Injectable(),
|
|
781
1025
|
_ts_param2(2, common.Optional()),
|
|
782
1026
|
_ts_param2(2, common.Inject("SSR_MODE")),
|
|
@@ -784,10 +1028,10 @@ exports.RenderService = _ts_decorate3([
|
|
|
784
1028
|
_ts_param2(3, common.Inject("DEFAULT_HEAD")),
|
|
785
1029
|
_ts_param2(4, common.Optional()),
|
|
786
1030
|
_ts_param2(4, common.Inject("CUSTOM_TEMPLATE")),
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
typeof
|
|
790
|
-
typeof
|
|
1031
|
+
_ts_metadata4("design:type", Function),
|
|
1032
|
+
_ts_metadata4("design:paramtypes", [
|
|
1033
|
+
typeof StringRenderer === "undefined" ? Object : StringRenderer,
|
|
1034
|
+
typeof StreamRenderer === "undefined" ? Object : StreamRenderer,
|
|
791
1035
|
typeof SSRMode === "undefined" ? Object : SSRMode,
|
|
792
1036
|
typeof HeadData === "undefined" ? Object : HeadData,
|
|
793
1037
|
String
|
|
@@ -816,17 +1060,17 @@ function Layout(layout, options) {
|
|
|
816
1060
|
__name(Layout, "Layout");
|
|
817
1061
|
|
|
818
1062
|
// src/render/render.interceptor.ts
|
|
819
|
-
function
|
|
1063
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
820
1064
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
821
1065
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
822
1066
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
823
1067
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
824
1068
|
}
|
|
825
|
-
__name(
|
|
826
|
-
function
|
|
1069
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1070
|
+
function _ts_metadata5(k, v) {
|
|
827
1071
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
828
1072
|
}
|
|
829
|
-
__name(
|
|
1073
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
830
1074
|
function _ts_param3(paramIndex, decorator) {
|
|
831
1075
|
return function(target, key) {
|
|
832
1076
|
decorator(target, key, paramIndex);
|
|
@@ -898,6 +1142,53 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
898
1142
|
}
|
|
899
1143
|
return layouts;
|
|
900
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Detect request type based on headers.
|
|
1147
|
+
* - If X-Current-Layouts header is present, this is a segment request
|
|
1148
|
+
* - Only GET requests can be segments
|
|
1149
|
+
*/
|
|
1150
|
+
detectRequestType(request) {
|
|
1151
|
+
if (request.method !== "GET") {
|
|
1152
|
+
return {
|
|
1153
|
+
type: "full"
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
const layoutsHeader = request.headers["x-current-layouts"];
|
|
1157
|
+
if (layoutsHeader && typeof layoutsHeader === "string") {
|
|
1158
|
+
const currentLayouts = layoutsHeader.split(",").map((s) => s.trim());
|
|
1159
|
+
return {
|
|
1160
|
+
type: "segment",
|
|
1161
|
+
currentLayouts
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
type: "full"
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Determine swap target by finding deepest common layout.
|
|
1170
|
+
* Returns null if no common ancestor (client should do full navigation).
|
|
1171
|
+
*/
|
|
1172
|
+
determineSwapTarget(currentLayouts, targetLayouts) {
|
|
1173
|
+
const targetNames = targetLayouts.map((l) => l.layout.displayName || l.layout.name);
|
|
1174
|
+
let commonLayout = null;
|
|
1175
|
+
for (let i = 0; i < Math.min(currentLayouts.length, targetNames.length); i++) {
|
|
1176
|
+
if (currentLayouts[i] === targetNames[i]) {
|
|
1177
|
+
commonLayout = currentLayouts[i];
|
|
1178
|
+
} else {
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return commonLayout;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Filter layouts to only include those below the swap target.
|
|
1186
|
+
* The swap target's outlet will contain the filtered layouts.
|
|
1187
|
+
*/
|
|
1188
|
+
filterLayoutsFromSwapTarget(layouts, swapTarget) {
|
|
1189
|
+
const index = layouts.findIndex((l) => (l.layout.displayName || l.layout.name) === swapTarget);
|
|
1190
|
+
return index >= 0 ? layouts.slice(index + 1) : layouts;
|
|
1191
|
+
}
|
|
901
1192
|
intercept(context, next) {
|
|
902
1193
|
const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
|
|
903
1194
|
if (!viewPathOrComponent) {
|
|
@@ -946,6 +1237,24 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
946
1237
|
__context: renderContext,
|
|
947
1238
|
__layouts: layoutChain
|
|
948
1239
|
};
|
|
1240
|
+
const { type, currentLayouts } = this.detectRequestType(request);
|
|
1241
|
+
if (type === "segment" && currentLayouts) {
|
|
1242
|
+
const swapTarget = this.determineSwapTarget(currentLayouts, layoutChain);
|
|
1243
|
+
if (!swapTarget) {
|
|
1244
|
+
response.type("application/json");
|
|
1245
|
+
return {
|
|
1246
|
+
swapTarget: null
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
const filteredLayouts = this.filterLayoutsFromSwapTarget(layoutChain, swapTarget);
|
|
1250
|
+
const segmentData = {
|
|
1251
|
+
...fullData,
|
|
1252
|
+
__layouts: filteredLayouts
|
|
1253
|
+
};
|
|
1254
|
+
const result = await this.renderService.renderSegment(viewPathOrComponent, segmentData, swapTarget, renderResponse.head);
|
|
1255
|
+
response.type("application/json");
|
|
1256
|
+
return result;
|
|
1257
|
+
}
|
|
949
1258
|
try {
|
|
950
1259
|
const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
|
|
951
1260
|
if (html !== void 0) {
|
|
@@ -959,31 +1268,31 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
959
1268
|
}));
|
|
960
1269
|
}
|
|
961
1270
|
};
|
|
962
|
-
exports.RenderInterceptor =
|
|
1271
|
+
exports.RenderInterceptor = _ts_decorate6([
|
|
963
1272
|
common.Injectable(),
|
|
964
1273
|
_ts_param3(2, common.Optional()),
|
|
965
1274
|
_ts_param3(2, common.Inject("ALLOWED_HEADERS")),
|
|
966
1275
|
_ts_param3(3, common.Optional()),
|
|
967
1276
|
_ts_param3(3, common.Inject("ALLOWED_COOKIES")),
|
|
968
|
-
|
|
969
|
-
|
|
1277
|
+
_ts_metadata5("design:type", Function),
|
|
1278
|
+
_ts_metadata5("design:paramtypes", [
|
|
970
1279
|
typeof core.Reflector === "undefined" ? Object : core.Reflector,
|
|
971
1280
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
972
1281
|
Array,
|
|
973
1282
|
Array
|
|
974
1283
|
])
|
|
975
1284
|
], exports.RenderInterceptor);
|
|
976
|
-
function
|
|
1285
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
977
1286
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
978
1287
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
979
1288
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
980
1289
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
981
1290
|
}
|
|
982
|
-
__name(
|
|
983
|
-
function
|
|
1291
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
1292
|
+
function _ts_metadata6(k, v) {
|
|
984
1293
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
985
1294
|
}
|
|
986
|
-
__name(
|
|
1295
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
987
1296
|
function _ts_param4(paramIndex, decorator) {
|
|
988
1297
|
return function(target, key) {
|
|
989
1298
|
decorator(target, key, paramIndex);
|
|
@@ -997,14 +1306,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
997
1306
|
renderService;
|
|
998
1307
|
httpAdapterHost;
|
|
999
1308
|
logger = new common.Logger(_ViteInitializerService.name);
|
|
1000
|
-
viteMode;
|
|
1001
1309
|
vitePort;
|
|
1002
1310
|
viteServer = null;
|
|
1003
1311
|
isShuttingDown = false;
|
|
1004
1312
|
constructor(renderService, httpAdapterHost, viteConfig) {
|
|
1005
1313
|
this.renderService = renderService;
|
|
1006
1314
|
this.httpAdapterHost = httpAdapterHost;
|
|
1007
|
-
this.viteMode = viteConfig?.mode || "embedded";
|
|
1008
1315
|
this.vitePort = viteConfig?.port || 5173;
|
|
1009
1316
|
this.registerSignalHandlers();
|
|
1010
1317
|
}
|
|
@@ -1036,30 +1343,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1036
1343
|
appType: "custom"
|
|
1037
1344
|
});
|
|
1038
1345
|
this.renderService.setViteServer(this.viteServer);
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
} else if (this.viteMode === "proxy") {
|
|
1042
|
-
await this.setupViteProxy();
|
|
1043
|
-
}
|
|
1044
|
-
this.logger.log(`\u2713 Vite initialized for SSR (mode: ${this.viteMode})`);
|
|
1346
|
+
await this.setupViteProxy();
|
|
1347
|
+
this.logger.log("\u2713 Vite initialized for SSR");
|
|
1045
1348
|
} catch (error) {
|
|
1046
1349
|
this.logger.warn(`Failed to initialize Vite: ${error.message}. Make sure vite is installed.`);
|
|
1047
1350
|
}
|
|
1048
1351
|
}
|
|
1049
|
-
async mountViteMiddleware(vite) {
|
|
1050
|
-
try {
|
|
1051
|
-
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
1052
|
-
if (!httpAdapter) {
|
|
1053
|
-
this.logger.warn("HTTP adapter not available, skipping Vite middleware setup");
|
|
1054
|
-
return;
|
|
1055
|
-
}
|
|
1056
|
-
const app = httpAdapter.getInstance();
|
|
1057
|
-
app.use(vite.middlewares);
|
|
1058
|
-
this.logger.log(`\u2713 Vite middleware mounted (embedded mode with HMR)`);
|
|
1059
|
-
} catch (error) {
|
|
1060
|
-
this.logger.warn(`Failed to mount Vite middleware: ${error.message}`);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
1352
|
async setupViteProxy() {
|
|
1064
1353
|
try {
|
|
1065
1354
|
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
@@ -1078,7 +1367,7 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1078
1367
|
}, "pathFilter")
|
|
1079
1368
|
});
|
|
1080
1369
|
app.use(viteProxy);
|
|
1081
|
-
this.logger.log(`\u2713 Vite HMR proxy configured (
|
|
1370
|
+
this.logger.log(`\u2713 Vite HMR proxy configured (Vite dev server on port ${this.vitePort})`);
|
|
1082
1371
|
} catch (error) {
|
|
1083
1372
|
this.logger.warn(`Failed to setup Vite proxy: ${error.message}. Make sure http-proxy-middleware is installed.`);
|
|
1084
1373
|
}
|
|
@@ -1129,12 +1418,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1129
1418
|
}
|
|
1130
1419
|
}
|
|
1131
1420
|
};
|
|
1132
|
-
ViteInitializerService =
|
|
1421
|
+
ViteInitializerService = _ts_decorate7([
|
|
1133
1422
|
common.Injectable(),
|
|
1134
1423
|
_ts_param4(2, common.Optional()),
|
|
1135
1424
|
_ts_param4(2, common.Inject("VITE_CONFIG")),
|
|
1136
|
-
|
|
1137
|
-
|
|
1425
|
+
_ts_metadata6("design:type", Function),
|
|
1426
|
+
_ts_metadata6("design:paramtypes", [
|
|
1138
1427
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
1139
1428
|
typeof core.HttpAdapterHost === "undefined" ? Object : core.HttpAdapterHost,
|
|
1140
1429
|
typeof ViteConfig === "undefined" ? Object : ViteConfig
|
|
@@ -1142,13 +1431,13 @@ ViteInitializerService = _ts_decorate5([
|
|
|
1142
1431
|
], ViteInitializerService);
|
|
1143
1432
|
|
|
1144
1433
|
// src/render/render.module.ts
|
|
1145
|
-
function
|
|
1434
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1146
1435
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1147
1436
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1148
1437
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1149
1438
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1150
1439
|
}
|
|
1151
|
-
__name(
|
|
1440
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
1152
1441
|
exports.RenderModule = class _RenderModule {
|
|
1153
1442
|
static {
|
|
1154
1443
|
__name(this, "RenderModule");
|
|
@@ -1161,17 +1450,17 @@ exports.RenderModule = class _RenderModule {
|
|
|
1161
1450
|
*
|
|
1162
1451
|
* @example
|
|
1163
1452
|
* ```ts
|
|
1164
|
-
* // Zero config - uses
|
|
1453
|
+
* // Zero config - uses string mode (default, recommended)
|
|
1165
1454
|
* RenderModule.forRoot()
|
|
1166
1455
|
*
|
|
1167
|
-
* //
|
|
1168
|
-
* RenderModule.forRoot({ mode: 'stream' })
|
|
1169
|
-
*
|
|
1170
|
-
* // Enable HMR with proxy mode
|
|
1456
|
+
* // Custom Vite port
|
|
1171
1457
|
* RenderModule.forRoot({
|
|
1172
|
-
* vite: {
|
|
1458
|
+
* vite: { port: 3001 }
|
|
1173
1459
|
* })
|
|
1174
1460
|
*
|
|
1461
|
+
* // Enable streaming SSR (advanced - see mode docs for trade-offs)
|
|
1462
|
+
* RenderModule.forRoot({ mode: 'stream' })
|
|
1463
|
+
*
|
|
1175
1464
|
* // Custom error pages
|
|
1176
1465
|
* RenderModule.forRoot({
|
|
1177
1466
|
* errorPageDevelopment: DevErrorPage,
|
|
@@ -1185,6 +1474,8 @@ exports.RenderModule = class _RenderModule {
|
|
|
1185
1474
|
exports.TemplateParserService,
|
|
1186
1475
|
exports.StreamingErrorHandler,
|
|
1187
1476
|
ViteInitializerService,
|
|
1477
|
+
StringRenderer,
|
|
1478
|
+
StreamRenderer,
|
|
1188
1479
|
{
|
|
1189
1480
|
provide: core.APP_INTERCEPTOR,
|
|
1190
1481
|
useClass: exports.RenderInterceptor
|
|
@@ -1289,6 +1580,8 @@ exports.RenderModule = class _RenderModule {
|
|
|
1289
1580
|
exports.TemplateParserService,
|
|
1290
1581
|
exports.StreamingErrorHandler,
|
|
1291
1582
|
ViteInitializerService,
|
|
1583
|
+
StringRenderer,
|
|
1584
|
+
StreamRenderer,
|
|
1292
1585
|
{
|
|
1293
1586
|
provide: core.APP_INTERCEPTOR,
|
|
1294
1587
|
useClass: exports.RenderInterceptor
|
|
@@ -1373,7 +1666,7 @@ exports.RenderModule = class _RenderModule {
|
|
|
1373
1666
|
return this.forRootAsync(options);
|
|
1374
1667
|
}
|
|
1375
1668
|
};
|
|
1376
|
-
exports.RenderModule =
|
|
1669
|
+
exports.RenderModule = _ts_decorate8([
|
|
1377
1670
|
common.Global(),
|
|
1378
1671
|
common.Module({
|
|
1379
1672
|
providers: [
|
|
@@ -1381,6 +1674,8 @@ exports.RenderModule = _ts_decorate6([
|
|
|
1381
1674
|
exports.TemplateParserService,
|
|
1382
1675
|
exports.StreamingErrorHandler,
|
|
1383
1676
|
ViteInitializerService,
|
|
1677
|
+
StringRenderer,
|
|
1678
|
+
StreamRenderer,
|
|
1384
1679
|
{
|
|
1385
1680
|
provide: core.APP_INTERCEPTOR,
|
|
1386
1681
|
useClass: exports.RenderInterceptor
|
|
@@ -1395,8 +1690,25 @@ exports.RenderModule = _ts_decorate6([
|
|
|
1395
1690
|
]
|
|
1396
1691
|
})
|
|
1397
1692
|
], exports.RenderModule);
|
|
1398
|
-
var
|
|
1399
|
-
|
|
1693
|
+
var CONTEXT_KEY = /* @__PURE__ */ Symbol.for("nestjs-ssr.PageContext");
|
|
1694
|
+
var globalStore = globalThis;
|
|
1695
|
+
function getOrCreateContext() {
|
|
1696
|
+
if (!globalStore[CONTEXT_KEY]) {
|
|
1697
|
+
globalStore[CONTEXT_KEY] = /* @__PURE__ */ React.createContext(null);
|
|
1698
|
+
}
|
|
1699
|
+
return globalStore[CONTEXT_KEY];
|
|
1700
|
+
}
|
|
1701
|
+
__name(getOrCreateContext, "getOrCreateContext");
|
|
1702
|
+
var PageContext = getOrCreateContext();
|
|
1703
|
+
function registerPageContextState(setter) {
|
|
1704
|
+
}
|
|
1705
|
+
__name(registerPageContextState, "registerPageContextState");
|
|
1706
|
+
function PageContextProvider({ context: initialContext, children, isSegment = false }) {
|
|
1707
|
+
const [context, setContext] = React.useState(initialContext);
|
|
1708
|
+
React.useEffect(() => {
|
|
1709
|
+
}, [
|
|
1710
|
+
isSegment
|
|
1711
|
+
]);
|
|
1400
1712
|
return /* @__PURE__ */ React__default.default.createElement(PageContext.Provider, {
|
|
1401
1713
|
value: context
|
|
1402
1714
|
}, children);
|
|
@@ -1589,6 +1901,15 @@ function createSSRHooks() {
|
|
|
1589
1901
|
};
|
|
1590
1902
|
}
|
|
1591
1903
|
__name(createSSRHooks, "createSSRHooks");
|
|
1904
|
+
var defaultHooks = createSSRHooks();
|
|
1905
|
+
var usePageContext = defaultHooks.usePageContext;
|
|
1906
|
+
var useParams = defaultHooks.useParams;
|
|
1907
|
+
var useQuery = defaultHooks.useQuery;
|
|
1908
|
+
var useRequest = defaultHooks.useRequest;
|
|
1909
|
+
var useHeaders = defaultHooks.useHeaders;
|
|
1910
|
+
var useHeader = defaultHooks.useHeader;
|
|
1911
|
+
var useCookies = defaultHooks.useCookies;
|
|
1912
|
+
var useCookie = defaultHooks.useCookie;
|
|
1592
1913
|
|
|
1593
1914
|
exports.ErrorPageDevelopment = ErrorPageDevelopment;
|
|
1594
1915
|
exports.ErrorPageProduction = ErrorPageProduction;
|
|
@@ -1596,3 +1917,11 @@ exports.Layout = Layout;
|
|
|
1596
1917
|
exports.PageContextProvider = PageContextProvider;
|
|
1597
1918
|
exports.Render = Render;
|
|
1598
1919
|
exports.createSSRHooks = createSSRHooks;
|
|
1920
|
+
exports.useCookie = useCookie;
|
|
1921
|
+
exports.useCookies = useCookies;
|
|
1922
|
+
exports.useHeader = useHeader;
|
|
1923
|
+
exports.useHeaders = useHeaders;
|
|
1924
|
+
exports.usePageContext = usePageContext;
|
|
1925
|
+
exports.useParams = useParams;
|
|
1926
|
+
exports.useQuery = useQuery;
|
|
1927
|
+
exports.useRequest = useRequest;
|