@taujs/server 0.1.3 → 0.1.5

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 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 SSRServerOptions = {
29
- alias?: Record<string, string>;
30
- clientRoot: string;
31
- clientHtmlTemplate: string;
32
- clientEntryClient: string;
33
- clientEntryServer: string;
34
- routes: Route<RouteParams>[];
35
- serviceRegistry: ServiceRegistry;
36
- isDebug?: boolean;
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
- options: RequestInit & {
63
- params?: Record<string, unknown>;
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
- render?: typeof RENDERTYPE.ssr | typeof RENDERTYPE.streaming;
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
@@ -118,7 +118,7 @@ var require_plugin = __commonJS({
118
118
  // src/SSRServer.ts
119
119
  var import_fastify_plugin = __toESM(require_plugin(), 1);
120
120
  import { readFile } from "node:fs/promises";
121
- import path from "node:path";
121
+ import path2 from "node:path";
122
122
  import { createViteRuntime } from "vite";
123
123
 
124
124
  // src/constants.ts
@@ -130,10 +130,16 @@ var SSRTAG = {
130
130
  ssrHead: "<!--ssr-head-->",
131
131
  ssrHtml: "<!--ssr-html-->"
132
132
  };
133
+ var TEMPLATE = {
134
+ defaultEntryClient: "entry-client",
135
+ defaultEntryServer: "entry-server",
136
+ defaultHtmlTemplate: "index.html"
137
+ };
133
138
 
134
139
  // src/utils/Utils.ts
135
- import { fileURLToPath } from "node:url";
136
140
  import { dirname, join } from "node:path";
141
+ import "node:path";
142
+ import { fileURLToPath } from "node:url";
137
143
  import { match } from "path-to-regexp";
138
144
  var isDevelopment = process.env.NODE_ENV === "development";
139
145
  var __filename = fileURLToPath(import.meta.url);
@@ -163,20 +169,20 @@ async function collectStyleUrls(server, entries) {
163
169
  await Promise.all(entries.map((url) => traverse(url)));
164
170
  return [...visited].filter((url) => url.match(CSS_LANGS_RE));
165
171
  }
166
- function renderPreloadLinks(modules, manifest) {
172
+ function renderPreloadLinks(ssrManifest, basePath = "") {
167
173
  const seen = /* @__PURE__ */ new Set();
168
174
  let links = "";
169
- modules.forEach((id) => {
170
- const files = manifest[id];
175
+ for (const moduleId in ssrManifest) {
176
+ const files = ssrManifest[moduleId];
171
177
  if (files) {
172
178
  files.forEach((file) => {
173
179
  if (!seen.has(file)) {
174
180
  seen.add(file);
175
- links += renderPreloadLink(file);
181
+ links += renderPreloadLink(basePath ? `${basePath}/${file}` : `${file}`);
176
182
  }
177
183
  });
178
184
  }
179
- });
185
+ }
180
186
  return links;
181
187
  }
182
188
  function renderPreloadLink(file) {
@@ -248,17 +254,22 @@ var matchRoute = (url, renderRoutes) => {
248
254
  }
249
255
  return null;
250
256
  };
251
- var getCssLinks = (manifest) => {
252
- const links = [];
253
- for (const value of Object.values(manifest)) {
254
- if (value.css && value.css.length > 0) {
255
- value.css.forEach((cssFile) => {
256
- links.push(`<link rel="preload stylesheet" as="style" type="text/css" href="/${cssFile}">`);
257
- });
257
+ function getCssLinks(manifest, basePath = "") {
258
+ const seen = /* @__PURE__ */ new Set();
259
+ const styles = [];
260
+ for (const key in manifest) {
261
+ const entry = manifest[key];
262
+ if (entry && entry.css) {
263
+ for (const cssFile of entry.css) {
264
+ if (!seen.has(cssFile)) {
265
+ seen.add(cssFile);
266
+ styles.push(`<link rel="preload stylesheet" as="style" type="text/css" href="${basePath}/${cssFile}">`);
267
+ }
268
+ }
258
269
  }
259
270
  }
260
- return links.join("");
261
- };
271
+ return styles.join("\n");
272
+ }
262
273
  var overrideCSSHMRConsoleError = () => {
263
274
  const originalConsoleError = console.error;
264
275
  console.error = function(message, ...optionalParams) {
@@ -266,29 +277,76 @@ var overrideCSSHMRConsoleError = () => {
266
277
  originalConsoleError.apply(console, [message, ...optionalParams]);
267
278
  };
268
279
  };
280
+ var ensureNonNull = (value, errorMessage) => {
281
+ if (value === void 0 || value === null) throw new Error(errorMessage);
282
+ return value;
283
+ };
269
284
 
270
285
  // src/SSRServer.ts
286
+ var createMaps = () => {
287
+ return {
288
+ bootstrapModules: /* @__PURE__ */ new Map(),
289
+ cssLinks: /* @__PURE__ */ new Map(),
290
+ manifests: /* @__PURE__ */ new Map(),
291
+ preloadLinks: /* @__PURE__ */ new Map(),
292
+ renderModules: /* @__PURE__ */ new Map(),
293
+ ssrManifests: /* @__PURE__ */ new Map(),
294
+ templates: /* @__PURE__ */ new Map()
295
+ };
296
+ };
297
+ var processConfigs = (configs, baseClientRoot, templateDefaults) => {
298
+ return configs.map((config) => {
299
+ const clientRoot = path2.resolve(baseClientRoot, config.entryPoint);
300
+ return {
301
+ clientRoot,
302
+ entryPoint: config.entryPoint,
303
+ entryClient: config.entryClient || templateDefaults.defaultEntryClient,
304
+ entryServer: config.entryServer || templateDefaults.defaultEntryServer,
305
+ htmlTemplate: config.htmlTemplate || templateDefaults.defaultHtmlTemplate,
306
+ appId: config.appId
307
+ };
308
+ });
309
+ };
271
310
  var SSRServer = (0, import_fastify_plugin.default)(
272
311
  async (app, opts) => {
273
- const { alias, clientRoot, clientHtmlTemplate, clientEntryClient, clientEntryServer, routes, serviceRegistry, isDebug } = opts;
274
- const templateHtmlPath = path.join(clientRoot, clientHtmlTemplate);
275
- const templateHtml = !isDevelopment ? await readFile(templateHtmlPath, "utf-8") : await readFile(path.join(clientRoot, clientHtmlTemplate), "utf-8");
276
- const ssrManifestPath = path.join(clientRoot, ".vite/ssr-manifest.json");
277
- const ssrManifest = !isDevelopment ? JSON.parse(await readFile(ssrManifestPath, "utf-8")) : void 0;
278
- const manifestPath = path.join(clientRoot, ".vite/manifest.json");
279
- const manifest = !isDevelopment ? JSON.parse(await readFile(manifestPath, "utf-8")) : void 0;
280
- const bootstrapModules = isDevelopment ? `/${clientEntryClient}.tsx` : `/${manifest[`${clientEntryClient}.tsx`]?.file}`;
281
- const preloadLinks = !isDevelopment ? renderPreloadLinks(Object.keys(ssrManifest), ssrManifest) : void 0;
282
- const cssLinks = !isDevelopment ? getCssLinks(manifest) : void 0;
283
- let renderModule;
284
- let styles;
285
- let template = templateHtml;
312
+ const { alias, configs, routes, serviceRegistry, isDebug, clientRoot: baseClientRoot } = opts;
313
+ const { bootstrapModules, cssLinks, manifests, preloadLinks, renderModules, ssrManifests, templates } = createMaps();
314
+ const processedConfigs = processConfigs(configs, baseClientRoot, TEMPLATE);
315
+ for (const config of processedConfigs) {
316
+ const { clientRoot, entryClient, htmlTemplate } = config;
317
+ const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
318
+ const templateHtml = await readFile(templateHtmlPath, "utf-8");
319
+ templates.set(clientRoot, templateHtml);
320
+ const relativeBasePath = path2.relative(baseClientRoot, clientRoot).replace(/\\/g, "/");
321
+ const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
322
+ if (!isDevelopment) {
323
+ const manifestPath = path2.join(clientRoot, ".vite/manifest.json");
324
+ const manifestContent = await readFile(manifestPath, "utf-8");
325
+ const manifest = JSON.parse(manifestContent);
326
+ manifests.set(clientRoot, manifest);
327
+ const ssrManifestPath = path2.join(clientRoot, ".vite/ssr-manifest.json");
328
+ const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
329
+ const ssrManifest = JSON.parse(ssrManifestContent);
330
+ ssrManifests.set(clientRoot, ssrManifest);
331
+ const entryClientFile = manifest[`${entryClient}.tsx`]?.file;
332
+ if (!entryClientFile) throw new Error(`Entry client file not found in manifest for ${entryClient}.tsx`);
333
+ const bootstrapModule = `/${adjustedRelativePath}/${entryClientFile}`.replace(/\/{2,}/g, "/");
334
+ bootstrapModules.set(clientRoot, bootstrapModule);
335
+ const preloadLink = renderPreloadLinks(ssrManifest, adjustedRelativePath);
336
+ preloadLinks.set(clientRoot, preloadLink);
337
+ const cssLink = getCssLinks(manifest, adjustedRelativePath);
338
+ cssLinks.set(clientRoot, cssLink);
339
+ } else {
340
+ const bootstrapModule = `/${adjustedRelativePath}/${entryClient}`.replace(/\/{2,}/g, "/");
341
+ bootstrapModules.set(clientRoot, bootstrapModule);
342
+ }
343
+ }
286
344
  let viteDevServer;
287
345
  let viteRuntime;
288
- void await app.register(import("@fastify/static"), {
346
+ await app.register(import("@fastify/static"), {
289
347
  index: false,
290
348
  prefix: "/",
291
- root: clientRoot,
349
+ root: baseClientRoot,
292
350
  wildcard: false
293
351
  });
294
352
  if (isDevelopment) {
@@ -306,31 +364,27 @@ var SSRServer = (0, import_fastify_plugin.default)(
306
364
  plugins: [
307
365
  ...isDebug ? [
308
366
  {
367
+ name: "taujs-development-server-debug-logging",
309
368
  configureServer(server) {
310
- console.log("\u03C4js debug ssr server started.");
369
+ console.log("\u03C4js development server debug started.");
311
370
  server.middlewares.use((req, res, next) => {
312
371
  console.log(`rx: ${req.url}`);
313
- res.on("finish", () => {
314
- console.log(`tx: ${req.url}`);
315
- });
372
+ res.on("finish", () => console.log(`tx: ${req.url}`));
316
373
  next();
317
374
  });
318
- },
319
- name: "taujs-ssr-server-debug-logging"
375
+ }
320
376
  }
321
377
  ] : []
322
378
  ],
323
379
  resolve: {
324
380
  alias: {
325
- ...{
326
- "@client": path.resolve(clientRoot),
327
- "@server": path.resolve(__dirname),
328
- "@shared": path.resolve(__dirname, "../shared")
329
- },
381
+ "@client": path2.resolve(baseClientRoot),
382
+ "@server": path2.resolve(__dirname),
383
+ "@shared": path2.resolve(__dirname, "../shared"),
330
384
  ...alias
331
385
  }
332
386
  },
333
- root: clientRoot,
387
+ root: baseClientRoot,
334
388
  server: {
335
389
  middlewareMode: true,
336
390
  hmr: {
@@ -340,17 +394,15 @@ var SSRServer = (0, import_fastify_plugin.default)(
340
394
  });
341
395
  viteRuntime = await createViteRuntime(viteDevServer);
342
396
  overrideCSSHMRConsoleError();
343
- void app.addHook("onRequest", async (request, reply) => {
397
+ app.addHook("onRequest", async (request, reply) => {
344
398
  await new Promise((resolve) => {
345
399
  viteDevServer.middlewares(request.raw, reply.raw, () => {
346
400
  if (!reply.sent) resolve();
347
401
  });
348
402
  });
349
403
  });
350
- } else {
351
- renderModule = await import(path.join(clientRoot, `${clientEntryServer}.js`));
352
404
  }
353
- void app.get("/*", async (req, reply) => {
405
+ app.get("/*", async (req, reply) => {
354
406
  try {
355
407
  if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
356
408
  const url = req.url ? new URL(req.url, `http://${req.headers.host}`).pathname : "/";
@@ -359,26 +411,49 @@ var SSRServer = (0, import_fastify_plugin.default)(
359
411
  reply.callNotFound();
360
412
  return;
361
413
  }
414
+ const { route, params } = matchedRoute;
415
+ const { attr, appId } = route;
416
+ const config = processedConfigs.find((config2) => config2.appId === appId) || processedConfigs[0];
417
+ if (!config) throw new Error("No configuration found for the request.");
418
+ const { clientRoot, entryServer } = config;
419
+ let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
420
+ const bootstrapModule = bootstrapModules.get(clientRoot);
421
+ const cssLink = cssLinks.get(clientRoot);
422
+ const manifest = manifests.get(clientRoot);
423
+ const preloadLink = preloadLinks.get(clientRoot);
424
+ const ssrManifest = ssrManifests.get(clientRoot);
425
+ let renderModule;
362
426
  if (isDevelopment) {
363
427
  template = template.replace(/<script type="module" src="\/@vite\/client"><\/script>/g, "");
364
428
  template = template.replace(/<style type="text\/css">[\s\S]*?<\/style>/g, "");
365
- renderModule = await viteRuntime.executeEntrypoint(path.join(clientRoot, `${clientEntryServer}.tsx`));
366
- styles = await collectStyle(viteDevServer, [`${clientRoot}/${clientEntryServer}.tsx`]);
367
- template = template.replace("</head>", `<style type="text/css">${styles}</style></head>`);
429
+ const entryServerPath = path2.join(clientRoot, `${entryServer}.tsx`);
430
+ const executedModule = await viteRuntime.executeEntrypoint(entryServerPath);
431
+ renderModule = executedModule;
432
+ const styles = await collectStyle(viteDevServer, [entryServerPath]);
433
+ template = template?.replace("</head>", `<style type="text/css">${styles}</style></head>`);
368
434
  template = await viteDevServer.transformIndexHtml(url, template);
435
+ } else {
436
+ renderModule = renderModules.get(clientRoot);
437
+ if (!renderModule) {
438
+ const renderModulePath = path2.join(clientRoot, `${entryServer}.js`);
439
+ const importedModule = await import(renderModulePath);
440
+ renderModule = importedModule;
441
+ renderModules.set(clientRoot, renderModule);
442
+ }
369
443
  }
370
- const { route, params } = matchedRoute;
371
- const { attr } = route;
372
- const renderType = attr?.render || RENDERTYPE.streaming;
373
- const [beforeBody = "", afterBody] = template.split(SSRTAG.ssrHtml);
374
- const [beforeHead, afterHead] = beforeBody.split(SSRTAG.ssrHead);
444
+ const renderType = attr?.render || RENDERTYPE.ssr;
445
+ const [beforeBody = "", afterBody = ""] = template.split(SSRTAG.ssrHtml);
446
+ const [beforeHead = "", afterHead = ""] = beforeBody.split(SSRTAG.ssrHead);
375
447
  const initialDataPromise = fetchInitialData(attr, params, serviceRegistry);
376
448
  if (renderType === RENDERTYPE.ssr) {
377
449
  const { renderSSR } = renderModule;
378
450
  const initialDataResolved = await initialDataPromise;
379
451
  const initialDataScript = `<script>window.__INITIAL_DATA__ = ${JSON.stringify(initialDataResolved).replace(/</g, "\\u003c")}</script>`;
380
452
  const { headContent, appHtml } = await renderSSR(initialDataResolved, req.url, attr?.meta);
381
- const fullHtml = template.replace(SSRTAG.ssrHead, headContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModules}" async=""></script>`);
453
+ let aggregateHeadContent = headContent;
454
+ if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
455
+ if (manifest && cssLink) aggregateHeadContent += cssLink;
456
+ const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModule}" async=""></script>`);
382
457
  return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
383
458
  } else {
384
459
  const { renderStream } = renderModule;
@@ -388,8 +463,8 @@ var SSRServer = (0, import_fastify_plugin.default)(
388
463
  {
389
464
  onHead: (headContent) => {
390
465
  let aggregateHeadContent = headContent;
391
- if (ssrManifest) aggregateHeadContent += preloadLinks;
392
- if (manifest) aggregateHeadContent += cssLinks;
466
+ if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
467
+ if (manifest && cssLink) aggregateHeadContent += cssLink;
393
468
  reply.raw.write(`${beforeHead}${aggregateHeadContent}${afterHead}`);
394
469
  },
395
470
  onFinish: async (initialDataResolved) => {
@@ -404,7 +479,7 @@ var SSRServer = (0, import_fastify_plugin.default)(
404
479
  },
405
480
  initialDataPromise,
406
481
  req.url,
407
- bootstrapModules,
482
+ bootstrapModule,
408
483
  attr?.meta
409
484
  );
410
485
  }
@@ -414,14 +489,19 @@ var SSRServer = (0, import_fastify_plugin.default)(
414
489
  reply.raw.end("Internal Server Error");
415
490
  }
416
491
  });
417
- void app.setNotFoundHandler(async (req, reply) => {
492
+ app.setNotFoundHandler(async (req, reply) => {
418
493
  if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
419
494
  try {
420
- let template2 = templateHtml;
421
- template2 = template2.replace(SSRTAG.ssrHead, "").replace(SSRTAG.ssrHtml, "");
422
- if (!isDevelopment) template2 = template2.replace("</head>", `${getCssLinks(manifest)}</head>`);
423
- template2 = template2.replace("</body>", `<script type="module" src="${bootstrapModules}" async=""></script></body>`);
424
- reply.status(200).type("text/html").send(template2);
495
+ const defaultConfig = processedConfigs[0];
496
+ if (!defaultConfig) throw new Error("No default configuration found.");
497
+ const { clientRoot } = defaultConfig;
498
+ let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
499
+ const cssLink = cssLinks.get(clientRoot);
500
+ const bootstrapModule = bootstrapModules.get(clientRoot);
501
+ template = template.replace(SSRTAG.ssrHead, "").replace(SSRTAG.ssrHtml, "");
502
+ if (!isDevelopment && cssLink) template = template.replace("</head>", `${cssLink}</head>`);
503
+ if (bootstrapModule) template = template.replace("</body>", `<script type="module" src="${bootstrapModule}" async=""></script></body>`);
504
+ reply.status(200).type("text/html").send(template);
425
505
  } catch (error) {
426
506
  console.error("Failed to serve clientHtmlTemplate:", error);
427
507
  reply.status(500).send("Internal Server Error");
@@ -431,5 +511,8 @@ var SSRServer = (0, import_fastify_plugin.default)(
431
511
  { name: "taujs-ssr-server" }
432
512
  );
433
513
  export {
434
- SSRServer
514
+ SSRServer,
515
+ TEMPLATE,
516
+ createMaps,
517
+ processConfigs
435
518
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taujs/server",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "taujs | τjs",
5
5
  "author": "Aoede <taujs@aoede.uk.net> (https://www.aoede.uk.net)",
6
6
  "license": "MIT",