@alepha/react 0.7.0 → 0.7.1
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 +21 -21
- package/dist/index.browser.js +2 -3
- package/dist/index.cjs +151 -83
- package/dist/index.d.ts +360 -205
- package/dist/index.js +129 -62
- package/dist/{useActive-DjpZBEuB.cjs → useRouterState-AdK-XeM2.cjs} +270 -81
- package/dist/{useActive-BX41CqY8.js → useRouterState-qoMq7Y9J.js} +272 -84
- 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/descriptors/$page.ts +139 -30
- package/src/errors/RedirectionError.ts +4 -1
- package/src/hooks/RouterHookApi.ts +42 -5
- 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 +1 -1
- package/src/index.shared.ts +11 -5
- package/src/index.ts +3 -4
- package/src/providers/BrowserRouterProvider.ts +1 -1
- package/src/providers/PageDescriptorProvider.ts +72 -21
- package/src/providers/ReactBrowserProvider.ts +5 -8
- package/src/providers/ReactServerProvider.ts +197 -80
- 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
|
@@ -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,99 @@ 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
|
+
reply.status = 200;
|
|
124
|
+
|
|
125
|
+
// serve index.html for all unmatched routes
|
|
126
|
+
return this.template;
|
|
127
|
+
},
|
|
128
|
+
});
|
|
96
129
|
},
|
|
97
130
|
});
|
|
98
131
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
public get template() {
|
|
133
|
+
return this.alepha.state("ReactServerProvider.template");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
protected async registerPages(templateLoader: TemplateLoader) {
|
|
102
137
|
for (const page of this.pageDescriptorProvider.getPages()) {
|
|
138
|
+
if (page.children?.length) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
103
142
|
this.log.debug(`+ ${page.match} -> ${page.name}`);
|
|
143
|
+
|
|
104
144
|
await this.serverRouterProvider.route({
|
|
145
|
+
...page,
|
|
146
|
+
schema: undefined, // schema is handled by the page descriptor provider for now (shared by browser and server)
|
|
105
147
|
method: "GET",
|
|
106
148
|
path: page.match,
|
|
107
149
|
handler: this.createHandler(page, templateLoader),
|
|
@@ -111,8 +153,8 @@ export class ReactServerProvider {
|
|
|
111
153
|
|
|
112
154
|
protected getPublicDirectory(): string {
|
|
113
155
|
const maybe = [
|
|
156
|
+
join(process.cwd(), `dist/${this.env.REACT_SERVER_DIST}`),
|
|
114
157
|
join(process.cwd(), this.env.REACT_SERVER_DIST),
|
|
115
|
-
join(process.cwd(), "..", this.env.REACT_SERVER_DIST),
|
|
116
158
|
];
|
|
117
159
|
|
|
118
160
|
for (const it of maybe) {
|
|
@@ -131,14 +173,18 @@ export class ReactServerProvider {
|
|
|
131
173
|
});
|
|
132
174
|
}
|
|
133
175
|
|
|
134
|
-
protected async configureVite() {
|
|
135
|
-
|
|
176
|
+
protected async configureVite(ssrEnabled: boolean) {
|
|
177
|
+
if (!ssrEnabled) {
|
|
178
|
+
// do nothing, vite will handle everything for us
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
136
182
|
this.log.info("SSR (vite) OK");
|
|
137
|
-
|
|
138
|
-
const
|
|
183
|
+
|
|
184
|
+
const url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;
|
|
139
185
|
|
|
140
186
|
await this.registerPages(() =>
|
|
141
|
-
fetch(
|
|
187
|
+
fetch(`${url}/index.html`)
|
|
142
188
|
.then((it) => it.text())
|
|
143
189
|
.catch(() => undefined),
|
|
144
190
|
);
|
|
@@ -147,7 +193,7 @@ export class ReactServerProvider {
|
|
|
147
193
|
/**
|
|
148
194
|
* For testing purposes, creates a render function that can be used.
|
|
149
195
|
*/
|
|
150
|
-
protected createRenderFunction(name: string) {
|
|
196
|
+
protected createRenderFunction(name: string, withIndex = false) {
|
|
151
197
|
return async (
|
|
152
198
|
options: {
|
|
153
199
|
params?: Record<string, string>;
|
|
@@ -155,27 +201,39 @@ export class ReactServerProvider {
|
|
|
155
201
|
} = {},
|
|
156
202
|
) => {
|
|
157
203
|
const page = this.pageDescriptorProvider.page(name);
|
|
204
|
+
const url = new URL(this.pageDescriptorProvider.url(name, options));
|
|
158
205
|
const context: PageRequest = {
|
|
159
|
-
url
|
|
206
|
+
url,
|
|
160
207
|
params: options.params ?? {},
|
|
161
208
|
query: options.query ?? {},
|
|
162
209
|
head: {},
|
|
163
210
|
onError: () => null,
|
|
164
211
|
};
|
|
165
212
|
|
|
166
|
-
// for testing
|
|
167
213
|
const state = await this.pageDescriptorProvider.createLayers(
|
|
168
214
|
page,
|
|
169
215
|
context,
|
|
170
216
|
);
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
if (!withIndex) {
|
|
219
|
+
return {
|
|
220
|
+
context,
|
|
221
|
+
html: renderToString(
|
|
222
|
+
this.pageDescriptorProvider.root(state, context),
|
|
223
|
+
),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
context,
|
|
229
|
+
html: this.renderToHtml(this.template ?? "", state, context),
|
|
230
|
+
};
|
|
173
231
|
};
|
|
174
232
|
}
|
|
175
233
|
|
|
176
234
|
protected createHandler(
|
|
177
235
|
page: PageRoute,
|
|
178
|
-
templateLoader:
|
|
236
|
+
templateLoader: TemplateLoader,
|
|
179
237
|
): ServerHandler {
|
|
180
238
|
return async (serverRequest) => {
|
|
181
239
|
const { url, reply, query, params } = serverRequest;
|
|
@@ -193,18 +251,43 @@ export class ReactServerProvider {
|
|
|
193
251
|
onError: () => null,
|
|
194
252
|
};
|
|
195
253
|
|
|
196
|
-
// -- links
|
|
197
254
|
if (this.alepha.has(ServerLinksProvider)) {
|
|
198
255
|
const srv = this.alepha.get(ServerLinksProvider);
|
|
256
|
+
const schema = apiLinksResponseSchema as any;
|
|
199
257
|
|
|
200
|
-
context.links =
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
258
|
+
context.links = this.alepha.parse(
|
|
259
|
+
schema,
|
|
260
|
+
await srv.getLinks({
|
|
261
|
+
user: serverRequest.user,
|
|
262
|
+
authorization: serverRequest.headers.authorization,
|
|
263
|
+
}),
|
|
264
|
+
) as any;
|
|
204
265
|
|
|
205
|
-
this.alepha.
|
|
266
|
+
this.alepha.context.set("links", context.links);
|
|
206
267
|
}
|
|
207
268
|
|
|
269
|
+
let target: PageRoute | undefined = page; // TODO: move to PageDescriptorProvider
|
|
270
|
+
while (target) {
|
|
271
|
+
if (page.can && !page.can()) {
|
|
272
|
+
// if the page is not accessible, return 403
|
|
273
|
+
reply.status = 403;
|
|
274
|
+
reply.headers["content-type"] = "text/plain";
|
|
275
|
+
return "Forbidden";
|
|
276
|
+
}
|
|
277
|
+
target = target.parent;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// TODO: SSR strategies
|
|
281
|
+
// - only when googlebot
|
|
282
|
+
// - only child pages
|
|
283
|
+
// if (page.client) {
|
|
284
|
+
// // if the page is a client-only page, return 404
|
|
285
|
+
// reply.status = 200;
|
|
286
|
+
// reply.headers["content-type"] = "text/html";
|
|
287
|
+
// reply.body = template;
|
|
288
|
+
// return;
|
|
289
|
+
// }
|
|
290
|
+
|
|
208
291
|
await this.alepha.emit(
|
|
209
292
|
"react:server:render",
|
|
210
293
|
{
|
|
@@ -216,69 +299,101 @@ export class ReactServerProvider {
|
|
|
216
299
|
},
|
|
217
300
|
);
|
|
218
301
|
|
|
302
|
+
this.serverTimingProvider.beginTiming("createLayers");
|
|
303
|
+
|
|
219
304
|
const state = await this.pageDescriptorProvider.createLayers(
|
|
220
305
|
page,
|
|
221
306
|
context,
|
|
222
307
|
);
|
|
223
308
|
|
|
309
|
+
this.serverTimingProvider.endTiming("createLayers");
|
|
310
|
+
|
|
224
311
|
if (state.redirect) {
|
|
225
312
|
return reply.redirect(state.redirect);
|
|
226
313
|
}
|
|
227
314
|
|
|
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
315
|
reply.status = 200;
|
|
257
316
|
reply.headers["content-type"] = "text/html";
|
|
317
|
+
|
|
318
|
+
// by default, disable caching for SSR responses
|
|
319
|
+
// some plugins may override this
|
|
258
320
|
reply.headers["cache-control"] =
|
|
259
321
|
"no-store, no-cache, must-revalidate, proxy-revalidate";
|
|
260
322
|
reply.headers.pragma = "no-cache";
|
|
261
323
|
reply.headers.expires = "0";
|
|
262
324
|
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// inject head meta
|
|
267
|
-
if (context.head) {
|
|
268
|
-
response.html = this.headProvider.renderHead(
|
|
269
|
-
response.html,
|
|
270
|
-
context.head,
|
|
271
|
-
);
|
|
325
|
+
// don't cache user links
|
|
326
|
+
if (page.cache && serverRequest.user) {
|
|
327
|
+
delete context.links;
|
|
272
328
|
}
|
|
273
329
|
|
|
274
|
-
|
|
275
|
-
|
|
330
|
+
return this.renderToHtml(template, state, context);
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
public renderToHtml(
|
|
335
|
+
template: string,
|
|
336
|
+
state: RouterState,
|
|
337
|
+
context: PageReactContext,
|
|
338
|
+
) {
|
|
339
|
+
const element = this.pageDescriptorProvider.root(state, context);
|
|
340
|
+
|
|
341
|
+
this.serverTimingProvider.beginTiming("renderToString");
|
|
342
|
+
|
|
343
|
+
let app = "";
|
|
344
|
+
try {
|
|
345
|
+
app = renderToString(element);
|
|
346
|
+
} catch (error) {
|
|
347
|
+
this.log.error("Error during SSR", error);
|
|
348
|
+
app = renderToString(context.onError(error as Error));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.serverTimingProvider.endTiming("renderToString");
|
|
352
|
+
|
|
353
|
+
const hydrationData: ReactHydrationState = {
|
|
354
|
+
links: context.links,
|
|
355
|
+
layers: state.layers.map((it) => ({
|
|
356
|
+
...it,
|
|
357
|
+
error: it.error
|
|
358
|
+
? {
|
|
359
|
+
...it.error,
|
|
360
|
+
name: it.error.name,
|
|
361
|
+
message: it.error.message,
|
|
362
|
+
stack: it.error.stack, // TODO: Hide stack in production ?
|
|
363
|
+
}
|
|
364
|
+
: undefined,
|
|
365
|
+
index: undefined,
|
|
366
|
+
path: undefined,
|
|
367
|
+
element: undefined,
|
|
368
|
+
})),
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// create hydration data
|
|
372
|
+
const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;
|
|
276
373
|
|
|
277
|
-
|
|
374
|
+
const response = {
|
|
375
|
+
html: template,
|
|
278
376
|
};
|
|
377
|
+
|
|
378
|
+
// inject app into template
|
|
379
|
+
this.fillTemplate(response, app, script);
|
|
380
|
+
|
|
381
|
+
// inject head meta
|
|
382
|
+
if (context.head) {
|
|
383
|
+
response.html = this.headProvider.renderHead(response.html, context.head);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// TODO: hook for plugins "react:server:template"
|
|
387
|
+
// { response: { html: string }, request, state }
|
|
388
|
+
|
|
389
|
+
return response.html;
|
|
279
390
|
}
|
|
280
391
|
|
|
281
|
-
fillTemplate(
|
|
392
|
+
protected fillTemplate(
|
|
393
|
+
response: { html: string },
|
|
394
|
+
app: string,
|
|
395
|
+
script: string,
|
|
396
|
+
) {
|
|
282
397
|
if (this.ROOT_DIV_REGEX.test(response.html)) {
|
|
283
398
|
// replace contents of the existing <div id="root">
|
|
284
399
|
response.html = response.html.replace(
|
|
@@ -305,3 +420,5 @@ export class ReactServerProvider {
|
|
|
305
420
|
}
|
|
306
421
|
}
|
|
307
422
|
}
|
|
423
|
+
|
|
424
|
+
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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"}
|