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