@nestjs-ssr/react 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- export { E as ErrorPageDevelopment, f as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-Bptct1Q3.mjs';
1
+ export { E as ErrorPageDevelopment, f as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-Bpzo1KfR.mjs';
2
2
  import '@nestjs/common';
3
3
  import 'react';
4
4
  import 'vite';
@@ -1,4 +1,4 @@
1
- export { E as ErrorPageDevelopment, f as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-Bptct1Q3.js';
1
+ export { E as ErrorPageDevelopment, f as ErrorPageProduction, b as RenderInterceptor, R as RenderModule, a as RenderService, S as StreamingErrorHandler, T as TemplateParserService } from '../index-Bpzo1KfR.js';
2
2
  import '@nestjs/common';
3
3
  import 'react';
4
4
  import 'vite';
@@ -109,7 +109,7 @@ exports.TemplateParserService = class TemplateParserService {
109
109
  * This library handles all edge cases including escaping dangerous characters,
110
110
  * functions, dates, regexes, and prevents prototype pollution.
111
111
  */
112
- buildInlineScripts(data, context, componentPath) {
112
+ buildInlineScripts(data, context, componentName) {
113
113
  return `<script>
114
114
  window.__INITIAL_STATE__ = ${serialize__default.default(data, {
115
115
  isJSON: true
@@ -117,7 +117,7 @@ window.__INITIAL_STATE__ = ${serialize__default.default(data, {
117
117
  window.__CONTEXT__ = ${serialize__default.default(context, {
118
118
  isJSON: true
119
119
  })};
120
- window.__COMPONENT_PATH__ = ${serialize__default.default(componentPath, {
120
+ window.__COMPONENT_NAME__ = ${serialize__default.default(componentName, {
121
121
  isJSON: true
122
122
  })};
123
123
  </script>`;
@@ -427,12 +427,28 @@ exports.RenderService = class _RenderService {
427
427
  serverManifest = null;
428
428
  isDevelopment;
429
429
  ssrMode;
430
+ entryServerPath;
431
+ entryClientPath;
430
432
  constructor(templateParser, streamingErrorHandler, ssrMode, defaultHead) {
431
433
  this.templateParser = templateParser;
432
434
  this.streamingErrorHandler = streamingErrorHandler;
433
435
  this.defaultHead = defaultHead;
434
436
  this.isDevelopment = process.env.NODE_ENV !== "production";
435
437
  this.ssrMode = ssrMode || process.env.SSR_MODE || "string";
438
+ const absoluteServerPath = path.join(__dirname, "/templates/entry-server.tsx");
439
+ const relativeServerPath = path.relative(process.cwd(), absoluteServerPath);
440
+ if (relativeServerPath.startsWith("..")) {
441
+ this.entryServerPath = absoluteServerPath;
442
+ } else {
443
+ this.entryServerPath = "/" + relativeServerPath.replace(/\\/g, "/");
444
+ }
445
+ const absoluteClientPath = path.join(__dirname, "/templates/entry-client.tsx");
446
+ const relativeClientPath = path.relative(process.cwd(), absoluteClientPath);
447
+ if (relativeClientPath.startsWith("..")) {
448
+ this.entryClientPath = absoluteClientPath;
449
+ } else {
450
+ this.entryClientPath = "/" + relativeClientPath.replace(/\\/g, "/");
451
+ }
436
452
  let templatePath;
437
453
  if (this.isDevelopment) {
438
454
  const packageTemplatePaths = [
@@ -484,15 +500,15 @@ exports.RenderService = class _RenderService {
484
500
  /**
485
501
  * Main render method that routes to string or stream mode
486
502
  */
487
- async render(viewPath, data = {}, res, head) {
503
+ async render(viewComponent, data = {}, res, head) {
488
504
  const mergedHead = this.mergeHead(this.defaultHead, head);
489
505
  if (this.ssrMode === "stream") {
490
506
  if (!res) {
491
507
  throw new Error("Response object is required for streaming SSR mode. Pass res as third parameter.");
492
508
  }
493
- return this.renderToStream(viewPath, data, res, mergedHead);
509
+ return this.renderToStream(viewComponent, data, res, mergedHead);
494
510
  }
495
- return this.renderToString(viewPath, data, mergedHead);
511
+ return this.renderToString(viewComponent, data, mergedHead);
496
512
  }
497
513
  /**
498
514
  * Merge default head with page-specific head
@@ -519,7 +535,7 @@ exports.RenderService = class _RenderService {
519
535
  /**
520
536
  * Traditional string-based SSR using renderToString
521
537
  */
522
- async renderToString(viewPath, data = {}, head) {
538
+ async renderToString(viewComponent, data = {}, head) {
523
539
  const startTime = Date.now();
524
540
  try {
525
541
  let template = this.template;
@@ -528,7 +544,7 @@ exports.RenderService = class _RenderService {
528
544
  }
529
545
  let renderModule;
530
546
  if (this.vite) {
531
- renderModule = await this.vite.ssrLoadModule("/src/entry-server.tsx");
547
+ renderModule = await this.vite.ssrLoadModule(this.entryServerPath);
532
548
  } else {
533
549
  if (this.serverManifest) {
534
550
  const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
@@ -544,7 +560,8 @@ exports.RenderService = class _RenderService {
544
560
  }
545
561
  }
546
562
  const { data: pageData, __context: context } = data;
547
- const appHtml = await renderModule.renderComponent(viewPath, data);
563
+ const appHtml = await renderModule.renderComponent(viewComponent, data);
564
+ const componentName = viewComponent.displayName || viewComponent.name || "Component";
548
565
  const initialStateScript = `
549
566
  <script>
550
567
  window.__INITIAL_STATE__ = ${serialize__default.default(pageData, {
@@ -553,7 +570,7 @@ exports.RenderService = class _RenderService {
553
570
  window.__CONTEXT__ = ${serialize__default.default(context, {
554
571
  isJSON: true
555
572
  })};
556
- window.__COMPONENT_PATH__ = ${serialize__default.default(viewPath, {
573
+ window.__COMPONENT_NAME__ = ${serialize__default.default(componentName, {
557
574
  isJSON: true
558
575
  })};
559
576
  </script>
@@ -561,7 +578,7 @@ exports.RenderService = class _RenderService {
561
578
  let clientScript = "";
562
579
  let styles = "";
563
580
  if (this.vite) {
564
- clientScript = `<script type="module" src="/src/entry-client.tsx"></script>`;
581
+ clientScript = `<script type="module" src="${this.entryClientPath}"></script>`;
565
582
  styles = "";
566
583
  } else {
567
584
  if (this.manifest) {
@@ -591,7 +608,8 @@ exports.RenderService = class _RenderService {
591
608
  html = html.replace("<!--head-meta-->", headTags);
592
609
  if (this.isDevelopment) {
593
610
  const duration = Date.now() - startTime;
594
- this.logger.log(`[SSR] ${viewPath} rendered in ${duration}ms (string mode)`);
611
+ const componentName2 = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
612
+ this.logger.log(`[SSR] ${componentName2} rendered in ${duration}ms (string mode)`);
595
613
  }
596
614
  return html;
597
615
  } catch (error) {
@@ -601,7 +619,7 @@ exports.RenderService = class _RenderService {
601
619
  /**
602
620
  * Modern streaming SSR using renderToPipeableStream
603
621
  */
604
- async renderToStream(viewPath, data = {}, res, head) {
622
+ async renderToStream(viewComponent, data = {}, res, head) {
605
623
  const startTime = Date.now();
606
624
  let shellReadyTime = 0;
607
625
  try {
@@ -612,7 +630,7 @@ exports.RenderService = class _RenderService {
612
630
  const templateParts = this.templateParser.parseTemplate(template);
613
631
  let renderModule;
614
632
  if (this.vite) {
615
- renderModule = await this.vite.ssrLoadModule("/src/entry-server.tsx");
633
+ renderModule = await this.vite.ssrLoadModule(this.entryServerPath);
616
634
  } else {
617
635
  if (this.serverManifest) {
618
636
  const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
@@ -628,12 +646,13 @@ exports.RenderService = class _RenderService {
628
646
  }
629
647
  }
630
648
  const { data: pageData, __context: context } = data;
631
- const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, viewPath);
649
+ const componentName = viewComponent.displayName || viewComponent.name || "Component";
650
+ const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName);
632
651
  const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
633
652
  const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
634
653
  const headTags = this.templateParser.buildHeadTags(head);
635
654
  let didError = false;
636
- const { pipe, abort } = renderModule.renderComponentStream(viewPath, data, {
655
+ const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
637
656
  onShellReady: /* @__PURE__ */ __name(() => {
638
657
  shellReadyTime = Date.now();
639
658
  res.statusCode = didError ? 500 : 200;
@@ -646,15 +665,15 @@ exports.RenderService = class _RenderService {
646
665
  pipe(res);
647
666
  if (this.isDevelopment) {
648
667
  const ttfb = shellReadyTime - startTime;
649
- this.logger.log(`[SSR] ${viewPath} shell ready in ${ttfb}ms (stream mode - TTFB)`);
668
+ this.logger.log(`[SSR] ${componentName} shell ready in ${ttfb}ms (stream mode - TTFB)`);
650
669
  }
651
670
  }, "onShellReady"),
652
671
  onShellError: /* @__PURE__ */ __name((error) => {
653
- this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
672
+ this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
654
673
  }, "onShellError"),
655
674
  onError: /* @__PURE__ */ __name((error) => {
656
675
  didError = true;
657
- this.streamingErrorHandler.handleStreamError(error, viewPath);
676
+ this.streamingErrorHandler.handleStreamError(error, componentName);
658
677
  }, "onError"),
659
678
  onAllReady: /* @__PURE__ */ __name(() => {
660
679
  res.write(inlineScripts);
@@ -665,7 +684,7 @@ exports.RenderService = class _RenderService {
665
684
  if (this.isDevelopment) {
666
685
  const totalTime = Date.now() - startTime;
667
686
  const streamTime = Date.now() - shellReadyTime;
668
- this.logger.log(`[SSR] ${viewPath} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)`);
687
+ this.logger.log(`[SSR] ${componentName} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)`);
669
688
  }
670
689
  }, "onAllReady")
671
690
  });
@@ -673,7 +692,8 @@ exports.RenderService = class _RenderService {
673
692
  abort();
674
693
  });
675
694
  } catch (error) {
676
- this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
695
+ const componentName = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
696
+ this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
677
697
  }
678
698
  }
679
699
  };
@@ -720,8 +740,8 @@ exports.RenderInterceptor = class RenderInterceptor {
720
740
  this.renderService = renderService;
721
741
  }
722
742
  intercept(context, next) {
723
- const viewPath = this.reflector.get(RENDER_KEY, context.getHandler());
724
- if (!viewPath) {
743
+ const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
744
+ if (!viewPathOrComponent) {
725
745
  return next.handle();
726
746
  }
727
747
  return next.handle().pipe(operators.switchMap(async (data) => {
@@ -745,7 +765,7 @@ exports.RenderInterceptor = class RenderInterceptor {
745
765
  __context: renderContext
746
766
  };
747
767
  try {
748
- const html = await this.renderService.render(viewPath, fullData, response, renderResponse.head);
768
+ const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
749
769
  if (html !== void 0) {
750
770
  response.type("text/html");
751
771
  return html;
@@ -791,6 +811,7 @@ var ViteInitializerService = class _ViteInitializerService {
791
811
  logger = new common.Logger(_ViteInitializerService.name);
792
812
  viteMode;
793
813
  vitePort;
814
+ viteServer = null;
794
815
  constructor(renderService, httpAdapterHost, viteConfig) {
795
816
  this.renderService = renderService;
796
817
  this.httpAdapterHost = httpAdapterHost;
@@ -808,15 +829,15 @@ var ViteInitializerService = class _ViteInitializerService {
808
829
  async setupDevelopmentMode() {
809
830
  try {
810
831
  const { createServer: createViteServer } = await import('vite');
811
- const vite = await createViteServer({
832
+ this.viteServer = await createViteServer({
812
833
  server: {
813
834
  middlewareMode: true
814
835
  },
815
836
  appType: "custom"
816
837
  });
817
- this.renderService.setViteServer(vite);
838
+ this.renderService.setViteServer(this.viteServer);
818
839
  if (this.viteMode === "embedded") {
819
- await this.mountViteMiddleware(vite);
840
+ await this.mountViteMiddleware(this.viteServer);
820
841
  } else if (this.viteMode === "proxy") {
821
842
  await this.setupViteProxy();
822
843
  }
@@ -879,6 +900,20 @@ var ViteInitializerService = class _ViteInitializerService {
879
900
  this.logger.warn(`Failed to setup static assets: ${error.message}`);
880
901
  }
881
902
  }
903
+ /**
904
+ * Cleanup: Close Vite server on module destroy
905
+ * This prevents port conflicts on hot reload
906
+ */
907
+ async onModuleDestroy() {
908
+ if (this.viteServer) {
909
+ try {
910
+ await this.viteServer.close();
911
+ this.logger.log("\u2713 Vite server closed");
912
+ } catch (error) {
913
+ this.logger.warn(`Failed to close Vite server: ${error.message}`);
914
+ }
915
+ }
916
+ }
882
917
  };
883
918
  ViteInitializerService = _ts_decorate5([
884
919
  common.Injectable(),