@alepha/react 0.7.6 → 0.7.7

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/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { $hook, $inject, $logger, Alepha, KIND, NotImplementedError, OPTIONS, __bind, __descriptor, t } from "@alepha/core";
2
- import { AlephaServer, HttpClient, ServerLinksProvider, ServerRouterProvider, ServerTimingProvider, apiLinksResponseSchema } from "@alepha/server";
2
+ import { AlephaServer, ServerRouterProvider, ServerTimingProvider, apiLinksResponseSchema } from "@alepha/server";
3
3
  import { AlephaServerCache } from "@alepha/server-cache";
4
4
  import React, { StrictMode, createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { existsSync } from "node:fs";
7
7
  import { join } from "node:path";
8
+ import { LinkProvider, ServerLinksProvider } from "@alepha/server-links";
8
9
  import { ServerStaticProvider } from "@alepha/server-static";
9
10
  import { renderToString } from "react-dom/server";
10
11
  import { RouterProvider } from "@alepha/router";
@@ -457,10 +458,6 @@ var PageDescriptorProvider = class {
457
458
  const props = it.props ?? {};
458
459
  const params = { ...it.config?.params };
459
460
  for (const key of Object.keys(params)) params[key] = String(params[key]);
460
- if (it.route.head && !it.error) this.fillHead(it.route, request, {
461
- ...props,
462
- ...context
463
- });
464
461
  acc += "/";
465
462
  acc += it.route.path ? this.compile(it.route.path, params) : "";
466
463
  const path = acc.replace(/\/+/, "/");
@@ -477,7 +474,8 @@ var PageDescriptorProvider = class {
477
474
  config: it.config,
478
475
  element: this.renderView(i + 1, path, element$1, it.route),
479
476
  index: i + 1,
480
- path
477
+ path,
478
+ route
481
479
  });
482
480
  break;
483
481
  }
@@ -492,7 +490,8 @@ var PageDescriptorProvider = class {
492
490
  config: it.config,
493
491
  element: this.renderView(i + 1, path, element, it.route),
494
492
  index: i + 1,
495
- path
493
+ path,
494
+ route
496
495
  });
497
496
  }
498
497
  return {
@@ -517,26 +516,6 @@ var PageDescriptorProvider = class {
517
516
  if (page.component) return createElement(page.component, props);
518
517
  return void 0;
519
518
  }
520
- fillHead(page, ctx, props) {
521
- if (!page.head) return;
522
- ctx.head ??= {};
523
- const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
524
- if (head.title) {
525
- ctx.head ??= {};
526
- if (ctx.head.titleSeparator) ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
527
- else ctx.head.title = head.title;
528
- ctx.head.titleSeparator = head.titleSeparator;
529
- }
530
- if (head.htmlAttributes) ctx.head.htmlAttributes = {
531
- ...ctx.head.htmlAttributes,
532
- ...head.htmlAttributes
533
- };
534
- if (head.bodyAttributes) ctx.head.bodyAttributes = {
535
- ...ctx.head.bodyAttributes,
536
- ...head.bodyAttributes
537
- };
538
- if (head.meta) ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
539
- }
540
519
  renderError(error) {
541
520
  return createElement(ErrorViewer_default, { error });
542
521
  }
@@ -629,46 +608,6 @@ const isPageRoute = (it) => {
629
608
  return it && typeof it === "object" && typeof it.path === "string" && typeof it.page === "object";
630
609
  };
631
610
 
632
- //#endregion
633
- //#region src/providers/ServerHeadProvider.ts
634
- var ServerHeadProvider = class {
635
- renderHead(template, head) {
636
- let result = template;
637
- const htmlAttributes = head.htmlAttributes;
638
- if (htmlAttributes) result = result.replace(/<html([^>]*)>/i, (_, existingAttrs) => `<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`);
639
- const bodyAttributes = head.bodyAttributes;
640
- if (bodyAttributes) result = result.replace(/<body([^>]*)>/i, (_, existingAttrs) => `<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`);
641
- let headContent = "";
642
- const title = head.title;
643
- if (title) if (template.includes("<title>")) result = result.replace(/<title>(.*?)<\/title>/i, () => `<title>${this.escapeHtml(title)}</title>`);
644
- else headContent += `<title>${this.escapeHtml(title)}</title>\n`;
645
- if (head.meta) for (const meta of head.meta) headContent += `<meta name="${this.escapeHtml(meta.name)}" content="${this.escapeHtml(meta.content)}">\n`;
646
- result = result.replace(/<head([^>]*)>(.*?)<\/head>/is, (_, existingAttrs, existingHead) => `<head${existingAttrs}>${existingHead}${headContent}</head>`);
647
- return result.trim();
648
- }
649
- mergeAttributes(existing, attrs) {
650
- const existingAttrs = this.parseAttributes(existing);
651
- const merged = {
652
- ...existingAttrs,
653
- ...attrs
654
- };
655
- return Object.entries(merged).map(([k, v]) => ` ${k}="${this.escapeHtml(v)}"`).join("");
656
- }
657
- parseAttributes(attrStr) {
658
- const attrs = {};
659
- const attrRegex = /([^\s=]+)(?:="([^"]*)")?/g;
660
- let match = attrRegex.exec(attrStr);
661
- while (match) {
662
- attrs[match[1]] = match[2] ?? "";
663
- match = attrRegex.exec(attrStr);
664
- }
665
- return attrs;
666
- }
667
- escapeHtml(str) {
668
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
669
- }
670
- };
671
-
672
611
  //#endregion
673
612
  //#region src/providers/ReactServerProvider.ts
674
613
  const envSchema = t.object({
@@ -683,7 +622,6 @@ var ReactServerProvider = class {
683
622
  pageDescriptorProvider = $inject(PageDescriptorProvider);
684
623
  serverStaticProvider = $inject(ServerStaticProvider);
685
624
  serverRouterProvider = $inject(ServerRouterProvider);
686
- headProvider = $inject(ServerHeadProvider);
687
625
  serverTimingProvider = $inject(ServerTimingProvider);
688
626
  env = $inject(envSchema);
689
627
  ROOT_DIV_REGEX = new RegExp(`<div([^>]*)\\s+id=["']${this.env.REACT_ROOT_ID}["']([^>]*)>(.*?)<\\/div>`, "is");
@@ -695,8 +633,7 @@ var ReactServerProvider = class {
695
633
  this.alepha.state("ReactServerProvider.ssr", ssrEnabled);
696
634
  for (const { key, instance, value } of pages) {
697
635
  const name = value[OPTIONS].name ?? key;
698
- instance[key].prerender = this.createRenderFunction(name, true);
699
- if (this.alepha.isTest()) instance[key].render = this.createRenderFunction(name);
636
+ instance[key].render = this.createRenderFunction(name);
700
637
  }
701
638
  if (this.alepha.isServerless() === "vite") {
702
639
  await this.configureVite(ssrEnabled);
@@ -733,7 +670,7 @@ var ReactServerProvider = class {
733
670
  }
734
671
  });
735
672
  get template() {
736
- return this.alepha.state("ReactServerProvider.template");
673
+ return this.alepha.state("ReactServerProvider.template") ?? "<!DOCTYPE html><html lang='en'><head></head><body></body></html>";
737
674
  }
738
675
  async registerPages(templateLoader) {
739
676
  for (const page of this.pageDescriptorProvider.getPages()) {
@@ -779,15 +716,20 @@ var ReactServerProvider = class {
779
716
  head: {},
780
717
  onError: () => null
781
718
  };
719
+ await this.alepha.emit("react:server:render:begin", { context });
782
720
  const state = await this.pageDescriptorProvider.createLayers(page, context);
783
- if (!withIndex) return {
721
+ if (!withIndex && !options.html) return {
784
722
  context,
785
723
  html: renderToString(this.pageDescriptorProvider.root(state, context))
786
724
  };
787
- return {
725
+ const html = this.renderToHtml(this.template ?? "", state, context, options.hydration);
726
+ const result = {
788
727
  context,
789
- html: this.renderToHtml(this.template ?? "", state, context)
728
+ state,
729
+ html
790
730
  };
731
+ await this.alepha.emit("react:server:render:end", result);
732
+ return result;
791
733
  };
792
734
  }
793
735
  createHandler(page, templateLoader) {
@@ -820,10 +762,10 @@ var ReactServerProvider = class {
820
762
  }
821
763
  target = target.parent;
822
764
  }
823
- await this.alepha.emit("react:server:render", {
765
+ await this.alepha.emit("react:server:render:begin", {
824
766
  request: serverRequest,
825
- pageRequest: context
826
- }, { log: false });
767
+ context
768
+ });
827
769
  this.serverTimingProvider.beginTiming("createLayers");
828
770
  const state = await this.pageDescriptorProvider.createLayers(page, context);
829
771
  this.serverTimingProvider.endTiming("createLayers");
@@ -834,11 +776,17 @@ var ReactServerProvider = class {
834
776
  reply.headers.expires = "0";
835
777
  if (page.cache && serverRequest.user) delete context.links;
836
778
  const html = this.renderToHtml(template, state, context);
779
+ await this.alepha.emit("react:server:render:end", {
780
+ request: serverRequest,
781
+ context,
782
+ state,
783
+ html
784
+ });
837
785
  page.afterHandler?.(serverRequest);
838
786
  return html;
839
787
  };
840
788
  }
841
- renderToHtml(template, state, context) {
789
+ renderToHtml(template, state, context, hydration = true) {
842
790
  const element = this.pageDescriptorProvider.root(state, context);
843
791
  this.serverTimingProvider.beginTiming("renderToString");
844
792
  let app = "";
@@ -849,25 +797,27 @@ var ReactServerProvider = class {
849
797
  app = renderToString(context.onError(error));
850
798
  }
851
799
  this.serverTimingProvider.endTiming("renderToString");
852
- const hydrationData = {
853
- links: context.links,
854
- layers: state.layers.map((it) => ({
855
- ...it,
856
- error: it.error ? {
857
- ...it.error,
858
- name: it.error.name,
859
- message: it.error.message,
860
- stack: it.error.stack
861
- } : void 0,
862
- index: void 0,
863
- path: void 0,
864
- element: void 0
865
- }))
866
- };
867
- const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
868
800
  const response = { html: template };
869
- this.fillTemplate(response, app, script);
870
- if (context.head) response.html = this.headProvider.renderHead(response.html, context.head);
801
+ if (hydration) {
802
+ const hydrationData = {
803
+ links: context.links,
804
+ layers: state.layers.map((it) => ({
805
+ ...it,
806
+ error: it.error ? {
807
+ ...it.error,
808
+ name: it.error.name,
809
+ message: it.error.message,
810
+ stack: it.error.stack
811
+ } : void 0,
812
+ index: void 0,
813
+ path: void 0,
814
+ element: void 0,
815
+ route: void 0
816
+ }))
817
+ };
818
+ const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
819
+ this.fillTemplate(response, app, script);
820
+ }
871
821
  return response.html;
872
822
  }
873
823
  fillTemplate(response, app, script) {
@@ -885,28 +835,6 @@ var ReactServerProvider = class {
885
835
  }
886
836
  };
887
837
 
888
- //#endregion
889
- //#region src/providers/BrowserHeadProvider.ts
890
- var BrowserHeadProvider = class {
891
- renderHead(document, head) {
892
- if (head.title) document.title = head.title;
893
- if (head.bodyAttributes) for (const [key, value] of Object.entries(head.bodyAttributes)) if (value) document.body.setAttribute(key, value);
894
- else document.body.removeAttribute(key);
895
- if (head.htmlAttributes) for (const [key, value] of Object.entries(head.htmlAttributes)) if (value) document.documentElement.setAttribute(key, value);
896
- else document.documentElement.removeAttribute(key);
897
- if (head.meta) for (const [key, value] of Object.entries(head.meta)) {
898
- const meta = document.querySelector(`meta[name="${key}"]`);
899
- if (meta) meta.setAttribute("content", value.content);
900
- else {
901
- const newMeta = document.createElement("meta");
902
- newMeta.setAttribute("name", key);
903
- newMeta.setAttribute("content", value.content);
904
- document.head.appendChild(newMeta);
905
- }
906
- }
907
- }
908
- };
909
-
910
838
  //#endregion
911
839
  //#region src/providers/BrowserRouterProvider.ts
912
840
  var BrowserRouterProvider = class extends RouterProvider {
@@ -936,7 +864,6 @@ var BrowserRouterProvider = class extends RouterProvider {
936
864
  url,
937
865
  query: {},
938
866
  params: {},
939
- head: {},
940
867
  onError: () => null,
941
868
  ...options.context ?? {}
942
869
  };
@@ -967,7 +894,10 @@ var BrowserRouterProvider = class extends RouterProvider {
967
894
  index: 0,
968
895
  path: "/"
969
896
  });
970
- await this.alepha.emit("react:transition:success", { state });
897
+ await this.alepha.emit("react:transition:success", {
898
+ state,
899
+ context
900
+ });
971
901
  } catch (e) {
972
902
  this.log.error(e);
973
903
  state.layers = [{
@@ -1005,10 +935,9 @@ var BrowserRouterProvider = class extends RouterProvider {
1005
935
  //#region src/providers/ReactBrowserProvider.ts
1006
936
  var ReactBrowserProvider = class {
1007
937
  log = $logger();
1008
- client = $inject(HttpClient);
938
+ client = $inject(LinkProvider);
1009
939
  alepha = $inject(Alepha);
1010
940
  router = $inject(BrowserRouterProvider);
1011
- headProvider = $inject(BrowserHeadProvider);
1012
941
  root;
1013
942
  transitioning;
1014
943
  state = {
@@ -1087,7 +1016,6 @@ var ReactBrowserProvider = class {
1087
1016
  const previous = hydration?.layers ?? [];
1088
1017
  if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink(link);
1089
1018
  const { context } = await this.render({ previous });
1090
- if (context.head) this.headProvider.renderHead(this.document, context.head);
1091
1019
  await this.alepha.emit("react:browser:render", {
1092
1020
  state: this.state,
1093
1021
  context,
@@ -1098,12 +1026,6 @@ var ReactBrowserProvider = class {
1098
1026
  });
1099
1027
  }
1100
1028
  });
1101
- onTransitionEnd = $hook({
1102
- name: "react:transition:end",
1103
- handler: async ({ context }) => {
1104
- this.headProvider.renderHead(this.document, context.head);
1105
- }
1106
- });
1107
1029
  };
1108
1030
 
1109
1031
  //#endregion
@@ -1262,7 +1184,7 @@ const useInject = (clazz) => {
1262
1184
  //#endregion
1263
1185
  //#region src/hooks/useClient.ts
1264
1186
  const useClient = (_scope) => {
1265
- return useInject(HttpClient).of();
1187
+ return useInject(LinkProvider).client();
1266
1188
  };
1267
1189
 
1268
1190
  //#endregion