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