@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/render/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
|
|
@@ -798,17 +1042,17 @@ var RENDER_OPTIONS_KEY = "render_options";
|
|
|
798
1042
|
var LAYOUT_KEY = "layout";
|
|
799
1043
|
|
|
800
1044
|
// src/render/render.interceptor.ts
|
|
801
|
-
function
|
|
1045
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
802
1046
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
803
1047
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
804
1048
|
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;
|
|
805
1049
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
806
1050
|
}
|
|
807
|
-
__name(
|
|
808
|
-
function
|
|
1051
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1052
|
+
function _ts_metadata5(k, v) {
|
|
809
1053
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
810
1054
|
}
|
|
811
|
-
__name(
|
|
1055
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
812
1056
|
function _ts_param3(paramIndex, decorator) {
|
|
813
1057
|
return function(target, key) {
|
|
814
1058
|
decorator(target, key, paramIndex);
|
|
@@ -880,6 +1124,53 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
880
1124
|
}
|
|
881
1125
|
return layouts;
|
|
882
1126
|
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Detect request type based on headers.
|
|
1129
|
+
* - If X-Current-Layouts header is present, this is a segment request
|
|
1130
|
+
* - Only GET requests can be segments
|
|
1131
|
+
*/
|
|
1132
|
+
detectRequestType(request) {
|
|
1133
|
+
if (request.method !== "GET") {
|
|
1134
|
+
return {
|
|
1135
|
+
type: "full"
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
const layoutsHeader = request.headers["x-current-layouts"];
|
|
1139
|
+
if (layoutsHeader && typeof layoutsHeader === "string") {
|
|
1140
|
+
const currentLayouts = layoutsHeader.split(",").map((s) => s.trim());
|
|
1141
|
+
return {
|
|
1142
|
+
type: "segment",
|
|
1143
|
+
currentLayouts
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
return {
|
|
1147
|
+
type: "full"
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Determine swap target by finding deepest common layout.
|
|
1152
|
+
* Returns null if no common ancestor (client should do full navigation).
|
|
1153
|
+
*/
|
|
1154
|
+
determineSwapTarget(currentLayouts, targetLayouts) {
|
|
1155
|
+
const targetNames = targetLayouts.map((l) => l.layout.displayName || l.layout.name);
|
|
1156
|
+
let commonLayout = null;
|
|
1157
|
+
for (let i = 0; i < Math.min(currentLayouts.length, targetNames.length); i++) {
|
|
1158
|
+
if (currentLayouts[i] === targetNames[i]) {
|
|
1159
|
+
commonLayout = currentLayouts[i];
|
|
1160
|
+
} else {
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return commonLayout;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Filter layouts to only include those below the swap target.
|
|
1168
|
+
* The swap target's outlet will contain the filtered layouts.
|
|
1169
|
+
*/
|
|
1170
|
+
filterLayoutsFromSwapTarget(layouts, swapTarget) {
|
|
1171
|
+
const index = layouts.findIndex((l) => (l.layout.displayName || l.layout.name) === swapTarget);
|
|
1172
|
+
return index >= 0 ? layouts.slice(index + 1) : layouts;
|
|
1173
|
+
}
|
|
883
1174
|
intercept(context, next) {
|
|
884
1175
|
const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
|
|
885
1176
|
if (!viewPathOrComponent) {
|
|
@@ -928,6 +1219,24 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
928
1219
|
__context: renderContext,
|
|
929
1220
|
__layouts: layoutChain
|
|
930
1221
|
};
|
|
1222
|
+
const { type, currentLayouts } = this.detectRequestType(request);
|
|
1223
|
+
if (type === "segment" && currentLayouts) {
|
|
1224
|
+
const swapTarget = this.determineSwapTarget(currentLayouts, layoutChain);
|
|
1225
|
+
if (!swapTarget) {
|
|
1226
|
+
response.type("application/json");
|
|
1227
|
+
return {
|
|
1228
|
+
swapTarget: null
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
const filteredLayouts = this.filterLayoutsFromSwapTarget(layoutChain, swapTarget);
|
|
1232
|
+
const segmentData = {
|
|
1233
|
+
...fullData,
|
|
1234
|
+
__layouts: filteredLayouts
|
|
1235
|
+
};
|
|
1236
|
+
const result = await this.renderService.renderSegment(viewPathOrComponent, segmentData, swapTarget, renderResponse.head);
|
|
1237
|
+
response.type("application/json");
|
|
1238
|
+
return result;
|
|
1239
|
+
}
|
|
931
1240
|
try {
|
|
932
1241
|
const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
|
|
933
1242
|
if (html !== void 0) {
|
|
@@ -941,31 +1250,31 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
941
1250
|
}));
|
|
942
1251
|
}
|
|
943
1252
|
};
|
|
944
|
-
exports.RenderInterceptor =
|
|
1253
|
+
exports.RenderInterceptor = _ts_decorate6([
|
|
945
1254
|
common.Injectable(),
|
|
946
1255
|
_ts_param3(2, common.Optional()),
|
|
947
1256
|
_ts_param3(2, common.Inject("ALLOWED_HEADERS")),
|
|
948
1257
|
_ts_param3(3, common.Optional()),
|
|
949
1258
|
_ts_param3(3, common.Inject("ALLOWED_COOKIES")),
|
|
950
|
-
|
|
951
|
-
|
|
1259
|
+
_ts_metadata5("design:type", Function),
|
|
1260
|
+
_ts_metadata5("design:paramtypes", [
|
|
952
1261
|
typeof core.Reflector === "undefined" ? Object : core.Reflector,
|
|
953
1262
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
954
1263
|
Array,
|
|
955
1264
|
Array
|
|
956
1265
|
])
|
|
957
1266
|
], exports.RenderInterceptor);
|
|
958
|
-
function
|
|
1267
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
959
1268
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
960
1269
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
961
1270
|
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;
|
|
962
1271
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
963
1272
|
}
|
|
964
|
-
__name(
|
|
965
|
-
function
|
|
1273
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
1274
|
+
function _ts_metadata6(k, v) {
|
|
966
1275
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
967
1276
|
}
|
|
968
|
-
__name(
|
|
1277
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
969
1278
|
function _ts_param4(paramIndex, decorator) {
|
|
970
1279
|
return function(target, key) {
|
|
971
1280
|
decorator(target, key, paramIndex);
|
|
@@ -979,14 +1288,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
979
1288
|
renderService;
|
|
980
1289
|
httpAdapterHost;
|
|
981
1290
|
logger = new common.Logger(_ViteInitializerService.name);
|
|
982
|
-
viteMode;
|
|
983
1291
|
vitePort;
|
|
984
1292
|
viteServer = null;
|
|
985
1293
|
isShuttingDown = false;
|
|
986
1294
|
constructor(renderService, httpAdapterHost, viteConfig) {
|
|
987
1295
|
this.renderService = renderService;
|
|
988
1296
|
this.httpAdapterHost = httpAdapterHost;
|
|
989
|
-
this.viteMode = viteConfig?.mode || "embedded";
|
|
990
1297
|
this.vitePort = viteConfig?.port || 5173;
|
|
991
1298
|
this.registerSignalHandlers();
|
|
992
1299
|
}
|
|
@@ -1018,30 +1325,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1018
1325
|
appType: "custom"
|
|
1019
1326
|
});
|
|
1020
1327
|
this.renderService.setViteServer(this.viteServer);
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
} else if (this.viteMode === "proxy") {
|
|
1024
|
-
await this.setupViteProxy();
|
|
1025
|
-
}
|
|
1026
|
-
this.logger.log(`\u2713 Vite initialized for SSR (mode: ${this.viteMode})`);
|
|
1328
|
+
await this.setupViteProxy();
|
|
1329
|
+
this.logger.log("\u2713 Vite initialized for SSR");
|
|
1027
1330
|
} catch (error) {
|
|
1028
1331
|
this.logger.warn(`Failed to initialize Vite: ${error.message}. Make sure vite is installed.`);
|
|
1029
1332
|
}
|
|
1030
1333
|
}
|
|
1031
|
-
async mountViteMiddleware(vite) {
|
|
1032
|
-
try {
|
|
1033
|
-
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
1034
|
-
if (!httpAdapter) {
|
|
1035
|
-
this.logger.warn("HTTP adapter not available, skipping Vite middleware setup");
|
|
1036
|
-
return;
|
|
1037
|
-
}
|
|
1038
|
-
const app = httpAdapter.getInstance();
|
|
1039
|
-
app.use(vite.middlewares);
|
|
1040
|
-
this.logger.log(`\u2713 Vite middleware mounted (embedded mode with HMR)`);
|
|
1041
|
-
} catch (error) {
|
|
1042
|
-
this.logger.warn(`Failed to mount Vite middleware: ${error.message}`);
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
1334
|
async setupViteProxy() {
|
|
1046
1335
|
try {
|
|
1047
1336
|
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
@@ -1060,7 +1349,7 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1060
1349
|
}, "pathFilter")
|
|
1061
1350
|
});
|
|
1062
1351
|
app.use(viteProxy);
|
|
1063
|
-
this.logger.log(`\u2713 Vite HMR proxy configured (
|
|
1352
|
+
this.logger.log(`\u2713 Vite HMR proxy configured (Vite dev server on port ${this.vitePort})`);
|
|
1064
1353
|
} catch (error) {
|
|
1065
1354
|
this.logger.warn(`Failed to setup Vite proxy: ${error.message}. Make sure http-proxy-middleware is installed.`);
|
|
1066
1355
|
}
|
|
@@ -1111,12 +1400,12 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
1111
1400
|
}
|
|
1112
1401
|
}
|
|
1113
1402
|
};
|
|
1114
|
-
ViteInitializerService =
|
|
1403
|
+
ViteInitializerService = _ts_decorate7([
|
|
1115
1404
|
common.Injectable(),
|
|
1116
1405
|
_ts_param4(2, common.Optional()),
|
|
1117
1406
|
_ts_param4(2, common.Inject("VITE_CONFIG")),
|
|
1118
|
-
|
|
1119
|
-
|
|
1407
|
+
_ts_metadata6("design:type", Function),
|
|
1408
|
+
_ts_metadata6("design:paramtypes", [
|
|
1120
1409
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
1121
1410
|
typeof core.HttpAdapterHost === "undefined" ? Object : core.HttpAdapterHost,
|
|
1122
1411
|
typeof ViteConfig === "undefined" ? Object : ViteConfig
|
|
@@ -1124,13 +1413,13 @@ ViteInitializerService = _ts_decorate5([
|
|
|
1124
1413
|
], ViteInitializerService);
|
|
1125
1414
|
|
|
1126
1415
|
// src/render/render.module.ts
|
|
1127
|
-
function
|
|
1416
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1128
1417
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1129
1418
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1130
1419
|
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;
|
|
1131
1420
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1132
1421
|
}
|
|
1133
|
-
__name(
|
|
1422
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
1134
1423
|
exports.RenderModule = class _RenderModule {
|
|
1135
1424
|
static {
|
|
1136
1425
|
__name(this, "RenderModule");
|
|
@@ -1143,17 +1432,17 @@ exports.RenderModule = class _RenderModule {
|
|
|
1143
1432
|
*
|
|
1144
1433
|
* @example
|
|
1145
1434
|
* ```ts
|
|
1146
|
-
* // Zero config - uses
|
|
1435
|
+
* // Zero config - uses string mode (default, recommended)
|
|
1147
1436
|
* RenderModule.forRoot()
|
|
1148
1437
|
*
|
|
1149
|
-
* //
|
|
1150
|
-
* RenderModule.forRoot({ mode: 'stream' })
|
|
1151
|
-
*
|
|
1152
|
-
* // Enable HMR with proxy mode
|
|
1438
|
+
* // Custom Vite port
|
|
1153
1439
|
* RenderModule.forRoot({
|
|
1154
|
-
* vite: {
|
|
1440
|
+
* vite: { port: 3001 }
|
|
1155
1441
|
* })
|
|
1156
1442
|
*
|
|
1443
|
+
* // Enable streaming SSR (advanced - see mode docs for trade-offs)
|
|
1444
|
+
* RenderModule.forRoot({ mode: 'stream' })
|
|
1445
|
+
*
|
|
1157
1446
|
* // Custom error pages
|
|
1158
1447
|
* RenderModule.forRoot({
|
|
1159
1448
|
* errorPageDevelopment: DevErrorPage,
|
|
@@ -1167,6 +1456,8 @@ exports.RenderModule = class _RenderModule {
|
|
|
1167
1456
|
exports.TemplateParserService,
|
|
1168
1457
|
exports.StreamingErrorHandler,
|
|
1169
1458
|
ViteInitializerService,
|
|
1459
|
+
StringRenderer,
|
|
1460
|
+
StreamRenderer,
|
|
1170
1461
|
{
|
|
1171
1462
|
provide: core.APP_INTERCEPTOR,
|
|
1172
1463
|
useClass: exports.RenderInterceptor
|
|
@@ -1271,6 +1562,8 @@ exports.RenderModule = class _RenderModule {
|
|
|
1271
1562
|
exports.TemplateParserService,
|
|
1272
1563
|
exports.StreamingErrorHandler,
|
|
1273
1564
|
ViteInitializerService,
|
|
1565
|
+
StringRenderer,
|
|
1566
|
+
StreamRenderer,
|
|
1274
1567
|
{
|
|
1275
1568
|
provide: core.APP_INTERCEPTOR,
|
|
1276
1569
|
useClass: exports.RenderInterceptor
|
|
@@ -1355,7 +1648,7 @@ exports.RenderModule = class _RenderModule {
|
|
|
1355
1648
|
return this.forRootAsync(options);
|
|
1356
1649
|
}
|
|
1357
1650
|
};
|
|
1358
|
-
exports.RenderModule =
|
|
1651
|
+
exports.RenderModule = _ts_decorate8([
|
|
1359
1652
|
common.Global(),
|
|
1360
1653
|
common.Module({
|
|
1361
1654
|
providers: [
|
|
@@ -1363,6 +1656,8 @@ exports.RenderModule = _ts_decorate6([
|
|
|
1363
1656
|
exports.TemplateParserService,
|
|
1364
1657
|
exports.StreamingErrorHandler,
|
|
1365
1658
|
ViteInitializerService,
|
|
1659
|
+
StringRenderer,
|
|
1660
|
+
StreamRenderer,
|
|
1366
1661
|
{
|
|
1367
1662
|
provide: core.APP_INTERCEPTOR,
|
|
1368
1663
|
useClass: exports.RenderInterceptor
|