@nestjs-ssr/react 0.1.4 → 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.
@@ -102,7 +102,7 @@ var TemplateParserService = class {
102
102
  * This library handles all edge cases including escaping dangerous characters,
103
103
  * functions, dates, regexes, and prevents prototype pollution.
104
104
  */
105
- buildInlineScripts(data, context, componentPath) {
105
+ buildInlineScripts(data, context, componentName) {
106
106
  return `<script>
107
107
  window.__INITIAL_STATE__ = ${serialize(data, {
108
108
  isJSON: true
@@ -110,7 +110,7 @@ window.__INITIAL_STATE__ = ${serialize(data, {
110
110
  window.__CONTEXT__ = ${serialize(context, {
111
111
  isJSON: true
112
112
  })};
113
- window.__COMPONENT_PATH__ = ${serialize(componentPath, {
113
+ window.__COMPONENT_NAME__ = ${serialize(componentName, {
114
114
  isJSON: true
115
115
  })};
116
116
  </script>`;
@@ -421,18 +421,26 @@ var RenderService = class _RenderService {
421
421
  isDevelopment;
422
422
  ssrMode;
423
423
  entryServerPath;
424
+ entryClientPath;
424
425
  constructor(templateParser, streamingErrorHandler, ssrMode, defaultHead) {
425
426
  this.templateParser = templateParser;
426
427
  this.streamingErrorHandler = streamingErrorHandler;
427
428
  this.defaultHead = defaultHead;
428
429
  this.isDevelopment = process.env.NODE_ENV !== "production";
429
430
  this.ssrMode = ssrMode || process.env.SSR_MODE || "string";
430
- const absoluteTemplatePath = join(__dirname, "templates/entry-server.tsx");
431
- const relativeToApp = relative(process.cwd(), absoluteTemplatePath);
432
- if (relativeToApp.startsWith("..")) {
433
- this.entryServerPath = absoluteTemplatePath;
431
+ const absoluteServerPath = join(__dirname, "/templates/entry-server.tsx");
432
+ const relativeServerPath = relative(process.cwd(), absoluteServerPath);
433
+ if (relativeServerPath.startsWith("..")) {
434
+ this.entryServerPath = absoluteServerPath;
434
435
  } else {
435
- this.entryServerPath = "/" + relativeToApp.replace(/\\/g, "/");
436
+ this.entryServerPath = "/" + relativeServerPath.replace(/\\/g, "/");
437
+ }
438
+ const absoluteClientPath = join(__dirname, "/templates/entry-client.tsx");
439
+ const relativeClientPath = relative(process.cwd(), absoluteClientPath);
440
+ if (relativeClientPath.startsWith("..")) {
441
+ this.entryClientPath = absoluteClientPath;
442
+ } else {
443
+ this.entryClientPath = "/" + relativeClientPath.replace(/\\/g, "/");
436
444
  }
437
445
  let templatePath;
438
446
  if (this.isDevelopment) {
@@ -485,15 +493,15 @@ var RenderService = class _RenderService {
485
493
  /**
486
494
  * Main render method that routes to string or stream mode
487
495
  */
488
- async render(viewPath, data = {}, res, head) {
496
+ async render(viewComponent, data = {}, res, head) {
489
497
  const mergedHead = this.mergeHead(this.defaultHead, head);
490
498
  if (this.ssrMode === "stream") {
491
499
  if (!res) {
492
500
  throw new Error("Response object is required for streaming SSR mode. Pass res as third parameter.");
493
501
  }
494
- return this.renderToStream(viewPath, data, res, mergedHead);
502
+ return this.renderToStream(viewComponent, data, res, mergedHead);
495
503
  }
496
- return this.renderToString(viewPath, data, mergedHead);
504
+ return this.renderToString(viewComponent, data, mergedHead);
497
505
  }
498
506
  /**
499
507
  * Merge default head with page-specific head
@@ -520,7 +528,7 @@ var RenderService = class _RenderService {
520
528
  /**
521
529
  * Traditional string-based SSR using renderToString
522
530
  */
523
- async renderToString(viewPath, data = {}, head) {
531
+ async renderToString(viewComponent, data = {}, head) {
524
532
  const startTime = Date.now();
525
533
  try {
526
534
  let template = this.template;
@@ -545,7 +553,8 @@ var RenderService = class _RenderService {
545
553
  }
546
554
  }
547
555
  const { data: pageData, __context: context } = data;
548
- const appHtml = await renderModule.renderComponent(viewPath, data);
556
+ const appHtml = await renderModule.renderComponent(viewComponent, data);
557
+ const componentName = viewComponent.displayName || viewComponent.name || "Component";
549
558
  const initialStateScript = `
550
559
  <script>
551
560
  window.__INITIAL_STATE__ = ${serialize(pageData, {
@@ -554,7 +563,7 @@ var RenderService = class _RenderService {
554
563
  window.__CONTEXT__ = ${serialize(context, {
555
564
  isJSON: true
556
565
  })};
557
- window.__COMPONENT_PATH__ = ${serialize(viewPath, {
566
+ window.__COMPONENT_NAME__ = ${serialize(componentName, {
558
567
  isJSON: true
559
568
  })};
560
569
  </script>
@@ -562,7 +571,7 @@ var RenderService = class _RenderService {
562
571
  let clientScript = "";
563
572
  let styles = "";
564
573
  if (this.vite) {
565
- clientScript = `<script type="module" src="/src/entry-client.tsx"></script>`;
574
+ clientScript = `<script type="module" src="${this.entryClientPath}"></script>`;
566
575
  styles = "";
567
576
  } else {
568
577
  if (this.manifest) {
@@ -592,7 +601,8 @@ var RenderService = class _RenderService {
592
601
  html = html.replace("<!--head-meta-->", headTags);
593
602
  if (this.isDevelopment) {
594
603
  const duration = Date.now() - startTime;
595
- this.logger.log(`[SSR] ${viewPath} rendered in ${duration}ms (string mode)`);
604
+ const componentName2 = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
605
+ this.logger.log(`[SSR] ${componentName2} rendered in ${duration}ms (string mode)`);
596
606
  }
597
607
  return html;
598
608
  } catch (error) {
@@ -602,7 +612,7 @@ var RenderService = class _RenderService {
602
612
  /**
603
613
  * Modern streaming SSR using renderToPipeableStream
604
614
  */
605
- async renderToStream(viewPath, data = {}, res, head) {
615
+ async renderToStream(viewComponent, data = {}, res, head) {
606
616
  const startTime = Date.now();
607
617
  let shellReadyTime = 0;
608
618
  try {
@@ -629,12 +639,13 @@ var RenderService = class _RenderService {
629
639
  }
630
640
  }
631
641
  const { data: pageData, __context: context } = data;
632
- const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, viewPath);
642
+ const componentName = viewComponent.displayName || viewComponent.name || "Component";
643
+ const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName);
633
644
  const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
634
645
  const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
635
646
  const headTags = this.templateParser.buildHeadTags(head);
636
647
  let didError = false;
637
- const { pipe, abort } = renderModule.renderComponentStream(viewPath, data, {
648
+ const { pipe, abort } = renderModule.renderComponentStream(viewComponent, data, {
638
649
  onShellReady: /* @__PURE__ */ __name(() => {
639
650
  shellReadyTime = Date.now();
640
651
  res.statusCode = didError ? 500 : 200;
@@ -647,15 +658,15 @@ var RenderService = class _RenderService {
647
658
  pipe(res);
648
659
  if (this.isDevelopment) {
649
660
  const ttfb = shellReadyTime - startTime;
650
- this.logger.log(`[SSR] ${viewPath} shell ready in ${ttfb}ms (stream mode - TTFB)`);
661
+ this.logger.log(`[SSR] ${componentName} shell ready in ${ttfb}ms (stream mode - TTFB)`);
651
662
  }
652
663
  }, "onShellReady"),
653
664
  onShellError: /* @__PURE__ */ __name((error) => {
654
- this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
665
+ this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
655
666
  }, "onShellError"),
656
667
  onError: /* @__PURE__ */ __name((error) => {
657
668
  didError = true;
658
- this.streamingErrorHandler.handleStreamError(error, viewPath);
669
+ this.streamingErrorHandler.handleStreamError(error, componentName);
659
670
  }, "onError"),
660
671
  onAllReady: /* @__PURE__ */ __name(() => {
661
672
  res.write(inlineScripts);
@@ -666,7 +677,7 @@ var RenderService = class _RenderService {
666
677
  if (this.isDevelopment) {
667
678
  const totalTime = Date.now() - startTime;
668
679
  const streamTime = Date.now() - shellReadyTime;
669
- this.logger.log(`[SSR] ${viewPath} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)`);
680
+ this.logger.log(`[SSR] ${componentName} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)`);
670
681
  }
671
682
  }, "onAllReady")
672
683
  });
@@ -674,7 +685,8 @@ var RenderService = class _RenderService {
674
685
  abort();
675
686
  });
676
687
  } catch (error) {
677
- this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
688
+ const componentName = typeof viewComponent === "function" ? viewComponent.name : String(viewComponent);
689
+ this.streamingErrorHandler.handleShellError(error, res, componentName, this.isDevelopment);
678
690
  }
679
691
  }
680
692
  };
@@ -721,8 +733,8 @@ var RenderInterceptor = class {
721
733
  this.renderService = renderService;
722
734
  }
723
735
  intercept(context, next) {
724
- const viewPath = this.reflector.get(RENDER_KEY, context.getHandler());
725
- if (!viewPath) {
736
+ const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
737
+ if (!viewPathOrComponent) {
726
738
  return next.handle();
727
739
  }
728
740
  return next.handle().pipe(switchMap(async (data) => {
@@ -746,7 +758,7 @@ var RenderInterceptor = class {
746
758
  __context: renderContext
747
759
  };
748
760
  try {
749
- const html = await this.renderService.render(viewPath, fullData, response, renderResponse.head);
761
+ const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
750
762
  if (html !== void 0) {
751
763
  response.type("text/html");
752
764
  return html;
@@ -792,6 +804,7 @@ var ViteInitializerService = class _ViteInitializerService {
792
804
  logger = new Logger(_ViteInitializerService.name);
793
805
  viteMode;
794
806
  vitePort;
807
+ viteServer = null;
795
808
  constructor(renderService, httpAdapterHost, viteConfig) {
796
809
  this.renderService = renderService;
797
810
  this.httpAdapterHost = httpAdapterHost;
@@ -809,15 +822,15 @@ var ViteInitializerService = class _ViteInitializerService {
809
822
  async setupDevelopmentMode() {
810
823
  try {
811
824
  const { createServer: createViteServer } = await import('vite');
812
- const vite = await createViteServer({
825
+ this.viteServer = await createViteServer({
813
826
  server: {
814
827
  middlewareMode: true
815
828
  },
816
829
  appType: "custom"
817
830
  });
818
- this.renderService.setViteServer(vite);
831
+ this.renderService.setViteServer(this.viteServer);
819
832
  if (this.viteMode === "embedded") {
820
- await this.mountViteMiddleware(vite);
833
+ await this.mountViteMiddleware(this.viteServer);
821
834
  } else if (this.viteMode === "proxy") {
822
835
  await this.setupViteProxy();
823
836
  }
@@ -880,6 +893,20 @@ var ViteInitializerService = class _ViteInitializerService {
880
893
  this.logger.warn(`Failed to setup static assets: ${error.message}`);
881
894
  }
882
895
  }
896
+ /**
897
+ * Cleanup: Close Vite server on module destroy
898
+ * This prevents port conflicts on hot reload
899
+ */
900
+ async onModuleDestroy() {
901
+ if (this.viteServer) {
902
+ try {
903
+ await this.viteServer.close();
904
+ this.logger.log("\u2713 Vite server closed");
905
+ } catch (error) {
906
+ this.logger.warn(`Failed to close Vite server: ${error.message}`);
907
+ }
908
+ }
909
+ }
883
910
  };
884
911
  ViteInitializerService = _ts_decorate5([
885
912
  Injectable(),