@alepha/react 0.7.6 → 0.8.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/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  const __alepha_core = __toESM(require("@alepha/core"));
25
25
  const __alepha_server = __toESM(require("@alepha/server"));
26
26
  const __alepha_server_cache = __toESM(require("@alepha/server-cache"));
27
+ const __alepha_server_links = __toESM(require("@alepha/server-links"));
27
28
  const react = __toESM(require("react"));
28
29
  const react_jsx_runtime = __toESM(require("react/jsx-runtime"));
29
30
  const node_fs = __toESM(require("node:fs"));
@@ -39,11 +40,6 @@ const KEY = "PAGE";
39
40
  */
40
41
  const $page = (options) => {
41
42
  (0, __alepha_core.__descriptor)(KEY);
42
- if (options.children) for (const child of options.children) child[__alepha_core.OPTIONS].parent = { [__alepha_core.OPTIONS]: options };
43
- if (options.parent) {
44
- options.parent[__alepha_core.OPTIONS].children ??= [];
45
- options.parent[__alepha_core.OPTIONS].children.push({ [__alepha_core.OPTIONS]: options });
46
- }
47
43
  return {
48
44
  [__alepha_core.KIND]: KEY,
49
45
  [__alepha_core.OPTIONS]: options,
@@ -480,10 +476,6 @@ var PageDescriptorProvider = class {
480
476
  const props = it.props ?? {};
481
477
  const params = { ...it.config?.params };
482
478
  for (const key of Object.keys(params)) params[key] = String(params[key]);
483
- if (it.route.head && !it.error) this.fillHead(it.route, request, {
484
- ...props,
485
- ...context
486
- });
487
479
  acc += "/";
488
480
  acc += it.route.path ? this.compile(it.route.path, params) : "";
489
481
  const path = acc.replace(/\/+/, "/");
@@ -500,7 +492,8 @@ var PageDescriptorProvider = class {
500
492
  config: it.config,
501
493
  element: this.renderView(i + 1, path, element$1, it.route),
502
494
  index: i + 1,
503
- path
495
+ path,
496
+ route
504
497
  });
505
498
  break;
506
499
  }
@@ -515,7 +508,8 @@ var PageDescriptorProvider = class {
515
508
  config: it.config,
516
509
  element: this.renderView(i + 1, path, element, it.route),
517
510
  index: i + 1,
518
- path
511
+ path,
512
+ route
519
513
  });
520
514
  }
521
515
  return {
@@ -540,26 +534,6 @@ var PageDescriptorProvider = class {
540
534
  if (page.component) return (0, react.createElement)(page.component, props);
541
535
  return void 0;
542
536
  }
543
- fillHead(page, ctx, props) {
544
- if (!page.head) return;
545
- ctx.head ??= {};
546
- const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
547
- if (head.title) {
548
- ctx.head ??= {};
549
- if (ctx.head.titleSeparator) ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
550
- else ctx.head.title = head.title;
551
- ctx.head.titleSeparator = head.titleSeparator;
552
- }
553
- if (head.htmlAttributes) ctx.head.htmlAttributes = {
554
- ...ctx.head.htmlAttributes,
555
- ...head.htmlAttributes
556
- };
557
- if (head.bodyAttributes) ctx.head.bodyAttributes = {
558
- ...ctx.head.bodyAttributes,
559
- ...head.bodyAttributes
560
- };
561
- if (head.meta) ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
562
- }
563
537
  renderError(error) {
564
538
  return (0, react.createElement)(ErrorViewer_default, { error });
565
539
  }
@@ -591,13 +565,19 @@ var PageDescriptorProvider = class {
591
565
  } }, element);
592
566
  }
593
567
  configure = (0, __alepha_core.$hook)({
594
- name: "configure",
568
+ on: "configure",
595
569
  handler: () => {
596
570
  let hasNotFoundHandler = false;
597
571
  const pages = this.alepha.getDescriptorValues($page);
572
+ const hasParent = (it) => {
573
+ for (const page of pages) {
574
+ const children = page.value[__alepha_core.OPTIONS].children ? Array.isArray(page.value[__alepha_core.OPTIONS].children) ? page.value[__alepha_core.OPTIONS].children : page.value[__alepha_core.OPTIONS].children() : [];
575
+ if (children.includes(it)) return true;
576
+ }
577
+ };
598
578
  for (const { value, key } of pages) value[__alepha_core.OPTIONS].name ??= key;
599
579
  for (const { value } of pages) {
600
- if (value[__alepha_core.OPTIONS].parent) continue;
580
+ if (hasParent(value)) continue;
601
581
  if (value[__alepha_core.OPTIONS].path === "/*") hasNotFoundHandler = true;
602
582
  this.add(this.map(pages, value));
603
583
  }
@@ -613,7 +593,7 @@ var PageDescriptorProvider = class {
613
593
  }
614
594
  });
615
595
  map(pages, target) {
616
- const children = target[__alepha_core.OPTIONS].children ?? [];
596
+ const children = target[__alepha_core.OPTIONS].children ? Array.isArray(target[__alepha_core.OPTIONS].children) ? target[__alepha_core.OPTIONS].children : target[__alepha_core.OPTIONS].children() : [];
617
597
  return {
618
598
  ...target[__alepha_core.OPTIONS],
619
599
  parent: void 0,
@@ -652,46 +632,6 @@ const isPageRoute = (it) => {
652
632
  return it && typeof it === "object" && typeof it.path === "string" && typeof it.page === "object";
653
633
  };
654
634
 
655
- //#endregion
656
- //#region src/providers/ServerHeadProvider.ts
657
- var ServerHeadProvider = class {
658
- renderHead(template, head) {
659
- let result = template;
660
- const htmlAttributes = head.htmlAttributes;
661
- if (htmlAttributes) result = result.replace(/<html([^>]*)>/i, (_, existingAttrs) => `<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`);
662
- const bodyAttributes = head.bodyAttributes;
663
- if (bodyAttributes) result = result.replace(/<body([^>]*)>/i, (_, existingAttrs) => `<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`);
664
- let headContent = "";
665
- const title = head.title;
666
- if (title) if (template.includes("<title>")) result = result.replace(/<title>(.*?)<\/title>/i, () => `<title>${this.escapeHtml(title)}</title>`);
667
- else headContent += `<title>${this.escapeHtml(title)}</title>\n`;
668
- if (head.meta) for (const meta of head.meta) headContent += `<meta name="${this.escapeHtml(meta.name)}" content="${this.escapeHtml(meta.content)}">\n`;
669
- result = result.replace(/<head([^>]*)>(.*?)<\/head>/is, (_, existingAttrs, existingHead) => `<head${existingAttrs}>${existingHead}${headContent}</head>`);
670
- return result.trim();
671
- }
672
- mergeAttributes(existing, attrs) {
673
- const existingAttrs = this.parseAttributes(existing);
674
- const merged = {
675
- ...existingAttrs,
676
- ...attrs
677
- };
678
- return Object.entries(merged).map(([k, v]) => ` ${k}="${this.escapeHtml(v)}"`).join("");
679
- }
680
- parseAttributes(attrStr) {
681
- const attrs = {};
682
- const attrRegex = /([^\s=]+)(?:="([^"]*)")?/g;
683
- let match = attrRegex.exec(attrStr);
684
- while (match) {
685
- attrs[match[1]] = match[2] ?? "";
686
- match = attrRegex.exec(attrStr);
687
- }
688
- return attrs;
689
- }
690
- escapeHtml(str) {
691
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
692
- }
693
- };
694
-
695
635
  //#endregion
696
636
  //#region src/providers/ReactServerProvider.ts
697
637
  const envSchema = __alepha_core.t.object({
@@ -706,20 +646,18 @@ var ReactServerProvider = class {
706
646
  pageDescriptorProvider = (0, __alepha_core.$inject)(PageDescriptorProvider);
707
647
  serverStaticProvider = (0, __alepha_core.$inject)(__alepha_server_static.ServerStaticProvider);
708
648
  serverRouterProvider = (0, __alepha_core.$inject)(__alepha_server.ServerRouterProvider);
709
- headProvider = (0, __alepha_core.$inject)(ServerHeadProvider);
710
649
  serverTimingProvider = (0, __alepha_core.$inject)(__alepha_server.ServerTimingProvider);
711
650
  env = (0, __alepha_core.$inject)(envSchema);
712
651
  ROOT_DIV_REGEX = new RegExp(`<div([^>]*)\\s+id=["']${this.env.REACT_ROOT_ID}["']([^>]*)>(.*?)<\\/div>`, "is");
713
652
  onConfigure = (0, __alepha_core.$hook)({
714
- name: "configure",
653
+ on: "configure",
715
654
  handler: async () => {
716
655
  const pages = this.alepha.getDescriptorValues($page);
717
656
  const ssrEnabled = pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
718
657
  this.alepha.state("ReactServerProvider.ssr", ssrEnabled);
719
658
  for (const { key, instance, value } of pages) {
720
659
  const name = value[__alepha_core.OPTIONS].name ?? key;
721
- instance[key].prerender = this.createRenderFunction(name, true);
722
- if (this.alepha.isTest()) instance[key].render = this.createRenderFunction(name);
660
+ instance[key].render = this.createRenderFunction(name);
723
661
  }
724
662
  if (this.alepha.isServerless() === "vite") {
725
663
  await this.configureVite(ssrEnabled);
@@ -756,7 +694,7 @@ var ReactServerProvider = class {
756
694
  }
757
695
  });
758
696
  get template() {
759
- return this.alepha.state("ReactServerProvider.template");
697
+ return this.alepha.state("ReactServerProvider.template") ?? "<!DOCTYPE html><html lang='en'><head></head><body></body></html>";
760
698
  }
761
699
  async registerPages(templateLoader) {
762
700
  for (const page of this.pageDescriptorProvider.getPages()) {
@@ -802,15 +740,20 @@ var ReactServerProvider = class {
802
740
  head: {},
803
741
  onError: () => null
804
742
  };
743
+ await this.alepha.emit("react:server:render:begin", { context });
805
744
  const state = await this.pageDescriptorProvider.createLayers(page, context);
806
- if (!withIndex) return {
745
+ if (!withIndex && !options.html) return {
807
746
  context,
808
747
  html: (0, react_dom_server.renderToString)(this.pageDescriptorProvider.root(state, context))
809
748
  };
810
- return {
749
+ const html = this.renderToHtml(this.template ?? "", state, context, options.hydration);
750
+ const result = {
811
751
  context,
812
- html: this.renderToHtml(this.template ?? "", state, context)
752
+ state,
753
+ html
813
754
  };
755
+ await this.alepha.emit("react:server:render:end", result);
756
+ return result;
814
757
  };
815
758
  }
816
759
  createHandler(page, templateLoader) {
@@ -825,8 +768,8 @@ var ReactServerProvider = class {
825
768
  head: {},
826
769
  onError: () => null
827
770
  };
828
- if (this.alepha.has(__alepha_server.ServerLinksProvider)) {
829
- const srv = this.alepha.get(__alepha_server.ServerLinksProvider);
771
+ if (this.alepha.has(__alepha_server_links.ServerLinksProvider)) {
772
+ const srv = this.alepha.get(__alepha_server_links.ServerLinksProvider);
830
773
  const schema = __alepha_server.apiLinksResponseSchema;
831
774
  context.links = this.alepha.parse(schema, await srv.getLinks({
832
775
  user: serverRequest.user,
@@ -843,10 +786,10 @@ var ReactServerProvider = class {
843
786
  }
844
787
  target = target.parent;
845
788
  }
846
- await this.alepha.emit("react:server:render", {
789
+ await this.alepha.emit("react:server:render:begin", {
847
790
  request: serverRequest,
848
- pageRequest: context
849
- }, { log: false });
791
+ context
792
+ });
850
793
  this.serverTimingProvider.beginTiming("createLayers");
851
794
  const state = await this.pageDescriptorProvider.createLayers(page, context);
852
795
  this.serverTimingProvider.endTiming("createLayers");
@@ -857,11 +800,17 @@ var ReactServerProvider = class {
857
800
  reply.headers.expires = "0";
858
801
  if (page.cache && serverRequest.user) delete context.links;
859
802
  const html = this.renderToHtml(template, state, context);
803
+ await this.alepha.emit("react:server:render:end", {
804
+ request: serverRequest,
805
+ context,
806
+ state,
807
+ html
808
+ });
860
809
  page.afterHandler?.(serverRequest);
861
810
  return html;
862
811
  };
863
812
  }
864
- renderToHtml(template, state, context) {
813
+ renderToHtml(template, state, context, hydration = true) {
865
814
  const element = this.pageDescriptorProvider.root(state, context);
866
815
  this.serverTimingProvider.beginTiming("renderToString");
867
816
  let app = "";
@@ -872,25 +821,27 @@ var ReactServerProvider = class {
872
821
  app = (0, react_dom_server.renderToString)(context.onError(error));
873
822
  }
874
823
  this.serverTimingProvider.endTiming("renderToString");
875
- const hydrationData = {
876
- links: context.links,
877
- layers: state.layers.map((it) => ({
878
- ...it,
879
- error: it.error ? {
880
- ...it.error,
881
- name: it.error.name,
882
- message: it.error.message,
883
- stack: it.error.stack
884
- } : void 0,
885
- index: void 0,
886
- path: void 0,
887
- element: void 0
888
- }))
889
- };
890
- const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
891
824
  const response = { html: template };
892
- this.fillTemplate(response, app, script);
893
- if (context.head) response.html = this.headProvider.renderHead(response.html, context.head);
825
+ if (hydration) {
826
+ const hydrationData = {
827
+ links: context.links,
828
+ layers: state.layers.map((it) => ({
829
+ ...it,
830
+ error: it.error ? {
831
+ ...it.error,
832
+ name: it.error.name,
833
+ message: it.error.message,
834
+ stack: it.error.stack
835
+ } : void 0,
836
+ index: void 0,
837
+ path: void 0,
838
+ element: void 0,
839
+ route: void 0
840
+ }))
841
+ };
842
+ const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
843
+ this.fillTemplate(response, app, script);
844
+ }
894
845
  return response.html;
895
846
  }
896
847
  fillTemplate(response, app, script) {
@@ -908,28 +859,6 @@ var ReactServerProvider = class {
908
859
  }
909
860
  };
910
861
 
911
- //#endregion
912
- //#region src/providers/BrowserHeadProvider.ts
913
- var BrowserHeadProvider = class {
914
- renderHead(document, head) {
915
- if (head.title) document.title = head.title;
916
- if (head.bodyAttributes) for (const [key, value] of Object.entries(head.bodyAttributes)) if (value) document.body.setAttribute(key, value);
917
- else document.body.removeAttribute(key);
918
- if (head.htmlAttributes) for (const [key, value] of Object.entries(head.htmlAttributes)) if (value) document.documentElement.setAttribute(key, value);
919
- else document.documentElement.removeAttribute(key);
920
- if (head.meta) for (const [key, value] of Object.entries(head.meta)) {
921
- const meta = document.querySelector(`meta[name="${key}"]`);
922
- if (meta) meta.setAttribute("content", value.content);
923
- else {
924
- const newMeta = document.createElement("meta");
925
- newMeta.setAttribute("name", key);
926
- newMeta.setAttribute("content", value.content);
927
- document.head.appendChild(newMeta);
928
- }
929
- }
930
- }
931
- };
932
-
933
862
  //#endregion
934
863
  //#region src/providers/BrowserRouterProvider.ts
935
864
  var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
@@ -940,7 +869,7 @@ var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
940
869
  this.pageDescriptorProvider.add(entry);
941
870
  }
942
871
  configure = (0, __alepha_core.$hook)({
943
- name: "configure",
872
+ on: "configure",
944
873
  handler: async () => {
945
874
  for (const page of this.pageDescriptorProvider.getPages()) if (page.component || page.lazy) this.push({
946
875
  path: page.match,
@@ -959,7 +888,6 @@ var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
959
888
  url,
960
889
  query: {},
961
890
  params: {},
962
- head: {},
963
891
  onError: () => null,
964
892
  ...options.context ?? {}
965
893
  };
@@ -990,7 +918,10 @@ var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
990
918
  index: 0,
991
919
  path: "/"
992
920
  });
993
- await this.alepha.emit("react:transition:success", { state });
921
+ await this.alepha.emit("react:transition:success", {
922
+ state,
923
+ context
924
+ });
994
925
  } catch (e) {
995
926
  this.log.error(e);
996
927
  state.layers = [{
@@ -1028,10 +959,9 @@ var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
1028
959
  //#region src/providers/ReactBrowserProvider.ts
1029
960
  var ReactBrowserProvider = class {
1030
961
  log = (0, __alepha_core.$logger)();
1031
- client = (0, __alepha_core.$inject)(__alepha_server.HttpClient);
962
+ client = (0, __alepha_core.$inject)(__alepha_server_links.LinkProvider);
1032
963
  alepha = (0, __alepha_core.$inject)(__alepha_core.Alepha);
1033
964
  router = (0, __alepha_core.$inject)(BrowserRouterProvider);
1034
- headProvider = (0, __alepha_core.$inject)(BrowserHeadProvider);
1035
965
  root;
1036
966
  transitioning;
1037
967
  state = {
@@ -1104,13 +1034,12 @@ var ReactBrowserProvider = class {
1104
1034
  }
1105
1035
  }
1106
1036
  ready = (0, __alepha_core.$hook)({
1107
- name: "ready",
1037
+ on: "ready",
1108
1038
  handler: async () => {
1109
1039
  const hydration = this.getHydrationState();
1110
1040
  const previous = hydration?.layers ?? [];
1111
1041
  if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink(link);
1112
1042
  const { context } = await this.render({ previous });
1113
- if (context.head) this.headProvider.renderHead(this.document, context.head);
1114
1043
  await this.alepha.emit("react:browser:render", {
1115
1044
  state: this.state,
1116
1045
  context,
@@ -1121,12 +1050,6 @@ var ReactBrowserProvider = class {
1121
1050
  });
1122
1051
  }
1123
1052
  });
1124
- onTransitionEnd = (0, __alepha_core.$hook)({
1125
- name: "react:transition:end",
1126
- handler: async ({ context }) => {
1127
- this.headProvider.renderHead(this.document, context.head);
1128
- }
1129
- });
1130
1053
  };
1131
1054
 
1132
1055
  //#endregion
@@ -1285,7 +1208,7 @@ const useInject = (clazz) => {
1285
1208
  //#endregion
1286
1209
  //#region src/hooks/useClient.ts
1287
1210
  const useClient = (_scope) => {
1288
- return useInject(__alepha_server.HttpClient).of();
1211
+ return useInject(__alepha_server_links.LinkProvider).client();
1289
1212
  };
1290
1213
 
1291
1214
  //#endregion
@@ -1345,7 +1268,7 @@ const useRouterState = () => {
1345
1268
  */
1346
1269
  var AlephaReact = class {
1347
1270
  name = "alepha.react";
1348
- $services = (alepha) => alepha.with(__alepha_server.AlephaServer).with(__alepha_server_cache.AlephaServerCache).with(ReactServerProvider).with(PageDescriptorProvider);
1271
+ $services = (alepha) => alepha.with(__alepha_server.AlephaServer).with(__alepha_server_cache.AlephaServerCache).with(__alepha_server_links.AlephaServerLinks).with(ReactServerProvider).with(PageDescriptorProvider);
1349
1272
  };
1350
1273
  (0, __alepha_core.__bind)($page, AlephaReact);
1351
1274