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