@blinkk/root 1.0.0-beta.0 → 1.0.0-beta.10
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/bin/root.js +3 -0
- package/client.d.ts +1 -0
- package/dist/chunk-LTSJAEBG.js +150 -0
- package/dist/chunk-LTSJAEBG.js.map +1 -0
- package/dist/{chunk-GGQGZ7ZE.js → chunk-WVRC46JG.js} +18 -18
- package/dist/chunk-WVRC46JG.js.map +1 -0
- package/dist/cli.d.ts +30 -4
- package/dist/cli.js +639 -697
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +2 -2
- package/dist/core.js +4 -4
- package/dist/node.d.ts +30 -0
- package/dist/node.js +12 -0
- package/dist/node.js.map +1 -0
- package/dist/render.d.ts +1 -1
- package/dist/render.js +85 -29
- package/dist/render.js.map +1 -1
- package/dist/{config-872b068d.d.ts → types-8310f09f.d.ts} +141 -131
- package/package.json +10 -4
- package/dist/chunk-GGQGZ7ZE.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,533 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
configureServerPlugins,
|
|
3
|
-
getVitePlugins
|
|
4
|
-
} from "./chunk-DTEQ2AIW.js";
|
|
5
1
|
import {
|
|
6
2
|
htmlMinify,
|
|
7
3
|
htmlPretty,
|
|
8
4
|
isValidTagName,
|
|
9
5
|
parseTagNames
|
|
10
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WVRC46JG.js";
|
|
7
|
+
import {
|
|
8
|
+
copyGlob,
|
|
9
|
+
createViteServer,
|
|
10
|
+
directoryContains,
|
|
11
|
+
fileExists,
|
|
12
|
+
isDirectory,
|
|
13
|
+
isJsFile,
|
|
14
|
+
loadJson,
|
|
15
|
+
loadRootConfig,
|
|
16
|
+
makeDir,
|
|
17
|
+
rmDir,
|
|
18
|
+
writeFile
|
|
19
|
+
} from "./chunk-LTSJAEBG.js";
|
|
20
|
+
import {
|
|
21
|
+
configureServerPlugins,
|
|
22
|
+
getVitePlugins
|
|
23
|
+
} from "./chunk-DTEQ2AIW.js";
|
|
11
24
|
|
|
12
|
-
// src/cli/commands/
|
|
13
|
-
import
|
|
25
|
+
// src/cli/commands/build.ts
|
|
26
|
+
import path3 from "node:path";
|
|
14
27
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { default as express } from "express";
|
|
16
|
-
import { createServer as createViteServer } from "vite";
|
|
17
|
-
|
|
18
|
-
// src/render/asset-map/dev-asset-map.ts
|
|
19
|
-
import path2 from "node:path";
|
|
20
|
-
import { searchForWorkspaceRoot } from "vite";
|
|
21
|
-
|
|
22
|
-
// src/utils/fsutils.ts
|
|
23
|
-
import { promises as fs } from "node:fs";
|
|
24
|
-
import path from "node:path";
|
|
25
28
|
import fsExtra from "fs-extra";
|
|
26
|
-
import glob from "tiny-glob";
|
|
27
|
-
function isJsFile(filename) {
|
|
28
|
-
return !!filename.match(/\.(j|t)sx?$/);
|
|
29
|
-
}
|
|
30
|
-
async function writeFile(filepath, content) {
|
|
31
|
-
const dirPath = path.dirname(filepath);
|
|
32
|
-
await makeDir(dirPath);
|
|
33
|
-
await fs.writeFile(filepath, content);
|
|
34
|
-
}
|
|
35
|
-
async function makeDir(dirpath) {
|
|
36
|
-
try {
|
|
37
|
-
await fs.access(dirpath);
|
|
38
|
-
} catch (e) {
|
|
39
|
-
await fs.mkdir(dirpath, { recursive: true });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async function copyGlob(pattern, srcdir, dstdir) {
|
|
43
|
-
const files = await glob(pattern, { cwd: srcdir });
|
|
44
|
-
if (files.length > 0) {
|
|
45
|
-
await makeDir(dstdir);
|
|
46
|
-
}
|
|
47
|
-
files.forEach((file) => {
|
|
48
|
-
fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
async function rmDir(dirpath) {
|
|
52
|
-
await fs.rm(dirpath, { recursive: true, force: true });
|
|
53
|
-
}
|
|
54
|
-
async function loadJson(filepath) {
|
|
55
|
-
const content = await fs.readFile(filepath, "utf-8");
|
|
56
|
-
return JSON.parse(content);
|
|
57
|
-
}
|
|
58
|
-
async function isDirectory(dirpath) {
|
|
59
|
-
return fs.stat(dirpath).then((fsStat) => {
|
|
60
|
-
return fsStat.isDirectory();
|
|
61
|
-
}).catch((err) => {
|
|
62
|
-
if (err.code === "ENOENT") {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
throw err;
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
function fileExists(filepath) {
|
|
69
|
-
return fs.access(filepath).then(() => true).catch(() => false);
|
|
70
|
-
}
|
|
71
|
-
async function directoryContains(dirpath, subpath) {
|
|
72
|
-
const outer = await fs.realpath(dirpath);
|
|
73
|
-
const inner = await fs.realpath(subpath);
|
|
74
|
-
const rel = path.relative(outer, inner);
|
|
75
|
-
return !rel.startsWith("..");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/render/asset-map/dev-asset-map.ts
|
|
79
|
-
var DevServerAssetMap = class {
|
|
80
|
-
constructor(rootConfig, moduleGraph) {
|
|
81
|
-
this.rootConfig = rootConfig;
|
|
82
|
-
this.moduleGraph = moduleGraph;
|
|
83
|
-
}
|
|
84
|
-
async get(src) {
|
|
85
|
-
const file = path2.resolve(this.rootConfig.rootDir, src);
|
|
86
|
-
const viteModules = this.moduleGraph.getModulesByFile(file);
|
|
87
|
-
if (viteModules && viteModules.size > 0) {
|
|
88
|
-
const [viteModule] = viteModules;
|
|
89
|
-
return new DevServerAsset(src, {
|
|
90
|
-
assetMap: this,
|
|
91
|
-
viteModule
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
if (file.startsWith(this.rootConfig.rootDir)) {
|
|
95
|
-
const assetUrl = file.slice(this.rootConfig.rootDir.length);
|
|
96
|
-
return {
|
|
97
|
-
src,
|
|
98
|
-
assetUrl,
|
|
99
|
-
getCssDeps: async () => [],
|
|
100
|
-
getJsDeps: async () => [assetUrl]
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
const workspaceRoot = searchForWorkspaceRoot(this.rootConfig.rootDir);
|
|
104
|
-
if (await directoryContains(workspaceRoot, file)) {
|
|
105
|
-
const assetUrl = `/@fs/${file}`;
|
|
106
|
-
return {
|
|
107
|
-
src,
|
|
108
|
-
assetUrl,
|
|
109
|
-
getCssDeps: async () => [],
|
|
110
|
-
getJsDeps: async () => [assetUrl]
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
console.log(`could not find asset in asset map: ${src}`);
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
filePathToSrc(file) {
|
|
117
|
-
return path2.relative(this.rootConfig.rootDir, file);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
var DevServerAsset = class {
|
|
121
|
-
constructor(src, options) {
|
|
122
|
-
this.src = src;
|
|
123
|
-
this.assetMap = options.assetMap;
|
|
124
|
-
this.viteModule = options.viteModule;
|
|
125
|
-
this.moduleId = this.viteModule.id;
|
|
126
|
-
this.assetUrl = this.viteModule.url;
|
|
127
|
-
}
|
|
128
|
-
async getCssDeps() {
|
|
129
|
-
const visited = /* @__PURE__ */ new Set();
|
|
130
|
-
const deps = /* @__PURE__ */ new Set();
|
|
131
|
-
this.collectCss(this, deps, visited);
|
|
132
|
-
return Array.from(deps);
|
|
133
|
-
}
|
|
134
|
-
async getJsDeps() {
|
|
135
|
-
const visited = /* @__PURE__ */ new Set();
|
|
136
|
-
const deps = /* @__PURE__ */ new Set();
|
|
137
|
-
this.collectJs(this, deps, visited);
|
|
138
|
-
return Array.from(deps);
|
|
139
|
-
}
|
|
140
|
-
getImportedModules() {
|
|
141
|
-
return this.viteModule.importedModules;
|
|
142
|
-
}
|
|
143
|
-
collectJs(asset, urls, visited) {
|
|
144
|
-
if (!asset) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (!asset.moduleId) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (visited.has(asset.moduleId)) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
visited.add(asset.moduleId);
|
|
154
|
-
const parts = path2.parse(asset.assetUrl);
|
|
155
|
-
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
156
|
-
urls.add(asset.assetUrl);
|
|
157
|
-
}
|
|
158
|
-
asset.getImportedModules().forEach((viteModule) => {
|
|
159
|
-
if (viteModule.file) {
|
|
160
|
-
const src = this.assetMap.filePathToSrc(viteModule.file);
|
|
161
|
-
const importedAsset = new DevServerAsset(src, {
|
|
162
|
-
assetMap: this.assetMap,
|
|
163
|
-
viteModule
|
|
164
|
-
});
|
|
165
|
-
this.collectJs(importedAsset, urls, visited);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
collectCss(asset, urls, visited) {
|
|
170
|
-
if (!asset) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (!asset.assetUrl) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
if (visited.has(asset.assetUrl)) {
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
visited.add(asset.assetUrl);
|
|
180
|
-
if (asset.src.endsWith(".scss")) {
|
|
181
|
-
const parts = path2.parse(asset.src);
|
|
182
|
-
if (!parts.name.startsWith("_")) {
|
|
183
|
-
urls.add(asset.assetUrl);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
asset.getImportedModules().forEach((viteModule) => {
|
|
187
|
-
if (viteModule.file) {
|
|
188
|
-
const src = this.assetMap.filePathToSrc(viteModule.file);
|
|
189
|
-
const importedAsset = new DevServerAsset(src, {
|
|
190
|
-
assetMap: this.assetMap,
|
|
191
|
-
viteModule
|
|
192
|
-
});
|
|
193
|
-
this.collectCss(importedAsset, urls, visited);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// src/cli/load-config.ts
|
|
200
|
-
import { bundleRequire } from "bundle-require";
|
|
201
|
-
import JoyCon from "joycon";
|
|
202
|
-
async function loadRootConfig(rootDir) {
|
|
203
|
-
const joycon = new JoyCon();
|
|
204
|
-
const configPath = await joycon.resolve({
|
|
205
|
-
cwd: rootDir,
|
|
206
|
-
files: ["root.config.ts"]
|
|
207
|
-
});
|
|
208
|
-
if (configPath) {
|
|
209
|
-
const configBundle = await bundleRequire({
|
|
210
|
-
filepath: configPath
|
|
211
|
-
});
|
|
212
|
-
return Object.assign({}, configBundle.mod.default || {}, { rootDir });
|
|
213
|
-
}
|
|
214
|
-
return { rootDir };
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/cli/commands/dev.ts
|
|
218
|
-
import glob3 from "tiny-glob";
|
|
219
|
-
import { dim } from "kleur/colors";
|
|
220
|
-
|
|
221
|
-
// src/core/middleware.ts
|
|
222
|
-
function rootProjectMiddleware(options) {
|
|
223
|
-
return (req, _, next) => {
|
|
224
|
-
req.rootConfig = Object.assign({}, options.rootConfig, {
|
|
225
|
-
rootDir: options.rootDir
|
|
226
|
-
});
|
|
227
|
-
next();
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// src/cli/ports.ts
|
|
232
|
-
import { createServer } from "node:net";
|
|
233
|
-
function isPortOpen(port) {
|
|
234
|
-
return new Promise((resolve, reject) => {
|
|
235
|
-
const server = createServer();
|
|
236
|
-
server.on("error", (err) => {
|
|
237
|
-
if (err.code === "EADDRINUSE") {
|
|
238
|
-
resolve(false);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
reject(err);
|
|
242
|
-
});
|
|
243
|
-
server.on("close", () => {
|
|
244
|
-
resolve(true);
|
|
245
|
-
});
|
|
246
|
-
server.listen(port, () => {
|
|
247
|
-
server.close((err) => {
|
|
248
|
-
if (err) {
|
|
249
|
-
console.log(`error closing server: ${err}`);
|
|
250
|
-
reject(err);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
async function findOpenPort(min, max) {
|
|
257
|
-
let port = min;
|
|
258
|
-
while (port <= max) {
|
|
259
|
-
const isOpen = await isPortOpen(port);
|
|
260
|
-
if (isOpen) {
|
|
261
|
-
return port;
|
|
262
|
-
}
|
|
263
|
-
port += 1;
|
|
264
|
-
}
|
|
265
|
-
throw new Error(`no ports open between ${min} and ${max}`);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// src/core/element-graph.ts
|
|
269
|
-
import fs2 from "node:fs";
|
|
270
|
-
import path3 from "node:path";
|
|
271
|
-
import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
|
|
272
29
|
import glob2 from "tiny-glob";
|
|
273
|
-
var ElementGraph = class {
|
|
274
|
-
constructor(sourceFiles) {
|
|
275
|
-
this.sourceFiles = {};
|
|
276
|
-
this.deps = {};
|
|
277
|
-
this.sourceFiles = sourceFiles;
|
|
278
|
-
}
|
|
279
|
-
getDeps(tagName, visited) {
|
|
280
|
-
visited ??= /* @__PURE__ */ new Set();
|
|
281
|
-
if (visited.has(tagName)) {
|
|
282
|
-
return [];
|
|
283
|
-
}
|
|
284
|
-
visited.add(tagName);
|
|
285
|
-
this.deps[tagName] ??= this.parseDepsFromSource(tagName);
|
|
286
|
-
const deps = new Set(this.deps[tagName]);
|
|
287
|
-
for (const depTagName of this.deps[tagName]) {
|
|
288
|
-
for (const childDep of this.getDeps(depTagName, visited)) {
|
|
289
|
-
deps.add(childDep);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return Array.from(deps);
|
|
293
|
-
}
|
|
294
|
-
parseDepsFromSource(tagName) {
|
|
295
|
-
const srcFile = this.sourceFiles[tagName];
|
|
296
|
-
if (!srcFile) {
|
|
297
|
-
throw new Error(`could not find file path for tagName <${tagName}>`);
|
|
298
|
-
}
|
|
299
|
-
const src = fs2.readFileSync(srcFile.filePath, "utf-8");
|
|
300
|
-
const tagNames = parseTagNames(src);
|
|
301
|
-
const deps = /* @__PURE__ */ new Set();
|
|
302
|
-
for (const depTagName of tagNames) {
|
|
303
|
-
if (depTagName !== tagName && depTagName in this.sourceFiles) {
|
|
304
|
-
deps.add(depTagName);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return Array.from(deps);
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
async function getElements(rootConfig) {
|
|
311
|
-
var _a, _b;
|
|
312
|
-
const rootDir = rootConfig.rootDir;
|
|
313
|
-
const workspaceRoot = searchForWorkspaceRoot2(rootDir);
|
|
314
|
-
const elementsDirs = [path3.join(rootDir, "elements")];
|
|
315
|
-
const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
|
|
316
|
-
const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
|
|
317
|
-
const excludeElement = (moduleId) => {
|
|
318
|
-
return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
|
|
319
|
-
};
|
|
320
|
-
for (const dirPath of elementsInclude) {
|
|
321
|
-
const elementsDir = path3.resolve(rootDir, dirPath);
|
|
322
|
-
if (!directoryContains(rootDir, elementsDir)) {
|
|
323
|
-
throw new Error(
|
|
324
|
-
`the elements dir (${dirPath}) should be within the project's workspace (${workspaceRoot})`
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
elementsDirs.push(elementsDir);
|
|
328
|
-
}
|
|
329
|
-
const elementFilePaths = {};
|
|
330
|
-
for (const dirPath of elementsDirs) {
|
|
331
|
-
if (await isDirectory(dirPath)) {
|
|
332
|
-
const files = await glob2("**/*", { cwd: dirPath });
|
|
333
|
-
files.forEach((file) => {
|
|
334
|
-
const parts = path3.parse(file);
|
|
335
|
-
if (isJsFile(parts.base) && isValidTagName(parts.name)) {
|
|
336
|
-
const tagName = parts.name;
|
|
337
|
-
const filePath = path3.join(dirPath, file);
|
|
338
|
-
const relPath = path3.relative(rootDir, filePath);
|
|
339
|
-
if (!excludeElement(relPath)) {
|
|
340
|
-
elementFilePaths[tagName] = { filePath, relPath };
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
const graph = new ElementGraph(elementFilePaths);
|
|
347
|
-
return graph;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// src/cli/commands/dev.ts
|
|
351
|
-
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
352
|
-
async function dev(rootProjectDir) {
|
|
353
|
-
process.env.NODE_ENV = "development";
|
|
354
|
-
const rootDir = path4.resolve(rootProjectDir || process.cwd());
|
|
355
|
-
const defaultPort = parseInt(process.env.PORT || "4007");
|
|
356
|
-
const port = await findOpenPort(defaultPort, defaultPort + 10);
|
|
357
|
-
console.log();
|
|
358
|
-
console.log(`${dim("\u2503")} project: ${rootDir}`);
|
|
359
|
-
console.log(`${dim("\u2503")} server: http://localhost:${port}`);
|
|
360
|
-
console.log(`${dim("\u2503")} mode: development`);
|
|
361
|
-
console.log();
|
|
362
|
-
const server = await createServer2({ rootDir, port });
|
|
363
|
-
server.listen(port);
|
|
364
|
-
}
|
|
365
|
-
async function createServer2(options) {
|
|
366
|
-
const rootDir = path4.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
|
|
367
|
-
const rootConfig = await loadRootConfig(rootDir);
|
|
368
|
-
const port = options == null ? void 0 : options.port;
|
|
369
|
-
const server = express();
|
|
370
|
-
server.disable("x-powered-by");
|
|
371
|
-
server.use(rootProjectMiddleware({ rootDir, rootConfig }));
|
|
372
|
-
server.use(await viteServerMiddleware({ rootDir, rootConfig, port }));
|
|
373
|
-
const plugins = rootConfig.plugins || [];
|
|
374
|
-
await configureServerPlugins(
|
|
375
|
-
server,
|
|
376
|
-
async () => {
|
|
377
|
-
var _a;
|
|
378
|
-
const userMiddlewares = ((_a = rootConfig.server) == null ? void 0 : _a.middlewares) || [];
|
|
379
|
-
for (const middleware of userMiddlewares) {
|
|
380
|
-
server.use(middleware);
|
|
381
|
-
}
|
|
382
|
-
server.use(rootDevServerMiddleware());
|
|
383
|
-
server.use(rootDevServer404Middleware());
|
|
384
|
-
server.use(rootDevServer500Middleware());
|
|
385
|
-
},
|
|
386
|
-
plugins,
|
|
387
|
-
{ type: "dev", rootConfig }
|
|
388
|
-
);
|
|
389
|
-
return server;
|
|
390
|
-
}
|
|
391
|
-
async function viteServerMiddleware(options) {
|
|
392
|
-
var _a, _b;
|
|
393
|
-
const rootDir = options.rootDir;
|
|
394
|
-
const rootConfig = options.rootConfig;
|
|
395
|
-
const viteConfig = rootConfig.vite || {};
|
|
396
|
-
let hmrOptions = (_a = viteConfig.server) == null ? void 0 : _a.hmr;
|
|
397
|
-
if (typeof hmrOptions === "undefined" && options.port) {
|
|
398
|
-
hmrOptions = { port: options.port + 10 };
|
|
399
|
-
}
|
|
400
|
-
const routeFiles = [];
|
|
401
|
-
if (await isDirectory(path4.join(rootDir, "routes"))) {
|
|
402
|
-
const pageFiles = await glob3("routes/**/*", { cwd: rootDir });
|
|
403
|
-
pageFiles.forEach((file) => {
|
|
404
|
-
const parts = path4.parse(file);
|
|
405
|
-
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
406
|
-
routeFiles.push(file);
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
const elementGraph = await getElements(rootConfig);
|
|
411
|
-
const elements = Object.values(elementGraph.sourceFiles).map((sourceFile) => {
|
|
412
|
-
return sourceFile.relPath;
|
|
413
|
-
});
|
|
414
|
-
const bundleScripts = [];
|
|
415
|
-
if (await isDirectory(path4.join(rootDir, "bundles"))) {
|
|
416
|
-
const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
|
|
417
|
-
bundleFiles.forEach((file) => {
|
|
418
|
-
const parts = path4.parse(file);
|
|
419
|
-
if (isJsFile(parts.base)) {
|
|
420
|
-
bundleScripts.push(file);
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
const viteServer = await createViteServer({
|
|
425
|
-
...viteConfig,
|
|
426
|
-
mode: "development",
|
|
427
|
-
root: rootDir,
|
|
428
|
-
publicDir: path4.join(rootDir, "public"),
|
|
429
|
-
server: {
|
|
430
|
-
...viteConfig.server || {},
|
|
431
|
-
middlewareMode: true,
|
|
432
|
-
hmr: hmrOptions
|
|
433
|
-
},
|
|
434
|
-
appType: "custom",
|
|
435
|
-
optimizeDeps: {
|
|
436
|
-
...viteConfig.optimizeDeps || {},
|
|
437
|
-
include: [
|
|
438
|
-
...elements,
|
|
439
|
-
...bundleScripts,
|
|
440
|
-
...((_b = viteConfig.optimizeDeps) == null ? void 0 : _b.include) || []
|
|
441
|
-
]
|
|
442
|
-
},
|
|
443
|
-
ssr: {
|
|
444
|
-
...viteConfig.ssr || {},
|
|
445
|
-
noExternal: ["@blinkk/root"]
|
|
446
|
-
},
|
|
447
|
-
esbuild: {
|
|
448
|
-
...viteConfig.esbuild || {},
|
|
449
|
-
jsx: "automatic",
|
|
450
|
-
jsxImportSource: "preact"
|
|
451
|
-
},
|
|
452
|
-
plugins: [
|
|
453
|
-
...viteConfig.plugins || [],
|
|
454
|
-
...getVitePlugins(rootConfig.plugins || [])
|
|
455
|
-
]
|
|
456
|
-
});
|
|
457
|
-
return async (req, res, next) => {
|
|
458
|
-
try {
|
|
459
|
-
req.viteServer = viteServer;
|
|
460
|
-
const renderModulePath = path4.resolve(__dirname, "./render.js");
|
|
461
|
-
const render = await viteServer.ssrLoadModule(renderModulePath);
|
|
462
|
-
const assetMap = new DevServerAssetMap(
|
|
463
|
-
rootConfig,
|
|
464
|
-
viteServer.moduleGraph
|
|
465
|
-
);
|
|
466
|
-
req.renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
467
|
-
viteServer.middlewares(req, res, next);
|
|
468
|
-
} catch (e) {
|
|
469
|
-
next(e);
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
function rootDevServerMiddleware() {
|
|
474
|
-
return async (req, res, next) => {
|
|
475
|
-
const renderer = req.renderer;
|
|
476
|
-
const viteServer = req.viteServer;
|
|
477
|
-
try {
|
|
478
|
-
await renderer.handle(req, res, next);
|
|
479
|
-
} catch (err) {
|
|
480
|
-
viteServer.ssrFixStacktrace(err);
|
|
481
|
-
next(err);
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
function rootDevServer404Middleware() {
|
|
486
|
-
return async (req, res) => {
|
|
487
|
-
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
488
|
-
if (req.renderer) {
|
|
489
|
-
const url = req.path;
|
|
490
|
-
const ext = path4.extname(url);
|
|
491
|
-
if (!ext) {
|
|
492
|
-
const renderer = req.renderer;
|
|
493
|
-
const data = await renderer.renderDevServer404(req);
|
|
494
|
-
const html = data.html || "";
|
|
495
|
-
res.status(404).set({ "Content-Type": "text/html" }).end(html);
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
res.status(404).set({ "Content-Type": "text/plain" }).end("404");
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
function rootDevServer500Middleware() {
|
|
503
|
-
return async (err, req, res, next) => {
|
|
504
|
-
console.error(`\u2757 500 ${req.originalUrl}`);
|
|
505
|
-
console.error(String(err.stack || err));
|
|
506
|
-
if (req.renderer) {
|
|
507
|
-
const url = req.path;
|
|
508
|
-
const ext = path4.extname(url);
|
|
509
|
-
if (!ext) {
|
|
510
|
-
const renderer = req.renderer;
|
|
511
|
-
const data = await renderer.renderDevServer500(req, err);
|
|
512
|
-
const html = data.html || "";
|
|
513
|
-
res.status(500).set({ "Content-Type": "text/html" }).end(html);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
next(err);
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// src/cli/commands/build.ts
|
|
522
|
-
import path6 from "node:path";
|
|
523
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
524
|
-
import fsExtra2 from "fs-extra";
|
|
525
|
-
import glob4 from "tiny-glob";
|
|
526
30
|
import { build as viteBuild } from "vite";
|
|
527
31
|
|
|
528
32
|
// src/render/asset-map/build-asset-map.ts
|
|
529
|
-
import
|
|
530
|
-
import
|
|
33
|
+
import fs from "node:fs";
|
|
34
|
+
import path from "node:path";
|
|
531
35
|
var BuildAssetMap = class {
|
|
532
36
|
constructor(rootConfig) {
|
|
533
37
|
this.rootConfig = rootConfig;
|
|
@@ -575,7 +79,7 @@ var BuildAssetMap = class {
|
|
|
575
79
|
const src = manifestKey;
|
|
576
80
|
const manifestChunk = clientManifest[manifestKey];
|
|
577
81
|
const isElement = elementFiles.has(src);
|
|
578
|
-
const assetUrl = src.startsWith("routes/") ? "" : `/${manifestChunk.file}`;
|
|
82
|
+
const assetUrl = src.startsWith("routes/") && isJsFile(src) ? "" : `/${manifestChunk.file}`;
|
|
579
83
|
const assetData = {
|
|
580
84
|
src,
|
|
581
85
|
assetUrl,
|
|
@@ -597,12 +101,12 @@ var BuildAssetMap = class {
|
|
|
597
101
|
}
|
|
598
102
|
};
|
|
599
103
|
function realPathRelativeTo(rootDir, src) {
|
|
600
|
-
const fullPath =
|
|
601
|
-
if (!
|
|
104
|
+
const fullPath = path.resolve(rootDir, src);
|
|
105
|
+
if (!fs.existsSync(fullPath)) {
|
|
602
106
|
return src;
|
|
603
107
|
}
|
|
604
|
-
const realpath =
|
|
605
|
-
return
|
|
108
|
+
const realpath = fs.realpathSync(path.resolve(rootDir, src));
|
|
109
|
+
return path.relative(rootDir, realpath);
|
|
606
110
|
}
|
|
607
111
|
var BuildAsset = class {
|
|
608
112
|
constructor(assetMap, assetData) {
|
|
@@ -676,33 +180,131 @@ var BuildAsset = class {
|
|
|
676
180
|
isElement: this.isElement
|
|
677
181
|
};
|
|
678
182
|
}
|
|
679
|
-
};
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// src/cli/commands/build.ts
|
|
186
|
+
import { dim, cyan } from "kleur/colors";
|
|
187
|
+
|
|
188
|
+
// src/node/element-graph.ts
|
|
189
|
+
import fs2 from "node:fs";
|
|
190
|
+
import path2 from "node:path";
|
|
191
|
+
import { searchForWorkspaceRoot } from "vite";
|
|
192
|
+
import glob from "tiny-glob";
|
|
193
|
+
var ElementGraph = class {
|
|
194
|
+
constructor(sourceFiles) {
|
|
195
|
+
this.sourceFiles = {};
|
|
196
|
+
this.deps = {};
|
|
197
|
+
this.sourceFiles = sourceFiles;
|
|
198
|
+
}
|
|
199
|
+
toJson() {
|
|
200
|
+
for (const tagName in this.sourceFiles) {
|
|
201
|
+
this.deps[tagName] ??= this.parseDepsFromSource(tagName);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
sourceFiles: this.sourceFiles,
|
|
205
|
+
deps: this.deps
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
static fromJson(data) {
|
|
209
|
+
const graph = new ElementGraph(data.sourceFiles);
|
|
210
|
+
graph.deps = data.deps;
|
|
211
|
+
return graph;
|
|
212
|
+
}
|
|
213
|
+
getDeps(tagName, visited) {
|
|
214
|
+
visited ??= /* @__PURE__ */ new Set();
|
|
215
|
+
if (visited.has(tagName)) {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
visited.add(tagName);
|
|
219
|
+
this.deps[tagName] ??= this.parseDepsFromSource(tagName);
|
|
220
|
+
const deps = new Set(this.deps[tagName]);
|
|
221
|
+
for (const depTagName of this.deps[tagName]) {
|
|
222
|
+
for (const childDep of this.getDeps(depTagName, visited)) {
|
|
223
|
+
deps.add(childDep);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return Array.from(deps);
|
|
227
|
+
}
|
|
228
|
+
parseDepsFromSource(tagName) {
|
|
229
|
+
const srcFile = this.sourceFiles[tagName];
|
|
230
|
+
if (!srcFile) {
|
|
231
|
+
throw new Error(`could not find file path for tagName <${tagName}>`);
|
|
232
|
+
}
|
|
233
|
+
const src = fs2.readFileSync(srcFile.filePath, "utf-8");
|
|
234
|
+
const tagNames = parseTagNames(src);
|
|
235
|
+
const deps = /* @__PURE__ */ new Set();
|
|
236
|
+
for (const depTagName of tagNames) {
|
|
237
|
+
if (depTagName !== tagName && depTagName in this.sourceFiles) {
|
|
238
|
+
deps.add(depTagName);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return Array.from(deps);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
async function getElements(rootConfig) {
|
|
245
|
+
var _a, _b;
|
|
246
|
+
const rootDir = rootConfig.rootDir;
|
|
247
|
+
const workspaceRoot = searchForWorkspaceRoot(rootDir);
|
|
248
|
+
const elementsDirs = [path2.join(rootDir, "elements")];
|
|
249
|
+
const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
|
|
250
|
+
const excludePatterns = ((_b = rootConfig.elements) == null ? void 0 : _b.exclude) || [];
|
|
251
|
+
const excludeElement = (moduleId) => {
|
|
252
|
+
return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
|
|
253
|
+
};
|
|
254
|
+
for (const dirPath of elementsInclude) {
|
|
255
|
+
const elementsDir = path2.resolve(rootDir, dirPath);
|
|
256
|
+
if (!directoryContains(rootDir, elementsDir)) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`the elements dir (${dirPath}) should be within the project's workspace (${workspaceRoot})`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
elementsDirs.push(elementsDir);
|
|
262
|
+
}
|
|
263
|
+
const elementFilePaths = {};
|
|
264
|
+
for (const dirPath of elementsDirs) {
|
|
265
|
+
if (await isDirectory(dirPath)) {
|
|
266
|
+
const files = await glob("**/*", { cwd: dirPath });
|
|
267
|
+
files.forEach((file) => {
|
|
268
|
+
const parts = path2.parse(file);
|
|
269
|
+
if (isJsFile(parts.base) && isValidTagName(parts.name)) {
|
|
270
|
+
const tagName = parts.name;
|
|
271
|
+
const filePath = path2.join(dirPath, file);
|
|
272
|
+
const relPath = path2.relative(rootDir, filePath);
|
|
273
|
+
if (!excludeElement(relPath)) {
|
|
274
|
+
elementFilePaths[tagName] = { filePath, relPath };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const graph = new ElementGraph(elementFilePaths);
|
|
281
|
+
return graph;
|
|
282
|
+
}
|
|
680
283
|
|
|
681
284
|
// src/cli/commands/build.ts
|
|
682
|
-
|
|
683
|
-
var __dirname2 = path6.dirname(fileURLToPath2(import.meta.url));
|
|
285
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
684
286
|
async function build(rootProjectDir, options) {
|
|
685
287
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
686
288
|
const mode = (options == null ? void 0 : options.mode) || "production";
|
|
687
289
|
process.env.NODE_ENV = mode;
|
|
688
|
-
const rootDir =
|
|
689
|
-
const rootConfig = await loadRootConfig(rootDir);
|
|
690
|
-
const distDir =
|
|
290
|
+
const rootDir = path3.resolve(rootProjectDir || process.cwd());
|
|
291
|
+
const rootConfig = await loadRootConfig(rootDir, { command: "build" });
|
|
292
|
+
const distDir = path3.join(rootDir, "dist");
|
|
691
293
|
const ssrOnly = (options == null ? void 0 : options.ssrOnly) || false;
|
|
692
294
|
console.log();
|
|
693
|
-
console.log(`${
|
|
694
|
-
console.log(`${
|
|
695
|
-
console.log(`${
|
|
295
|
+
console.log(`${dim("\u2503")} project: ${rootDir}`);
|
|
296
|
+
console.log(`${dim("\u2503")} output: ${distDir}/html`);
|
|
297
|
+
console.log(`${dim("\u2503")} mode: ${mode}`);
|
|
696
298
|
console.log();
|
|
697
299
|
await rmDir(distDir);
|
|
698
300
|
await makeDir(distDir);
|
|
699
301
|
const routeFiles = [];
|
|
700
|
-
if (await isDirectory(
|
|
701
|
-
const pageFiles = await
|
|
302
|
+
if (await isDirectory(path3.join(rootDir, "routes"))) {
|
|
303
|
+
const pageFiles = await glob2("routes/**/*", { cwd: rootDir });
|
|
702
304
|
pageFiles.forEach((file) => {
|
|
703
|
-
const parts =
|
|
305
|
+
const parts = path3.parse(file);
|
|
704
306
|
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
705
|
-
routeFiles.push(
|
|
307
|
+
routeFiles.push(path3.resolve(rootDir, file));
|
|
706
308
|
}
|
|
707
309
|
});
|
|
708
310
|
}
|
|
@@ -711,12 +313,12 @@ async function build(rootProjectDir, options) {
|
|
|
711
313
|
return sourceFile.filePath;
|
|
712
314
|
});
|
|
713
315
|
const bundleScripts = [];
|
|
714
|
-
if (await isDirectory(
|
|
715
|
-
const bundleFiles = await
|
|
316
|
+
if (await isDirectory(path3.join(rootDir, "bundles"))) {
|
|
317
|
+
const bundleFiles = await glob2("bundles/*", { cwd: rootDir });
|
|
716
318
|
bundleFiles.forEach((file) => {
|
|
717
|
-
const parts =
|
|
319
|
+
const parts = path3.parse(file);
|
|
718
320
|
if (isJsFile(parts.base)) {
|
|
719
|
-
bundleScripts.push(
|
|
321
|
+
bundleScripts.push(path3.resolve(rootDir, file));
|
|
720
322
|
}
|
|
721
323
|
});
|
|
722
324
|
}
|
|
@@ -739,7 +341,7 @@ async function build(rootProjectDir, options) {
|
|
|
739
341
|
plugins: vitePlugins
|
|
740
342
|
};
|
|
741
343
|
const ssrInput = {
|
|
742
|
-
render:
|
|
344
|
+
render: path3.resolve(__dirname, "./render.js")
|
|
743
345
|
};
|
|
744
346
|
rootPlugins.forEach((plugin) => {
|
|
745
347
|
if (plugin.ssrInput) {
|
|
@@ -769,7 +371,7 @@ async function build(rootProjectDir, options) {
|
|
|
769
371
|
assetFileNames: "assets/[name].[hash][extname]"
|
|
770
372
|
}
|
|
771
373
|
},
|
|
772
|
-
outDir:
|
|
374
|
+
outDir: path3.join(distDir, "server"),
|
|
773
375
|
ssr: true,
|
|
774
376
|
ssrManifest: false,
|
|
775
377
|
cssCodeSplit: true,
|
|
@@ -800,7 +402,7 @@ async function build(rootProjectDir, options) {
|
|
|
800
402
|
...(_e = (_d = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _d.rollupOptions) == null ? void 0 : _e.output
|
|
801
403
|
}
|
|
802
404
|
},
|
|
803
|
-
outDir:
|
|
405
|
+
outDir: path3.join(distDir, "routes"),
|
|
804
406
|
ssr: false,
|
|
805
407
|
ssrManifest: false,
|
|
806
408
|
manifest: true,
|
|
@@ -829,7 +431,7 @@ async function build(rootProjectDir, options) {
|
|
|
829
431
|
...(_h = (_g = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _g.rollupOptions) == null ? void 0 : _h.output
|
|
830
432
|
}
|
|
831
433
|
},
|
|
832
|
-
outDir:
|
|
434
|
+
outDir: path3.join(distDir, "client"),
|
|
833
435
|
ssr: false,
|
|
834
436
|
ssrManifest: false,
|
|
835
437
|
manifest: true,
|
|
@@ -840,164 +442,480 @@ async function build(rootProjectDir, options) {
|
|
|
840
442
|
reportCompressedSize: false
|
|
841
443
|
}
|
|
842
444
|
});
|
|
843
|
-
} else {
|
|
844
|
-
await writeFile(
|
|
845
|
-
}
|
|
846
|
-
await copyGlob(
|
|
847
|
-
"*.css",
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
);
|
|
851
|
-
const routesManifest = await loadJson(
|
|
852
|
-
|
|
853
|
-
);
|
|
854
|
-
const clientManifest = await loadJson(
|
|
855
|
-
|
|
856
|
-
);
|
|
857
|
-
function collectRouteCss(asset, cssDeps, visited) {
|
|
858
|
-
if (!asset || !asset.file || visited.has(asset.file)) {
|
|
859
|
-
return;
|
|
860
|
-
}
|
|
861
|
-
visited.add(asset.file);
|
|
862
|
-
if (asset.css) {
|
|
863
|
-
asset.css.forEach((dep) => cssDeps.add(dep));
|
|
864
|
-
}
|
|
865
|
-
if (asset.imports) {
|
|
866
|
-
asset.imports.forEach((manifestKey) => {
|
|
867
|
-
collectRouteCss(routesManifest[manifestKey], cssDeps, visited);
|
|
445
|
+
} else {
|
|
446
|
+
await writeFile(path3.join(distDir, "client/manifest.json"), "{}");
|
|
447
|
+
}
|
|
448
|
+
await copyGlob(
|
|
449
|
+
"*.css",
|
|
450
|
+
path3.join(distDir, "routes/assets"),
|
|
451
|
+
path3.join(distDir, "client/assets")
|
|
452
|
+
);
|
|
453
|
+
const routesManifest = await loadJson(
|
|
454
|
+
path3.join(distDir, "routes/manifest.json")
|
|
455
|
+
);
|
|
456
|
+
const clientManifest = await loadJson(
|
|
457
|
+
path3.join(distDir, "client/manifest.json")
|
|
458
|
+
);
|
|
459
|
+
function collectRouteCss(asset, cssDeps, visited) {
|
|
460
|
+
if (!asset || !asset.file || visited.has(asset.file)) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
visited.add(asset.file);
|
|
464
|
+
if (asset.css) {
|
|
465
|
+
asset.css.forEach((dep) => cssDeps.add(dep));
|
|
466
|
+
}
|
|
467
|
+
if (asset.imports) {
|
|
468
|
+
asset.imports.forEach((manifestKey) => {
|
|
469
|
+
collectRouteCss(routesManifest[manifestKey], cssDeps, visited);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
Object.keys(routesManifest).forEach((manifestKey) => {
|
|
474
|
+
const asset = routesManifest[manifestKey];
|
|
475
|
+
if (asset.isEntry) {
|
|
476
|
+
const visited = /* @__PURE__ */ new Set();
|
|
477
|
+
const cssDeps = /* @__PURE__ */ new Set();
|
|
478
|
+
collectRouteCss(asset, cssDeps, visited);
|
|
479
|
+
asset.css = Array.from(cssDeps);
|
|
480
|
+
asset.imports = [];
|
|
481
|
+
clientManifest[manifestKey] = asset;
|
|
482
|
+
} else if (asset.file.endsWith(".css")) {
|
|
483
|
+
clientManifest[manifestKey] = asset;
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
const assetMap = BuildAssetMap.fromViteManifest(
|
|
487
|
+
rootConfig,
|
|
488
|
+
clientManifest,
|
|
489
|
+
elementGraph
|
|
490
|
+
);
|
|
491
|
+
const rootManifest = assetMap.toJson();
|
|
492
|
+
await writeFile(
|
|
493
|
+
path3.join(distDir, "client/root-manifest.json"),
|
|
494
|
+
JSON.stringify(rootManifest, null, 2)
|
|
495
|
+
);
|
|
496
|
+
const elementGraphJson = elementGraph.toJson();
|
|
497
|
+
await writeFile(
|
|
498
|
+
path3.join(distDir, "client/root-element-graph.json"),
|
|
499
|
+
JSON.stringify(elementGraphJson, null, 2)
|
|
500
|
+
);
|
|
501
|
+
const buildDir = path3.join(distDir, "html");
|
|
502
|
+
const publicDir = path3.join(rootDir, "public");
|
|
503
|
+
if (fsExtra.existsSync(path3.join(rootDir, "public"))) {
|
|
504
|
+
fsExtra.copySync(publicDir, buildDir, { dereference: true });
|
|
505
|
+
} else {
|
|
506
|
+
await makeDir(buildDir);
|
|
507
|
+
}
|
|
508
|
+
await makeDir(path3.join(buildDir, "assets"));
|
|
509
|
+
await makeDir(path3.join(buildDir, "chunks"));
|
|
510
|
+
console.log("\njs/css output:");
|
|
511
|
+
await Promise.all(
|
|
512
|
+
Object.keys(rootManifest).map(async (src) => {
|
|
513
|
+
if (isRouteFile(src)) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const assetData = rootManifest[src];
|
|
517
|
+
if (!assetData.assetUrl) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const assetRelPath = assetData.assetUrl.slice(1);
|
|
521
|
+
const assetFrom = path3.join(distDir, "client", assetRelPath);
|
|
522
|
+
const assetTo = path3.join(buildDir, assetRelPath);
|
|
523
|
+
if (!await fileExists(assetFrom)) {
|
|
524
|
+
console.log(`${assetFrom} does not exist`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
await fsExtra.copy(assetFrom, assetTo);
|
|
528
|
+
printFileOutput(fileSize(assetTo), "dist/html/", assetRelPath);
|
|
529
|
+
})
|
|
530
|
+
);
|
|
531
|
+
if (!ssrOnly) {
|
|
532
|
+
const render = await import(path3.join(distDir, "server/render.js"));
|
|
533
|
+
const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
534
|
+
const sitemap = await renderer.getSitemap();
|
|
535
|
+
console.log("\nhtml output:");
|
|
536
|
+
await Promise.all(
|
|
537
|
+
Object.keys(sitemap).map(async (urlPath) => {
|
|
538
|
+
const { route, params } = sitemap[urlPath];
|
|
539
|
+
const data = await renderer.renderRoute(route, {
|
|
540
|
+
routeParams: params
|
|
541
|
+
});
|
|
542
|
+
if (data.notFound) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
let outFilePath = path3.join(urlPath.slice(1), "index.html");
|
|
546
|
+
if (outFilePath.endsWith("404/index.html")) {
|
|
547
|
+
outFilePath = outFilePath.replace("404/index.html", "404.html");
|
|
548
|
+
}
|
|
549
|
+
const outPath = path3.join(buildDir, outFilePath);
|
|
550
|
+
let html = data.html || "";
|
|
551
|
+
if (rootConfig.prettyHtml !== false) {
|
|
552
|
+
html = await htmlPretty(html, rootConfig.prettyHtmlOptions);
|
|
553
|
+
}
|
|
554
|
+
if (rootConfig.minifyHtml !== false) {
|
|
555
|
+
html = await htmlMinify(html, rootConfig.minifyHtmlOptions);
|
|
556
|
+
}
|
|
557
|
+
await writeFile(outPath, html);
|
|
558
|
+
printFileOutput(fileSize(outPath), "dist/html/", outFilePath);
|
|
559
|
+
})
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function isRouteFile(filepath) {
|
|
564
|
+
return filepath.startsWith("routes") && isJsFile(filepath);
|
|
565
|
+
}
|
|
566
|
+
function fileSize(filepath) {
|
|
567
|
+
const stats = fsExtra.statSync(filepath);
|
|
568
|
+
const bytes = stats.size;
|
|
569
|
+
const k = 1024;
|
|
570
|
+
if (bytes < k) {
|
|
571
|
+
return (bytes / k).toFixed(2) + " kB";
|
|
572
|
+
}
|
|
573
|
+
const units = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
574
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
575
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + units[i];
|
|
576
|
+
}
|
|
577
|
+
function printFileOutput(fileSize2, outputDir, outputFile) {
|
|
578
|
+
const indent = " ".repeat(2);
|
|
579
|
+
const paddedSize = fileSize2.padStart(9, " ");
|
|
580
|
+
console.log(
|
|
581
|
+
`${indent}${dim(paddedSize)} ${dim(outputDir)}${cyan(outputFile)}`
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/cli/commands/dev.ts
|
|
586
|
+
import path5 from "node:path";
|
|
587
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
588
|
+
import { default as express } from "express";
|
|
589
|
+
|
|
590
|
+
// src/render/asset-map/dev-asset-map.ts
|
|
591
|
+
import path4 from "node:path";
|
|
592
|
+
import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
|
|
593
|
+
var DevServerAssetMap = class {
|
|
594
|
+
constructor(rootConfig, moduleGraph) {
|
|
595
|
+
this.rootConfig = rootConfig;
|
|
596
|
+
this.moduleGraph = moduleGraph;
|
|
597
|
+
}
|
|
598
|
+
async get(src) {
|
|
599
|
+
const file = path4.resolve(this.rootConfig.rootDir, src);
|
|
600
|
+
const viteModules = this.moduleGraph.getModulesByFile(file);
|
|
601
|
+
if (viteModules && viteModules.size > 0) {
|
|
602
|
+
const [viteModule] = viteModules;
|
|
603
|
+
return new DevServerAsset(src, {
|
|
604
|
+
assetMap: this,
|
|
605
|
+
viteModule
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (file.startsWith(this.rootConfig.rootDir)) {
|
|
609
|
+
const assetUrl = file.slice(this.rootConfig.rootDir.length);
|
|
610
|
+
return {
|
|
611
|
+
src,
|
|
612
|
+
assetUrl,
|
|
613
|
+
getCssDeps: async () => [],
|
|
614
|
+
getJsDeps: async () => [assetUrl]
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const workspaceRoot = searchForWorkspaceRoot2(this.rootConfig.rootDir);
|
|
618
|
+
if (await directoryContains(workspaceRoot, file)) {
|
|
619
|
+
const assetUrl = `/@fs/${file}`;
|
|
620
|
+
return {
|
|
621
|
+
src,
|
|
622
|
+
assetUrl,
|
|
623
|
+
getCssDeps: async () => [],
|
|
624
|
+
getJsDeps: async () => [assetUrl]
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
console.log(`could not find asset in asset map: ${src}`);
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
filePathToSrc(file) {
|
|
631
|
+
return path4.relative(this.rootConfig.rootDir, file);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
var DevServerAsset = class {
|
|
635
|
+
constructor(src, options) {
|
|
636
|
+
this.src = src;
|
|
637
|
+
this.assetMap = options.assetMap;
|
|
638
|
+
this.viteModule = options.viteModule;
|
|
639
|
+
this.moduleId = this.viteModule.id;
|
|
640
|
+
this.assetUrl = this.viteModule.url;
|
|
641
|
+
}
|
|
642
|
+
async getCssDeps() {
|
|
643
|
+
const visited = /* @__PURE__ */ new Set();
|
|
644
|
+
const deps = /* @__PURE__ */ new Set();
|
|
645
|
+
this.collectCss(this, deps, visited);
|
|
646
|
+
return Array.from(deps);
|
|
647
|
+
}
|
|
648
|
+
async getJsDeps() {
|
|
649
|
+
const visited = /* @__PURE__ */ new Set();
|
|
650
|
+
const deps = /* @__PURE__ */ new Set();
|
|
651
|
+
this.collectJs(this, deps, visited);
|
|
652
|
+
return Array.from(deps);
|
|
653
|
+
}
|
|
654
|
+
getImportedModules() {
|
|
655
|
+
return this.viteModule.importedModules;
|
|
656
|
+
}
|
|
657
|
+
collectJs(asset, urls, visited) {
|
|
658
|
+
if (!asset) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (!asset.moduleId) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (visited.has(asset.moduleId)) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
visited.add(asset.moduleId);
|
|
668
|
+
const parts = path4.parse(asset.assetUrl);
|
|
669
|
+
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
670
|
+
urls.add(asset.assetUrl);
|
|
671
|
+
}
|
|
672
|
+
asset.getImportedModules().forEach((viteModule) => {
|
|
673
|
+
if (viteModule.file) {
|
|
674
|
+
const src = this.assetMap.filePathToSrc(viteModule.file);
|
|
675
|
+
const importedAsset = new DevServerAsset(src, {
|
|
676
|
+
assetMap: this.assetMap,
|
|
677
|
+
viteModule
|
|
678
|
+
});
|
|
679
|
+
this.collectJs(importedAsset, urls, visited);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
collectCss(asset, urls, visited) {
|
|
684
|
+
if (!asset) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if (!asset.assetUrl) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (visited.has(asset.assetUrl)) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
visited.add(asset.assetUrl);
|
|
694
|
+
if (asset.src.endsWith(".scss")) {
|
|
695
|
+
const parts = path4.parse(asset.src);
|
|
696
|
+
if (!parts.name.startsWith("_")) {
|
|
697
|
+
urls.add(asset.assetUrl);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
asset.getImportedModules().forEach((viteModule) => {
|
|
701
|
+
if (viteModule.file) {
|
|
702
|
+
const src = this.assetMap.filePathToSrc(viteModule.file);
|
|
703
|
+
const importedAsset = new DevServerAsset(src, {
|
|
704
|
+
assetMap: this.assetMap,
|
|
705
|
+
viteModule
|
|
706
|
+
});
|
|
707
|
+
this.collectCss(importedAsset, urls, visited);
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// src/cli/commands/dev.ts
|
|
714
|
+
import { dim as dim2 } from "kleur/colors";
|
|
715
|
+
|
|
716
|
+
// src/core/middleware.ts
|
|
717
|
+
function rootProjectMiddleware(options) {
|
|
718
|
+
return (req, _, next) => {
|
|
719
|
+
req.rootConfig = options.rootConfig;
|
|
720
|
+
next();
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/utils/ports.ts
|
|
725
|
+
import { createServer } from "node:net";
|
|
726
|
+
function isPortOpen(port) {
|
|
727
|
+
return new Promise((resolve, reject) => {
|
|
728
|
+
const server = createServer();
|
|
729
|
+
server.on("error", (err) => {
|
|
730
|
+
if (err.code === "EADDRINUSE") {
|
|
731
|
+
resolve(false);
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
reject(err);
|
|
735
|
+
});
|
|
736
|
+
server.on("close", () => {
|
|
737
|
+
resolve(true);
|
|
738
|
+
});
|
|
739
|
+
server.listen(port, () => {
|
|
740
|
+
server.close((err) => {
|
|
741
|
+
if (err) {
|
|
742
|
+
console.log(`error closing server: ${err}`);
|
|
743
|
+
reject(err);
|
|
744
|
+
}
|
|
868
745
|
});
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
Object.keys(routesManifest).forEach((manifestKey) => {
|
|
872
|
-
const asset = routesManifest[manifestKey];
|
|
873
|
-
if (asset.isEntry) {
|
|
874
|
-
const visited = /* @__PURE__ */ new Set();
|
|
875
|
-
const cssDeps = /* @__PURE__ */ new Set();
|
|
876
|
-
collectRouteCss(asset, cssDeps, visited);
|
|
877
|
-
asset.css = Array.from(cssDeps);
|
|
878
|
-
asset.imports = [];
|
|
879
|
-
clientManifest[manifestKey] = asset;
|
|
880
|
-
} else if (asset.file.endsWith(".css")) {
|
|
881
|
-
clientManifest[manifestKey] = asset;
|
|
882
|
-
}
|
|
746
|
+
});
|
|
883
747
|
});
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
);
|
|
894
|
-
const buildDir = path6.join(distDir, "html");
|
|
895
|
-
const publicDir = path6.join(rootDir, "public");
|
|
896
|
-
if (fsExtra2.existsSync(path6.join(rootDir, "public"))) {
|
|
897
|
-
fsExtra2.copySync(publicDir, buildDir, { dereference: true });
|
|
898
|
-
} else {
|
|
899
|
-
makeDir(buildDir);
|
|
748
|
+
}
|
|
749
|
+
async function findOpenPort(min, max) {
|
|
750
|
+
let port = min;
|
|
751
|
+
while (port <= max) {
|
|
752
|
+
const isOpen = await isPortOpen(port);
|
|
753
|
+
if (isOpen) {
|
|
754
|
+
return port;
|
|
755
|
+
}
|
|
756
|
+
port += 1;
|
|
900
757
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
758
|
+
throw new Error(`no ports open between ${min} and ${max}`);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/cli/commands/dev.ts
|
|
762
|
+
import glob3 from "tiny-glob";
|
|
763
|
+
var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
764
|
+
async function dev(rootProjectDir, options) {
|
|
765
|
+
process.env.NODE_ENV = "development";
|
|
766
|
+
const rootDir = path5.resolve(rootProjectDir || process.cwd());
|
|
767
|
+
const defaultPort = parseInt(process.env.PORT || "4007");
|
|
768
|
+
const host = (options == null ? void 0 : options.host) || "localhost";
|
|
769
|
+
const port = await findOpenPort(defaultPort, defaultPort + 10);
|
|
770
|
+
console.log();
|
|
771
|
+
console.log(`${dim2("\u2503")} project: ${rootDir}`);
|
|
772
|
+
console.log(`${dim2("\u2503")} server: http://${host}:${port}`);
|
|
773
|
+
console.log(`${dim2("\u2503")} mode: development`);
|
|
774
|
+
console.log();
|
|
775
|
+
const server = await createDevServer({ rootDir, port });
|
|
776
|
+
server.listen(port, host);
|
|
777
|
+
}
|
|
778
|
+
async function createDevServer(options) {
|
|
779
|
+
const rootDir = path5.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
|
|
780
|
+
const rootConfig = await loadRootConfig(rootDir, { command: "dev" });
|
|
781
|
+
const port = options == null ? void 0 : options.port;
|
|
782
|
+
const server = express();
|
|
783
|
+
server.disable("x-powered-by");
|
|
784
|
+
server.use(rootProjectMiddleware({ rootConfig }));
|
|
785
|
+
server.use(await viteServerMiddleware({ rootConfig, port }));
|
|
786
|
+
const plugins = rootConfig.plugins || [];
|
|
787
|
+
await configureServerPlugins(
|
|
788
|
+
server,
|
|
789
|
+
async () => {
|
|
790
|
+
var _a;
|
|
791
|
+
const userMiddlewares = ((_a = rootConfig.server) == null ? void 0 : _a.middlewares) || [];
|
|
792
|
+
for (const middleware of userMiddlewares) {
|
|
793
|
+
server.use(middleware);
|
|
916
794
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
795
|
+
server.use(rootDevServerMiddleware());
|
|
796
|
+
server.use(rootDevServer404Middleware());
|
|
797
|
+
server.use(rootDevServer500Middleware());
|
|
798
|
+
},
|
|
799
|
+
plugins,
|
|
800
|
+
{ type: "dev", rootConfig }
|
|
920
801
|
);
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
const outPath = path6.join(buildDir, outFilePath);
|
|
940
|
-
let html = data.html || "";
|
|
941
|
-
if (rootConfig.prettyHtml !== false) {
|
|
942
|
-
html = await htmlPretty(html, rootConfig.prettyHtmlOptions);
|
|
943
|
-
}
|
|
944
|
-
if (rootConfig.minifyHtml !== false) {
|
|
945
|
-
html = await htmlMinify(html, rootConfig.minifyHtmlOptions);
|
|
946
|
-
}
|
|
947
|
-
await writeFile(outPath, html);
|
|
948
|
-
printFileOutput(fileSize(outPath), "dist/html/", outFilePath);
|
|
949
|
-
})
|
|
950
|
-
);
|
|
802
|
+
return server;
|
|
803
|
+
}
|
|
804
|
+
async function viteServerMiddleware(options) {
|
|
805
|
+
const rootConfig = options.rootConfig;
|
|
806
|
+
const rootDir = rootConfig.rootDir;
|
|
807
|
+
const elementGraph = await getElements(rootConfig);
|
|
808
|
+
const elements = Object.values(elementGraph.sourceFiles).map((sourceFile) => {
|
|
809
|
+
return sourceFile.relPath;
|
|
810
|
+
});
|
|
811
|
+
const bundleScripts = [];
|
|
812
|
+
if (await isDirectory(path5.join(rootDir, "bundles"))) {
|
|
813
|
+
const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
|
|
814
|
+
bundleFiles.forEach((file) => {
|
|
815
|
+
const parts = path5.parse(file);
|
|
816
|
+
if (isJsFile(parts.base)) {
|
|
817
|
+
bundleScripts.push(file);
|
|
818
|
+
}
|
|
819
|
+
});
|
|
951
820
|
}
|
|
821
|
+
const optimizeDeps = [...elements, ...bundleScripts];
|
|
822
|
+
const viteServer = await createViteServer(rootConfig, {
|
|
823
|
+
port: options.port,
|
|
824
|
+
optimizeDeps
|
|
825
|
+
});
|
|
826
|
+
return async (req, res, next) => {
|
|
827
|
+
try {
|
|
828
|
+
req.viteServer = viteServer;
|
|
829
|
+
const renderModulePath = path5.resolve(__dirname2, "./render.js");
|
|
830
|
+
const render = await viteServer.ssrLoadModule(
|
|
831
|
+
renderModulePath
|
|
832
|
+
);
|
|
833
|
+
const assetMap = new DevServerAssetMap(
|
|
834
|
+
rootConfig,
|
|
835
|
+
viteServer.moduleGraph
|
|
836
|
+
);
|
|
837
|
+
req.renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
838
|
+
viteServer.middlewares(req, res, next);
|
|
839
|
+
} catch (e) {
|
|
840
|
+
next(e);
|
|
841
|
+
}
|
|
842
|
+
};
|
|
952
843
|
}
|
|
953
|
-
function
|
|
954
|
-
return
|
|
844
|
+
function rootDevServerMiddleware() {
|
|
845
|
+
return async (req, res, next) => {
|
|
846
|
+
const renderer = req.renderer;
|
|
847
|
+
const viteServer = req.viteServer;
|
|
848
|
+
try {
|
|
849
|
+
await renderer.handle(req, res, next);
|
|
850
|
+
} catch (err) {
|
|
851
|
+
viteServer.ssrFixStacktrace(err);
|
|
852
|
+
next(err);
|
|
853
|
+
}
|
|
854
|
+
};
|
|
955
855
|
}
|
|
956
|
-
function
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
856
|
+
function rootDevServer404Middleware() {
|
|
857
|
+
return async (req, res) => {
|
|
858
|
+
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
859
|
+
if (req.renderer) {
|
|
860
|
+
const url = req.path;
|
|
861
|
+
const ext = path5.extname(url);
|
|
862
|
+
if (!ext) {
|
|
863
|
+
const renderer = req.renderer;
|
|
864
|
+
const data = await renderer.renderDevServer404(req);
|
|
865
|
+
const html = data.html || "";
|
|
866
|
+
res.status(404).set({ "Content-Type": "text/html" }).end(html);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
res.status(404).set({ "Content-Type": "text/plain" }).end("404");
|
|
871
|
+
};
|
|
966
872
|
}
|
|
967
|
-
function
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
873
|
+
function rootDevServer500Middleware() {
|
|
874
|
+
return async (err, req, res, next) => {
|
|
875
|
+
console.error(`\u2757 500 ${req.originalUrl}`);
|
|
876
|
+
console.error(String(err.stack || err));
|
|
877
|
+
if (req.renderer) {
|
|
878
|
+
const url = req.path;
|
|
879
|
+
const ext = path5.extname(url);
|
|
880
|
+
if (!ext) {
|
|
881
|
+
const renderer = req.renderer;
|
|
882
|
+
const data = await renderer.renderDevServer500(req, err);
|
|
883
|
+
const html = data.html || "";
|
|
884
|
+
res.status(500).set({ "Content-Type": "text/html" }).end(html);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
next(err);
|
|
889
|
+
};
|
|
973
890
|
}
|
|
974
891
|
|
|
975
892
|
// src/cli/commands/preview.ts
|
|
976
|
-
import
|
|
893
|
+
import path6 from "node:path";
|
|
977
894
|
import { default as express2 } from "express";
|
|
978
895
|
import { dim as dim3 } from "kleur/colors";
|
|
979
896
|
import sirv from "sirv";
|
|
980
897
|
import compression from "compression";
|
|
981
|
-
async function preview(rootProjectDir) {
|
|
898
|
+
async function preview(rootProjectDir, options) {
|
|
982
899
|
process.env.NODE_ENV = "development";
|
|
983
|
-
const rootDir =
|
|
984
|
-
const server = await
|
|
900
|
+
const rootDir = path6.resolve(rootProjectDir || process.cwd());
|
|
901
|
+
const server = await createPreviewServer({ rootDir });
|
|
985
902
|
const port = parseInt(process.env.PORT || "4007");
|
|
903
|
+
const host = (options == null ? void 0 : options.host) || "localhost";
|
|
986
904
|
console.log();
|
|
987
905
|
console.log(`${dim3("\u2503")} project: ${rootDir}`);
|
|
988
|
-
console.log(`${dim3("\u2503")} server: http
|
|
906
|
+
console.log(`${dim3("\u2503")} server: http://${host}:${port}`);
|
|
989
907
|
console.log(`${dim3("\u2503")} mode: preview`);
|
|
990
908
|
console.log();
|
|
991
|
-
server.listen(port);
|
|
909
|
+
server.listen(port, host);
|
|
992
910
|
}
|
|
993
|
-
async function
|
|
911
|
+
async function createPreviewServer(options) {
|
|
994
912
|
const rootDir = options.rootDir;
|
|
995
|
-
const rootConfig = await loadRootConfig(rootDir);
|
|
996
|
-
const distDir =
|
|
913
|
+
const rootConfig = await loadRootConfig(rootDir, { command: "preview" });
|
|
914
|
+
const distDir = path6.join(rootDir, "dist");
|
|
997
915
|
const server = express2();
|
|
998
916
|
server.disable("x-powered-by");
|
|
999
917
|
server.use(compression());
|
|
1000
|
-
server.use(rootProjectMiddleware({
|
|
918
|
+
server.use(rootProjectMiddleware({ rootConfig }));
|
|
1001
919
|
server.use(await rootPreviewRendererMiddleware({ rootConfig, distDir }));
|
|
1002
920
|
const plugins = rootConfig.plugins || [];
|
|
1003
921
|
configureServerPlugins(
|
|
@@ -1008,7 +926,7 @@ async function createServer3(options) {
|
|
|
1008
926
|
userMiddlewares.forEach((middleware) => {
|
|
1009
927
|
server.use(middleware);
|
|
1010
928
|
});
|
|
1011
|
-
const publicDir =
|
|
929
|
+
const publicDir = path6.join(distDir, "html");
|
|
1012
930
|
server.use(sirv(publicDir, { dev: false }));
|
|
1013
931
|
server.use(rootPreviewServerMiddleware());
|
|
1014
932
|
server.use(rootPreviewServer404Middleware());
|
|
@@ -1021,16 +939,26 @@ async function createServer3(options) {
|
|
|
1021
939
|
}
|
|
1022
940
|
async function rootPreviewRendererMiddleware(options) {
|
|
1023
941
|
const { distDir, rootConfig } = options;
|
|
1024
|
-
const render = await import(
|
|
1025
|
-
const manifestPath =
|
|
942
|
+
const render = await import(path6.join(distDir, "server/render.js"));
|
|
943
|
+
const manifestPath = path6.join(distDir, "client/root-manifest.json");
|
|
1026
944
|
if (!await fileExists(manifestPath)) {
|
|
1027
945
|
throw new Error(
|
|
1028
946
|
`could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
|
|
1029
947
|
);
|
|
1030
948
|
}
|
|
949
|
+
const elementGraphJsonPath = path6.join(
|
|
950
|
+
distDir,
|
|
951
|
+
"client/root-element-graph.json"
|
|
952
|
+
);
|
|
953
|
+
if (!await fileExists(elementGraphJsonPath)) {
|
|
954
|
+
throw new Error(
|
|
955
|
+
`could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
|
|
956
|
+
);
|
|
957
|
+
}
|
|
1031
958
|
const rootManifest = await loadJson(manifestPath);
|
|
1032
959
|
const assetMap = BuildAssetMap.fromRootManifest(rootConfig, rootManifest);
|
|
1033
|
-
const
|
|
960
|
+
const elementGraphJson = await loadJson(elementGraphJsonPath);
|
|
961
|
+
const elementGraph = ElementGraph.fromJson(elementGraphJson);
|
|
1034
962
|
const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
1035
963
|
return async (req, _, next) => {
|
|
1036
964
|
req.renderer = renderer;
|
|
@@ -1058,7 +986,7 @@ function rootPreviewServer404Middleware() {
|
|
|
1058
986
|
return async (req, res) => {
|
|
1059
987
|
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
1060
988
|
const url = req.path;
|
|
1061
|
-
const ext =
|
|
989
|
+
const ext = path6.extname(url);
|
|
1062
990
|
const renderer = req.renderer;
|
|
1063
991
|
if (!ext) {
|
|
1064
992
|
const data = await renderer.render404();
|
|
@@ -1074,7 +1002,7 @@ function rootPreviewServer500Middleware() {
|
|
|
1074
1002
|
console.error(`\u2757 500 ${req.originalUrl}`);
|
|
1075
1003
|
console.error(String(err.stack || err));
|
|
1076
1004
|
const url = req.path;
|
|
1077
|
-
const ext =
|
|
1005
|
+
const ext = path6.extname(url);
|
|
1078
1006
|
const renderer = req.renderer;
|
|
1079
1007
|
if (!ext) {
|
|
1080
1008
|
const data = await renderer.renderError(err);
|
|
@@ -1087,31 +1015,32 @@ function rootPreviewServer500Middleware() {
|
|
|
1087
1015
|
}
|
|
1088
1016
|
|
|
1089
1017
|
// src/cli/commands/start.ts
|
|
1090
|
-
import
|
|
1018
|
+
import path7 from "node:path";
|
|
1091
1019
|
import { default as express3 } from "express";
|
|
1092
1020
|
import { dim as dim4 } from "kleur/colors";
|
|
1093
1021
|
import sirv2 from "sirv";
|
|
1094
1022
|
import compression2 from "compression";
|
|
1095
|
-
async function start(rootProjectDir) {
|
|
1023
|
+
async function start(rootProjectDir, options) {
|
|
1096
1024
|
process.env.NODE_ENV = "production";
|
|
1097
|
-
const rootDir =
|
|
1098
|
-
const server = await
|
|
1025
|
+
const rootDir = path7.resolve(rootProjectDir || process.cwd());
|
|
1026
|
+
const server = await createProdServer({ rootDir });
|
|
1099
1027
|
const port = parseInt(process.env.PORT || "4007");
|
|
1028
|
+
const host = (options == null ? void 0 : options.host) || "localhost";
|
|
1100
1029
|
console.log();
|
|
1101
1030
|
console.log(`${dim4("\u2503")} project: ${rootDir}`);
|
|
1102
|
-
console.log(`${dim4("\u2503")} server: http
|
|
1031
|
+
console.log(`${dim4("\u2503")} server: http://${host}:${port}`);
|
|
1103
1032
|
console.log(`${dim4("\u2503")} mode: production`);
|
|
1104
1033
|
console.log();
|
|
1105
|
-
server.listen(port);
|
|
1034
|
+
server.listen(port, host);
|
|
1106
1035
|
}
|
|
1107
|
-
async function
|
|
1036
|
+
async function createProdServer(options) {
|
|
1108
1037
|
const rootDir = options.rootDir;
|
|
1109
|
-
const rootConfig = await loadRootConfig(rootDir);
|
|
1110
|
-
const distDir =
|
|
1038
|
+
const rootConfig = await loadRootConfig(rootDir, { command: "start" });
|
|
1039
|
+
const distDir = path7.join(rootDir, "dist");
|
|
1111
1040
|
const server = express3();
|
|
1112
1041
|
server.disable("x-powered-by");
|
|
1113
1042
|
server.use(compression2());
|
|
1114
|
-
server.use(rootProjectMiddleware({
|
|
1043
|
+
server.use(rootProjectMiddleware({ rootConfig }));
|
|
1115
1044
|
server.use(await rootProdRendererMiddleware({ rootConfig, distDir }));
|
|
1116
1045
|
const plugins = rootConfig.plugins || [];
|
|
1117
1046
|
configureServerPlugins(
|
|
@@ -1122,7 +1051,7 @@ async function createServer4(options) {
|
|
|
1122
1051
|
userMiddlewares.forEach((middleware) => {
|
|
1123
1052
|
server.use(middleware);
|
|
1124
1053
|
});
|
|
1125
|
-
const publicDir =
|
|
1054
|
+
const publicDir = path7.join(distDir, "html");
|
|
1126
1055
|
server.use(sirv2(publicDir, { dev: false }));
|
|
1127
1056
|
server.use(rootProdServerMiddleware());
|
|
1128
1057
|
server.use(rootProdServer404Middleware());
|
|
@@ -1135,16 +1064,26 @@ async function createServer4(options) {
|
|
|
1135
1064
|
}
|
|
1136
1065
|
async function rootProdRendererMiddleware(options) {
|
|
1137
1066
|
const { distDir, rootConfig } = options;
|
|
1138
|
-
const render = await import(
|
|
1139
|
-
const manifestPath =
|
|
1067
|
+
const render = await import(path7.join(distDir, "server/render.js"));
|
|
1068
|
+
const manifestPath = path7.join(distDir, "client/root-manifest.json");
|
|
1140
1069
|
if (!await fileExists(manifestPath)) {
|
|
1141
1070
|
throw new Error(
|
|
1142
1071
|
`could not find ${manifestPath}. run \`root build\` before \`root start\`.`
|
|
1143
1072
|
);
|
|
1144
1073
|
}
|
|
1074
|
+
const elementGraphJsonPath = path7.join(
|
|
1075
|
+
distDir,
|
|
1076
|
+
"client/root-element-graph.json"
|
|
1077
|
+
);
|
|
1078
|
+
if (!await fileExists(elementGraphJsonPath)) {
|
|
1079
|
+
throw new Error(
|
|
1080
|
+
`could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1145
1083
|
const rootManifest = await loadJson(manifestPath);
|
|
1146
1084
|
const assetMap = BuildAssetMap.fromRootManifest(rootConfig, rootManifest);
|
|
1147
|
-
const
|
|
1085
|
+
const elementGraphJson = await loadJson(elementGraphJsonPath);
|
|
1086
|
+
const elementGraph = ElementGraph.fromJson(elementGraphJson);
|
|
1148
1087
|
const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
1149
1088
|
return async (req, _, next) => {
|
|
1150
1089
|
req.renderer = renderer;
|
|
@@ -1173,7 +1112,7 @@ function rootProdServer404Middleware() {
|
|
|
1173
1112
|
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
1174
1113
|
if (req.renderer) {
|
|
1175
1114
|
const url = req.path;
|
|
1176
|
-
const ext =
|
|
1115
|
+
const ext = path7.extname(url);
|
|
1177
1116
|
if (!ext) {
|
|
1178
1117
|
const renderer = req.renderer;
|
|
1179
1118
|
const data = await renderer.render404();
|
|
@@ -1191,7 +1130,7 @@ function rootProdServer500Middleware() {
|
|
|
1191
1130
|
console.error(String(err.stack || err));
|
|
1192
1131
|
if (req.renderer) {
|
|
1193
1132
|
const url = req.path;
|
|
1194
|
-
const ext =
|
|
1133
|
+
const ext = path7.extname(url);
|
|
1195
1134
|
if (!ext) {
|
|
1196
1135
|
const renderer = req.renderer;
|
|
1197
1136
|
const data = await renderer.renderError(err);
|
|
@@ -1205,6 +1144,9 @@ function rootProdServer500Middleware() {
|
|
|
1205
1144
|
}
|
|
1206
1145
|
export {
|
|
1207
1146
|
build,
|
|
1147
|
+
createDevServer,
|
|
1148
|
+
createPreviewServer,
|
|
1149
|
+
createProdServer,
|
|
1208
1150
|
dev,
|
|
1209
1151
|
preview,
|
|
1210
1152
|
start
|