@taujs/server 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts +15 -0
- package/dist/build.js +669 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/package.json +6 -12
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PluginOption } from 'vite';
|
|
2
|
+
|
|
3
|
+
type Config = {
|
|
4
|
+
appId: string;
|
|
5
|
+
entryPoint: string;
|
|
6
|
+
plugins?: PluginOption[];
|
|
7
|
+
};
|
|
8
|
+
declare function taujsBuild({ config, projectRoot, clientBaseDir, isSSRBuild, }: {
|
|
9
|
+
config: Config[];
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
clientBaseDir: string;
|
|
12
|
+
isSSRBuild?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
|
|
15
|
+
export { type Config, taujsBuild };
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/fastify-plugin/lib/getPluginName.js
|
|
28
|
+
var require_getPluginName = __commonJS({
|
|
29
|
+
"node_modules/fastify-plugin/lib/getPluginName.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
var fpStackTracePattern = /at\s{1}(?:.*\.)?plugin\s{1}.*\n\s*(.*)/;
|
|
32
|
+
var fileNamePattern = /(\w*(\.\w*)*)\..*/;
|
|
33
|
+
module.exports = function getPluginName(fn) {
|
|
34
|
+
if (fn.name.length > 0) return fn.name;
|
|
35
|
+
const stackTraceLimit = Error.stackTraceLimit;
|
|
36
|
+
Error.stackTraceLimit = 10;
|
|
37
|
+
try {
|
|
38
|
+
throw new Error("anonymous function");
|
|
39
|
+
} catch (e) {
|
|
40
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
41
|
+
return extractPluginName(e.stack);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function extractPluginName(stack) {
|
|
45
|
+
const m = stack.match(fpStackTracePattern);
|
|
46
|
+
return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : "anonymous";
|
|
47
|
+
}
|
|
48
|
+
module.exports.extractPluginName = extractPluginName;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// node_modules/fastify-plugin/lib/toCamelCase.js
|
|
53
|
+
var require_toCamelCase = __commonJS({
|
|
54
|
+
"node_modules/fastify-plugin/lib/toCamelCase.js"(exports, module) {
|
|
55
|
+
"use strict";
|
|
56
|
+
module.exports = function toCamelCase(name) {
|
|
57
|
+
if (name[0] === "@") {
|
|
58
|
+
name = name.slice(1).replace("/", "-");
|
|
59
|
+
}
|
|
60
|
+
return name.replace(/-(.)/g, function(match2, g1) {
|
|
61
|
+
return g1.toUpperCase();
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// node_modules/fastify-plugin/plugin.js
|
|
68
|
+
var require_plugin = __commonJS({
|
|
69
|
+
"node_modules/fastify-plugin/plugin.js"(exports, module) {
|
|
70
|
+
"use strict";
|
|
71
|
+
var getPluginName = require_getPluginName();
|
|
72
|
+
var toCamelCase = require_toCamelCase();
|
|
73
|
+
var count = 0;
|
|
74
|
+
function plugin(fn, options = {}) {
|
|
75
|
+
let autoName = false;
|
|
76
|
+
if (fn.default !== void 0) {
|
|
77
|
+
fn = fn.default;
|
|
78
|
+
}
|
|
79
|
+
if (typeof fn !== "function") {
|
|
80
|
+
throw new TypeError(
|
|
81
|
+
`fastify-plugin expects a function, instead got a '${typeof fn}'`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (typeof options === "string") {
|
|
85
|
+
options = {
|
|
86
|
+
fastify: options
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (typeof options !== "object" || Array.isArray(options) || options === null) {
|
|
90
|
+
throw new TypeError("The options object should be an object");
|
|
91
|
+
}
|
|
92
|
+
if (options.fastify !== void 0 && typeof options.fastify !== "string") {
|
|
93
|
+
throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`);
|
|
94
|
+
}
|
|
95
|
+
if (!options.name) {
|
|
96
|
+
autoName = true;
|
|
97
|
+
options.name = getPluginName(fn) + "-auto-" + count++;
|
|
98
|
+
}
|
|
99
|
+
fn[Symbol.for("skip-override")] = options.encapsulate !== true;
|
|
100
|
+
fn[Symbol.for("fastify.display-name")] = options.name;
|
|
101
|
+
fn[Symbol.for("plugin-meta")] = options;
|
|
102
|
+
if (!fn.default) {
|
|
103
|
+
fn.default = fn;
|
|
104
|
+
}
|
|
105
|
+
const camelCase = toCamelCase(options.name);
|
|
106
|
+
if (!autoName && !fn[camelCase]) {
|
|
107
|
+
fn[camelCase] = fn;
|
|
108
|
+
}
|
|
109
|
+
return fn;
|
|
110
|
+
}
|
|
111
|
+
module.exports = plugin;
|
|
112
|
+
module.exports.default = plugin;
|
|
113
|
+
module.exports.fastifyPlugin = plugin;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// node_modules/picocolors/picocolors.js
|
|
118
|
+
var require_picocolors = __commonJS({
|
|
119
|
+
"node_modules/picocolors/picocolors.js"(exports, module) {
|
|
120
|
+
"use strict";
|
|
121
|
+
var p = process || {};
|
|
122
|
+
var argv = p.argv || [];
|
|
123
|
+
var env = p.env || {};
|
|
124
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
125
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
126
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
127
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
128
|
+
};
|
|
129
|
+
var replaceClose = (string, close, replace, index) => {
|
|
130
|
+
let result = "", cursor = 0;
|
|
131
|
+
do {
|
|
132
|
+
result += string.substring(cursor, index) + replace;
|
|
133
|
+
cursor = index + close.length;
|
|
134
|
+
index = string.indexOf(close, cursor);
|
|
135
|
+
} while (~index);
|
|
136
|
+
return result + string.substring(cursor);
|
|
137
|
+
};
|
|
138
|
+
var createColors = (enabled = isColorSupported) => {
|
|
139
|
+
let f = enabled ? formatter : () => String;
|
|
140
|
+
return {
|
|
141
|
+
isColorSupported: enabled,
|
|
142
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
143
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
144
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
145
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
146
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
147
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
148
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
149
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
150
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
151
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
152
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
153
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
154
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
155
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
156
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
157
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
158
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
159
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
160
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
161
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
162
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
163
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
164
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
165
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
166
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
167
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
168
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
169
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
170
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
171
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
172
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
173
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
174
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
175
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
176
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
177
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
178
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
179
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
180
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
181
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
182
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
module.exports = createColors();
|
|
186
|
+
module.exports.createColors = createColors;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// src/build.ts
|
|
191
|
+
import fs from "fs/promises";
|
|
192
|
+
import path3 from "path";
|
|
193
|
+
import { build } from "vite";
|
|
194
|
+
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
|
195
|
+
|
|
196
|
+
// src/SSRServer.ts
|
|
197
|
+
var import_fastify_plugin = __toESM(require_plugin(), 1);
|
|
198
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
199
|
+
import { readFile } from "fs/promises";
|
|
200
|
+
import path2 from "path";
|
|
201
|
+
|
|
202
|
+
// src/constants.ts
|
|
203
|
+
var RENDERTYPE = {
|
|
204
|
+
ssr: "ssr",
|
|
205
|
+
streaming: "streaming"
|
|
206
|
+
};
|
|
207
|
+
var SSRTAG = {
|
|
208
|
+
ssrHead: "<!--ssr-head-->",
|
|
209
|
+
ssrHtml: "<!--ssr-html-->"
|
|
210
|
+
};
|
|
211
|
+
var TEMPLATE = {
|
|
212
|
+
defaultEntryClient: "entry-client",
|
|
213
|
+
defaultEntryServer: "entry-server",
|
|
214
|
+
defaultHtmlTemplate: "index.html"
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// src/utils/Utils.ts
|
|
218
|
+
import { dirname, join } from "path";
|
|
219
|
+
import "path";
|
|
220
|
+
import { fileURLToPath } from "url";
|
|
221
|
+
import { match } from "path-to-regexp";
|
|
222
|
+
var isDevelopment = process.env.NODE_ENV === "development";
|
|
223
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
224
|
+
var __dirname = join(dirname(__filename), !isDevelopment ? "./" : "..");
|
|
225
|
+
var CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
|
|
226
|
+
async function collectStyle(server, entries) {
|
|
227
|
+
const urls = await collectStyleUrls(server, entries);
|
|
228
|
+
const codes = await Promise.all(
|
|
229
|
+
urls.map(async (url) => {
|
|
230
|
+
const res = await server.transformRequest(url + "?direct");
|
|
231
|
+
return [`/* [collectStyle] ${url} */`, res?.code];
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
return codes.flat().filter(Boolean).join("\n\n");
|
|
235
|
+
}
|
|
236
|
+
async function collectStyleUrls(server, entries) {
|
|
237
|
+
const visited = /* @__PURE__ */ new Set();
|
|
238
|
+
async function traverse(url) {
|
|
239
|
+
const [, id] = await server.moduleGraph.resolveUrl(url);
|
|
240
|
+
if (visited.has(id)) return;
|
|
241
|
+
visited.add(id);
|
|
242
|
+
const mod = server.moduleGraph.getModuleById(id);
|
|
243
|
+
if (!mod) return;
|
|
244
|
+
await Promise.all([...mod.importedModules].map((childMod) => traverse(childMod.url)));
|
|
245
|
+
}
|
|
246
|
+
await Promise.all(entries.map((e) => server.transformRequest(e)));
|
|
247
|
+
await Promise.all(entries.map((url) => traverse(url)));
|
|
248
|
+
return [...visited].filter((url) => url.match(CSS_LANGS_RE));
|
|
249
|
+
}
|
|
250
|
+
function renderPreloadLinks(ssrManifest, basePath = "") {
|
|
251
|
+
const seen = /* @__PURE__ */ new Set();
|
|
252
|
+
let links = "";
|
|
253
|
+
for (const moduleId in ssrManifest) {
|
|
254
|
+
const files = ssrManifest[moduleId];
|
|
255
|
+
if (files) {
|
|
256
|
+
files.forEach((file) => {
|
|
257
|
+
if (!seen.has(file)) {
|
|
258
|
+
seen.add(file);
|
|
259
|
+
links += renderPreloadLink(basePath ? `${basePath}/${file}` : `${file}`);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return links;
|
|
265
|
+
}
|
|
266
|
+
function renderPreloadLink(file) {
|
|
267
|
+
const fileType = file.match(/\.(js|css|woff2?|gif|jpe?g|png|svg)$/)?.[1];
|
|
268
|
+
switch (fileType) {
|
|
269
|
+
case "js":
|
|
270
|
+
return `<link rel="modulepreload" href="${file}">`;
|
|
271
|
+
case "css":
|
|
272
|
+
return `<link rel="stylesheet" href="${file}">`;
|
|
273
|
+
case "woff":
|
|
274
|
+
case "woff2":
|
|
275
|
+
return `<link rel="preload" href="${file}" as="font" type="font/${fileType}" crossorigin>`;
|
|
276
|
+
case "gif":
|
|
277
|
+
case "jpeg":
|
|
278
|
+
case "jpg":
|
|
279
|
+
case "png":
|
|
280
|
+
return `<link rel="preload" href="${file}" as="image" type="image/${fileType}">`;
|
|
281
|
+
case "svg":
|
|
282
|
+
return `<link rel="preload" href="${file}" as="image" type="image/svg+xml">`;
|
|
283
|
+
default:
|
|
284
|
+
return "";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
var callServiceMethod = async (serviceRegistry, serviceName, serviceMethod, params) => {
|
|
288
|
+
const service = serviceRegistry[serviceName];
|
|
289
|
+
if (service && typeof service[serviceMethod] === "function") {
|
|
290
|
+
const method = service[serviceMethod];
|
|
291
|
+
const data = await method(params);
|
|
292
|
+
if (typeof data !== "object" || data === null)
|
|
293
|
+
throw new Error(`Expected object response from service method ${serviceMethod} on ${serviceName}, but got ${typeof data}`);
|
|
294
|
+
return data;
|
|
295
|
+
}
|
|
296
|
+
throw new Error(`Service method ${serviceMethod} does not exist on ${serviceName}`);
|
|
297
|
+
};
|
|
298
|
+
var fetchData = async ({ url, options }) => {
|
|
299
|
+
if (url) {
|
|
300
|
+
const response = await fetch(url, options);
|
|
301
|
+
if (!response.ok) throw new Error(`Failed to fetch data from ${url}`);
|
|
302
|
+
const data = await response.json();
|
|
303
|
+
if (typeof data !== "object" || data === null) throw new Error(`Expected object response from ${url}, but got ${typeof data}`);
|
|
304
|
+
return data;
|
|
305
|
+
}
|
|
306
|
+
throw new Error("URL must be provided to fetch data");
|
|
307
|
+
};
|
|
308
|
+
var fetchInitialData = async (attr, params, serviceRegistry) => {
|
|
309
|
+
if (attr && typeof attr.fetch === "function") {
|
|
310
|
+
return attr.fetch(params, {
|
|
311
|
+
headers: { "Content-Type": "application/json" },
|
|
312
|
+
params
|
|
313
|
+
}).then(async (data) => {
|
|
314
|
+
if (data.serviceName && data.serviceMethod) {
|
|
315
|
+
return await callServiceMethod(serviceRegistry, data.serviceName, data.serviceMethod, data.options?.params ?? {});
|
|
316
|
+
}
|
|
317
|
+
return await fetchData(data);
|
|
318
|
+
}).catch((error) => {
|
|
319
|
+
console.error("Error fetching initial data:", error);
|
|
320
|
+
throw error;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
return Promise.resolve({});
|
|
324
|
+
};
|
|
325
|
+
var matchRoute = (url, renderRoutes) => {
|
|
326
|
+
for (const route of renderRoutes) {
|
|
327
|
+
const matcher = match(route.path, {
|
|
328
|
+
decode: decodeURIComponent
|
|
329
|
+
});
|
|
330
|
+
const matched = matcher(url);
|
|
331
|
+
if (matched) return { route, params: matched.params };
|
|
332
|
+
}
|
|
333
|
+
return null;
|
|
334
|
+
};
|
|
335
|
+
function getCssLinks(manifest, basePath = "") {
|
|
336
|
+
const seen = /* @__PURE__ */ new Set();
|
|
337
|
+
const styles = [];
|
|
338
|
+
for (const key in manifest) {
|
|
339
|
+
const entry = manifest[key];
|
|
340
|
+
if (entry && entry.css) {
|
|
341
|
+
for (const cssFile of entry.css) {
|
|
342
|
+
if (!seen.has(cssFile)) {
|
|
343
|
+
seen.add(cssFile);
|
|
344
|
+
styles.push(`<link rel="preload stylesheet" as="style" type="text/css" href="${basePath}/${cssFile}">`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return styles.join("\n");
|
|
350
|
+
}
|
|
351
|
+
var overrideCSSHMRConsoleError = () => {
|
|
352
|
+
const originalConsoleError = console.error;
|
|
353
|
+
console.error = function(message, ...optionalParams) {
|
|
354
|
+
if (typeof message === "string" && message.includes("css hmr is not supported in runtime mode")) return;
|
|
355
|
+
originalConsoleError.apply(console, [message, ...optionalParams]);
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
var ensureNonNull = (value, errorMessage) => {
|
|
359
|
+
if (value === void 0 || value === null) throw new Error(errorMessage);
|
|
360
|
+
return value;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// src/SSRServer.ts
|
|
364
|
+
var createMaps = () => {
|
|
365
|
+
return {
|
|
366
|
+
bootstrapModules: /* @__PURE__ */ new Map(),
|
|
367
|
+
cssLinks: /* @__PURE__ */ new Map(),
|
|
368
|
+
manifests: /* @__PURE__ */ new Map(),
|
|
369
|
+
preloadLinks: /* @__PURE__ */ new Map(),
|
|
370
|
+
renderModules: /* @__PURE__ */ new Map(),
|
|
371
|
+
ssrManifests: /* @__PURE__ */ new Map(),
|
|
372
|
+
templates: /* @__PURE__ */ new Map()
|
|
373
|
+
};
|
|
374
|
+
};
|
|
375
|
+
var processConfigs = (configs, baseClientRoot, templateDefaults) => {
|
|
376
|
+
return configs.map((config) => {
|
|
377
|
+
const clientRoot = path2.resolve(baseClientRoot, config.entryPoint);
|
|
378
|
+
return {
|
|
379
|
+
clientRoot,
|
|
380
|
+
entryPoint: config.entryPoint,
|
|
381
|
+
entryClient: config.entryClient || templateDefaults.defaultEntryClient,
|
|
382
|
+
entryServer: config.entryServer || templateDefaults.defaultEntryServer,
|
|
383
|
+
htmlTemplate: config.htmlTemplate || templateDefaults.defaultHtmlTemplate,
|
|
384
|
+
appId: config.appId
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
var SSRServer = (0, import_fastify_plugin.default)(
|
|
389
|
+
async (app, opts) => {
|
|
390
|
+
const { alias, configs, routes, serviceRegistry, isDebug, clientRoot: baseClientRoot } = opts;
|
|
391
|
+
const { bootstrapModules, cssLinks, manifests, preloadLinks, renderModules, ssrManifests, templates } = createMaps();
|
|
392
|
+
const processedConfigs = processConfigs(configs, baseClientRoot, TEMPLATE);
|
|
393
|
+
for (const config of processedConfigs) {
|
|
394
|
+
const { clientRoot, entryClient, htmlTemplate } = config;
|
|
395
|
+
const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
|
|
396
|
+
const templateHtml = await readFile(templateHtmlPath, "utf-8");
|
|
397
|
+
templates.set(clientRoot, templateHtml);
|
|
398
|
+
const relativeBasePath = path2.relative(baseClientRoot, clientRoot).replace(/\\/g, "/");
|
|
399
|
+
const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
|
|
400
|
+
if (!isDevelopment) {
|
|
401
|
+
const manifestPath = path2.join(clientRoot, ".vite/manifest.json");
|
|
402
|
+
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
403
|
+
const manifest = JSON.parse(manifestContent);
|
|
404
|
+
manifests.set(clientRoot, manifest);
|
|
405
|
+
const ssrManifestPath = path2.join(clientRoot, ".vite/ssr-manifest.json");
|
|
406
|
+
const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
|
|
407
|
+
const ssrManifest = JSON.parse(ssrManifestContent);
|
|
408
|
+
ssrManifests.set(clientRoot, ssrManifest);
|
|
409
|
+
const entryClientFile = manifest[`${entryClient}.tsx`]?.file;
|
|
410
|
+
if (!entryClientFile) throw new Error(`Entry client file not found in manifest for ${entryClient}.tsx`);
|
|
411
|
+
const bootstrapModule = `/${adjustedRelativePath}/${entryClientFile}`.replace(/\/{2,}/g, "/");
|
|
412
|
+
bootstrapModules.set(clientRoot, bootstrapModule);
|
|
413
|
+
const preloadLink = renderPreloadLinks(ssrManifest, adjustedRelativePath);
|
|
414
|
+
preloadLinks.set(clientRoot, preloadLink);
|
|
415
|
+
const cssLink = getCssLinks(manifest, adjustedRelativePath);
|
|
416
|
+
cssLinks.set(clientRoot, cssLink);
|
|
417
|
+
} else {
|
|
418
|
+
const bootstrapModule = `/${adjustedRelativePath}/${entryClient}`.replace(/\/{2,}/g, "/");
|
|
419
|
+
bootstrapModules.set(clientRoot, bootstrapModule);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
let viteDevServer;
|
|
423
|
+
await app.register(import("@fastify/static"), {
|
|
424
|
+
index: false,
|
|
425
|
+
prefix: "/",
|
|
426
|
+
root: baseClientRoot,
|
|
427
|
+
wildcard: false
|
|
428
|
+
});
|
|
429
|
+
if (isDevelopment) {
|
|
430
|
+
const { createServer } = await import("vite");
|
|
431
|
+
viteDevServer = await createServer({
|
|
432
|
+
appType: "custom",
|
|
433
|
+
css: {
|
|
434
|
+
preprocessorOptions: {
|
|
435
|
+
scss: {
|
|
436
|
+
api: "modern-compiler"
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
mode: "development",
|
|
441
|
+
plugins: [
|
|
442
|
+
...isDebug ? [
|
|
443
|
+
{
|
|
444
|
+
name: "taujs-development-server-debug-logging",
|
|
445
|
+
configureServer(server) {
|
|
446
|
+
console.log(import_picocolors.default.green("\u03C4js development server debug started."));
|
|
447
|
+
server.middlewares.use((req, res, next) => {
|
|
448
|
+
console.log(import_picocolors.default.cyan(`\u2190 rx: ${req.url}`));
|
|
449
|
+
res.on("finish", () => console.log(import_picocolors.default.yellow(`\u2192 tx: ${req.url}`)));
|
|
450
|
+
next();
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
] : []
|
|
455
|
+
],
|
|
456
|
+
resolve: {
|
|
457
|
+
alias: {
|
|
458
|
+
"@client": path2.resolve(baseClientRoot),
|
|
459
|
+
"@server": path2.resolve(__dirname),
|
|
460
|
+
"@shared": path2.resolve(__dirname, "../shared"),
|
|
461
|
+
...alias
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
root: baseClientRoot,
|
|
465
|
+
server: {
|
|
466
|
+
middlewareMode: true,
|
|
467
|
+
hmr: {
|
|
468
|
+
port: 5174
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
overrideCSSHMRConsoleError();
|
|
473
|
+
app.addHook("onRequest", async (request, reply) => {
|
|
474
|
+
await new Promise((resolve) => {
|
|
475
|
+
viteDevServer.middlewares(request.raw, reply.raw, () => {
|
|
476
|
+
if (!reply.sent) resolve();
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
app.get("/*", async (req, reply) => {
|
|
482
|
+
try {
|
|
483
|
+
if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
|
|
484
|
+
const url = req.url ? new URL(req.url, `http://${req.headers.host}`).pathname : "/";
|
|
485
|
+
const matchedRoute = matchRoute(url, routes);
|
|
486
|
+
if (!matchedRoute) {
|
|
487
|
+
reply.callNotFound();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const { route, params } = matchedRoute;
|
|
491
|
+
const { attr, appId } = route;
|
|
492
|
+
const config = processedConfigs.find((config2) => config2.appId === appId) || processedConfigs[0];
|
|
493
|
+
if (!config) throw new Error("No configuration found for the request.");
|
|
494
|
+
const { clientRoot, entryServer } = config;
|
|
495
|
+
let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
|
|
496
|
+
const bootstrapModule = bootstrapModules.get(clientRoot);
|
|
497
|
+
const cssLink = cssLinks.get(clientRoot);
|
|
498
|
+
const manifest = manifests.get(clientRoot);
|
|
499
|
+
const preloadLink = preloadLinks.get(clientRoot);
|
|
500
|
+
const ssrManifest = ssrManifests.get(clientRoot);
|
|
501
|
+
let renderModule;
|
|
502
|
+
if (isDevelopment) {
|
|
503
|
+
template = template.replace(/<script type="module" src="\/@vite\/client"><\/script>/g, "");
|
|
504
|
+
template = template.replace(/<style type="text\/css">[\s\S]*?<\/style>/g, "");
|
|
505
|
+
const entryServerPath = path2.join(clientRoot, `${entryServer}.tsx`);
|
|
506
|
+
const executedModule = await viteDevServer.ssrLoadModule(entryServerPath);
|
|
507
|
+
renderModule = executedModule;
|
|
508
|
+
const styles = await collectStyle(viteDevServer, [entryServerPath]);
|
|
509
|
+
template = template?.replace("</head>", `<style type="text/css">${styles}</style></head>`);
|
|
510
|
+
template = await viteDevServer.transformIndexHtml(url, template);
|
|
511
|
+
} else {
|
|
512
|
+
renderModule = renderModules.get(clientRoot);
|
|
513
|
+
if (!renderModule) {
|
|
514
|
+
const renderModulePath = path2.join(clientRoot, `${entryServer}.js`);
|
|
515
|
+
const importedModule = await import(renderModulePath);
|
|
516
|
+
renderModule = importedModule;
|
|
517
|
+
renderModules.set(clientRoot, renderModule);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const renderType = attr?.render || RENDERTYPE.ssr;
|
|
521
|
+
const [beforeBody = "", afterBody = ""] = template.split(SSRTAG.ssrHtml);
|
|
522
|
+
const [beforeHead = "", afterHead = ""] = beforeBody.split(SSRTAG.ssrHead);
|
|
523
|
+
const initialDataPromise = fetchInitialData(attr, params, serviceRegistry);
|
|
524
|
+
if (renderType === RENDERTYPE.ssr) {
|
|
525
|
+
const { renderSSR } = renderModule;
|
|
526
|
+
const initialDataResolved = await initialDataPromise;
|
|
527
|
+
const initialDataScript = `<script>window.__INITIAL_DATA__ = ${JSON.stringify(initialDataResolved).replace(/</g, "\\u003c")}</script>`;
|
|
528
|
+
const { headContent, appHtml } = await renderSSR(initialDataResolved, req.url, attr?.meta);
|
|
529
|
+
let aggregateHeadContent = headContent;
|
|
530
|
+
if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
|
|
531
|
+
if (manifest && cssLink) aggregateHeadContent += cssLink;
|
|
532
|
+
const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModule}" defer></script>`);
|
|
533
|
+
return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
|
|
534
|
+
} else {
|
|
535
|
+
const { renderStream } = renderModule;
|
|
536
|
+
reply.raw.writeHead(200, { "Content-Type": "text/html" });
|
|
537
|
+
renderStream(
|
|
538
|
+
reply.raw,
|
|
539
|
+
{
|
|
540
|
+
onHead: (headContent) => {
|
|
541
|
+
let aggregateHeadContent = headContent;
|
|
542
|
+
if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
|
|
543
|
+
if (manifest && cssLink) aggregateHeadContent += cssLink;
|
|
544
|
+
reply.raw.write(`${beforeHead}${aggregateHeadContent}${afterHead}`);
|
|
545
|
+
},
|
|
546
|
+
onFinish: async (initialDataResolved) => {
|
|
547
|
+
reply.raw.write(`<script>window.__INITIAL_DATA__ = ${JSON.stringify(initialDataResolved).replace(/</g, "\\u003c")}</script>`);
|
|
548
|
+
reply.raw.write(afterBody);
|
|
549
|
+
reply.raw.end();
|
|
550
|
+
},
|
|
551
|
+
onError: (error) => {
|
|
552
|
+
console.error("Critical rendering onError:", error);
|
|
553
|
+
reply.raw.end("Internal Server Error");
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
initialDataPromise,
|
|
557
|
+
req.url,
|
|
558
|
+
bootstrapModule,
|
|
559
|
+
attr?.meta
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error("Error setting up SSR stream:", error);
|
|
564
|
+
if (!reply.raw.headersSent) reply.raw.writeHead(500, { "Content-Type": "text/plain" });
|
|
565
|
+
reply.raw.end("Internal Server Error");
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
app.setNotFoundHandler(async (req, reply) => {
|
|
569
|
+
if (/\.\w+$/.test(req.raw.url ?? "")) return reply.callNotFound();
|
|
570
|
+
try {
|
|
571
|
+
const defaultConfig = processedConfigs[0];
|
|
572
|
+
if (!defaultConfig) throw new Error("No default configuration found.");
|
|
573
|
+
const { clientRoot } = defaultConfig;
|
|
574
|
+
let template = ensureNonNull(templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
|
|
575
|
+
const cssLink = cssLinks.get(clientRoot);
|
|
576
|
+
const bootstrapModule = bootstrapModules.get(clientRoot);
|
|
577
|
+
template = template.replace(SSRTAG.ssrHead, "").replace(SSRTAG.ssrHtml, "");
|
|
578
|
+
if (!isDevelopment && cssLink) template = template.replace("</head>", `${cssLink}</head>`);
|
|
579
|
+
if (bootstrapModule) template = template.replace("</body>", `<script type="module" src="${bootstrapModule}" defer></script></body>`);
|
|
580
|
+
reply.status(200).type("text/html").send(template);
|
|
581
|
+
} catch (error) {
|
|
582
|
+
console.error("Failed to serve clientHtmlTemplate:", error);
|
|
583
|
+
reply.status(500).send("Internal Server Error");
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
},
|
|
587
|
+
{ name: "taujs-ssr-server" }
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
// src/build.ts
|
|
591
|
+
async function taujsBuild({
|
|
592
|
+
config,
|
|
593
|
+
projectRoot,
|
|
594
|
+
clientBaseDir,
|
|
595
|
+
isSSRBuild = process.env.BUILD_MODE === "ssr"
|
|
596
|
+
}) {
|
|
597
|
+
const deleteDist = async () => {
|
|
598
|
+
const distPath = path3.resolve(projectRoot, "dist");
|
|
599
|
+
try {
|
|
600
|
+
await fs.rm(distPath, { recursive: true, force: true });
|
|
601
|
+
console.log("Deleted the dist directory\n");
|
|
602
|
+
} catch (err) {
|
|
603
|
+
console.error("Error deleting dist directory:", err);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
const processedConfigs = processConfigs(config, clientBaseDir, TEMPLATE);
|
|
607
|
+
if (!isSSRBuild) await deleteDist();
|
|
608
|
+
for (const config2 of processedConfigs) {
|
|
609
|
+
const { appId, entryPoint, clientRoot, entryClient, entryServer, htmlTemplate, plugins = [] } = config2;
|
|
610
|
+
const outDir = path3.resolve(projectRoot, `dist/client/${entryPoint}`);
|
|
611
|
+
const root = entryPoint ? path3.resolve(clientBaseDir, entryPoint) : clientBaseDir;
|
|
612
|
+
const server = path3.resolve(clientRoot, `${entryServer}.tsx`);
|
|
613
|
+
const client = path3.resolve(clientRoot, `${entryClient}.tsx`);
|
|
614
|
+
const main = path3.resolve(clientRoot, htmlTemplate);
|
|
615
|
+
const viteConfig = {
|
|
616
|
+
base: entryPoint ? `/${entryPoint}/` : "/",
|
|
617
|
+
build: {
|
|
618
|
+
outDir,
|
|
619
|
+
manifest: !isSSRBuild,
|
|
620
|
+
rollupOptions: {
|
|
621
|
+
input: isSSRBuild ? { server } : { client, main }
|
|
622
|
+
},
|
|
623
|
+
ssr: isSSRBuild ? server : void 0,
|
|
624
|
+
ssrManifest: isSSRBuild,
|
|
625
|
+
...isSSRBuild && {
|
|
626
|
+
format: "esm",
|
|
627
|
+
target: `node${process.versions.node.split(".").map(Number)[0]}`
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
css: {
|
|
631
|
+
preprocessorOptions: {
|
|
632
|
+
scss: { api: "modern-compiler" }
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
plugins: [...config2.plugins ?? [], nodePolyfills({ include: ["fs", "stream"] })],
|
|
636
|
+
publicDir: "public",
|
|
637
|
+
resolve: {
|
|
638
|
+
alias: {
|
|
639
|
+
"@client": root,
|
|
640
|
+
"@server": path3.resolve(projectRoot, "src/server"),
|
|
641
|
+
"@shared": path3.resolve(projectRoot, "src/shared")
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
root,
|
|
645
|
+
server: {
|
|
646
|
+
proxy: {
|
|
647
|
+
"/api": {
|
|
648
|
+
target: "http://localhost:3000",
|
|
649
|
+
changeOrigin: true,
|
|
650
|
+
rewrite: (path4) => path4.replace(/^\/api/, "")
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
try {
|
|
656
|
+
console.log(`Building for entryPoint: "${entryPoint}" (${appId})`);
|
|
657
|
+
await build(viteConfig);
|
|
658
|
+
console.log(`Build complete for entryPoint: "${entryPoint}"
|
|
659
|
+
`);
|
|
660
|
+
} catch (error) {
|
|
661
|
+
console.error(`Error building for entryPoint: "${entryPoint}"
|
|
662
|
+
`, error);
|
|
663
|
+
process.exit(1);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
export {
|
|
668
|
+
taujsBuild
|
|
669
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ServerResponse } from 'node:http';
|
|
2
2
|
import { FastifyPluginAsync } from 'fastify';
|
|
3
|
+
import { PluginOption } from 'vite';
|
|
3
4
|
|
|
4
5
|
declare const RENDERTYPE: {
|
|
5
6
|
ssr: string;
|
|
@@ -36,6 +37,7 @@ type ProcessedConfig = {
|
|
|
36
37
|
entryPoint: string;
|
|
37
38
|
entryServer: string;
|
|
38
39
|
htmlTemplate: string;
|
|
40
|
+
plugins?: PluginOption[];
|
|
39
41
|
};
|
|
40
42
|
type SSRServerOptions = {
|
|
41
43
|
alias?: Record<string, string>;
|
package/dist/index.js
CHANGED
|
@@ -523,7 +523,7 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
523
523
|
let aggregateHeadContent = headContent;
|
|
524
524
|
if (ssrManifest && preloadLink) aggregateHeadContent += preloadLink;
|
|
525
525
|
if (manifest && cssLink) aggregateHeadContent += cssLink;
|
|
526
|
-
const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModule}"
|
|
526
|
+
const fullHtml = template.replace(SSRTAG.ssrHead, aggregateHeadContent).replace(SSRTAG.ssrHtml, `${appHtml}${initialDataScript}<script type="module" src="${bootstrapModule}" defer></script>`);
|
|
527
527
|
return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
|
|
528
528
|
} else {
|
|
529
529
|
const { renderStream } = renderModule;
|
|
@@ -570,7 +570,7 @@ var SSRServer = (0, import_fastify_plugin.default)(
|
|
|
570
570
|
const bootstrapModule = bootstrapModules.get(clientRoot);
|
|
571
571
|
template = template.replace(SSRTAG.ssrHead, "").replace(SSRTAG.ssrHtml, "");
|
|
572
572
|
if (!isDevelopment && cssLink) template = template.replace("</head>", `${cssLink}</head>`);
|
|
573
|
-
if (bootstrapModule) template = template.replace("</body>", `<script type="module" src="${bootstrapModule}"
|
|
573
|
+
if (bootstrapModule) template = template.replace("</body>", `<script type="module" src="${bootstrapModule}" defer></script></body>`);
|
|
574
574
|
reply.status(200).type("text/html").send(template);
|
|
575
575
|
} catch (error) {
|
|
576
576
|
console.error("Failed to serve clientHtmlTemplate:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taujs/server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "taujs | τjs",
|
|
5
5
|
"author": "Aoede <taujs@aoede.uk.net> (https://www.aoede.uk.net)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"import": "./dist/index.js",
|
|
30
30
|
"types": "./dist/index.d.ts"
|
|
31
31
|
},
|
|
32
|
-
"./
|
|
33
|
-
"import": "./dist/
|
|
34
|
-
"types": "./dist/
|
|
32
|
+
"./build": {
|
|
33
|
+
"import": "./dist/build.js",
|
|
34
|
+
"types": "./dist/build.d.ts"
|
|
35
35
|
},
|
|
36
36
|
"./package.json": "./package.json"
|
|
37
37
|
},
|
|
@@ -40,22 +40,18 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@fastify/static": "^8.0.3",
|
|
43
|
-
"path-to-regexp": "^8.1.0"
|
|
43
|
+
"path-to-regexp": "^8.1.0",
|
|
44
|
+
"vite-plugin-node-polyfills": "^0.23.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@arethetypeswrong/cli": "^0.15.4",
|
|
47
48
|
"@babel/preset-typescript": "^7.24.7",
|
|
48
49
|
"@changesets/cli": "^2.27.7",
|
|
49
|
-
"@testing-library/dom": "^10.4.0",
|
|
50
|
-
"@testing-library/react": "^16.1.0",
|
|
51
50
|
"@types/node": "^20.14.9",
|
|
52
|
-
"@types/react": "^19.0.2",
|
|
53
|
-
"@types/react-dom": "^19.0.2",
|
|
54
51
|
"@vitest/coverage-v8": "^2.1.0",
|
|
55
52
|
"fastify": "^5.3.3",
|
|
56
53
|
"jsdom": "^25.0.0",
|
|
57
54
|
"prettier": "^3.3.3",
|
|
58
|
-
"react-dom": "^19.0.0",
|
|
59
55
|
"tsup": "^8.2.4",
|
|
60
56
|
"typescript": "^5.5.4",
|
|
61
57
|
"vite": "^6.3.5",
|
|
@@ -63,8 +59,6 @@
|
|
|
63
59
|
},
|
|
64
60
|
"peerDependencies": {
|
|
65
61
|
"fastify": "^5.3.3",
|
|
66
|
-
"react": "^19.0.0",
|
|
67
|
-
"react-dom": "^19.0.0",
|
|
68
62
|
"typescript": "^5.5.4",
|
|
69
63
|
"vite": "^6.3.5"
|
|
70
64
|
},
|