@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.browser.d.ts +26 -81
- package/dist/index.browser.js +11 -61
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +53 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -95
- package/dist/index.d.ts +54 -103
- package/dist/index.js +52 -130
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/src/descriptors/$page.ts +2 -47
- package/src/hooks/useClient.ts +3 -3
- package/src/index.ts +16 -4
- package/src/providers/BrowserRouterProvider.ts +3 -4
- package/src/providers/PageDescriptorProvider.ts +10 -57
- package/src/providers/ReactBrowserProvider.ts +3 -14
- package/src/providers/ReactServerProvider.ts +66 -58
- package/src/providers/BrowserHeadProvider.ts +0 -43
- package/src/providers/ServerHeadProvider.ts +0 -91
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,
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
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].
|
|
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
|
-
|
|
725
|
+
const html = this.renderToHtml(this.template ?? "", state, context, options.hydration);
|
|
726
|
+
const result = {
|
|
788
727
|
context,
|
|
789
|
-
|
|
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
|
-
|
|
826
|
-
}
|
|
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
|
-
|
|
870
|
-
|
|
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", {
|
|
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(
|
|
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(
|
|
1187
|
+
return useInject(LinkProvider).client();
|
|
1266
1188
|
};
|
|
1267
1189
|
|
|
1268
1190
|
//#endregion
|