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