@alepha/react 0.7.0 → 0.7.2
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/README.md +1 -1
- package/dist/index.browser.cjs +59 -22
- package/dist/index.browser.js +42 -6
- package/dist/index.cjs +152 -85
- package/dist/index.d.ts +317 -206
- package/dist/index.js +130 -64
- package/dist/{useActive-DjpZBEuB.cjs → useRouterState-C2uo0jXu.cjs} +319 -140
- package/dist/{useActive-BX41CqY8.js → useRouterState-D5__ZcUV.js} +321 -143
- package/package.json +11 -10
- package/src/components/ClientOnly.tsx +35 -0
- package/src/components/ErrorBoundary.tsx +1 -1
- package/src/components/ErrorViewer.tsx +161 -0
- package/src/components/Link.tsx +9 -3
- package/src/components/NestedView.tsx +18 -3
- package/src/components/NotFound.tsx +30 -0
- package/src/descriptors/$page.ts +141 -30
- package/src/errors/RedirectionError.ts +4 -1
- package/src/hooks/RouterHookApi.ts +42 -24
- package/src/hooks/useAlepha.ts +12 -0
- package/src/hooks/useClient.ts +8 -6
- package/src/hooks/useInject.ts +2 -2
- package/src/hooks/useQueryParams.ts +1 -1
- package/src/hooks/useRouter.ts +6 -0
- package/src/index.browser.ts +4 -2
- package/src/index.shared.ts +11 -5
- package/src/index.ts +3 -4
- package/src/providers/BrowserRouterProvider.ts +4 -3
- package/src/providers/PageDescriptorProvider.ts +91 -20
- package/src/providers/ReactBrowserProvider.ts +6 -59
- package/src/providers/ReactBrowserRenderer.ts +72 -0
- package/src/providers/ReactServerProvider.ts +200 -81
- package/dist/index.browser.cjs.map +0 -1
- package/dist/index.browser.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/useActive-BX41CqY8.js.map +0 -1
- package/dist/useActive-DjpZBEuB.cjs.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { $hook, $inject, $logger, type Static, t } from "@alepha/core";
|
|
2
|
+
import type { ApiLinksResponse } from "@alepha/server";
|
|
3
|
+
import type { Root } from "react-dom/client";
|
|
4
|
+
import { createRoot, hydrateRoot } from "react-dom/client";
|
|
5
|
+
import { BrowserRouterProvider } from "./BrowserRouterProvider.ts";
|
|
6
|
+
import type {
|
|
7
|
+
PreviousLayerData,
|
|
8
|
+
TransitionOptions,
|
|
9
|
+
} from "./PageDescriptorProvider.ts";
|
|
10
|
+
import { ReactBrowserProvider } from "./ReactBrowserProvider.ts";
|
|
11
|
+
|
|
12
|
+
const envSchema = t.object({
|
|
13
|
+
REACT_ROOT_ID: t.string({ default: "root" }),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
declare module "@alepha/core" {
|
|
17
|
+
interface Env extends Partial<Static<typeof envSchema>> {}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class ReactBrowserRenderer {
|
|
21
|
+
protected readonly browserProvider = $inject(ReactBrowserProvider);
|
|
22
|
+
protected readonly browserRouterProvider = $inject(BrowserRouterProvider);
|
|
23
|
+
protected readonly env = $inject(envSchema);
|
|
24
|
+
protected readonly log = $logger();
|
|
25
|
+
|
|
26
|
+
protected root!: Root;
|
|
27
|
+
|
|
28
|
+
protected getRootElement() {
|
|
29
|
+
const root = this.browserProvider.document.getElementById(
|
|
30
|
+
this.env.REACT_ROOT_ID,
|
|
31
|
+
);
|
|
32
|
+
if (root) {
|
|
33
|
+
return root;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const div = this.browserProvider.document.createElement("div");
|
|
37
|
+
div.id = this.env.REACT_ROOT_ID;
|
|
38
|
+
|
|
39
|
+
this.browserProvider.document.body.prepend(div);
|
|
40
|
+
|
|
41
|
+
return div;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public readonly ready = $hook({
|
|
45
|
+
name: "react:browser:render",
|
|
46
|
+
handler: async ({ state, context, hydration }) => {
|
|
47
|
+
const element = this.browserRouterProvider.root(state, context);
|
|
48
|
+
|
|
49
|
+
if (hydration?.layers) {
|
|
50
|
+
this.root = hydrateRoot(this.getRootElement(), element);
|
|
51
|
+
this.log.info("Hydrated root element");
|
|
52
|
+
} else {
|
|
53
|
+
this.root ??= createRoot(this.getRootElement());
|
|
54
|
+
this.root.render(element);
|
|
55
|
+
this.log.info("Created root element");
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
export interface RouterGoOptions {
|
|
64
|
+
replace?: boolean;
|
|
65
|
+
match?: TransitionOptions;
|
|
66
|
+
params?: Record<string, string>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ReactHydrationState {
|
|
70
|
+
layers?: Array<PreviousLayerData>;
|
|
71
|
+
links?: ApiLinksResponse;
|
|
72
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
2
|
import { join } from "node:path";
|
|
4
3
|
import {
|
|
5
4
|
$hook,
|
|
@@ -11,24 +10,29 @@ import {
|
|
|
11
10
|
t,
|
|
12
11
|
} from "@alepha/core";
|
|
13
12
|
import {
|
|
13
|
+
apiLinksResponseSchema,
|
|
14
14
|
type ServerHandler,
|
|
15
15
|
ServerLinksProvider,
|
|
16
16
|
ServerRouterProvider,
|
|
17
|
+
ServerTimingProvider,
|
|
17
18
|
} from "@alepha/server";
|
|
18
19
|
import { ServerStaticProvider } from "@alepha/server-static";
|
|
19
20
|
import { renderToString } from "react-dom/server";
|
|
20
21
|
import { $page } from "../descriptors/$page.ts";
|
|
21
22
|
import {
|
|
22
23
|
PageDescriptorProvider,
|
|
24
|
+
type PageReactContext,
|
|
23
25
|
type PageRequest,
|
|
24
26
|
type PageRoute,
|
|
27
|
+
type RouterState,
|
|
25
28
|
} from "./PageDescriptorProvider.ts";
|
|
29
|
+
import type { ReactHydrationState } from "./ReactBrowserProvider.ts";
|
|
26
30
|
import { ServerHeadProvider } from "./ServerHeadProvider.ts";
|
|
27
31
|
|
|
28
32
|
export const envSchema = t.object({
|
|
29
|
-
REACT_SERVER_DIST: t.string({ default: "
|
|
33
|
+
REACT_SERVER_DIST: t.string({ default: "public" }),
|
|
30
34
|
REACT_SERVER_PREFIX: t.string({ default: "" }),
|
|
31
|
-
REACT_SSR_ENABLED: t.boolean(
|
|
35
|
+
REACT_SSR_ENABLED: t.optional(t.boolean()),
|
|
32
36
|
REACT_ROOT_ID: t.string({ default: "root" }),
|
|
33
37
|
});
|
|
34
38
|
|
|
@@ -47,61 +51,98 @@ export class ReactServerProvider {
|
|
|
47
51
|
protected readonly serverStaticProvider = $inject(ServerStaticProvider);
|
|
48
52
|
protected readonly serverRouterProvider = $inject(ServerRouterProvider);
|
|
49
53
|
protected readonly headProvider = $inject(ServerHeadProvider);
|
|
54
|
+
protected readonly serverTimingProvider = $inject(ServerTimingProvider);
|
|
50
55
|
protected readonly env = $inject(envSchema);
|
|
51
56
|
protected readonly ROOT_DIV_REGEX = new RegExp(
|
|
52
57
|
`<div([^>]*)\\s+id=["']${this.env.REACT_ROOT_ID}["']([^>]*)>(.*?)<\\/div>`,
|
|
53
58
|
"is",
|
|
54
59
|
);
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
public readonly onConfigure = $hook({
|
|
57
62
|
name: "configure",
|
|
58
63
|
handler: async () => {
|
|
59
64
|
const pages = this.alepha.getDescriptorValues($page);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
|
|
66
|
+
const ssrEnabled =
|
|
67
|
+
pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
|
|
68
|
+
|
|
69
|
+
this.alepha.state("ReactServerProvider.ssr", ssrEnabled);
|
|
63
70
|
|
|
64
71
|
for (const { key, instance, value } of pages) {
|
|
65
72
|
const name = value[OPTIONS].name ?? key;
|
|
66
73
|
|
|
74
|
+
instance[key].prerender = this.createRenderFunction(name, true);
|
|
75
|
+
|
|
67
76
|
if (this.alepha.isTest()) {
|
|
68
77
|
instance[key].render = this.createRenderFunction(name);
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
|
|
81
|
+
// development mode
|
|
72
82
|
if (this.alepha.isServerless() === "vite") {
|
|
73
|
-
await this.configureVite();
|
|
83
|
+
await this.configureVite(ssrEnabled);
|
|
74
84
|
return;
|
|
75
85
|
}
|
|
76
86
|
|
|
87
|
+
// production mode
|
|
77
88
|
let root = "";
|
|
89
|
+
|
|
90
|
+
// non-serverless mode only -> serve static files
|
|
78
91
|
if (!this.alepha.isServerless()) {
|
|
79
92
|
root = this.getPublicDirectory();
|
|
80
|
-
|
|
81
93
|
if (!root) {
|
|
82
|
-
this.log.warn(
|
|
83
|
-
|
|
94
|
+
this.log.warn(
|
|
95
|
+
"Missing static files, static file server will be disabled",
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
this.log.debug(`Using static files from: ${root}`);
|
|
99
|
+
await this.configureStaticServer(root);
|
|
84
100
|
}
|
|
85
|
-
|
|
86
|
-
await this.configureStaticServer(root);
|
|
87
101
|
}
|
|
88
102
|
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
(
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
if (ssrEnabled) {
|
|
104
|
+
await this.registerPages(async () => this.template);
|
|
105
|
+
this.log.info("SSR OK");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
94
108
|
|
|
95
|
-
|
|
109
|
+
// no SSR enabled, serve index.html for all unmatched routes
|
|
110
|
+
this.log.info("SSR is disabled, use History API fallback");
|
|
111
|
+
await this.serverRouterProvider.route({
|
|
112
|
+
path: "*",
|
|
113
|
+
handler: async ({ url, reply }) => {
|
|
114
|
+
if (url.pathname.includes(".")) {
|
|
115
|
+
// If the request is for a file (e.g., /style.css), do not fallback
|
|
116
|
+
reply.headers["content-type"] = "text/plain";
|
|
117
|
+
reply.body = "Not Found";
|
|
118
|
+
reply.status = 404;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
reply.headers["content-type"] = "text/html";
|
|
123
|
+
|
|
124
|
+
// serve index.html for all unmatched routes
|
|
125
|
+
return this.template;
|
|
126
|
+
},
|
|
127
|
+
});
|
|
96
128
|
},
|
|
97
129
|
});
|
|
98
130
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
131
|
+
public get template() {
|
|
132
|
+
return this.alepha.state("ReactServerProvider.template");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
protected async registerPages(templateLoader: TemplateLoader) {
|
|
102
136
|
for (const page of this.pageDescriptorProvider.getPages()) {
|
|
137
|
+
if (page.children?.length) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
103
141
|
this.log.debug(`+ ${page.match} -> ${page.name}`);
|
|
142
|
+
|
|
104
143
|
await this.serverRouterProvider.route({
|
|
144
|
+
...page,
|
|
145
|
+
schema: undefined, // schema is handled by the page descriptor provider for now (shared by browser and server)
|
|
105
146
|
method: "GET",
|
|
106
147
|
path: page.match,
|
|
107
148
|
handler: this.createHandler(page, templateLoader),
|
|
@@ -111,8 +152,8 @@ export class ReactServerProvider {
|
|
|
111
152
|
|
|
112
153
|
protected getPublicDirectory(): string {
|
|
113
154
|
const maybe = [
|
|
155
|
+
join(process.cwd(), `dist/${this.env.REACT_SERVER_DIST}`),
|
|
114
156
|
join(process.cwd(), this.env.REACT_SERVER_DIST),
|
|
115
|
-
join(process.cwd(), "..", this.env.REACT_SERVER_DIST),
|
|
116
157
|
];
|
|
117
158
|
|
|
118
159
|
for (const it of maybe) {
|
|
@@ -131,14 +172,18 @@ export class ReactServerProvider {
|
|
|
131
172
|
});
|
|
132
173
|
}
|
|
133
174
|
|
|
134
|
-
protected async configureVite() {
|
|
135
|
-
|
|
175
|
+
protected async configureVite(ssrEnabled: boolean) {
|
|
176
|
+
if (!ssrEnabled) {
|
|
177
|
+
// do nothing, vite will handle everything for us
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
136
181
|
this.log.info("SSR (vite) OK");
|
|
137
|
-
|
|
138
|
-
const
|
|
182
|
+
|
|
183
|
+
const url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;
|
|
139
184
|
|
|
140
185
|
await this.registerPages(() =>
|
|
141
|
-
fetch(
|
|
186
|
+
fetch(`${url}/index.html`)
|
|
142
187
|
.then((it) => it.text())
|
|
143
188
|
.catch(() => undefined),
|
|
144
189
|
);
|
|
@@ -147,7 +192,7 @@ export class ReactServerProvider {
|
|
|
147
192
|
/**
|
|
148
193
|
* For testing purposes, creates a render function that can be used.
|
|
149
194
|
*/
|
|
150
|
-
protected createRenderFunction(name: string) {
|
|
195
|
+
protected createRenderFunction(name: string, withIndex = false) {
|
|
151
196
|
return async (
|
|
152
197
|
options: {
|
|
153
198
|
params?: Record<string, string>;
|
|
@@ -155,27 +200,39 @@ export class ReactServerProvider {
|
|
|
155
200
|
} = {},
|
|
156
201
|
) => {
|
|
157
202
|
const page = this.pageDescriptorProvider.page(name);
|
|
203
|
+
const url = new URL(this.pageDescriptorProvider.url(name, options));
|
|
158
204
|
const context: PageRequest = {
|
|
159
|
-
url
|
|
205
|
+
url,
|
|
160
206
|
params: options.params ?? {},
|
|
161
207
|
query: options.query ?? {},
|
|
162
208
|
head: {},
|
|
163
209
|
onError: () => null,
|
|
164
210
|
};
|
|
165
211
|
|
|
166
|
-
// for testing
|
|
167
212
|
const state = await this.pageDescriptorProvider.createLayers(
|
|
168
213
|
page,
|
|
169
214
|
context,
|
|
170
215
|
);
|
|
171
216
|
|
|
172
|
-
|
|
217
|
+
if (!withIndex) {
|
|
218
|
+
return {
|
|
219
|
+
context,
|
|
220
|
+
html: renderToString(
|
|
221
|
+
this.pageDescriptorProvider.root(state, context),
|
|
222
|
+
),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
context,
|
|
228
|
+
html: this.renderToHtml(this.template ?? "", state, context),
|
|
229
|
+
};
|
|
173
230
|
};
|
|
174
231
|
}
|
|
175
232
|
|
|
176
233
|
protected createHandler(
|
|
177
234
|
page: PageRoute,
|
|
178
|
-
templateLoader:
|
|
235
|
+
templateLoader: TemplateLoader,
|
|
179
236
|
): ServerHandler {
|
|
180
237
|
return async (serverRequest) => {
|
|
181
238
|
const { url, reply, query, params } = serverRequest;
|
|
@@ -193,18 +250,43 @@ export class ReactServerProvider {
|
|
|
193
250
|
onError: () => null,
|
|
194
251
|
};
|
|
195
252
|
|
|
196
|
-
// -- links
|
|
197
253
|
if (this.alepha.has(ServerLinksProvider)) {
|
|
198
254
|
const srv = this.alepha.get(ServerLinksProvider);
|
|
255
|
+
const schema = apiLinksResponseSchema as any;
|
|
199
256
|
|
|
200
|
-
context.links =
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
257
|
+
context.links = this.alepha.parse(
|
|
258
|
+
schema,
|
|
259
|
+
await srv.getLinks({
|
|
260
|
+
user: serverRequest.user,
|
|
261
|
+
authorization: serverRequest.headers.authorization,
|
|
262
|
+
}),
|
|
263
|
+
) as any;
|
|
204
264
|
|
|
205
|
-
this.alepha.
|
|
265
|
+
this.alepha.context.set("links", context.links);
|
|
206
266
|
}
|
|
207
267
|
|
|
268
|
+
let target: PageRoute | undefined = page; // TODO: move to PageDescriptorProvider
|
|
269
|
+
while (target) {
|
|
270
|
+
if (page.can && !page.can()) {
|
|
271
|
+
// if the page is not accessible, return 403
|
|
272
|
+
reply.status = 403;
|
|
273
|
+
reply.headers["content-type"] = "text/plain";
|
|
274
|
+
return "Forbidden";
|
|
275
|
+
}
|
|
276
|
+
target = target.parent;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// TODO: SSR strategies
|
|
280
|
+
// - only when googlebot
|
|
281
|
+
// - only child pages
|
|
282
|
+
// if (page.client) {
|
|
283
|
+
// // if the page is a client-only page, return 404
|
|
284
|
+
// reply.status = 200;
|
|
285
|
+
// reply.headers["content-type"] = "text/html";
|
|
286
|
+
// reply.body = template;
|
|
287
|
+
// return;
|
|
288
|
+
// }
|
|
289
|
+
|
|
208
290
|
await this.alepha.emit(
|
|
209
291
|
"react:server:render",
|
|
210
292
|
{
|
|
@@ -216,69 +298,104 @@ export class ReactServerProvider {
|
|
|
216
298
|
},
|
|
217
299
|
);
|
|
218
300
|
|
|
301
|
+
this.serverTimingProvider.beginTiming("createLayers");
|
|
302
|
+
|
|
219
303
|
const state = await this.pageDescriptorProvider.createLayers(
|
|
220
304
|
page,
|
|
221
305
|
context,
|
|
222
306
|
);
|
|
223
307
|
|
|
308
|
+
this.serverTimingProvider.endTiming("createLayers");
|
|
309
|
+
|
|
224
310
|
if (state.redirect) {
|
|
225
311
|
return reply.redirect(state.redirect);
|
|
226
312
|
}
|
|
227
313
|
|
|
228
|
-
const element = this.pageDescriptorProvider.root(state, context);
|
|
229
|
-
const app = renderToString(element);
|
|
230
|
-
|
|
231
|
-
const hydrationData = {
|
|
232
|
-
links: context.links,
|
|
233
|
-
layers: state.layers.map((it) => ({
|
|
234
|
-
...it,
|
|
235
|
-
error: it.error
|
|
236
|
-
? {
|
|
237
|
-
...it.error,
|
|
238
|
-
name: it.error.name,
|
|
239
|
-
message: it.error.message,
|
|
240
|
-
stack: it.error.stack, // TODO: Hide stack in production ?
|
|
241
|
-
}
|
|
242
|
-
: undefined,
|
|
243
|
-
index: undefined,
|
|
244
|
-
path: undefined,
|
|
245
|
-
element: undefined,
|
|
246
|
-
})),
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
// create hydration data
|
|
250
|
-
const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
|
|
251
|
-
|
|
252
|
-
const response = {
|
|
253
|
-
html: template,
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
reply.status = 200;
|
|
257
314
|
reply.headers["content-type"] = "text/html";
|
|
315
|
+
|
|
316
|
+
// by default, disable caching for SSR responses
|
|
317
|
+
// some plugins may override this
|
|
258
318
|
reply.headers["cache-control"] =
|
|
259
319
|
"no-store, no-cache, must-revalidate, proxy-revalidate";
|
|
260
320
|
reply.headers.pragma = "no-cache";
|
|
261
321
|
reply.headers.expires = "0";
|
|
262
322
|
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// inject head meta
|
|
267
|
-
if (context.head) {
|
|
268
|
-
response.html = this.headProvider.renderHead(
|
|
269
|
-
response.html,
|
|
270
|
-
context.head,
|
|
271
|
-
);
|
|
323
|
+
// don't cache user links
|
|
324
|
+
if (page.cache && serverRequest.user) {
|
|
325
|
+
delete context.links;
|
|
272
326
|
}
|
|
273
327
|
|
|
274
|
-
|
|
275
|
-
// { response: { html: string }, request, state }
|
|
328
|
+
const html = this.renderToHtml(template, state, context);
|
|
276
329
|
|
|
277
|
-
|
|
330
|
+
page.afterHandler?.(serverRequest);
|
|
331
|
+
|
|
332
|
+
return html;
|
|
278
333
|
};
|
|
279
334
|
}
|
|
280
335
|
|
|
281
|
-
|
|
336
|
+
public renderToHtml(
|
|
337
|
+
template: string,
|
|
338
|
+
state: RouterState,
|
|
339
|
+
context: PageReactContext,
|
|
340
|
+
) {
|
|
341
|
+
const element = this.pageDescriptorProvider.root(state, context);
|
|
342
|
+
|
|
343
|
+
this.serverTimingProvider.beginTiming("renderToString");
|
|
344
|
+
|
|
345
|
+
let app = "";
|
|
346
|
+
try {
|
|
347
|
+
app = renderToString(element);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
this.log.error("Error during SSR", error);
|
|
350
|
+
app = renderToString(context.onError(error as Error));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
this.serverTimingProvider.endTiming("renderToString");
|
|
354
|
+
|
|
355
|
+
const hydrationData: ReactHydrationState = {
|
|
356
|
+
links: context.links,
|
|
357
|
+
layers: state.layers.map((it) => ({
|
|
358
|
+
...it,
|
|
359
|
+
error: it.error
|
|
360
|
+
? {
|
|
361
|
+
...it.error,
|
|
362
|
+
name: it.error.name,
|
|
363
|
+
message: it.error.message,
|
|
364
|
+
stack: it.error.stack, // TODO: Hide stack in production ?
|
|
365
|
+
}
|
|
366
|
+
: undefined,
|
|
367
|
+
index: undefined,
|
|
368
|
+
path: undefined,
|
|
369
|
+
element: undefined,
|
|
370
|
+
})),
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// create hydration data
|
|
374
|
+
const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
|
|
375
|
+
|
|
376
|
+
const response = {
|
|
377
|
+
html: template,
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// inject app into template
|
|
381
|
+
this.fillTemplate(response, app, script);
|
|
382
|
+
|
|
383
|
+
// inject head meta
|
|
384
|
+
if (context.head) {
|
|
385
|
+
response.html = this.headProvider.renderHead(response.html, context.head);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// TODO: hook for plugins "react:server:template"
|
|
389
|
+
// { response: { html: string }, request, state }
|
|
390
|
+
|
|
391
|
+
return response.html;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
protected fillTemplate(
|
|
395
|
+
response: { html: string },
|
|
396
|
+
app: string,
|
|
397
|
+
script: string,
|
|
398
|
+
) {
|
|
282
399
|
if (this.ROOT_DIV_REGEX.test(response.html)) {
|
|
283
400
|
// replace contents of the existing <div id="root">
|
|
284
401
|
response.html = response.html.replace(
|
|
@@ -305,3 +422,5 @@ export class ReactServerProvider {
|
|
|
305
422
|
}
|
|
306
423
|
}
|
|
307
424
|
}
|
|
425
|
+
|
|
426
|
+
type TemplateLoader = () => Promise<string | undefined>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.cjs","sources":["../src/index.browser.ts"],"sourcesContent":["import { $inject, Alepha, __bind } from \"@alepha/core\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport { BrowserRouterProvider } from \"./providers/BrowserRouterProvider.ts\";\nimport { PageDescriptorProvider } from \"./providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./providers/ReactBrowserProvider.ts\";\n\nexport * from \"./index.shared\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\n\nexport class ReactModule {\n\tprotected readonly alepha = $inject(Alepha);\n\n\tconstructor() {\n\t\tthis.alepha //\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactBrowserProvider)\n\t\t\t.with(BrowserRouterProvider);\n\t}\n}\n\n__bind($page, ReactModule);\n"],"names":["$inject","Alepha","PageDescriptorProvider","ReactBrowserProvider","BrowserRouterProvider","__bind","$page"],"mappings":";;;;;;;;;;AAQO,MAAM,WAAW,CAAC;AACzB,EAAE,MAAM,GAAGA,YAAO,CAACC,WAAM,CAAC;AAC1B,EAAE,WAAW,GAAG;AAChB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAACC,gCAAsB,CAAC,CAAC,IAAI,CAACC,8BAAoB,CAAC,CAAC,IAAI,CAACC,+BAAqB,CAAC;AACnG;AACA;AACAC,WAAM,CAACC,eAAK,EAAE,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","sources":["../src/index.browser.ts"],"sourcesContent":["import { $inject, Alepha, __bind } from \"@alepha/core\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport { BrowserRouterProvider } from \"./providers/BrowserRouterProvider.ts\";\nimport { PageDescriptorProvider } from \"./providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./providers/ReactBrowserProvider.ts\";\n\nexport * from \"./index.shared\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\n\nexport class ReactModule {\n\tprotected readonly alepha = $inject(Alepha);\n\n\tconstructor() {\n\t\tthis.alepha //\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactBrowserProvider)\n\t\t\t.with(BrowserRouterProvider);\n\t}\n}\n\n__bind($page, ReactModule);\n"],"names":[],"mappings":";;;;;;;;;AAQO,MAAM,WAAW,CAAC;AACzB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;AAC1B,EAAE,WAAW,GAAG;AAChB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC;AACnG;AACA;AACA,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC;;;;"}
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/providers/ServerHeadProvider.ts","../src/providers/ReactServerProvider.ts","../src/index.ts"],"sourcesContent":["export interface Head {\n\ttitle?: string;\n\thtmlAttributes?: Record<string, string>;\n\tbodyAttributes?: Record<string, string>;\n\tmeta?: Array<{ name: string; content: string }>;\n}\n\nexport class ServerHeadProvider {\n\trenderHead(template: string, head: Head): string {\n\t\tlet result = template;\n\n\t\t// Inject htmlAttributes\n\t\tconst htmlAttributes = head.htmlAttributes;\n\t\tif (htmlAttributes) {\n\t\t\tresult = result.replace(\n\t\t\t\t/<html([^>]*)>/i,\n\t\t\t\t(_, existingAttrs) =>\n\t\t\t\t\t`<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`,\n\t\t\t);\n\t\t}\n\n\t\t// Inject bodyAttributes\n\t\tconst bodyAttributes = head.bodyAttributes;\n\t\tif (bodyAttributes) {\n\t\t\tresult = result.replace(\n\t\t\t\t/<body([^>]*)>/i,\n\t\t\t\t(_, existingAttrs) =>\n\t\t\t\t\t`<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`,\n\t\t\t);\n\t\t}\n\n\t\t// Build head content\n\t\tlet headContent = \"\";\n\t\tconst title = head.title;\n\t\tif (title) {\n\t\t\tif (template.includes(\"<title>\")) {\n\t\t\t\tresult = result.replace(\n\t\t\t\t\t/<title>(.*?)<\\/title>/i,\n\t\t\t\t\t() => `<title>${this.escapeHtml(title)}</title>`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\theadContent += `<title>${this.escapeHtml(title)}</title>\\n`;\n\t\t\t}\n\t\t}\n\n\t\tif (head.meta) {\n\t\t\tfor (const meta of head.meta) {\n\t\t\t\theadContent += `<meta name=\"${this.escapeHtml(meta.name)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Inject into <head>...</head>\n\t\tresult = result.replace(\n\t\t\t/<head([^>]*)>(.*?)<\\/head>/is,\n\t\t\t(_, existingAttrs, existingHead) =>\n\t\t\t\t`<head${existingAttrs}>${existingHead}${headContent}</head>`,\n\t\t);\n\n\t\treturn result.trim();\n\t}\n\n\tmergeAttributes(existing: string, attrs: Record<string, string>): string {\n\t\tconst existingAttrs = this.parseAttributes(existing);\n\t\tconst merged = { ...existingAttrs, ...attrs };\n\t\treturn Object.entries(merged)\n\t\t\t.map(([k, v]) => ` ${k}=\"${this.escapeHtml(v)}\"`)\n\t\t\t.join(\"\");\n\t}\n\n\tparseAttributes(attrStr: string): Record<string, string> {\n\t\tconst attrs: Record<string, string> = {};\n\t\tconst attrRegex = /([^\\s=]+)(?:=\"([^\"]*)\")?/g;\n\t\tlet match: RegExpExecArray | null = attrRegex.exec(attrStr);\n\n\t\twhile (match) {\n\t\t\tattrs[match[1]] = match[2] ?? \"\";\n\t\t\tmatch = attrRegex.exec(attrStr);\n\t\t}\n\n\t\treturn attrs;\n\t}\n\n\tescapeHtml(str: string): string {\n\t\treturn str\n\t\t\t.replace(/&/g, \"&\")\n\t\t\t.replace(/</g, \"<\")\n\t\t\t.replace(/>/g, \">\")\n\t\t\t.replace(/\"/g, \""\")\n\t\t\t.replace(/'/g, \"'\");\n\t}\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n\t$hook,\n\t$inject,\n\t$logger,\n\tAlepha,\n\tOPTIONS,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport {\n\ttype ServerHandler,\n\tServerLinksProvider,\n\tServerRouterProvider,\n} from \"@alepha/server\";\nimport { ServerStaticProvider } from \"@alepha/server-static\";\nimport { renderToString } from \"react-dom/server\";\nimport { $page } from \"../descriptors/$page.ts\";\nimport {\n\tPageDescriptorProvider,\n\ttype PageRequest,\n\ttype PageRoute,\n} from \"./PageDescriptorProvider.ts\";\nimport { ServerHeadProvider } from \"./ServerHeadProvider.ts\";\n\nexport const envSchema = t.object({\n\tREACT_SERVER_DIST: t.string({ default: \"client\" }),\n\tREACT_SERVER_PREFIX: t.string({ default: \"\" }),\n\tREACT_SSR_ENABLED: t.boolean({ default: false }),\n\tREACT_ROOT_ID: t.string({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n\tinterface State {\n\t\t\"ReactServerProvider.template\"?: string;\n\t\t\"ReactServerProvider.ssr\"?: boolean;\n\t}\n}\n\nexport class ReactServerProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageDescriptorProvider = $inject(PageDescriptorProvider);\n\tprotected readonly serverStaticProvider = $inject(ServerStaticProvider);\n\tprotected readonly serverRouterProvider = $inject(ServerRouterProvider);\n\tprotected readonly headProvider = $inject(ServerHeadProvider);\n\tprotected readonly env = $inject(envSchema);\n\tprotected readonly ROOT_DIV_REGEX = new RegExp(\n\t\t`<div([^>]*)\\\\s+id=[\"']${this.env.REACT_ROOT_ID}[\"']([^>]*)>(.*?)<\\\\/div>`,\n\t\t\"is\",\n\t);\n\n\tprotected readonly configure = $hook({\n\t\tname: \"configure\",\n\t\thandler: async () => {\n\t\t\tconst pages = this.alepha.getDescriptorValues($page);\n\t\t\tif (pages.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const { key, instance, value } of pages) {\n\t\t\t\tconst name = value[OPTIONS].name ?? key;\n\n\t\t\t\tif (this.alepha.isTest()) {\n\t\t\t\t\tinstance[key].render = this.createRenderFunction(name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.alepha.isServerless() === \"vite\") {\n\t\t\t\tawait this.configureVite();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet root = \"\";\n\t\t\tif (!this.alepha.isServerless()) {\n\t\t\t\troot = this.getPublicDirectory();\n\n\t\t\t\tif (!root) {\n\t\t\t\t\tthis.log.warn(\"Missing static files, SSR will be disabled\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tawait this.configureStaticServer(root);\n\t\t\t}\n\n\t\t\tconst template =\n\t\t\t\tthis.alepha.state(\"ReactServerProvider.template\") ??\n\t\t\t\t(await readFile(join(root, \"index.html\"), \"utf-8\"));\n\n\t\t\tawait this.registerPages(async () => template);\n\n\t\t\tthis.alepha.state(\"ReactServerProvider.ssr\", true);\n\t\t},\n\t});\n\n\tprotected async registerPages(\n\t\ttemplateLoader: () => Promise<string | undefined>,\n\t) {\n\t\tfor (const page of this.pageDescriptorProvider.getPages()) {\n\t\t\tthis.log.debug(`+ ${page.match} -> ${page.name}`);\n\t\t\tawait this.serverRouterProvider.route({\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: page.match,\n\t\t\t\thandler: this.createHandler(page, templateLoader),\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected getPublicDirectory(): string {\n\t\tconst maybe = [\n\t\t\tjoin(process.cwd(), this.env.REACT_SERVER_DIST),\n\t\t\tjoin(process.cwd(), \"..\", this.env.REACT_SERVER_DIST),\n\t\t];\n\n\t\tfor (const it of maybe) {\n\t\t\tif (existsSync(it)) {\n\t\t\t\treturn it;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tprotected async configureStaticServer(root: string) {\n\t\tawait this.serverStaticProvider.serve({\n\t\t\troot,\n\t\t\tpath: this.env.REACT_SERVER_PREFIX,\n\t\t});\n\t}\n\n\tprotected async configureVite() {\n\t\tconst url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;\n\t\tthis.log.info(\"SSR (vite) OK\");\n\t\tthis.alepha.state(\"ReactServerProvider.ssr\", true);\n\t\tconst templateUrl = `${url}/index.html`;\n\n\t\tawait this.registerPages(() =>\n\t\t\tfetch(templateUrl)\n\t\t\t\t.then((it) => it.text())\n\t\t\t\t.catch(() => undefined),\n\t\t);\n\t}\n\n\t/**\n\t * For testing purposes, creates a render function that can be used.\n\t */\n\tprotected createRenderFunction(name: string) {\n\t\treturn async (\n\t\t\toptions: {\n\t\t\t\tparams?: Record<string, string>;\n\t\t\t\tquery?: Record<string, string>;\n\t\t\t} = {},\n\t\t) => {\n\t\t\tconst page = this.pageDescriptorProvider.page(name);\n\t\t\tconst context: PageRequest = {\n\t\t\t\turl: new URL(\"http://localhost\"),\n\t\t\t\tparams: options.params ?? {},\n\t\t\t\tquery: options.query ?? {},\n\t\t\t\thead: {},\n\t\t\t\tonError: () => null,\n\t\t\t};\n\n\t\t\t// for testing\n\t\t\tconst state = await this.pageDescriptorProvider.createLayers(\n\t\t\t\tpage,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\treturn renderToString(this.pageDescriptorProvider.root(state, context));\n\t\t};\n\t}\n\n\tprotected createHandler(\n\t\tpage: PageRoute,\n\t\ttemplateLoader: () => Promise<string | undefined>,\n\t): ServerHandler {\n\t\treturn async (serverRequest) => {\n\t\t\tconst { url, reply, query, params } = serverRequest;\n\t\t\tconst template = await templateLoader();\n\t\t\tif (!template) {\n\t\t\t\tthrow new Error(\"Template not found\");\n\t\t\t}\n\n\t\t\tconst context: PageRequest = {\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tquery,\n\t\t\t\t// plugins\n\t\t\t\thead: {},\n\t\t\t\tonError: () => null,\n\t\t\t};\n\n\t\t\t// -- links\n\t\t\tif (this.alepha.has(ServerLinksProvider)) {\n\t\t\t\tconst srv = this.alepha.get(ServerLinksProvider);\n\n\t\t\t\tcontext.links = await srv.getLinks({\n\t\t\t\t\tuser: serverRequest.user,\n\t\t\t\t\tauthorization: serverRequest.headers.authorization,\n\t\t\t\t});\n\n\t\t\t\tthis.alepha.als.set(\"links\", context.links);\n\t\t\t}\n\n\t\t\tawait this.alepha.emit(\n\t\t\t\t\"react:server:render\",\n\t\t\t\t{\n\t\t\t\t\trequest: serverRequest,\n\t\t\t\t\tpageRequest: context,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlog: false,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst state = await this.pageDescriptorProvider.createLayers(\n\t\t\t\tpage,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tif (state.redirect) {\n\t\t\t\treturn reply.redirect(state.redirect);\n\t\t\t}\n\n\t\t\tconst element = this.pageDescriptorProvider.root(state, context);\n\t\t\tconst app = renderToString(element);\n\n\t\t\tconst hydrationData = {\n\t\t\t\tlinks: context.links,\n\t\t\t\tlayers: state.layers.map((it) => ({\n\t\t\t\t\t...it,\n\t\t\t\t\terror: it.error\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...it.error,\n\t\t\t\t\t\t\t\tname: it.error.name,\n\t\t\t\t\t\t\t\tmessage: it.error.message,\n\t\t\t\t\t\t\t\tstack: it.error.stack, // TODO: Hide stack in production ?\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tindex: undefined,\n\t\t\t\t\tpath: undefined,\n\t\t\t\t\telement: undefined,\n\t\t\t\t})),\n\t\t\t};\n\n\t\t\t// create hydration data\n\t\t\tconst script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;\n\n\t\t\tconst response = {\n\t\t\t\thtml: template,\n\t\t\t};\n\n\t\t\treply.status = 200;\n\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\t\t\treply.headers[\"cache-control\"] =\n\t\t\t\t\"no-store, no-cache, must-revalidate, proxy-revalidate\";\n\t\t\treply.headers.pragma = \"no-cache\";\n\t\t\treply.headers.expires = \"0\";\n\n\t\t\t// inject app into template\n\t\t\tthis.fillTemplate(response, app, script);\n\n\t\t\t// inject head meta\n\t\t\tif (context.head) {\n\t\t\t\tresponse.html = this.headProvider.renderHead(\n\t\t\t\t\tresponse.html,\n\t\t\t\t\tcontext.head,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// TODO: hook for plugins \"react:server:template\"\n\t\t\t// { response: { html: string }, request, state }\n\n\t\t\treturn response.html;\n\t\t};\n\t}\n\n\tfillTemplate(response: { html: string }, app: string, script: string) {\n\t\tif (this.ROOT_DIV_REGEX.test(response.html)) {\n\t\t\t// replace contents of the existing <div id=\"root\">\n\t\t\tresponse.html = response.html.replace(\n\t\t\t\tthis.ROOT_DIV_REGEX,\n\t\t\t\t(_match, beforeId, afterId) => {\n\t\t\t\t\treturn `<div${beforeId} id=\"${this.env.REACT_ROOT_ID}\"${afterId}>${app}</div>`;\n\t\t\t\t},\n\t\t\t);\n\t\t} else {\n\t\t\tconst bodyOpenTag = /<body([^>]*)>/i;\n\t\t\tif (bodyOpenTag.test(response.html)) {\n\t\t\t\tresponse.html = response.html.replace(bodyOpenTag, (match) => {\n\t\t\t\t\treturn `${match}\\n<div id=\"${this.env.REACT_ROOT_ID}\">${app}</div>`;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst bodyCloseTagRegex = /<\\/body>/i;\n\t\tif (bodyCloseTagRegex.test(response.html)) {\n\t\t\tresponse.html = response.html.replace(\n\t\t\t\tbodyCloseTagRegex,\n\t\t\t\t`${script}\\n</body>`,\n\t\t\t);\n\t\t}\n\t}\n}\n","import { $inject, Alepha, __bind } from \"@alepha/core\";\nimport {\n\tServerLinksProvider,\n\tServerModule,\n\ttype ServerRequest,\n} from \"@alepha/server\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport {\n\tPageDescriptorProvider,\n\ttype PageReactContext,\n\ttype PageRequest,\n\ttype RouterState,\n} from \"./providers/PageDescriptorProvider.ts\";\nimport type { ReactHydrationState } from \"./providers/ReactBrowserProvider.ts\";\nimport { ReactServerProvider } from \"./providers/ReactServerProvider.ts\";\nexport { default as NestedView } from \"./components/NestedView.tsx\";\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/PageDescriptorProvider.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\nexport * from \"./providers/ReactServerProvider.ts\";\nexport * from \"./errors/RedirectionError.ts\";\n\ndeclare module \"@alepha/core\" {\n\tinterface Hooks {\n\t\t\"react:browser:render\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t\thydration?: ReactHydrationState;\n\t\t};\n\t\t\"react:server:render\": {\n\t\t\trequest: ServerRequest;\n\t\t\tpageRequest: PageRequest;\n\t\t};\n\n\t\t\"react:transition:begin\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t\t\"react:transition:success\": {\n\t\t\tstate: RouterState;\n\t\t};\n\t\t\"react:transition:error\": {\n\t\t\terror: Error;\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t\t\"react:transition:end\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t}\n}\n\nexport class ReactModule {\n\tprotected readonly alepha = $inject(Alepha);\n\n\tconstructor() {\n\t\tthis.alepha //\n\t\t\t.with(ServerModule)\n\t\t\t.with(ServerLinksProvider)\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactServerProvider);\n\t}\n}\n\n__bind($page, ReactModule);\n"],"names":["t","$logger","$inject","Alepha","PageDescriptorProvider","ServerStaticProvider","ServerRouterProvider","$hook","$page","OPTIONS","readFile","join","existsSync","renderToString","ServerLinksProvider","ServerModule","__bind"],"mappings":"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"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/providers/ServerHeadProvider.ts","../src/providers/ReactServerProvider.ts","../src/index.ts"],"sourcesContent":["export interface Head {\n\ttitle?: string;\n\thtmlAttributes?: Record<string, string>;\n\tbodyAttributes?: Record<string, string>;\n\tmeta?: Array<{ name: string; content: string }>;\n}\n\nexport class ServerHeadProvider {\n\trenderHead(template: string, head: Head): string {\n\t\tlet result = template;\n\n\t\t// Inject htmlAttributes\n\t\tconst htmlAttributes = head.htmlAttributes;\n\t\tif (htmlAttributes) {\n\t\t\tresult = result.replace(\n\t\t\t\t/<html([^>]*)>/i,\n\t\t\t\t(_, existingAttrs) =>\n\t\t\t\t\t`<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`,\n\t\t\t);\n\t\t}\n\n\t\t// Inject bodyAttributes\n\t\tconst bodyAttributes = head.bodyAttributes;\n\t\tif (bodyAttributes) {\n\t\t\tresult = result.replace(\n\t\t\t\t/<body([^>]*)>/i,\n\t\t\t\t(_, existingAttrs) =>\n\t\t\t\t\t`<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`,\n\t\t\t);\n\t\t}\n\n\t\t// Build head content\n\t\tlet headContent = \"\";\n\t\tconst title = head.title;\n\t\tif (title) {\n\t\t\tif (template.includes(\"<title>\")) {\n\t\t\t\tresult = result.replace(\n\t\t\t\t\t/<title>(.*?)<\\/title>/i,\n\t\t\t\t\t() => `<title>${this.escapeHtml(title)}</title>`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\theadContent += `<title>${this.escapeHtml(title)}</title>\\n`;\n\t\t\t}\n\t\t}\n\n\t\tif (head.meta) {\n\t\t\tfor (const meta of head.meta) {\n\t\t\t\theadContent += `<meta name=\"${this.escapeHtml(meta.name)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Inject into <head>...</head>\n\t\tresult = result.replace(\n\t\t\t/<head([^>]*)>(.*?)<\\/head>/is,\n\t\t\t(_, existingAttrs, existingHead) =>\n\t\t\t\t`<head${existingAttrs}>${existingHead}${headContent}</head>`,\n\t\t);\n\n\t\treturn result.trim();\n\t}\n\n\tmergeAttributes(existing: string, attrs: Record<string, string>): string {\n\t\tconst existingAttrs = this.parseAttributes(existing);\n\t\tconst merged = { ...existingAttrs, ...attrs };\n\t\treturn Object.entries(merged)\n\t\t\t.map(([k, v]) => ` ${k}=\"${this.escapeHtml(v)}\"`)\n\t\t\t.join(\"\");\n\t}\n\n\tparseAttributes(attrStr: string): Record<string, string> {\n\t\tconst attrs: Record<string, string> = {};\n\t\tconst attrRegex = /([^\\s=]+)(?:=\"([^\"]*)\")?/g;\n\t\tlet match: RegExpExecArray | null = attrRegex.exec(attrStr);\n\n\t\twhile (match) {\n\t\t\tattrs[match[1]] = match[2] ?? \"\";\n\t\t\tmatch = attrRegex.exec(attrStr);\n\t\t}\n\n\t\treturn attrs;\n\t}\n\n\tescapeHtml(str: string): string {\n\t\treturn str\n\t\t\t.replace(/&/g, \"&\")\n\t\t\t.replace(/</g, \"<\")\n\t\t\t.replace(/>/g, \">\")\n\t\t\t.replace(/\"/g, \""\")\n\t\t\t.replace(/'/g, \"'\");\n\t}\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n\t$hook,\n\t$inject,\n\t$logger,\n\tAlepha,\n\tOPTIONS,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport {\n\ttype ServerHandler,\n\tServerLinksProvider,\n\tServerRouterProvider,\n} from \"@alepha/server\";\nimport { ServerStaticProvider } from \"@alepha/server-static\";\nimport { renderToString } from \"react-dom/server\";\nimport { $page } from \"../descriptors/$page.ts\";\nimport {\n\tPageDescriptorProvider,\n\ttype PageRequest,\n\ttype PageRoute,\n} from \"./PageDescriptorProvider.ts\";\nimport { ServerHeadProvider } from \"./ServerHeadProvider.ts\";\n\nexport const envSchema = t.object({\n\tREACT_SERVER_DIST: t.string({ default: \"client\" }),\n\tREACT_SERVER_PREFIX: t.string({ default: \"\" }),\n\tREACT_SSR_ENABLED: t.boolean({ default: false }),\n\tREACT_ROOT_ID: t.string({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n\tinterface State {\n\t\t\"ReactServerProvider.template\"?: string;\n\t\t\"ReactServerProvider.ssr\"?: boolean;\n\t}\n}\n\nexport class ReactServerProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageDescriptorProvider = $inject(PageDescriptorProvider);\n\tprotected readonly serverStaticProvider = $inject(ServerStaticProvider);\n\tprotected readonly serverRouterProvider = $inject(ServerRouterProvider);\n\tprotected readonly headProvider = $inject(ServerHeadProvider);\n\tprotected readonly env = $inject(envSchema);\n\tprotected readonly ROOT_DIV_REGEX = new RegExp(\n\t\t`<div([^>]*)\\\\s+id=[\"']${this.env.REACT_ROOT_ID}[\"']([^>]*)>(.*?)<\\\\/div>`,\n\t\t\"is\",\n\t);\n\n\tprotected readonly configure = $hook({\n\t\tname: \"configure\",\n\t\thandler: async () => {\n\t\t\tconst pages = this.alepha.getDescriptorValues($page);\n\t\t\tif (pages.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const { key, instance, value } of pages) {\n\t\t\t\tconst name = value[OPTIONS].name ?? key;\n\n\t\t\t\tif (this.alepha.isTest()) {\n\t\t\t\t\tinstance[key].render = this.createRenderFunction(name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.alepha.isServerless() === \"vite\") {\n\t\t\t\tawait this.configureVite();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet root = \"\";\n\t\t\tif (!this.alepha.isServerless()) {\n\t\t\t\troot = this.getPublicDirectory();\n\n\t\t\t\tif (!root) {\n\t\t\t\t\tthis.log.warn(\"Missing static files, SSR will be disabled\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tawait this.configureStaticServer(root);\n\t\t\t}\n\n\t\t\tconst template =\n\t\t\t\tthis.alepha.state(\"ReactServerProvider.template\") ??\n\t\t\t\t(await readFile(join(root, \"index.html\"), \"utf-8\"));\n\n\t\t\tawait this.registerPages(async () => template);\n\n\t\t\tthis.alepha.state(\"ReactServerProvider.ssr\", true);\n\t\t},\n\t});\n\n\tprotected async registerPages(\n\t\ttemplateLoader: () => Promise<string | undefined>,\n\t) {\n\t\tfor (const page of this.pageDescriptorProvider.getPages()) {\n\t\t\tthis.log.debug(`+ ${page.match} -> ${page.name}`);\n\t\t\tawait this.serverRouterProvider.route({\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: page.match,\n\t\t\t\thandler: this.createHandler(page, templateLoader),\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected getPublicDirectory(): string {\n\t\tconst maybe = [\n\t\t\tjoin(process.cwd(), this.env.REACT_SERVER_DIST),\n\t\t\tjoin(process.cwd(), \"..\", this.env.REACT_SERVER_DIST),\n\t\t];\n\n\t\tfor (const it of maybe) {\n\t\t\tif (existsSync(it)) {\n\t\t\t\treturn it;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tprotected async configureStaticServer(root: string) {\n\t\tawait this.serverStaticProvider.serve({\n\t\t\troot,\n\t\t\tpath: this.env.REACT_SERVER_PREFIX,\n\t\t});\n\t}\n\n\tprotected async configureVite() {\n\t\tconst url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;\n\t\tthis.log.info(\"SSR (vite) OK\");\n\t\tthis.alepha.state(\"ReactServerProvider.ssr\", true);\n\t\tconst templateUrl = `${url}/index.html`;\n\n\t\tawait this.registerPages(() =>\n\t\t\tfetch(templateUrl)\n\t\t\t\t.then((it) => it.text())\n\t\t\t\t.catch(() => undefined),\n\t\t);\n\t}\n\n\t/**\n\t * For testing purposes, creates a render function that can be used.\n\t */\n\tprotected createRenderFunction(name: string) {\n\t\treturn async (\n\t\t\toptions: {\n\t\t\t\tparams?: Record<string, string>;\n\t\t\t\tquery?: Record<string, string>;\n\t\t\t} = {},\n\t\t) => {\n\t\t\tconst page = this.pageDescriptorProvider.page(name);\n\t\t\tconst context: PageRequest = {\n\t\t\t\turl: new URL(\"http://localhost\"),\n\t\t\t\tparams: options.params ?? {},\n\t\t\t\tquery: options.query ?? {},\n\t\t\t\thead: {},\n\t\t\t\tonError: () => null,\n\t\t\t};\n\n\t\t\t// for testing\n\t\t\tconst state = await this.pageDescriptorProvider.createLayers(\n\t\t\t\tpage,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\treturn renderToString(this.pageDescriptorProvider.root(state, context));\n\t\t};\n\t}\n\n\tprotected createHandler(\n\t\tpage: PageRoute,\n\t\ttemplateLoader: () => Promise<string | undefined>,\n\t): ServerHandler {\n\t\treturn async (serverRequest) => {\n\t\t\tconst { url, reply, query, params } = serverRequest;\n\t\t\tconst template = await templateLoader();\n\t\t\tif (!template) {\n\t\t\t\tthrow new Error(\"Template not found\");\n\t\t\t}\n\n\t\t\tconst context: PageRequest = {\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tquery,\n\t\t\t\t// plugins\n\t\t\t\thead: {},\n\t\t\t\tonError: () => null,\n\t\t\t};\n\n\t\t\t// -- links\n\t\t\tif (this.alepha.has(ServerLinksProvider)) {\n\t\t\t\tconst srv = this.alepha.get(ServerLinksProvider);\n\n\t\t\t\tcontext.links = await srv.getLinks({\n\t\t\t\t\tuser: serverRequest.user,\n\t\t\t\t\tauthorization: serverRequest.headers.authorization,\n\t\t\t\t});\n\n\t\t\t\tthis.alepha.als.set(\"links\", context.links);\n\t\t\t}\n\n\t\t\tawait this.alepha.emit(\n\t\t\t\t\"react:server:render\",\n\t\t\t\t{\n\t\t\t\t\trequest: serverRequest,\n\t\t\t\t\tpageRequest: context,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlog: false,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst state = await this.pageDescriptorProvider.createLayers(\n\t\t\t\tpage,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tif (state.redirect) {\n\t\t\t\treturn reply.redirect(state.redirect);\n\t\t\t}\n\n\t\t\tconst element = this.pageDescriptorProvider.root(state, context);\n\t\t\tconst app = renderToString(element);\n\n\t\t\tconst hydrationData = {\n\t\t\t\tlinks: context.links,\n\t\t\t\tlayers: state.layers.map((it) => ({\n\t\t\t\t\t...it,\n\t\t\t\t\terror: it.error\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...it.error,\n\t\t\t\t\t\t\t\tname: it.error.name,\n\t\t\t\t\t\t\t\tmessage: it.error.message,\n\t\t\t\t\t\t\t\tstack: it.error.stack, // TODO: Hide stack in production ?\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tindex: undefined,\n\t\t\t\t\tpath: undefined,\n\t\t\t\t\telement: undefined,\n\t\t\t\t})),\n\t\t\t};\n\n\t\t\t// create hydration data\n\t\t\tconst script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;\n\n\t\t\tconst response = {\n\t\t\t\thtml: template,\n\t\t\t};\n\n\t\t\treply.status = 200;\n\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\t\t\treply.headers[\"cache-control\"] =\n\t\t\t\t\"no-store, no-cache, must-revalidate, proxy-revalidate\";\n\t\t\treply.headers.pragma = \"no-cache\";\n\t\t\treply.headers.expires = \"0\";\n\n\t\t\t// inject app into template\n\t\t\tthis.fillTemplate(response, app, script);\n\n\t\t\t// inject head meta\n\t\t\tif (context.head) {\n\t\t\t\tresponse.html = this.headProvider.renderHead(\n\t\t\t\t\tresponse.html,\n\t\t\t\t\tcontext.head,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// TODO: hook for plugins \"react:server:template\"\n\t\t\t// { response: { html: string }, request, state }\n\n\t\t\treturn response.html;\n\t\t};\n\t}\n\n\tfillTemplate(response: { html: string }, app: string, script: string) {\n\t\tif (this.ROOT_DIV_REGEX.test(response.html)) {\n\t\t\t// replace contents of the existing <div id=\"root\">\n\t\t\tresponse.html = response.html.replace(\n\t\t\t\tthis.ROOT_DIV_REGEX,\n\t\t\t\t(_match, beforeId, afterId) => {\n\t\t\t\t\treturn `<div${beforeId} id=\"${this.env.REACT_ROOT_ID}\"${afterId}>${app}</div>`;\n\t\t\t\t},\n\t\t\t);\n\t\t} else {\n\t\t\tconst bodyOpenTag = /<body([^>]*)>/i;\n\t\t\tif (bodyOpenTag.test(response.html)) {\n\t\t\t\tresponse.html = response.html.replace(bodyOpenTag, (match) => {\n\t\t\t\t\treturn `${match}\\n<div id=\"${this.env.REACT_ROOT_ID}\">${app}</div>`;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst bodyCloseTagRegex = /<\\/body>/i;\n\t\tif (bodyCloseTagRegex.test(response.html)) {\n\t\t\tresponse.html = response.html.replace(\n\t\t\t\tbodyCloseTagRegex,\n\t\t\t\t`${script}\\n</body>`,\n\t\t\t);\n\t\t}\n\t}\n}\n","import { $inject, Alepha, __bind } from \"@alepha/core\";\nimport {\n\tServerLinksProvider,\n\tServerModule,\n\ttype ServerRequest,\n} from \"@alepha/server\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport {\n\tPageDescriptorProvider,\n\ttype PageReactContext,\n\ttype PageRequest,\n\ttype RouterState,\n} from \"./providers/PageDescriptorProvider.ts\";\nimport type { ReactHydrationState } from \"./providers/ReactBrowserProvider.ts\";\nimport { ReactServerProvider } from \"./providers/ReactServerProvider.ts\";\nexport { default as NestedView } from \"./components/NestedView.tsx\";\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/PageDescriptorProvider.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\nexport * from \"./providers/ReactServerProvider.ts\";\nexport * from \"./errors/RedirectionError.ts\";\n\ndeclare module \"@alepha/core\" {\n\tinterface Hooks {\n\t\t\"react:browser:render\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t\thydration?: ReactHydrationState;\n\t\t};\n\t\t\"react:server:render\": {\n\t\t\trequest: ServerRequest;\n\t\t\tpageRequest: PageRequest;\n\t\t};\n\n\t\t\"react:transition:begin\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t\t\"react:transition:success\": {\n\t\t\tstate: RouterState;\n\t\t};\n\t\t\"react:transition:error\": {\n\t\t\terror: Error;\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t\t\"react:transition:end\": {\n\t\t\tstate: RouterState;\n\t\t\tcontext: PageReactContext;\n\t\t};\n\t}\n}\n\nexport class ReactModule {\n\tprotected readonly alepha = $inject(Alepha);\n\n\tconstructor() {\n\t\tthis.alepha //\n\t\t\t.with(ServerModule)\n\t\t\t.with(ServerLinksProvider)\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactServerProvider);\n\t}\n}\n\n__bind($page, ReactModule);\n"],"names":[],"mappings":"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"}
|