@taujs/server 0.1.4 → 0.1.6
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 +8 -0
- package/dist/index.d.ts +58 -28
- package/dist/index.js +150 -71
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,6 +14,14 @@ Supports rendering modes:
|
|
|
14
14
|
- Server-side rendering (SSR)
|
|
15
15
|
- Streaming SSR
|
|
16
16
|
|
|
17
|
+
Supported application structure and composition:
|
|
18
|
+
|
|
19
|
+
- Single-page Application (SPA)
|
|
20
|
+
- Multi-page Application (MPA)
|
|
21
|
+
- Build-time Micro-Frontends, server orchestration and delivery
|
|
22
|
+
|
|
23
|
+
Assemble independently built frontends at build time incorporating flexible per-route SPA-MPA hybrid with CSR, SSR, and Streaming SSR, rendering options.
|
|
24
|
+
|
|
17
25
|
Fastify Plugin for integration with taujs [ τjs ] template https://github.com/aoede3/taujs
|
|
18
26
|
|
|
19
27
|
- Production: Fastify, React
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,46 @@ declare const RENDERTYPE: {
|
|
|
5
5
|
ssr: string;
|
|
6
6
|
streaming: string;
|
|
7
7
|
};
|
|
8
|
+
declare const TEMPLATE: {
|
|
9
|
+
defaultEntryClient: string;
|
|
10
|
+
defaultEntryServer: string;
|
|
11
|
+
defaultHtmlTemplate: string;
|
|
12
|
+
};
|
|
8
13
|
|
|
14
|
+
declare const createMaps: () => {
|
|
15
|
+
bootstrapModules: Map<string, string>;
|
|
16
|
+
cssLinks: Map<string, string>;
|
|
17
|
+
manifests: Map<string, Manifest>;
|
|
18
|
+
preloadLinks: Map<string, string>;
|
|
19
|
+
renderModules: Map<string, RenderModule>;
|
|
20
|
+
ssrManifests: Map<string, SSRManifest>;
|
|
21
|
+
templates: Map<string, string>;
|
|
22
|
+
};
|
|
23
|
+
declare const processConfigs: (configs: Config[], baseClientRoot: string, templateDefaults: typeof TEMPLATE) => ProcessedConfig[];
|
|
9
24
|
declare const SSRServer: FastifyPluginAsync<SSRServerOptions>;
|
|
25
|
+
type Config = {
|
|
26
|
+
appId: string;
|
|
27
|
+
entryPoint: string;
|
|
28
|
+
entryClient?: string;
|
|
29
|
+
entryServer?: string;
|
|
30
|
+
htmlTemplate?: string;
|
|
31
|
+
};
|
|
32
|
+
type ProcessedConfig = {
|
|
33
|
+
appId: string;
|
|
34
|
+
clientRoot: string;
|
|
35
|
+
entryClient: string;
|
|
36
|
+
entryPoint: string;
|
|
37
|
+
entryServer: string;
|
|
38
|
+
htmlTemplate: string;
|
|
39
|
+
};
|
|
40
|
+
type SSRServerOptions = {
|
|
41
|
+
alias?: Record<string, string>;
|
|
42
|
+
clientRoot: string;
|
|
43
|
+
configs: Config[];
|
|
44
|
+
routes: Route<RouteParams>[];
|
|
45
|
+
serviceRegistry: ServiceRegistry;
|
|
46
|
+
isDebug?: boolean;
|
|
47
|
+
};
|
|
10
48
|
type ServiceRegistry = {
|
|
11
49
|
[serviceName: string]: {
|
|
12
50
|
[methodName: string]: (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
@@ -25,25 +63,19 @@ type FetchConfig = {
|
|
|
25
63
|
serviceName?: string;
|
|
26
64
|
serviceMethod?: string;
|
|
27
65
|
};
|
|
28
|
-
type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
type SSRManifest = {
|
|
67
|
+
[key: string]: string[];
|
|
68
|
+
};
|
|
69
|
+
type ManifestEntry = {
|
|
70
|
+
file: string;
|
|
71
|
+
src?: string;
|
|
72
|
+
isDynamicEntry?: boolean;
|
|
73
|
+
imports?: string[];
|
|
74
|
+
css?: string[];
|
|
75
|
+
assets?: string[];
|
|
37
76
|
};
|
|
38
77
|
type Manifest = {
|
|
39
|
-
[key: string]:
|
|
40
|
-
file: string;
|
|
41
|
-
src?: string;
|
|
42
|
-
isDynamicEntry?: boolean;
|
|
43
|
-
imports?: string[];
|
|
44
|
-
css?: string[];
|
|
45
|
-
assets?: string[];
|
|
46
|
-
};
|
|
78
|
+
[key: string]: ManifestEntry;
|
|
47
79
|
};
|
|
48
80
|
type RenderSSR = (initialDataResolved: Record<string, unknown>, location: string, meta?: Record<string, unknown>) => Promise<{
|
|
49
81
|
headContent: string;
|
|
@@ -58,20 +90,18 @@ type RenderModule = {
|
|
|
58
90
|
type RouteAttributes<Params = {}> = {
|
|
59
91
|
fetch?: (params?: Params, options?: RequestInit & {
|
|
60
92
|
params?: Record<string, unknown>;
|
|
61
|
-
}) => Promise<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
serviceName?: string;
|
|
66
|
-
serviceMethod?: string;
|
|
67
|
-
url?: string;
|
|
68
|
-
}>;
|
|
93
|
+
}) => Promise<FetchConfig>;
|
|
94
|
+
} & ({
|
|
95
|
+
render?: typeof RENDERTYPE.ssr;
|
|
69
96
|
meta?: Record<string, unknown>;
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
} | {
|
|
98
|
+
render: typeof RENDERTYPE.streaming;
|
|
99
|
+
meta: Record<string, unknown>;
|
|
100
|
+
});
|
|
72
101
|
type Route<Params = {}> = {
|
|
73
102
|
attr?: RouteAttributes<Params>;
|
|
74
103
|
path: string;
|
|
104
|
+
appId?: string;
|
|
75
105
|
};
|
|
76
106
|
interface InitialRouteParams extends Record<string, unknown> {
|
|
77
107
|
serviceName?: string;
|
|
@@ -80,4 +110,4 @@ interface InitialRouteParams extends Record<string, unknown> {
|
|
|
80
110
|
type RouteParams = InitialRouteParams & Record<string, unknown>;
|
|
81
111
|
type RoutePathsAndAttributes<Params = {}> = Omit<Route<Params>, 'element'>;
|
|
82
112
|
|
|
83
|
-
export { type FetchConfig, type InitialRouteParams, type Manifest, type RenderCallbacks, type RenderModule, type RenderSSR, type RenderStream, type Route, type RouteAttributes, type RouteParams, type RoutePathsAndAttributes, SSRServer, type SSRServerOptions, type ServiceRegistry };
|
|
113
|
+
export { type Config, type FetchConfig, type InitialRouteParams, type Manifest, type ManifestEntry, type ProcessedConfig, type RenderCallbacks, type RenderModule, type RenderSSR, type RenderStream, type Route, type RouteAttributes, type RouteParams, type RoutePathsAndAttributes, type SSRManifest, SSRServer, type SSRServerOptions, type ServiceRegistry, TEMPLATE, createMaps, processConfigs };
|
package/dist/index.js
CHANGED
|
@@ -57,10 +57,9 @@ var require_toCamelCase = __commonJS({
|
|
|
57
57
|
if (name[0] === "@") {
|
|
58
58
|
name = name.slice(1).replace("/", "-");
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
return name.replace(/-(.)/g, function(match2, g1) {
|
|
61
61
|
return g1.toUpperCase();
|
|
62
62
|
});
|
|
63
|
-
return newName;
|
|
64
63
|
};
|
|
65
64
|
}
|
|
66
65
|
});
|
|
@@ -74,7 +73,7 @@ var require_plugin = __commonJS({
|
|
|
74
73
|
var count = 0;
|
|
75
74
|
function plugin(fn, options = {}) {
|
|
76
75
|
let autoName = false;
|
|
77
|
-
if (
|
|
76
|
+
if (fn.default !== void 0) {
|
|
78
77
|
fn = fn.default;
|
|
79
78
|
}
|
|
80
79
|
if (typeof fn !== "function") {
|
|
@@ -118,7 +117,7 @@ var require_plugin = __commonJS({
|
|
|
118
117
|
// src/SSRServer.ts
|
|
119
118
|
var import_fastify_plugin = __toESM(require_plugin(), 1);
|
|
120
119
|
import { readFile } from "node:fs/promises";
|
|
121
|
-
import
|
|
120
|
+
import path2 from "node:path";
|
|
122
121
|
import { createViteRuntime } from "vite";
|
|
123
122
|
|
|
124
123
|
// src/constants.ts
|
|
@@ -130,10 +129,16 @@ var SSRTAG = {
|
|
|
130
129
|
ssrHead: "<!--ssr-head-->",
|
|
131
130
|
ssrHtml: "<!--ssr-html-->"
|
|
132
131
|
};
|
|
132
|
+
var TEMPLATE = {
|
|
133
|
+
defaultEntryClient: "entry-client",
|
|
134
|
+
defaultEntryServer: "entry-server",
|
|
135
|
+
defaultHtmlTemplate: "index.html"
|
|
136
|
+
};
|
|
133
137
|
|
|
134
138
|
// src/utils/Utils.ts
|
|
135
|
-
import { fileURLToPath } from "node:url";
|
|
136
139
|
import { dirname, join } from "node:path";
|
|
140
|
+
import "node:path";
|
|
141
|
+
import { fileURLToPath } from "node:url";
|
|
137
142
|
import { match } from "path-to-regexp";
|
|
138
143
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
139
144
|
var __filename = fileURLToPath(import.meta.url);
|
|
@@ -163,20 +168,20 @@ async function collectStyleUrls(server, entries) {
|
|
|
163
168
|
await Promise.all(entries.map((url) => traverse(url)));
|
|
164
169
|
return [...visited].filter((url) => url.match(CSS_LANGS_RE));
|
|
165
170
|
}
|
|
166
|
-
function renderPreloadLinks(
|
|
171
|
+
function renderPreloadLinks(ssrManifest, basePath = "") {
|
|
167
172
|
const seen = /* @__PURE__ */ new Set();
|
|
168
173
|
let links = "";
|
|
169
|
-
|
|
170
|
-
const files =
|
|
174
|
+
for (const moduleId in ssrManifest) {
|
|
175
|
+
const files = ssrManifest[moduleId];
|
|
171
176
|
if (files) {
|
|
172
177
|
files.forEach((file) => {
|
|
173
178
|
if (!seen.has(file)) {
|
|
174
179
|
seen.add(file);
|
|
175
|
-
links += renderPreloadLink(file);
|
|
180
|
+
links += renderPreloadLink(basePath ? `${basePath}/${file}` : `${file}`);
|
|
176
181
|
}
|
|
177
182
|
});
|
|
178
183
|
}
|
|
179
|
-
}
|
|
184
|
+
}
|
|
180
185
|
return links;
|
|
181
186
|
}
|
|
182
187
|
function renderPreloadLink(file) {
|
|
@@ -248,17 +253,22 @@ var matchRoute = (url, renderRoutes) => {
|
|
|
248
253
|
}
|
|
249
254
|
return null;
|
|
250
255
|
};
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
256
|
+
function getCssLinks(manifest, basePath = "") {
|
|
257
|
+
const seen = /* @__PURE__ */ new Set();
|
|
258
|
+
const styles = [];
|
|
259
|
+
for (const key in manifest) {
|
|
260
|
+
const entry = manifest[key];
|
|
261
|
+
if (entry && entry.css) {
|
|
262
|
+
for (const cssFile of entry.css) {
|
|
263
|
+
if (!seen.has(cssFile)) {
|
|
264
|
+
seen.add(cssFile);
|
|
265
|
+
styles.push(`<link rel="preload stylesheet" as="style" type="text/css" href="${basePath}/${cssFile}">`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
258
268
|
}
|
|
259
269
|
}
|
|
260
|
-
return
|
|
261
|
-
}
|
|
270
|
+
return styles.join("\n");
|
|
271
|
+
}
|
|
262
272
|
var overrideCSSHMRConsoleError = () => {
|
|
263
273
|
const originalConsoleError = console.error;
|
|
264
274
|
console.error = function(message, ...optionalParams) {
|
|
@@ -266,29 +276,76 @@ var overrideCSSHMRConsoleError = () => {
|
|
|
266
276
|
originalConsoleError.apply(console, [message, ...optionalParams]);
|
|
267
277
|
};
|
|
268
278
|
};
|
|
279
|
+
var ensureNonNull = (value, errorMessage) => {
|
|
280
|
+
if (value === void 0 || value === null) throw new Error(errorMessage);
|
|
281
|
+
return value;
|
|
282
|
+
};
|
|
269
283
|
|
|
270
284
|
// src/SSRServer.ts
|
|
285
|
+
var createMaps = () => {
|
|
286
|
+
return {
|
|
287
|
+
bootstrapModules: /* @__PURE__ */ new Map(),
|
|
288
|
+
cssLinks: /* @__PURE__ */ new Map(),
|
|
289
|
+
manifests: /* @__PURE__ */ new Map(),
|
|
290
|
+
preloadLinks: /* @__PURE__ */ new Map(),
|
|
291
|
+
renderModules: /* @__PURE__ */ new Map(),
|
|
292
|
+
ssrManifests: /* @__PURE__ */ new Map(),
|
|
293
|
+
templates: /* @__PURE__ */ new Map()
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
var processConfigs = (configs, baseClientRoot, templateDefaults) => {
|
|
297
|
+
return configs.map((config) => {
|
|
298
|
+
const clientRoot = path2.resolve(baseClientRoot, config.entryPoint);
|
|
299
|
+
return {
|
|
300
|
+
clientRoot,
|
|
301
|
+
entryPoint: config.entryPoint,
|
|
302
|
+
entryClient: config.entryClient || templateDefaults.defaultEntryClient,
|
|
303
|
+
entryServer: config.entryServer || templateDefaults.defaultEntryServer,
|
|
304
|
+
htmlTemplate: config.htmlTemplate || templateDefaults.defaultHtmlTemplate,
|
|
305
|
+
appId: config.appId
|
|
306
|
+
};
|
|
307
|
+
});
|
|
308
|
+
};
|
|
271
309
|
var SSRServer = (0, import_fastify_plugin.default)(
|
|
272
310
|
async (app, opts) => {
|
|
273
|
-
const { alias,
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
311
|
+
const { alias, configs, routes, serviceRegistry, isDebug, clientRoot: baseClientRoot } = opts;
|
|
312
|
+
const { bootstrapModules, cssLinks, manifests, preloadLinks, renderModules, ssrManifests, templates } = createMaps();
|
|
313
|
+
const processedConfigs = processConfigs(configs, baseClientRoot, TEMPLATE);
|
|
314
|
+
for (const config of processedConfigs) {
|
|
315
|
+
const { clientRoot, entryClient, htmlTemplate } = config;
|
|
316
|
+
const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
|
|
317
|
+
const templateHtml = await readFile(templateHtmlPath, "utf-8");
|
|
318
|
+
templates.set(clientRoot, templateHtml);
|
|
319
|
+
const relativeBasePath = path2.relative(baseClientRoot, clientRoot).replace(/\\/g, "/");
|
|
320
|
+
const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
|
|
321
|
+
if (!isDevelopment) {
|
|
322
|
+
const manifestPath = path2.join(clientRoot, ".vite/manifest.json");
|
|
323
|
+
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
324
|
+
const manifest = JSON.parse(manifestContent);
|
|
325
|
+
manifests.set(clientRoot, manifest);
|
|
326
|
+
const ssrManifestPath = path2.join(clientRoot, ".vite/ssr-manifest.json");
|
|
327
|
+
const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
|
|
328
|
+
const ssrManifest = JSON.parse(ssrManifestContent);
|
|
329
|
+
ssrManifests.set(clientRoot, ssrManifest);
|
|
330
|
+
const entryClientFile = manifest[`${entryClient}.tsx`]?.file;
|
|
331
|
+
if (!entryClientFile) throw new Error(`Entry client file not found in manifest for ${entryClient}.tsx`);
|
|
332
|
+
const bootstrapModule = `/${adjustedRelativePath}/${entryClientFile}`.replace(/\/{2,}/g, "/");
|
|
333
|
+
bootstrapModules.set(clientRoot, bootstrapModule);
|
|
334
|
+
const preloadLink = renderPreloadLinks(ssrManifest, adjustedRelativePath);
|
|
335
|
+
preloadLinks.set(clientRoot, preloadLink);
|
|
336
|
+
const cssLink = getCssLinks(manifest, adjustedRelativePath);
|
|
337
|
+
cssLinks.set(clientRoot, cssLink);
|
|
338
|
+
} else {
|
|
339
|
+
const bootstrapModule = `/${adjustedRelativePath}/${entryClient}`.replace(/\/{2,}/g, "/");
|
|
340
|
+
bootstrapModules.set(clientRoot, bootstrapModule);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
286
343
|
let viteDevServer;
|
|
287
344
|
let viteRuntime;
|
|
288
|
-
|
|
345
|
+
await app.register(import("@fastify/static"), {
|
|
289
346
|
index: false,
|
|
290
347
|
prefix: "/",
|
|
291
|
-
root:
|
|
348
|
+
root: baseClientRoot,
|
|
292
349
|
wildcard: false
|
|
293
350
|
});
|
|
294
351
|
if (isDevelopment) {
|
|
@@ -306,31 +363,27 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
306
363
|
plugins: [
|
|
307
364
|
...isDebug ? [
|
|
308
365
|
{
|
|
366
|
+
name: "taujs-development-server-debug-logging",
|
|
309
367
|
configureServer(server) {
|
|
310
|
-
console.log("\u03C4js
|
|
368
|
+
console.log("\u03C4js development server debug started.");
|
|
311
369
|
server.middlewares.use((req, res, next) => {
|
|
312
370
|
console.log(`rx: ${req.url}`);
|
|
313
|
-
res.on("finish", () => {
|
|
314
|
-
console.log(`tx: ${req.url}`);
|
|
315
|
-
});
|
|
371
|
+
res.on("finish", () => console.log(`tx: ${req.url}`));
|
|
316
372
|
next();
|
|
317
373
|
});
|
|
318
|
-
}
|
|
319
|
-
name: "taujs-ssr-server-debug-logging"
|
|
374
|
+
}
|
|
320
375
|
}
|
|
321
376
|
] : []
|
|
322
377
|
],
|
|
323
378
|
resolve: {
|
|
324
379
|
alias: {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
"@shared": path.resolve(__dirname, "../shared")
|
|
329
|
-
},
|
|
380
|
+
"@client": path2.resolve(baseClientRoot),
|
|
381
|
+
"@server": path2.resolve(__dirname),
|
|
382
|
+
"@shared": path2.resolve(__dirname, "../shared"),
|
|
330
383
|
...alias
|
|
331
384
|
}
|
|
332
385
|
},
|
|
333
|
-
root:
|
|
386
|
+
root: baseClientRoot,
|
|
334
387
|
server: {
|
|
335
388
|
middlewareMode: true,
|
|
336
389
|
hmr: {
|
|
@@ -340,17 +393,15 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
340
393
|
});
|
|
341
394
|
viteRuntime = await createViteRuntime(viteDevServer);
|
|
342
395
|
overrideCSSHMRConsoleError();
|
|
343
|
-
|
|
396
|
+
app.addHook("onRequest", async (request, reply) => {
|
|
344
397
|
await new Promise((resolve) => {
|
|
345
398
|
viteDevServer.middlewares(request.raw, reply.raw, () => {
|
|
346
399
|
if (!reply.sent) resolve();
|
|
347
400
|
});
|
|
348
401
|
});
|
|
349
402
|
});
|
|
350
|
-
} else {
|
|
351
|
-
renderModule = await import(path.join(clientRoot, `${clientEntryServer}.js`));
|
|
352
403
|
}
|
|
353
|
-
|
|
404
|
+
app.get("/*", async (req, reply) => {
|
|
354
405
|
try {
|
|
355
406
|
if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
|
|
356
407
|
const url = req.url ? new URL(req.url, `http://${req.headers.host}`).pathname : "/";
|
|
@@ -359,19 +410,39 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
359
410
|
reply.callNotFound();
|
|
360
411
|
return;
|
|
361
412
|
}
|
|
413
|
+
const { route, params } = matchedRoute;
|
|
414
|
+
const { attr, appId } = route;
|
|
415
|
+
const config = processedConfigs.find((config2) => config2.appId === appId) || processedConfigs[0];
|
|
416
|
+
if (!config) throw new Error("No configuration found for the request.");
|
|
417
|
+
const { clientRoot, entryServer } = config;
|
|
418
|
+
let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
|
|
419
|
+
const bootstrapModule = bootstrapModules.get(clientRoot);
|
|
420
|
+
const cssLink = cssLinks.get(clientRoot);
|
|
421
|
+
const manifest = manifests.get(clientRoot);
|
|
422
|
+
const preloadLink = preloadLinks.get(clientRoot);
|
|
423
|
+
const ssrManifest = ssrManifests.get(clientRoot);
|
|
424
|
+
let renderModule;
|
|
362
425
|
if (isDevelopment) {
|
|
363
426
|
template = template.replace(/<script type="module" src="\/@vite\/client"><\/script>/g, "");
|
|
364
427
|
template = template.replace(/<style type="text\/css">[\s\S]*?<\/style>/g, "");
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
428
|
+
const entryServerPath = path2.join(clientRoot, `${entryServer}.tsx`);
|
|
429
|
+
const executedModule = await viteRuntime.executeEntrypoint(entryServerPath);
|
|
430
|
+
renderModule = executedModule;
|
|
431
|
+
const styles = await collectStyle(viteDevServer, [entryServerPath]);
|
|
432
|
+
template = template?.replace("</head>", `<style type="text/css">${styles}</style></head>`);
|
|
368
433
|
template = await viteDevServer.transformIndexHtml(url, template);
|
|
434
|
+
} else {
|
|
435
|
+
renderModule = renderModules.get(clientRoot);
|
|
436
|
+
if (!renderModule) {
|
|
437
|
+
const renderModulePath = path2.join(clientRoot, `${entryServer}.js`);
|
|
438
|
+
const importedModule = await import(renderModulePath);
|
|
439
|
+
renderModule = importedModule;
|
|
440
|
+
renderModules.set(clientRoot, renderModule);
|
|
441
|
+
}
|
|
369
442
|
}
|
|
370
|
-
const
|
|
371
|
-
const
|
|
372
|
-
const
|
|
373
|
-
const [beforeBody = "", afterBody] = template.split(SSRTAG.ssrHtml);
|
|
374
|
-
const [beforeHead, afterHead] = beforeBody.split(SSRTAG.ssrHead);
|
|
443
|
+
const renderType = attr?.render || RENDERTYPE.ssr;
|
|
444
|
+
const [beforeBody = "", afterBody = ""] = template.split(SSRTAG.ssrHtml);
|
|
445
|
+
const [beforeHead = "", afterHead = ""] = beforeBody.split(SSRTAG.ssrHead);
|
|
375
446
|
const initialDataPromise = fetchInitialData(attr, params, serviceRegistry);
|
|
376
447
|
if (renderType === RENDERTYPE.ssr) {
|
|
377
448
|
const { renderSSR } = renderModule;
|
|
@@ -379,9 +450,9 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
379
450
|
const initialDataScript = `<script>window.__INITIAL_DATA__ = ${JSON.stringify(initialDataResolved).replace(/</g, "\\u003c")}</script>`;
|
|
380
451
|
const { headContent, appHtml } = await renderSSR(initialDataResolved, req.url, attr?.meta);
|
|
381
452
|
let aggregateHeadContent = headContent;
|
|
382
|
-
if (ssrManifest) aggregateHeadContent +=
|
|
383
|
-
if (manifest) aggregateHeadContent +=
|
|
384
|
-
const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${
|
|
453
|
+
if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
|
|
454
|
+
if (manifest && cssLink) aggregateHeadContent += cssLink;
|
|
455
|
+
const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModule}" async=""></script>`);
|
|
385
456
|
return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
|
|
386
457
|
} else {
|
|
387
458
|
const { renderStream } = renderModule;
|
|
@@ -391,8 +462,8 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
391
462
|
{
|
|
392
463
|
onHead: (headContent) => {
|
|
393
464
|
let aggregateHeadContent = headContent;
|
|
394
|
-
if (ssrManifest) aggregateHeadContent +=
|
|
395
|
-
if (manifest) aggregateHeadContent +=
|
|
465
|
+
if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
|
|
466
|
+
if (manifest && cssLink) aggregateHeadContent += cssLink;
|
|
396
467
|
reply.raw.write(`${beforeHead}${aggregateHeadContent}${afterHead}`);
|
|
397
468
|
},
|
|
398
469
|
onFinish: async (initialDataResolved) => {
|
|
@@ -407,7 +478,7 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
407
478
|
},
|
|
408
479
|
initialDataPromise,
|
|
409
480
|
req.url,
|
|
410
|
-
|
|
481
|
+
bootstrapModule,
|
|
411
482
|
attr?.meta
|
|
412
483
|
);
|
|
413
484
|
}
|
|
@@ -417,14 +488,19 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
417
488
|
reply.raw.end("Internal Server Error");
|
|
418
489
|
}
|
|
419
490
|
});
|
|
420
|
-
|
|
491
|
+
app.setNotFoundHandler(async (req, reply) => {
|
|
421
492
|
if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
|
|
422
493
|
try {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
494
|
+
const defaultConfig = processedConfigs[0];
|
|
495
|
+
if (!defaultConfig) throw new Error("No default configuration found.");
|
|
496
|
+
const { clientRoot } = defaultConfig;
|
|
497
|
+
let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
|
|
498
|
+
const cssLink = cssLinks.get(clientRoot);
|
|
499
|
+
const bootstrapModule = bootstrapModules.get(clientRoot);
|
|
500
|
+
template = template.replace(SSRTAG.ssrHead, "").replace(SSRTAG.ssrHtml, "");
|
|
501
|
+
if (!isDevelopment && cssLink) template = template.replace("</head>", `${cssLink}</head>`);
|
|
502
|
+
if (bootstrapModule) template = template.replace("</body>", `<script type="module" src="${bootstrapModule}" async=""></script></body>`);
|
|
503
|
+
reply.status(200).type("text/html").send(template);
|
|
428
504
|
} catch (error) {
|
|
429
505
|
console.error("Failed to serve clientHtmlTemplate:", error);
|
|
430
506
|
reply.status(500).send("Internal Server Error");
|
|
@@ -434,5 +510,8 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
434
510
|
{ name: "taujs-ssr-server" }
|
|
435
511
|
);
|
|
436
512
|
export {
|
|
437
|
-
SSRServer
|
|
513
|
+
SSRServer,
|
|
514
|
+
TEMPLATE,
|
|
515
|
+
createMaps,
|
|
516
|
+
processConfigs
|
|
438
517
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taujs/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "taujs | τjs",
|
|
5
5
|
"author": "Aoede <taujs@aoede.uk.net> (https://www.aoede.uk.net)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dist"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@fastify/static": "^
|
|
42
|
+
"@fastify/static": "^8.0.3",
|
|
43
43
|
"path-to-regexp": "^8.1.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@types/react": "^18.3.3",
|
|
53
53
|
"@types/react-dom": "^18.3.0",
|
|
54
54
|
"@vitest/coverage-v8": "^2.1.0",
|
|
55
|
-
"fastify": "^
|
|
55
|
+
"fastify": "^5.2.0",
|
|
56
56
|
"jsdom": "^25.0.0",
|
|
57
57
|
"prettier": "^3.3.3",
|
|
58
58
|
"react-dom": "^18.3.1",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"vitest": "^2.0.5"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"fastify": "^
|
|
65
|
+
"fastify": "^5.2.0",
|
|
66
66
|
"react": "^18.3.1",
|
|
67
67
|
"react-dom": "^18.3.1",
|
|
68
68
|
"typescript": "^5.5.4",
|