@blinkk/root 3.0.6 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-worker.js +108 -0
- package/dist/build-worker.js.map +7 -0
- package/dist/chunk-3PWR4F2R.js +77 -0
- package/dist/chunk-3PWR4F2R.js.map +7 -0
- package/dist/{chunk-3EFECH2D.js → chunk-GK3TDYUY.js} +727 -611
- package/dist/chunk-GK3TDYUY.js.map +7 -0
- package/dist/{chunk-7HK6F5RQ.js → chunk-I3RCAIW7.js} +1 -75
- package/dist/chunk-I3RCAIW7.js.map +7 -0
- package/dist/chunk-KHO3HMX6.js +291 -0
- package/dist/chunk-KHO3HMX6.js.map +7 -0
- package/dist/chunk-M3E4RKS7.js +374 -0
- package/dist/chunk-M3E4RKS7.js.map +7 -0
- package/dist/{chunk-6NBKAR5Y.js → chunk-TM6QRBGS.js} +31 -1
- package/dist/chunk-TM6QRBGS.js.map +7 -0
- package/dist/chunk-WX62JK5E.js +81 -0
- package/dist/chunk-WX62JK5E.js.map +7 -0
- package/dist/{chunk-7PSEEE6C.js → chunk-YU22SAIG.js} +31 -317
- package/dist/chunk-YU22SAIG.js.map +7 -0
- package/dist/cli/build-page.d.ts +57 -0
- package/dist/cli/build-progress.d.ts +82 -0
- package/dist/cli/build-worker-pool.d.ts +46 -0
- package/dist/cli/build-worker.d.ts +4 -0
- package/dist/cli/build.d.ts +14 -0
- package/dist/cli.js +8 -4
- package/dist/core/config.d.ts +41 -3
- package/dist/core/security.d.ts +14 -0
- package/dist/core.js.map +2 -2
- package/dist/functions.js +8 -4
- package/dist/functions.js.map +1 -1
- package/dist/middleware/common.d.ts +18 -0
- package/dist/middleware/compression.d.ts +12 -0
- package/dist/middleware/middleware.d.ts +1 -0
- package/dist/middleware.js +6 -1
- package/dist/node.js +7 -5
- package/dist/render/render.d.ts +15 -9
- package/dist/render.js +42 -95
- package/dist/render.js.map +2 -2
- package/package.json +2 -2
- package/dist/chunk-3EFECH2D.js.map +0 -7
- package/dist/chunk-6NBKAR5Y.js.map +0 -7
- package/dist/chunk-7HK6F5RQ.js.map +0 -7
- package/dist/chunk-7PSEEE6C.js.map +0 -7
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "./chunk-
|
|
2
|
+
collectPods,
|
|
3
|
+
createViteServer,
|
|
4
|
+
preactToRootJsxPlugin,
|
|
5
|
+
rootPodsVitePlugin
|
|
6
|
+
} from "./chunk-YU22SAIG.js";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
RouteTrie
|
|
9
|
+
} from "./chunk-I3RCAIW7.js";
|
|
10
|
+
import {
|
|
11
|
+
BuildAssetMap,
|
|
12
|
+
ElementGraph,
|
|
13
|
+
buildPage,
|
|
14
|
+
getElements,
|
|
15
|
+
getElementsDirs
|
|
16
|
+
} from "./chunk-M3E4RKS7.js";
|
|
13
17
|
import {
|
|
14
18
|
bundleRootConfig,
|
|
15
|
-
collectPods,
|
|
16
19
|
copyDir,
|
|
17
20
|
copyGlob,
|
|
18
|
-
createViteServer,
|
|
19
21
|
dirExists,
|
|
20
22
|
directoryContains,
|
|
21
23
|
fileExists,
|
|
@@ -27,144 +29,35 @@ import {
|
|
|
27
29
|
loadRootConfig,
|
|
28
30
|
loadRootConfigWithDeps,
|
|
29
31
|
makeDir,
|
|
30
|
-
preactToRootJsxPlugin,
|
|
31
32
|
rmDir,
|
|
32
|
-
rootPodsVitePlugin,
|
|
33
33
|
writeFile,
|
|
34
34
|
writeJson
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-KHO3HMX6.js";
|
|
36
36
|
import {
|
|
37
37
|
configureServerPlugins,
|
|
38
38
|
getVitePlugins
|
|
39
39
|
} from "./chunk-XSNCF7WU.js";
|
|
40
|
+
import {
|
|
41
|
+
compressionMiddleware,
|
|
42
|
+
headersMiddleware,
|
|
43
|
+
rootProjectMiddleware,
|
|
44
|
+
securityHeadersMiddleware,
|
|
45
|
+
sessionMiddleware,
|
|
46
|
+
trailingSlashMiddleware
|
|
47
|
+
} from "./chunk-TM6QRBGS.js";
|
|
40
48
|
|
|
41
49
|
// src/cli/cli.ts
|
|
42
|
-
import { Command, InvalidArgumentError } from "commander";
|
|
50
|
+
import { Command, InvalidArgumentError, Option } from "commander";
|
|
43
51
|
import { bgGreen, black } from "kleur/colors";
|
|
44
52
|
|
|
45
53
|
// src/cli/build.ts
|
|
46
|
-
import
|
|
47
|
-
import
|
|
54
|
+
import os from "node:os";
|
|
55
|
+
import path2 from "node:path";
|
|
56
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
48
57
|
import fsExtra from "fs-extra";
|
|
49
|
-
import { dim as
|
|
50
|
-
import glob2 from "tiny-glob";
|
|
51
|
-
import { build as viteBuild } from "vite";
|
|
52
|
-
|
|
53
|
-
// src/node/element-graph.ts
|
|
54
|
-
import fs from "node:fs";
|
|
55
|
-
import path from "node:path";
|
|
58
|
+
import { dim as dim3, cyan as cyan2 } from "kleur/colors";
|
|
56
59
|
import glob from "tiny-glob";
|
|
57
|
-
import {
|
|
58
|
-
var ElementGraph = class _ElementGraph {
|
|
59
|
-
/**
|
|
60
|
-
* Element tagName => sourceFile.
|
|
61
|
-
*/
|
|
62
|
-
sourceFiles = {};
|
|
63
|
-
/**
|
|
64
|
-
* Element tagName => set of element tagName dependencies.
|
|
65
|
-
*/
|
|
66
|
-
deps = {};
|
|
67
|
-
constructor(sourceFiles) {
|
|
68
|
-
this.sourceFiles = sourceFiles;
|
|
69
|
-
}
|
|
70
|
-
toJson() {
|
|
71
|
-
for (const tagName in this.sourceFiles) {
|
|
72
|
-
this.deps[tagName] ??= this.parseDepsFromSource(tagName);
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
sourceFiles: this.sourceFiles,
|
|
76
|
-
deps: this.deps
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
static fromJson(data) {
|
|
80
|
-
const graph = new _ElementGraph(data.sourceFiles);
|
|
81
|
-
graph.deps = data.deps;
|
|
82
|
-
return graph;
|
|
83
|
-
}
|
|
84
|
-
getDeps(tagName, visited) {
|
|
85
|
-
visited ??= /* @__PURE__ */ new Set();
|
|
86
|
-
if (visited.has(tagName)) {
|
|
87
|
-
return [];
|
|
88
|
-
}
|
|
89
|
-
visited.add(tagName);
|
|
90
|
-
this.deps[tagName] ??= this.parseDepsFromSource(tagName);
|
|
91
|
-
const deps = new Set(this.deps[tagName]);
|
|
92
|
-
for (const depTagName of this.deps[tagName]) {
|
|
93
|
-
for (const childDep of this.getDeps(depTagName, visited)) {
|
|
94
|
-
deps.add(childDep);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return Array.from(deps);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Parses an element's source file for usage of other custom elements.
|
|
101
|
-
*/
|
|
102
|
-
parseDepsFromSource(tagName) {
|
|
103
|
-
const srcFile = this.sourceFiles[tagName];
|
|
104
|
-
if (!srcFile) {
|
|
105
|
-
throw new Error(`could not find file path for tagName <${tagName}>`);
|
|
106
|
-
}
|
|
107
|
-
const src = fs.readFileSync(srcFile.filePath, "utf-8");
|
|
108
|
-
const tagNames = parseTagNames(src);
|
|
109
|
-
const deps = /* @__PURE__ */ new Set();
|
|
110
|
-
for (const depTagName of tagNames) {
|
|
111
|
-
if (depTagName !== tagName && depTagName in this.sourceFiles) {
|
|
112
|
-
deps.add(depTagName);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return Array.from(deps);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
async function getElements(rootConfig, pods) {
|
|
119
|
-
const rootDir = rootConfig.rootDir;
|
|
120
|
-
const elementsDirs = getElementsDirs(rootConfig, pods);
|
|
121
|
-
const excludePatterns = rootConfig.elements?.exclude || [];
|
|
122
|
-
const excludeElement = (moduleId) => {
|
|
123
|
-
return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
|
|
124
|
-
};
|
|
125
|
-
const elementFilePaths = {};
|
|
126
|
-
for (const dirPath of elementsDirs) {
|
|
127
|
-
if (await isDirectory(dirPath)) {
|
|
128
|
-
const files = await glob("**/*", { cwd: dirPath });
|
|
129
|
-
files.forEach((file) => {
|
|
130
|
-
const parts = path.parse(file);
|
|
131
|
-
if (isJsFile(parts.base) && isValidTagName(parts.name)) {
|
|
132
|
-
const tagName = parts.name;
|
|
133
|
-
const filePath = path.join(dirPath, file);
|
|
134
|
-
const relPath = path.relative(rootDir, filePath);
|
|
135
|
-
if (!excludeElement(relPath)) {
|
|
136
|
-
elementFilePaths[tagName] = { filePath, relPath };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const graph = new ElementGraph(elementFilePaths);
|
|
143
|
-
return graph;
|
|
144
|
-
}
|
|
145
|
-
function getElementsDirs(rootConfig, pods) {
|
|
146
|
-
const rootDir = rootConfig.rootDir;
|
|
147
|
-
const workspaceRoot = searchForWorkspaceRoot(rootDir);
|
|
148
|
-
const elementsDirs = [path.join(rootDir, "elements")];
|
|
149
|
-
const elementsInclude = rootConfig.elements?.include || [];
|
|
150
|
-
for (const dirPath of elementsInclude) {
|
|
151
|
-
const elementsDir = path.resolve(rootDir, dirPath);
|
|
152
|
-
if (!directoryContains(rootDir, elementsDir)) {
|
|
153
|
-
throw new Error(
|
|
154
|
-
`the elements dir (${dirPath}) should be within the project's workspace (${workspaceRoot})`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
elementsDirs.push(elementsDir);
|
|
158
|
-
}
|
|
159
|
-
if (pods) {
|
|
160
|
-
for (const pod of pods) {
|
|
161
|
-
for (const dir of pod.elementsDirs) {
|
|
162
|
-
elementsDirs.push(dir);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return elementsDirs;
|
|
167
|
-
}
|
|
60
|
+
import { build as viteBuild } from "vite";
|
|
168
61
|
|
|
169
62
|
// src/node/vite-plugin-prune-empty-chunks.ts
|
|
170
63
|
import { dim } from "kleur/colors";
|
|
@@ -231,233 +124,371 @@ function removeSideEffectImport(code, fileName) {
|
|
|
231
124
|
return code.replace(re, "");
|
|
232
125
|
}
|
|
233
126
|
|
|
234
|
-
// src/
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
this.srcToAsset = /* @__PURE__ */ new Map();
|
|
243
|
-
}
|
|
244
|
-
async get(src) {
|
|
245
|
-
const asset = this.srcToAsset.get(src);
|
|
246
|
-
if (asset) {
|
|
247
|
-
return asset;
|
|
248
|
-
}
|
|
249
|
-
const realSrc = realPathRelativeTo(this.rootConfig.rootDir, src);
|
|
250
|
-
if (realSrc !== src) {
|
|
251
|
-
const asset2 = this.srcToAsset.get(realSrc);
|
|
252
|
-
if (asset2) {
|
|
253
|
-
return asset2;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
console.log(`could not find build asset: ${src}`);
|
|
257
|
-
return null;
|
|
258
|
-
}
|
|
259
|
-
add(asset) {
|
|
260
|
-
this.srcToAsset.set(asset.src, asset);
|
|
261
|
-
}
|
|
262
|
-
toJson() {
|
|
263
|
-
const result = {};
|
|
264
|
-
for (const src of this.srcToAsset.keys()) {
|
|
265
|
-
result[src] = this.srcToAsset.get(src).toJson();
|
|
127
|
+
// src/utils/batch.ts
|
|
128
|
+
async function batchAsyncCalls(data, concurrency, asyncFunction) {
|
|
129
|
+
const result = new Array(data.length);
|
|
130
|
+
let nextIndex = 0;
|
|
131
|
+
async function worker() {
|
|
132
|
+
while (nextIndex < data.length) {
|
|
133
|
+
const index = nextIndex++;
|
|
134
|
+
result[index] = await asyncFunction(data[index]);
|
|
266
135
|
}
|
|
267
|
-
return result;
|
|
268
136
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
rootConfig.rootDir,
|
|
276
|
-
elementSource.relPath
|
|
277
|
-
);
|
|
278
|
-
if (realSrc !== elementSource.filePath) {
|
|
279
|
-
elementFiles.add(realSrc);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
Object.keys(clientManifest).forEach((manifestKey) => {
|
|
283
|
-
const src = manifestKey;
|
|
284
|
-
const manifestChunk = clientManifest[manifestKey];
|
|
285
|
-
const isElement = elementFiles.has(src);
|
|
286
|
-
const assetUrl = src.startsWith("routes/") && isJsFile(src) ? "" : `/${manifestChunk.file}`;
|
|
287
|
-
const assetData = {
|
|
288
|
-
src,
|
|
289
|
-
assetUrl,
|
|
290
|
-
importedModules: manifestChunk.imports || [],
|
|
291
|
-
importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),
|
|
292
|
-
isElement
|
|
293
|
-
};
|
|
294
|
-
assetMap.add(new BuildAsset(assetMap, assetData));
|
|
295
|
-
});
|
|
296
|
-
podRoutes.forEach((podRoute) => {
|
|
297
|
-
if (assetMap.srcToAsset.has(podRoute.src)) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
const relPath = path2.relative(rootConfig.rootDir, podRoute.filePath).replace(/\\/g, "/");
|
|
301
|
-
const realPath = realPathRelativeTo(rootConfig.rootDir, relPath).replace(
|
|
302
|
-
/\\/g,
|
|
303
|
-
"/"
|
|
304
|
-
);
|
|
305
|
-
const candidateKeys = [relPath, realPath];
|
|
306
|
-
for (const key of candidateKeys) {
|
|
307
|
-
const asset = assetMap.srcToAsset.get(key);
|
|
308
|
-
if (asset) {
|
|
309
|
-
assetMap.add(
|
|
310
|
-
new BuildAsset(assetMap, {
|
|
311
|
-
...asset.toJson(),
|
|
312
|
-
src: podRoute.src,
|
|
313
|
-
assetUrl: ""
|
|
314
|
-
})
|
|
315
|
-
);
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
return assetMap;
|
|
321
|
-
}
|
|
322
|
-
static fromRootManifest(rootConfig, rootManifest) {
|
|
323
|
-
const assetMap = new _BuildAssetMap(rootConfig);
|
|
324
|
-
Object.keys(rootManifest).forEach((moduleId) => {
|
|
325
|
-
const assetData = rootManifest[moduleId];
|
|
326
|
-
assetMap.add(new BuildAsset(assetMap, assetData));
|
|
327
|
-
});
|
|
328
|
-
return assetMap;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
function realPathRelativeTo(rootDir, src) {
|
|
332
|
-
const fullPath = path2.resolve(rootDir, src);
|
|
333
|
-
if (!fs2.existsSync(fullPath)) {
|
|
334
|
-
return src;
|
|
335
|
-
}
|
|
336
|
-
const realpath = fs2.realpathSync(path2.resolve(rootDir, src));
|
|
337
|
-
return path2.relative(rootDir, realpath);
|
|
137
|
+
const workers = Array.from(
|
|
138
|
+
{ length: Math.min(concurrency, data.length) },
|
|
139
|
+
() => worker()
|
|
140
|
+
);
|
|
141
|
+
await Promise.all(workers);
|
|
142
|
+
return result;
|
|
338
143
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
isElement;
|
|
346
|
-
constructor(assetMap, assetData) {
|
|
347
|
-
this.assetMap = assetMap;
|
|
348
|
-
this.src = assetData.src;
|
|
349
|
-
this.assetUrl = assetData.assetUrl;
|
|
350
|
-
this.importedModules = assetData.importedModules;
|
|
351
|
-
this.importedCss = assetData.importedCss;
|
|
352
|
-
this.isElement = assetData.isElement;
|
|
144
|
+
|
|
145
|
+
// src/cli/build-progress.ts
|
|
146
|
+
import { cyan, dim as dim2, green } from "kleur/colors";
|
|
147
|
+
function parseBuildLogMode(value) {
|
|
148
|
+
if (value === void 0 || value === null || value === "") {
|
|
149
|
+
return "progress";
|
|
353
150
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const deps = /* @__PURE__ */ new Set();
|
|
357
|
-
await this.collectCss(this, deps, visited);
|
|
358
|
-
return Array.from(deps);
|
|
151
|
+
if (value === "progress" || value === "verbose" || value === "quiet") {
|
|
152
|
+
return value;
|
|
359
153
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
154
|
+
throw new Error(
|
|
155
|
+
`invalid --log value: "${value}" (expected "progress", "verbose", or "quiet")`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
function formatBytes(bytes) {
|
|
159
|
+
const k = 1024;
|
|
160
|
+
if (bytes < k) {
|
|
161
|
+
return (bytes / k).toFixed(2) + " kB";
|
|
365
162
|
}
|
|
366
|
-
|
|
367
|
-
|
|
163
|
+
const units = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
164
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
165
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + units[i];
|
|
166
|
+
}
|
|
167
|
+
function formatDuration(ms) {
|
|
168
|
+
const secs = ms / 1e3;
|
|
169
|
+
if (secs < 60) {
|
|
170
|
+
return `${secs.toFixed(1)}s`;
|
|
171
|
+
}
|
|
172
|
+
const mins = Math.floor(secs / 60);
|
|
173
|
+
const rem = Math.round(secs - mins * 60);
|
|
174
|
+
return `${mins}m${String(rem).padStart(2, "0")}s`;
|
|
175
|
+
}
|
|
176
|
+
var BAR_WIDTH = 20;
|
|
177
|
+
var BuildProgress = class {
|
|
178
|
+
total;
|
|
179
|
+
mode;
|
|
180
|
+
itemLabel;
|
|
181
|
+
outputDirLabel;
|
|
182
|
+
stream;
|
|
183
|
+
now;
|
|
184
|
+
intervalMs;
|
|
185
|
+
summaryTopN;
|
|
186
|
+
isTTY;
|
|
187
|
+
startedAt;
|
|
188
|
+
completed = 0;
|
|
189
|
+
totalBytes = 0;
|
|
190
|
+
files = [];
|
|
191
|
+
lastPrintAt = 0;
|
|
192
|
+
lastMilestone = 0;
|
|
193
|
+
ttyLineActive = false;
|
|
194
|
+
done = false;
|
|
195
|
+
constructor(options) {
|
|
196
|
+
this.total = options.total;
|
|
197
|
+
this.mode = options.mode;
|
|
198
|
+
this.itemLabel = options.itemLabel ?? "pages";
|
|
199
|
+
this.outputDirLabel = options.outputDirLabel ?? "";
|
|
200
|
+
this.stream = options.stream ?? process.stdout;
|
|
201
|
+
this.now = options.now ?? Date.now;
|
|
202
|
+
this.isTTY = !!this.stream.isTTY;
|
|
203
|
+
this.intervalMs = options.intervalMs ?? (this.isTTY ? 80 : 5e3);
|
|
204
|
+
this.summaryTopN = options.summaryTopN ?? 5;
|
|
205
|
+
this.startedAt = this.now();
|
|
206
|
+
}
|
|
207
|
+
/** Records a completed output file. */
|
|
208
|
+
add(outputFile, sizeBytes) {
|
|
209
|
+
this.completed += 1;
|
|
210
|
+
this.totalBytes += sizeBytes;
|
|
211
|
+
this.files.push({ path: outputFile, size: sizeBytes });
|
|
212
|
+
if (this.mode === "verbose") {
|
|
213
|
+
const paddedSize = formatBytes(sizeBytes).padStart(9, " ");
|
|
214
|
+
this.println(
|
|
215
|
+
` ${dim2(paddedSize)} ${dim2(this.outputDirLabel)}${cyan(outputFile)}`
|
|
216
|
+
);
|
|
368
217
|
return;
|
|
369
218
|
}
|
|
370
|
-
if (
|
|
371
|
-
|
|
219
|
+
if (this.mode === "progress") {
|
|
220
|
+
this.maybePrintProgress();
|
|
372
221
|
}
|
|
373
|
-
|
|
222
|
+
}
|
|
223
|
+
/** Clears any in-place progress line (call before printing errors). */
|
|
224
|
+
abort() {
|
|
225
|
+
this.clearTtyLine();
|
|
226
|
+
this.done = true;
|
|
227
|
+
}
|
|
228
|
+
/** Prints the final summary. */
|
|
229
|
+
finish() {
|
|
230
|
+
if (this.done) {
|
|
374
231
|
return;
|
|
375
232
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
233
|
+
this.done = true;
|
|
234
|
+
this.clearTtyLine();
|
|
235
|
+
const elapsed = formatDuration(this.now() - this.startedAt);
|
|
236
|
+
const summary = `${this.completed} ${this.itemLabel} (${formatBytes(
|
|
237
|
+
this.totalBytes
|
|
238
|
+
)}) in ${elapsed}`;
|
|
239
|
+
this.println(` ${green("\u2713")} ${summary}`);
|
|
240
|
+
if (this.mode === "progress" && this.summaryTopN > 0) {
|
|
241
|
+
const largest = [...this.files].sort((a, b) => b.size - a.size).slice(0, this.summaryTopN);
|
|
242
|
+
if (largest.length > 0) {
|
|
243
|
+
this.println(` ${dim2(`largest ${this.itemLabel}:`)}`);
|
|
244
|
+
for (const file of largest) {
|
|
245
|
+
const paddedSize = formatBytes(file.size).padStart(9, " ");
|
|
246
|
+
this.println(
|
|
247
|
+
` ${dim2(paddedSize)} ${dim2(this.outputDirLabel)}${cyan(
|
|
248
|
+
file.path
|
|
249
|
+
)}`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
379
253
|
}
|
|
380
|
-
await Promise.all(
|
|
381
|
-
asset.importedModules.map(async (src) => {
|
|
382
|
-
const importedAsset = await this.assetMap.get(src);
|
|
383
|
-
this.collectJs(importedAsset, urls, visited);
|
|
384
|
-
})
|
|
385
|
-
);
|
|
386
254
|
}
|
|
387
|
-
|
|
388
|
-
|
|
255
|
+
maybePrintProgress() {
|
|
256
|
+
const now = this.now();
|
|
257
|
+
if (this.isTTY) {
|
|
258
|
+
if (now - this.lastPrintAt < this.intervalMs) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
this.lastPrintAt = now;
|
|
262
|
+
this.renderTtyLine(now);
|
|
389
263
|
return;
|
|
390
264
|
}
|
|
391
|
-
|
|
265
|
+
const milestone = Math.floor(this.completed / this.total * 10);
|
|
266
|
+
if (milestone <= this.lastMilestone || this.completed === this.total) {
|
|
392
267
|
return;
|
|
393
268
|
}
|
|
394
|
-
if (
|
|
269
|
+
if (now - this.lastPrintAt < this.intervalMs) {
|
|
395
270
|
return;
|
|
396
271
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
asset.importedModules.map(async (moduleId) => {
|
|
403
|
-
const importedAsset = await this.assetMap.get(moduleId);
|
|
404
|
-
this.collectCss(importedAsset, urls, visited);
|
|
405
|
-
})
|
|
272
|
+
this.lastMilestone = milestone;
|
|
273
|
+
this.lastPrintAt = now;
|
|
274
|
+
const pct = Math.floor(this.completed / this.total * 100);
|
|
275
|
+
this.println(
|
|
276
|
+
` ${this.completed}/${this.total} ${this.itemLabel} (${pct}%) \xB7 ${formatBytes(this.totalBytes)} \xB7 ${formatDuration(now - this.startedAt)}${this.eta(now)}`
|
|
406
277
|
);
|
|
407
278
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
279
|
+
renderTtyLine(now) {
|
|
280
|
+
const ratio = this.total > 0 ? this.completed / this.total : 0;
|
|
281
|
+
const filled = Math.round(ratio * BAR_WIDTH);
|
|
282
|
+
const bar = "\u2595" + "\u2588".repeat(filled) + "\u2591".repeat(BAR_WIDTH - filled) + "\u258F";
|
|
283
|
+
const pct = String(Math.floor(ratio * 100)).padStart(3, " ");
|
|
284
|
+
const line = ` ${bar} ${pct}% \xB7 ${this.completed}/${this.total} ${this.itemLabel} \xB7 ${formatBytes(this.totalBytes)} \xB7 ${formatDuration(now - this.startedAt)}${this.eta(now)}`;
|
|
285
|
+
this.stream.write(`\r\x1B[2K${line}`);
|
|
286
|
+
this.ttyLineActive = true;
|
|
287
|
+
}
|
|
288
|
+
/** Returns an " · eta 12.3s" suffix once enough progress exists to estimate. */
|
|
289
|
+
eta(now) {
|
|
290
|
+
if (this.completed < 10 || this.completed / this.total < 0.05) {
|
|
291
|
+
return "";
|
|
292
|
+
}
|
|
293
|
+
const elapsed = now - this.startedAt;
|
|
294
|
+
const remaining = elapsed / this.completed * (this.total - this.completed);
|
|
295
|
+
return ` \xB7 eta ${formatDuration(remaining)}`;
|
|
296
|
+
}
|
|
297
|
+
clearTtyLine() {
|
|
298
|
+
if (this.ttyLineActive) {
|
|
299
|
+
this.stream.write("\r\x1B[2K");
|
|
300
|
+
this.ttyLineActive = false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
println(line) {
|
|
304
|
+
this.clearTtyLine();
|
|
305
|
+
this.stream.write(line + "\n");
|
|
416
306
|
}
|
|
417
307
|
};
|
|
418
308
|
|
|
419
|
-
// src/
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
309
|
+
// src/cli/build-worker-pool.ts
|
|
310
|
+
import path from "node:path";
|
|
311
|
+
import { fileURLToPath } from "node:url";
|
|
312
|
+
import v8 from "node:v8";
|
|
313
|
+
import { Worker } from "node:worker_threads";
|
|
314
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
315
|
+
var WORKER_HEAP_LIMIT_MB = Math.ceil(
|
|
316
|
+
v8.getHeapStatistics().heap_size_limit / (1024 * 1024)
|
|
317
|
+
);
|
|
318
|
+
var BuildPageError = class extends Error {
|
|
319
|
+
urlPath;
|
|
320
|
+
params;
|
|
321
|
+
routeSrc;
|
|
322
|
+
workerError;
|
|
323
|
+
constructor(urlPath, params, routeSrc, workerError) {
|
|
324
|
+
super(
|
|
325
|
+
`BuildError: ${urlPath} (${routeSrc || "unknown route"}) failed to build.`
|
|
326
|
+
);
|
|
327
|
+
this.urlPath = urlPath;
|
|
328
|
+
this.params = params;
|
|
329
|
+
this.routeSrc = routeSrc;
|
|
330
|
+
this.workerError = workerError;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
var BuildWorker = class {
|
|
334
|
+
worker;
|
|
335
|
+
pool;
|
|
336
|
+
concurrency;
|
|
337
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
338
|
+
isReady = false;
|
|
339
|
+
ready;
|
|
340
|
+
constructor(pool, options) {
|
|
341
|
+
this.pool = pool;
|
|
342
|
+
this.concurrency = options.workerConcurrency;
|
|
343
|
+
this.worker = new Worker(path.resolve(__dirname, "./build-worker.js"), {
|
|
344
|
+
workerData: { rootDir: options.rootDir, mode: options.mode },
|
|
345
|
+
resourceLimits: { maxOldGenerationSizeMb: WORKER_HEAP_LIMIT_MB }
|
|
346
|
+
});
|
|
347
|
+
let onReady;
|
|
348
|
+
let onFailed;
|
|
349
|
+
this.ready = new Promise((resolve, reject) => {
|
|
350
|
+
onReady = resolve;
|
|
351
|
+
onFailed = reject;
|
|
352
|
+
});
|
|
353
|
+
this.worker.on("message", (msg) => {
|
|
354
|
+
if (msg.type === "ready") {
|
|
355
|
+
this.isReady = true;
|
|
356
|
+
onReady();
|
|
357
|
+
this.next();
|
|
358
|
+
} else if (msg.type === "result") {
|
|
359
|
+
const pending = this.inFlight.get(msg.id);
|
|
360
|
+
this.inFlight.delete(msg.id);
|
|
361
|
+
pending?.resolve(msg.result);
|
|
362
|
+
this.next();
|
|
363
|
+
} else if (msg.type === "error") {
|
|
364
|
+
const pending = this.inFlight.get(msg.id);
|
|
365
|
+
this.inFlight.delete(msg.id);
|
|
366
|
+
pending?.reject(
|
|
367
|
+
new BuildPageError(msg.urlPath, msg.params, msg.routeSrc, msg.error)
|
|
368
|
+
);
|
|
369
|
+
this.next();
|
|
370
|
+
} else if (msg.type === "fatal") {
|
|
371
|
+
const err = new Error(`build worker failed: ${msg.error}`);
|
|
372
|
+
onFailed(err);
|
|
373
|
+
this.failAll(err);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
this.worker.on("error", (err) => {
|
|
377
|
+
onFailed(err);
|
|
378
|
+
this.failAll(err);
|
|
379
|
+
});
|
|
380
|
+
this.worker.on("exit", (code) => {
|
|
381
|
+
if (code !== 0) {
|
|
382
|
+
const err = new Error(`build worker exited with code ${code}`);
|
|
383
|
+
onFailed(err);
|
|
384
|
+
this.failAll(err);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Rejects all in-flight tasks after a worker-level failure (fatal error,
|
|
390
|
+
* crash, or non-zero exit — e.g. an OOM kill).
|
|
391
|
+
*
|
|
392
|
+
* Each task is rejected with its own `BuildPageError` so the build log
|
|
393
|
+
* names every page that was in flight when the worker died. Without this,
|
|
394
|
+
* worker deaths surface as a single generic error with no route context,
|
|
395
|
+
* making OOM crashes impossible to trace back to pages. Note the in-flight
|
|
396
|
+
* pages are the OOM *suspects*, not necessarily the cause (memory pressure
|
|
397
|
+
* is cumulative), which is why the message says "while rendering".
|
|
398
|
+
*/
|
|
399
|
+
failAll(err) {
|
|
400
|
+
const pendingTasks = Array.from(this.inFlight.values());
|
|
401
|
+
this.inFlight.clear();
|
|
402
|
+
pendingTasks.forEach(
|
|
403
|
+
(pending) => pending.reject(
|
|
404
|
+
new BuildPageError(
|
|
405
|
+
pending.task.urlPath,
|
|
406
|
+
pending.task.params,
|
|
407
|
+
pending.task.routeSrc,
|
|
408
|
+
`worker thread died while rendering this page (${pendingTasks.length} page(s) were in flight): ` + String(err.message || err)
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
/** Pulls tasks off the pool's queue until at max concurrency. */
|
|
414
|
+
next() {
|
|
415
|
+
if (!this.isReady) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
while (this.inFlight.size < this.concurrency) {
|
|
419
|
+
const pending = this.pool.dequeue();
|
|
420
|
+
if (!pending) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
this.inFlight.set(pending.id, pending);
|
|
424
|
+
const req = {
|
|
425
|
+
type: "render",
|
|
426
|
+
id: pending.id,
|
|
427
|
+
task: pending.task
|
|
428
|
+
};
|
|
429
|
+
this.worker.postMessage(req);
|
|
427
430
|
}
|
|
428
431
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
async terminate() {
|
|
433
|
+
await this.worker.terminate();
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
var BuildWorkerPool = class {
|
|
437
|
+
workers = [];
|
|
438
|
+
queue = [];
|
|
439
|
+
nextTaskId = 0;
|
|
440
|
+
constructor(options) {
|
|
441
|
+
for (let i = 0; i < options.numWorkers; i++) {
|
|
442
|
+
this.workers.push(new BuildWorker(this, options));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/** Waits for all workers to finish initializing. */
|
|
446
|
+
async ready() {
|
|
447
|
+
await Promise.all(this.workers.map((worker) => worker.ready));
|
|
448
|
+
}
|
|
449
|
+
/** Schedules a page build and resolves when the page finishes. */
|
|
450
|
+
run(task) {
|
|
451
|
+
return new Promise((resolve, reject) => {
|
|
452
|
+
this.queue.push({ id: this.nextTaskId++, task, resolve, reject });
|
|
453
|
+
this.workers.forEach((worker) => worker.next());
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
dequeue() {
|
|
457
|
+
return this.queue.shift();
|
|
458
|
+
}
|
|
459
|
+
async terminate() {
|
|
460
|
+
await Promise.all(this.workers.map((worker) => worker.terminate()));
|
|
461
|
+
}
|
|
462
|
+
};
|
|
436
463
|
|
|
437
464
|
// src/cli/build.ts
|
|
438
|
-
var
|
|
465
|
+
var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
|
|
466
|
+
var activeLogMode = "progress";
|
|
439
467
|
async function build(rootProjectDir, options) {
|
|
440
468
|
const mode = options?.mode || "production";
|
|
441
469
|
process.env.NODE_ENV = mode;
|
|
442
|
-
|
|
470
|
+
activeLogMode = options?.quiet ? "quiet" : parseBuildLogMode(options?.log);
|
|
471
|
+
const rootDir = path2.resolve(rootProjectDir || process.cwd());
|
|
443
472
|
const rootConfig = await loadRootConfig(rootDir, { command: "build" });
|
|
444
|
-
const distDir =
|
|
473
|
+
const distDir = path2.join(rootDir, "dist");
|
|
445
474
|
const ssrOnly = options?.ssrOnly || false;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
475
|
+
if (activeLogMode !== "quiet") {
|
|
476
|
+
console.log();
|
|
477
|
+
console.log(`${dim3("\u2503")} project: ${rootDir}`);
|
|
478
|
+
console.log(`${dim3("\u2503")} output: ${distDir}/html`);
|
|
479
|
+
console.log(`${dim3("\u2503")} mode: ${mode}`);
|
|
480
|
+
console.log();
|
|
481
|
+
}
|
|
451
482
|
await rmDir(distDir);
|
|
452
483
|
await makeDir(distDir);
|
|
453
484
|
const pods = await collectPods(rootConfig);
|
|
454
485
|
const routeFiles = [];
|
|
455
|
-
if (await isDirectory(
|
|
456
|
-
const pageFiles = await
|
|
486
|
+
if (await isDirectory(path2.join(rootDir, "routes"))) {
|
|
487
|
+
const pageFiles = await glob("routes/**/*", { cwd: rootDir });
|
|
457
488
|
pageFiles.forEach((file) => {
|
|
458
|
-
const parts =
|
|
489
|
+
const parts = path2.parse(file);
|
|
459
490
|
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
460
|
-
routeFiles.push(
|
|
491
|
+
routeFiles.push(path2.resolve(rootDir, file));
|
|
461
492
|
}
|
|
462
493
|
});
|
|
463
494
|
}
|
|
@@ -471,12 +502,12 @@ async function build(rootProjectDir, options) {
|
|
|
471
502
|
return sourceFile.filePath;
|
|
472
503
|
});
|
|
473
504
|
const bundleScripts = [];
|
|
474
|
-
if (await isDirectory(
|
|
475
|
-
const bundleFiles = await
|
|
505
|
+
if (await isDirectory(path2.join(rootDir, "bundles"))) {
|
|
506
|
+
const bundleFiles = await glob("bundles/*", { cwd: rootDir });
|
|
476
507
|
bundleFiles.forEach((file) => {
|
|
477
|
-
const parts =
|
|
508
|
+
const parts = path2.parse(file);
|
|
478
509
|
if (isJsFile(parts.base)) {
|
|
479
|
-
bundleScripts.push(
|
|
510
|
+
bundleScripts.push(path2.resolve(rootDir, file));
|
|
480
511
|
}
|
|
481
512
|
});
|
|
482
513
|
}
|
|
@@ -503,10 +534,12 @@ async function build(rootProjectDir, options) {
|
|
|
503
534
|
...viteConfig,
|
|
504
535
|
root: rootDir,
|
|
505
536
|
mode,
|
|
506
|
-
plugins: vitePlugins
|
|
537
|
+
plugins: vitePlugins,
|
|
538
|
+
// In quiet mode, only surface vite warnings and errors.
|
|
539
|
+
logLevel: activeLogMode === "quiet" ? "warn" : viteConfig.logLevel
|
|
507
540
|
};
|
|
508
541
|
const ssrInput = {
|
|
509
|
-
render:
|
|
542
|
+
render: path2.resolve(__dirname2, "./render.js")
|
|
510
543
|
};
|
|
511
544
|
rootPlugins.forEach((plugin) => {
|
|
512
545
|
if (plugin.ssrInput) {
|
|
@@ -537,7 +570,7 @@ async function build(rootProjectDir, options) {
|
|
|
537
570
|
sanitizeFileName
|
|
538
571
|
}
|
|
539
572
|
},
|
|
540
|
-
outDir:
|
|
573
|
+
outDir: path2.join(distDir, "server"),
|
|
541
574
|
ssr: true,
|
|
542
575
|
ssrManifest: false,
|
|
543
576
|
cssCodeSplit: true,
|
|
@@ -570,7 +603,7 @@ async function build(rootProjectDir, options) {
|
|
|
570
603
|
...viteConfig?.build?.rolldownOptions?.output
|
|
571
604
|
}
|
|
572
605
|
},
|
|
573
|
-
outDir:
|
|
606
|
+
outDir: path2.join(distDir, ".build/routes"),
|
|
574
607
|
ssr: true,
|
|
575
608
|
ssrManifest: false,
|
|
576
609
|
ssrEmitAssets: true,
|
|
@@ -601,7 +634,7 @@ async function build(rootProjectDir, options) {
|
|
|
601
634
|
...viteConfig?.build?.rolldownOptions?.output
|
|
602
635
|
}
|
|
603
636
|
},
|
|
604
|
-
outDir:
|
|
637
|
+
outDir: path2.join(distDir, ".build/client"),
|
|
605
638
|
ssr: false,
|
|
606
639
|
ssrManifest: false,
|
|
607
640
|
manifest: true,
|
|
@@ -614,21 +647,21 @@ async function build(rootProjectDir, options) {
|
|
|
614
647
|
});
|
|
615
648
|
} else {
|
|
616
649
|
await writeFile(
|
|
617
|
-
|
|
650
|
+
path2.join(distDir, ".build/client/.vite/manifest.json"),
|
|
618
651
|
"{}"
|
|
619
652
|
);
|
|
620
653
|
}
|
|
621
|
-
await bundleRootConfig(rootDir,
|
|
654
|
+
await bundleRootConfig(rootDir, path2.join(distDir, "root.config.js"));
|
|
622
655
|
await copyGlob(
|
|
623
656
|
"**/*.css",
|
|
624
|
-
|
|
625
|
-
|
|
657
|
+
path2.join(distDir, ".build/routes"),
|
|
658
|
+
path2.join(distDir, ".build/client")
|
|
626
659
|
);
|
|
627
660
|
const routesManifest = await loadJson(
|
|
628
|
-
|
|
661
|
+
path2.join(distDir, ".build/routes/.vite/manifest.json")
|
|
629
662
|
);
|
|
630
663
|
const clientManifest = await loadJson(
|
|
631
|
-
|
|
664
|
+
path2.join(distDir, ".build/client/.vite/manifest.json")
|
|
632
665
|
);
|
|
633
666
|
function collectRouteCss(asset, cssDeps, visited) {
|
|
634
667
|
if (!asset || !asset.file || visited.has(asset.file)) {
|
|
@@ -671,17 +704,17 @@ async function build(rootProjectDir, options) {
|
|
|
671
704
|
);
|
|
672
705
|
const rootManifest = assetMap.toJson();
|
|
673
706
|
await writeFile(
|
|
674
|
-
|
|
707
|
+
path2.join(distDir, ".root/manifest.json"),
|
|
675
708
|
JSON.stringify(rootManifest, null, 2)
|
|
676
709
|
);
|
|
677
710
|
const elementGraphJson = elementGraph.toJson();
|
|
678
711
|
await writeFile(
|
|
679
|
-
|
|
712
|
+
path2.join(distDir, ".root/elements.json"),
|
|
680
713
|
JSON.stringify(elementGraphJson, null, 2)
|
|
681
714
|
);
|
|
682
|
-
const buildDir =
|
|
683
|
-
const publicDir =
|
|
684
|
-
if (fsExtra.existsSync(
|
|
715
|
+
const buildDir = path2.join(distDir, "html");
|
|
716
|
+
const publicDir = path2.join(rootDir, "public");
|
|
717
|
+
if (fsExtra.existsSync(path2.join(rootDir, "public"))) {
|
|
685
718
|
fsExtra.copySync(publicDir, buildDir, { dereference: true });
|
|
686
719
|
} else {
|
|
687
720
|
await makeDir(buildDir);
|
|
@@ -693,8 +726,8 @@ async function build(rootProjectDir, options) {
|
|
|
693
726
|
}
|
|
694
727
|
seenAssets.add(assetUrl);
|
|
695
728
|
const assetRelPath = assetUrl.slice(1);
|
|
696
|
-
const assetFrom =
|
|
697
|
-
const assetTo =
|
|
729
|
+
const assetFrom = path2.join(distDir, ".build/client", assetRelPath);
|
|
730
|
+
const assetTo = path2.join(buildDir, assetRelPath);
|
|
698
731
|
if (!await fileExists(assetFrom)) {
|
|
699
732
|
console.log(`${assetFrom} does not exist`);
|
|
700
733
|
return;
|
|
@@ -702,7 +735,9 @@ async function build(rootProjectDir, options) {
|
|
|
702
735
|
await fsExtra.copy(assetFrom, assetTo);
|
|
703
736
|
printFileOutput(fileSize(assetTo), "dist/html/", assetRelPath);
|
|
704
737
|
}
|
|
705
|
-
|
|
738
|
+
if (activeLogMode !== "quiet") {
|
|
739
|
+
console.log("\njs/css output:");
|
|
740
|
+
}
|
|
706
741
|
await Promise.all(
|
|
707
742
|
Object.keys(rootManifest).map(async (src) => {
|
|
708
743
|
const assetData = rootManifest[src];
|
|
@@ -724,7 +759,7 @@ async function build(rootProjectDir, options) {
|
|
|
724
759
|
})
|
|
725
760
|
);
|
|
726
761
|
if (!ssrOnly) {
|
|
727
|
-
const render = await import(
|
|
762
|
+
const render = await import(path2.join(distDir, "server/render.js"));
|
|
728
763
|
const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
|
|
729
764
|
let sitemap = await renderer.getSitemap();
|
|
730
765
|
if (options?.filter) {
|
|
@@ -744,92 +779,141 @@ async function build(rootProjectDir, options) {
|
|
|
744
779
|
);
|
|
745
780
|
}
|
|
746
781
|
const domain = rootConfig.domain;
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
782
|
+
const addSitemapXmlItem = (urlPath, sitemapItem, outFilePath) => {
|
|
783
|
+
if (!rootConfig.sitemap || !outFilePath.endsWith("index.html")) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const sitemapXmlItem = {
|
|
787
|
+
url: `${domain}${urlPath}`,
|
|
788
|
+
locale: sitemapItem.locale,
|
|
789
|
+
alts: []
|
|
790
|
+
};
|
|
791
|
+
sitemapXmlItems.push(sitemapXmlItem);
|
|
792
|
+
if (sitemapItem.alts) {
|
|
793
|
+
Object.entries(sitemapItem.alts).forEach(([altLocale, item]) => {
|
|
794
|
+
sitemapXmlItem.alts.push({
|
|
795
|
+
url: `${domain}${item.urlPath}`,
|
|
796
|
+
locale: altLocale,
|
|
797
|
+
hreflang: item.hrefLang
|
|
798
|
+
});
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
const onPageResult = (sitemapItem, result) => {
|
|
803
|
+
if (result.notFound || !result.outFilePath) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (!result.staticContent) {
|
|
807
|
+
addSitemapXmlItem(result.urlPath, sitemapItem, result.outFilePath);
|
|
808
|
+
}
|
|
809
|
+
progress.add(
|
|
810
|
+
result.outFilePath,
|
|
811
|
+
fileSizeBytes(path2.join(buildDir, result.outFilePath))
|
|
812
|
+
);
|
|
813
|
+
};
|
|
814
|
+
const sitemapEntries = Object.entries(sitemap).filter(([, sitemapItem]) => {
|
|
815
|
+
if (rootConfig.build?.excludeDefaultLocaleFromIntlPaths) {
|
|
816
|
+
const defaultLocale = rootConfig.i18n?.defaultLocale || "en";
|
|
817
|
+
if (sitemapItem.locale === defaultLocale) {
|
|
818
|
+
return false;
|
|
758
819
|
}
|
|
820
|
+
}
|
|
821
|
+
return true;
|
|
822
|
+
});
|
|
823
|
+
if (activeLogMode !== "quiet") {
|
|
824
|
+
console.log("\nhtml output:");
|
|
825
|
+
}
|
|
826
|
+
const concurrency = Number(options?.concurrency || 10);
|
|
827
|
+
const resolvedThreads = resolveNumThreads(
|
|
828
|
+
options?.threads,
|
|
829
|
+
sitemapEntries.length
|
|
830
|
+
);
|
|
831
|
+
const numThreads = resolvedThreads.count;
|
|
832
|
+
const workerConcurrency = numThreads > 0 ? Math.max(Math.ceil(concurrency / numThreads), 1) : 0;
|
|
833
|
+
if (activeLogMode !== "quiet") {
|
|
834
|
+
const threadsDesc = numThreads > 0 ? `${numThreads} workers x ${workerConcurrency} pages/worker` : `in-process, ${concurrency} concurrent pages`;
|
|
835
|
+
console.log(
|
|
836
|
+
` ${dim3(`threads: ${threadsDesc} (${resolvedThreads.source})`)}`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
const progress = new BuildProgress({
|
|
840
|
+
total: sitemapEntries.length,
|
|
841
|
+
mode: activeLogMode,
|
|
842
|
+
itemLabel: "pages",
|
|
843
|
+
outputDirLabel: "dist/html/"
|
|
844
|
+
});
|
|
845
|
+
try {
|
|
846
|
+
if (numThreads > 0) {
|
|
847
|
+
const pool = new BuildWorkerPool({
|
|
848
|
+
numWorkers: numThreads,
|
|
849
|
+
workerConcurrency,
|
|
850
|
+
rootDir,
|
|
851
|
+
mode
|
|
852
|
+
});
|
|
759
853
|
try {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
props = { rootConfig, params: sitemapItem.params };
|
|
773
|
-
}
|
|
774
|
-
const result = await routeModule.getStaticContent(props);
|
|
775
|
-
let body;
|
|
776
|
-
if (typeof result === "string") {
|
|
777
|
-
body = result;
|
|
778
|
-
} else if (result && typeof result === "object") {
|
|
779
|
-
body = result.body;
|
|
780
|
-
} else {
|
|
781
|
-
body = "";
|
|
782
|
-
}
|
|
783
|
-
const outFilePath2 = urlPath.slice(1);
|
|
784
|
-
const outPath2 = path3.join(buildDir, outFilePath2);
|
|
785
|
-
await makeDir(path3.dirname(outPath2));
|
|
786
|
-
await writeFile(outPath2, normalizeLineEndings(body));
|
|
787
|
-
printFileOutput(fileSize(outPath2), "dist/html/", outFilePath2);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
const data = await renderer.renderRoute(sitemapItem.route, {
|
|
791
|
-
routeParams: sitemapItem.params
|
|
792
|
-
});
|
|
793
|
-
if (data.notFound) {
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
let outFilePath = path3.join(urlPath.slice(1), "index.html");
|
|
797
|
-
if (outFilePath.endsWith("404/index.html")) {
|
|
798
|
-
outFilePath = outFilePath.replace("404/index.html", "404.html");
|
|
799
|
-
}
|
|
800
|
-
const outPath = path3.join(buildDir, outFilePath);
|
|
801
|
-
if (rootConfig.sitemap && outFilePath.endsWith("index.html")) {
|
|
802
|
-
const sitemapXmlItem = {
|
|
803
|
-
url: `${domain}${urlPath}`,
|
|
804
|
-
locale: sitemapItem.locale,
|
|
805
|
-
alts: []
|
|
806
|
-
};
|
|
807
|
-
sitemapXmlItems.push(sitemapXmlItem);
|
|
808
|
-
if (sitemapItem.alts) {
|
|
809
|
-
Object.entries(sitemapItem.alts).forEach(([altLocale, item]) => {
|
|
810
|
-
sitemapXmlItem.alts.push({
|
|
811
|
-
url: `${domain}${item.urlPath}`,
|
|
812
|
-
locale: altLocale,
|
|
813
|
-
hreflang: item.hrefLang
|
|
854
|
+
await pool.ready();
|
|
855
|
+
await Promise.all(
|
|
856
|
+
sitemapEntries.map(async ([urlPath, sitemapItem]) => {
|
|
857
|
+
try {
|
|
858
|
+
const result = await pool.run({
|
|
859
|
+
urlPath,
|
|
860
|
+
params: sitemapItem.params,
|
|
861
|
+
routeSrc: sitemapItem.route.src,
|
|
862
|
+
locale: sitemapItem.locale
|
|
814
863
|
});
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
864
|
+
onPageResult(sitemapItem, result);
|
|
865
|
+
} catch (e) {
|
|
866
|
+
if (e instanceof BuildPageError) {
|
|
867
|
+
progress.abort();
|
|
868
|
+
logBuildError(
|
|
869
|
+
{
|
|
870
|
+
route: sitemapItem.route,
|
|
871
|
+
params: sitemapItem.params,
|
|
872
|
+
urlPath
|
|
873
|
+
},
|
|
874
|
+
new Error(e.workerError)
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
throw e;
|
|
878
|
+
}
|
|
879
|
+
})
|
|
829
880
|
);
|
|
881
|
+
} finally {
|
|
882
|
+
await pool.terminate();
|
|
830
883
|
}
|
|
884
|
+
} else {
|
|
885
|
+
await batchAsyncCalls(
|
|
886
|
+
sitemapEntries,
|
|
887
|
+
concurrency,
|
|
888
|
+
async ([urlPath, sitemapItem]) => {
|
|
889
|
+
try {
|
|
890
|
+
const result = await buildPage(
|
|
891
|
+
renderer,
|
|
892
|
+
rootConfig,
|
|
893
|
+
buildDir,
|
|
894
|
+
sitemapItem.route,
|
|
895
|
+
{ urlPath, params: sitemapItem.params }
|
|
896
|
+
);
|
|
897
|
+
onPageResult(sitemapItem, result);
|
|
898
|
+
} catch (e) {
|
|
899
|
+
progress.abort();
|
|
900
|
+
logBuildError(
|
|
901
|
+
{ route: sitemapItem.route, params: sitemapItem.params, urlPath },
|
|
902
|
+
e
|
|
903
|
+
);
|
|
904
|
+
throw new Error(
|
|
905
|
+
`BuildError: ${urlPath} (${sitemapItem.route.src}) failed to build.`,
|
|
906
|
+
{ cause: e }
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
);
|
|
831
911
|
}
|
|
832
|
-
)
|
|
912
|
+
} catch (e) {
|
|
913
|
+
progress.abort();
|
|
914
|
+
throw e;
|
|
915
|
+
}
|
|
916
|
+
progress.finish();
|
|
833
917
|
if (rootConfig.sitemap) {
|
|
834
918
|
const sitemapXmlBuilder = [];
|
|
835
919
|
sitemapXmlItems.sort((a, b) => a.url.localeCompare(b.url));
|
|
@@ -855,7 +939,7 @@ async function build(rootProjectDir, options) {
|
|
|
855
939
|
"</urlset>"
|
|
856
940
|
];
|
|
857
941
|
const sitemapXml = sitemapXmlLines.join("\n");
|
|
858
|
-
const outPath =
|
|
942
|
+
const outPath = path2.join(buildDir, "sitemap.xml");
|
|
859
943
|
await writeFile(outPath, sitemapXml);
|
|
860
944
|
printFileOutput(fileSize(outPath), "dist/html/", "sitemap.xml");
|
|
861
945
|
}
|
|
@@ -869,22 +953,46 @@ async function build(rootProjectDir, options) {
|
|
|
869
953
|
function isRouteFile(filepath) {
|
|
870
954
|
return filepath.startsWith("routes") && isJsFile(filepath);
|
|
871
955
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
956
|
+
var MIN_PAGES_PER_THREAD = 10;
|
|
957
|
+
var MEMORY_PER_THREAD = 1024 * 1024 * 1024;
|
|
958
|
+
function resolveNumThreads(threads, numPages) {
|
|
959
|
+
if (threads === void 0 || threads === false) {
|
|
960
|
+
return { count: 0, source: "--threads not set" };
|
|
961
|
+
}
|
|
962
|
+
if (threads === true || threads === "auto") {
|
|
963
|
+
const maxByCpu = Math.max(os.availableParallelism() - 1, 1);
|
|
964
|
+
const maxByPages = Math.floor(numPages / MIN_PAGES_PER_THREAD);
|
|
965
|
+
const maxByMemory = Math.max(
|
|
966
|
+
Math.floor(os.freemem() / MEMORY_PER_THREAD) - 1,
|
|
967
|
+
1
|
|
968
|
+
);
|
|
969
|
+
const numThreads = Math.min(maxByCpu, maxByPages, maxByMemory);
|
|
970
|
+
const source = `auto = min(cpu ${maxByCpu}, pages ${maxByPages}, memory ${maxByMemory})`;
|
|
971
|
+
if (numThreads <= 1) {
|
|
972
|
+
return { count: 0, source };
|
|
973
|
+
}
|
|
974
|
+
return { count: numThreads, source };
|
|
878
975
|
}
|
|
879
|
-
const
|
|
880
|
-
|
|
881
|
-
|
|
976
|
+
const num = parseInt(threads);
|
|
977
|
+
if (isNaN(num) || num < 0) {
|
|
978
|
+
throw new Error(`invalid --threads value: ${threads}`);
|
|
979
|
+
}
|
|
980
|
+
return { count: num, source: `--threads=${num}` };
|
|
981
|
+
}
|
|
982
|
+
function fileSizeBytes(filepath) {
|
|
983
|
+
return fsExtra.statSync(filepath).size;
|
|
984
|
+
}
|
|
985
|
+
function fileSize(filepath) {
|
|
986
|
+
return formatBytes(fileSizeBytes(filepath));
|
|
882
987
|
}
|
|
883
988
|
function printFileOutput(fileSize2, outputDir, outputFile) {
|
|
989
|
+
if (activeLogMode === "quiet") {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
884
992
|
const indent = " ".repeat(2);
|
|
885
993
|
const paddedSize = fileSize2.padStart(9, " ");
|
|
886
994
|
console.log(
|
|
887
|
-
`${indent}${
|
|
995
|
+
`${indent}${dim3(paddedSize)} ${dim3(outputDir)}${cyan2(outputFile)}`
|
|
888
996
|
);
|
|
889
997
|
}
|
|
890
998
|
function sanitizeFileName(name) {
|
|
@@ -917,18 +1025,15 @@ function formatParams(params) {
|
|
|
917
1025
|
return ` ${key}: ${value}`;
|
|
918
1026
|
}).join("\n");
|
|
919
1027
|
}
|
|
920
|
-
function normalizeLineEndings(str) {
|
|
921
|
-
return str.replace(/\r\n?/g, "\n");
|
|
922
|
-
}
|
|
923
1028
|
|
|
924
1029
|
// src/cli/codegen.ts
|
|
925
|
-
import { promises as
|
|
926
|
-
import
|
|
927
|
-
import { fileURLToPath as
|
|
928
|
-
import
|
|
929
|
-
var
|
|
1030
|
+
import { promises as fs } from "node:fs";
|
|
1031
|
+
import path3 from "node:path";
|
|
1032
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1033
|
+
import glob2 from "tiny-glob";
|
|
1034
|
+
var __dirname3 = path3.dirname(fileURLToPath3(import.meta.url));
|
|
930
1035
|
async function codegen(type, name, options) {
|
|
931
|
-
const rootDir =
|
|
1036
|
+
const rootDir = path3.resolve(process.cwd());
|
|
932
1037
|
const project = new Project(rootDir);
|
|
933
1038
|
await project.generateCode(type, name, options);
|
|
934
1039
|
}
|
|
@@ -938,8 +1043,8 @@ var Project = class {
|
|
|
938
1043
|
constructor(rootDir) {
|
|
939
1044
|
this.rootDir = rootDir;
|
|
940
1045
|
this.tplDirs = [
|
|
941
|
-
|
|
942
|
-
|
|
1046
|
+
path3.join(rootDir, "codegen"),
|
|
1047
|
+
path3.join(__dirname3, "../codegen")
|
|
943
1048
|
];
|
|
944
1049
|
}
|
|
945
1050
|
async generateCode(type, name, options) {
|
|
@@ -949,7 +1054,7 @@ var Project = class {
|
|
|
949
1054
|
return;
|
|
950
1055
|
}
|
|
951
1056
|
const outname = options?.out || `${type}s`;
|
|
952
|
-
const outdir =
|
|
1057
|
+
const outdir = path3.join(this.rootDir, outname, name);
|
|
953
1058
|
if (await dirExists(outdir)) {
|
|
954
1059
|
await rmDir(outdir);
|
|
955
1060
|
}
|
|
@@ -958,7 +1063,7 @@ var Project = class {
|
|
|
958
1063
|
const tpl = await files[tplName].read();
|
|
959
1064
|
const content = tpl.replaceAll("[[name]]", name).replaceAll("[[name:camel_upper]]", toCamelCaseUpper(name));
|
|
960
1065
|
const filename = tplName.replace("[name]", name);
|
|
961
|
-
const filepath =
|
|
1066
|
+
const filepath = path3.join(outdir, filename);
|
|
962
1067
|
await writeFile(filepath, content);
|
|
963
1068
|
console.log(`saved ${filepath}`);
|
|
964
1069
|
}
|
|
@@ -969,7 +1074,7 @@ var Project = class {
|
|
|
969
1074
|
*/
|
|
970
1075
|
async loadFiles(type) {
|
|
971
1076
|
for (const tplDir of this.tplDirs) {
|
|
972
|
-
const typeDir =
|
|
1077
|
+
const typeDir = path3.join(tplDir, type);
|
|
973
1078
|
if (await dirExists(typeDir)) {
|
|
974
1079
|
return this.loadTplFiles(typeDir);
|
|
975
1080
|
}
|
|
@@ -981,12 +1086,12 @@ var Project = class {
|
|
|
981
1086
|
*/
|
|
982
1087
|
async loadTplFiles(dirpath) {
|
|
983
1088
|
const tplFiles = {};
|
|
984
|
-
const files = await
|
|
1089
|
+
const files = await glob2("*.tpl", { cwd: dirpath });
|
|
985
1090
|
for (const filename of files) {
|
|
986
|
-
const filepath =
|
|
1091
|
+
const filepath = path3.join(dirpath, filename);
|
|
987
1092
|
const name = filename.slice(0, -4);
|
|
988
1093
|
tplFiles[name] = {
|
|
989
|
-
read: () =>
|
|
1094
|
+
read: () => fs.readFile(filepath, "utf-8")
|
|
990
1095
|
};
|
|
991
1096
|
}
|
|
992
1097
|
return tplFiles;
|
|
@@ -1002,23 +1107,23 @@ function toTitleCase(str) {
|
|
|
1002
1107
|
}
|
|
1003
1108
|
|
|
1004
1109
|
// src/cli/create-package.ts
|
|
1005
|
-
import { promises as
|
|
1006
|
-
import
|
|
1110
|
+
import { promises as fs2 } from "node:fs";
|
|
1111
|
+
import path4 from "node:path";
|
|
1007
1112
|
import { build as esbuild } from "esbuild";
|
|
1008
1113
|
async function createPackage(rootProjectDir, options) {
|
|
1009
1114
|
const mode = options?.mode || "production";
|
|
1010
1115
|
process.env.NODE_ENV = mode;
|
|
1011
|
-
const rootDir =
|
|
1012
|
-
const distDir =
|
|
1116
|
+
const rootDir = path4.resolve(rootProjectDir || process.cwd());
|
|
1117
|
+
const distDir = path4.join(rootDir, "dist");
|
|
1013
1118
|
const target = options?.target || await getDefaultTarget(rootDir);
|
|
1014
|
-
const outDir =
|
|
1119
|
+
const outDir = path4.resolve(options?.out || target || "out");
|
|
1015
1120
|
await build(rootProjectDir, { ssrOnly: true, mode });
|
|
1016
1121
|
await rmDir(outDir);
|
|
1017
1122
|
await makeDir(outDir);
|
|
1018
|
-
await copyDir(distDir,
|
|
1019
|
-
const collectionsDir =
|
|
1123
|
+
await copyDir(distDir, path4.resolve(outDir, "dist"));
|
|
1124
|
+
const collectionsDir = path4.resolve(rootDir, "collections");
|
|
1020
1125
|
if (await dirExists(collectionsDir)) {
|
|
1021
|
-
await copyDir(collectionsDir,
|
|
1126
|
+
await copyDir(collectionsDir, path4.join(outDir, "collections"));
|
|
1022
1127
|
}
|
|
1023
1128
|
const packageJson = await generatePackageJson(rootDir, options);
|
|
1024
1129
|
if (options?.version && packageJson.dependencies) {
|
|
@@ -1033,21 +1138,21 @@ async function createPackage(rootProjectDir, options) {
|
|
|
1033
1138
|
}
|
|
1034
1139
|
}
|
|
1035
1140
|
if (target === "appengine") {
|
|
1036
|
-
const appYamlPath = options?.appYaml ||
|
|
1141
|
+
const appYamlPath = options?.appYaml || path4.join(rootDir, "app.yaml");
|
|
1037
1142
|
await onAppEngine({ packageJson, outDir, appYamlPath });
|
|
1038
1143
|
} else if (target === "firebase") {
|
|
1039
1144
|
await onFirebase({ rootDir, packageJson, outDir });
|
|
1040
1145
|
}
|
|
1041
|
-
await writeJson(
|
|
1146
|
+
await writeJson(path4.resolve(outDir, "package.json"), packageJson);
|
|
1042
1147
|
console.log("done!");
|
|
1043
1148
|
console.log(`saved package to ${outDir}`);
|
|
1044
1149
|
}
|
|
1045
1150
|
async function getDefaultTarget(rootDir) {
|
|
1046
|
-
const firebaseConfigPath =
|
|
1151
|
+
const firebaseConfigPath = path4.resolve(rootDir, "firebase.json");
|
|
1047
1152
|
if (await fileExists(firebaseConfigPath)) {
|
|
1048
1153
|
return "firebase";
|
|
1049
1154
|
}
|
|
1050
|
-
const appEngineConfigPath =
|
|
1155
|
+
const appEngineConfigPath = path4.resolve(rootDir, "app.yaml");
|
|
1051
1156
|
if (await fileExists(appEngineConfigPath)) {
|
|
1052
1157
|
return "appengine";
|
|
1053
1158
|
}
|
|
@@ -1055,7 +1160,7 @@ async function getDefaultTarget(rootDir) {
|
|
|
1055
1160
|
}
|
|
1056
1161
|
async function generatePackageJson(rootDir, options) {
|
|
1057
1162
|
const packageJson = await loadJson(
|
|
1058
|
-
|
|
1163
|
+
path4.resolve(rootDir, "package.json")
|
|
1059
1164
|
);
|
|
1060
1165
|
const allDeps = flattenPackageDepsFromMonorepo(rootDir);
|
|
1061
1166
|
packageJson.dependencies ??= {};
|
|
@@ -1082,7 +1187,7 @@ async function generatePackageJson(rootDir, options) {
|
|
|
1082
1187
|
async function onAppEngine(options) {
|
|
1083
1188
|
const { outDir, packageJson, appYamlPath } = options;
|
|
1084
1189
|
if (await fileExists(appYamlPath)) {
|
|
1085
|
-
await
|
|
1190
|
+
await fs2.copyFile(appYamlPath, path4.resolve(outDir, "app.yaml"));
|
|
1086
1191
|
}
|
|
1087
1192
|
if (packageJson.scripts?.start) {
|
|
1088
1193
|
packageJson.scripts = { start: packageJson.scripts.start };
|
|
@@ -1092,11 +1197,11 @@ async function onAppEngine(options) {
|
|
|
1092
1197
|
}
|
|
1093
1198
|
async function onFirebase(options) {
|
|
1094
1199
|
const { rootDir, outDir, packageJson } = options;
|
|
1095
|
-
const outBasename =
|
|
1200
|
+
const outBasename = path4.basename(outDir);
|
|
1096
1201
|
if (outBasename === "functions") {
|
|
1097
|
-
const indexTsFile =
|
|
1202
|
+
const indexTsFile = path4.resolve(rootDir, "index.ts");
|
|
1098
1203
|
if (await fileExists(indexTsFile)) {
|
|
1099
|
-
await bundleTsFile(indexTsFile,
|
|
1204
|
+
await bundleTsFile(indexTsFile, path4.resolve(outDir, "index.js"));
|
|
1100
1205
|
}
|
|
1101
1206
|
}
|
|
1102
1207
|
if (packageJson.scripts?.start) {
|
|
@@ -1121,7 +1226,7 @@ async function bundleTsFile(srcPath, outPath) {
|
|
|
1121
1226
|
setup(build2) {
|
|
1122
1227
|
build2.onResolve({ filter: /.*/ }, (args) => {
|
|
1123
1228
|
const id = args.path;
|
|
1124
|
-
if (id[0] !== "." && !
|
|
1229
|
+
if (id[0] !== "." && !path4.isAbsolute(id)) {
|
|
1125
1230
|
return {
|
|
1126
1231
|
external: true
|
|
1127
1232
|
};
|
|
@@ -1135,13 +1240,13 @@ async function bundleTsFile(srcPath, outPath) {
|
|
|
1135
1240
|
}
|
|
1136
1241
|
|
|
1137
1242
|
// src/cli/dev.ts
|
|
1138
|
-
import
|
|
1139
|
-
import { fileURLToPath as
|
|
1243
|
+
import path11 from "node:path";
|
|
1244
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
1140
1245
|
import cookieParser from "cookie-parser";
|
|
1141
1246
|
import { default as express } from "express";
|
|
1142
|
-
import { dim as
|
|
1247
|
+
import { dim as dim6 } from "kleur/colors";
|
|
1143
1248
|
import sirv from "sirv";
|
|
1144
|
-
import
|
|
1249
|
+
import glob3 from "tiny-glob";
|
|
1145
1250
|
|
|
1146
1251
|
// src/middleware/hooks.ts
|
|
1147
1252
|
function hooksMiddleware() {
|
|
@@ -1229,8 +1334,8 @@ function testIsRedirectValid(url) {
|
|
|
1229
1334
|
}
|
|
1230
1335
|
|
|
1231
1336
|
// src/render/asset-map/dev-asset-map.ts
|
|
1232
|
-
import
|
|
1233
|
-
import { searchForWorkspaceRoot
|
|
1337
|
+
import path5 from "node:path";
|
|
1338
|
+
import { searchForWorkspaceRoot } from "vite";
|
|
1234
1339
|
var DevServerAssetMap = class {
|
|
1235
1340
|
rootConfig;
|
|
1236
1341
|
moduleGraph;
|
|
@@ -1239,7 +1344,7 @@ var DevServerAssetMap = class {
|
|
|
1239
1344
|
this.moduleGraph = moduleGraph;
|
|
1240
1345
|
}
|
|
1241
1346
|
async get(src) {
|
|
1242
|
-
const file =
|
|
1347
|
+
const file = path5.resolve(this.rootConfig.rootDir, src);
|
|
1243
1348
|
const viteModules = this.moduleGraph.getModulesByFile(file);
|
|
1244
1349
|
if (viteModules && viteModules.size > 0) {
|
|
1245
1350
|
const [viteModule] = viteModules;
|
|
@@ -1257,7 +1362,7 @@ var DevServerAssetMap = class {
|
|
|
1257
1362
|
getJsDeps: async () => [assetUrl]
|
|
1258
1363
|
};
|
|
1259
1364
|
}
|
|
1260
|
-
const workspaceRoot =
|
|
1365
|
+
const workspaceRoot = searchForWorkspaceRoot(this.rootConfig.rootDir);
|
|
1261
1366
|
if (await directoryContains(workspaceRoot, file)) {
|
|
1262
1367
|
const assetUrl = `/@fs/${file}`;
|
|
1263
1368
|
return {
|
|
@@ -1271,7 +1376,7 @@ var DevServerAssetMap = class {
|
|
|
1271
1376
|
return null;
|
|
1272
1377
|
}
|
|
1273
1378
|
filePathToSrc(file) {
|
|
1274
|
-
return
|
|
1379
|
+
return path5.relative(this.rootConfig.rootDir, file);
|
|
1275
1380
|
}
|
|
1276
1381
|
};
|
|
1277
1382
|
var DevServerAsset = class _DevServerAsset {
|
|
@@ -1313,7 +1418,7 @@ var DevServerAsset = class _DevServerAsset {
|
|
|
1313
1418
|
return;
|
|
1314
1419
|
}
|
|
1315
1420
|
visited.add(asset.moduleId);
|
|
1316
|
-
const parts =
|
|
1421
|
+
const parts = path5.parse(asset.assetUrl);
|
|
1317
1422
|
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
1318
1423
|
urls.add(asset.assetUrl);
|
|
1319
1424
|
}
|
|
@@ -1340,7 +1445,7 @@ var DevServerAsset = class _DevServerAsset {
|
|
|
1340
1445
|
}
|
|
1341
1446
|
visited.add(asset.assetUrl);
|
|
1342
1447
|
if (asset.src.endsWith(".scss")) {
|
|
1343
|
-
const parts =
|
|
1448
|
+
const parts = path5.parse(asset.src);
|
|
1344
1449
|
if (!parts.name.startsWith("_")) {
|
|
1345
1450
|
urls.add(asset.assetUrl);
|
|
1346
1451
|
}
|
|
@@ -1421,19 +1526,19 @@ function getSessionCookieSecret(rootConfig, rootDir) {
|
|
|
1421
1526
|
|
|
1422
1527
|
// src/cli/secrets.ts
|
|
1423
1528
|
import { spawn as spawn3 } from "node:child_process";
|
|
1424
|
-
import
|
|
1425
|
-
import
|
|
1529
|
+
import fs6 from "node:fs";
|
|
1530
|
+
import path9 from "node:path";
|
|
1426
1531
|
import * as readline from "node:readline";
|
|
1427
|
-
import { dim as
|
|
1532
|
+
import { dim as dim4, green as green2, red, yellow } from "kleur/colors";
|
|
1428
1533
|
|
|
1429
1534
|
// src/secrets/manifest.ts
|
|
1430
|
-
import
|
|
1431
|
-
import
|
|
1535
|
+
import fs3 from "node:fs";
|
|
1536
|
+
import path6 from "node:path";
|
|
1432
1537
|
var MANIFEST_FILENAME = ".root.secrets.json";
|
|
1433
1538
|
var GSM_KEY_RE = /^[A-Za-z0-9_-]{1,255}$/;
|
|
1434
1539
|
var ENV_NAME_RE = /^[A-Za-z0-9_]+$/;
|
|
1435
1540
|
function manifestPath(dir) {
|
|
1436
|
-
return
|
|
1541
|
+
return path6.join(dir, MANIFEST_FILENAME);
|
|
1437
1542
|
}
|
|
1438
1543
|
function isValidEnvName(name) {
|
|
1439
1544
|
return ENV_NAME_RE.test(name);
|
|
@@ -1441,7 +1546,7 @@ function isValidEnvName(name) {
|
|
|
1441
1546
|
async function readManifest(filePath) {
|
|
1442
1547
|
let raw;
|
|
1443
1548
|
try {
|
|
1444
|
-
raw = await
|
|
1549
|
+
raw = await fs3.promises.readFile(filePath, "utf8");
|
|
1445
1550
|
} catch (err) {
|
|
1446
1551
|
if (err.code === "ENOENT") {
|
|
1447
1552
|
return null;
|
|
@@ -1468,8 +1573,8 @@ async function writeManifest(filePath, manifest) {
|
|
|
1468
1573
|
...manifest.import ? { import: manifest.import } : {},
|
|
1469
1574
|
secrets: sortedSecrets
|
|
1470
1575
|
};
|
|
1471
|
-
await
|
|
1472
|
-
await
|
|
1576
|
+
await fs3.promises.mkdir(path6.dirname(filePath), { recursive: true });
|
|
1577
|
+
await fs3.promises.writeFile(
|
|
1473
1578
|
filePath,
|
|
1474
1579
|
JSON.stringify(ordered, null, 2) + "\n",
|
|
1475
1580
|
"utf8"
|
|
@@ -1497,7 +1602,7 @@ async function resolveManagedKeys(rootDir) {
|
|
|
1497
1602
|
}
|
|
1498
1603
|
let shared;
|
|
1499
1604
|
if (site.import) {
|
|
1500
|
-
const sharedPath =
|
|
1605
|
+
const sharedPath = path6.resolve(rootDir, site.import.manifest);
|
|
1501
1606
|
const loaded = await readManifest(sharedPath);
|
|
1502
1607
|
if (!loaded) {
|
|
1503
1608
|
throw new Error(`imported manifest not found: ${sharedPath}`);
|
|
@@ -1624,16 +1729,16 @@ function validateManifest(value, filePath) {
|
|
|
1624
1729
|
|
|
1625
1730
|
// src/secrets/secrets.ts
|
|
1626
1731
|
import { spawn as spawn2 } from "node:child_process";
|
|
1627
|
-
import
|
|
1628
|
-
import
|
|
1732
|
+
import fs5 from "node:fs";
|
|
1733
|
+
import path8 from "node:path";
|
|
1629
1734
|
|
|
1630
1735
|
// src/secrets/env-file.ts
|
|
1631
|
-
import
|
|
1632
|
-
import
|
|
1736
|
+
import fs4 from "node:fs";
|
|
1737
|
+
import path7 from "node:path";
|
|
1633
1738
|
import dotenv from "dotenv";
|
|
1634
1739
|
async function readEnvFile(envPath2) {
|
|
1635
1740
|
try {
|
|
1636
|
-
return await
|
|
1741
|
+
return await fs4.promises.readFile(envPath2, "utf8");
|
|
1637
1742
|
} catch (err) {
|
|
1638
1743
|
if (err.code === "ENOENT") {
|
|
1639
1744
|
return "";
|
|
@@ -1642,11 +1747,11 @@ async function readEnvFile(envPath2) {
|
|
|
1642
1747
|
}
|
|
1643
1748
|
}
|
|
1644
1749
|
async function writeEnvFile(envPath2, content) {
|
|
1645
|
-
const dir =
|
|
1646
|
-
await
|
|
1647
|
-
const tmp =
|
|
1648
|
-
await
|
|
1649
|
-
await
|
|
1750
|
+
const dir = path7.dirname(envPath2);
|
|
1751
|
+
await fs4.promises.mkdir(dir, { recursive: true });
|
|
1752
|
+
const tmp = path7.join(dir, `.env.tmp-${process.pid}-${Date.now()}`);
|
|
1753
|
+
await fs4.promises.writeFile(tmp, content, "utf8");
|
|
1754
|
+
await fs4.promises.rename(tmp, envPath2);
|
|
1650
1755
|
}
|
|
1651
1756
|
function parseEnv(content) {
|
|
1652
1757
|
return dotenv.parse(content);
|
|
@@ -1864,10 +1969,10 @@ function hashValue(salt, value) {
|
|
|
1864
1969
|
// src/secrets/secrets.ts
|
|
1865
1970
|
var STATE_FILENAME = "secrets-sync.json";
|
|
1866
1971
|
function localStatePath(rootDir) {
|
|
1867
|
-
return
|
|
1972
|
+
return path8.join(rootDir, ".root", STATE_FILENAME);
|
|
1868
1973
|
}
|
|
1869
1974
|
function envPath(rootDir) {
|
|
1870
|
-
return
|
|
1975
|
+
return path8.join(rootDir, ".env");
|
|
1871
1976
|
}
|
|
1872
1977
|
var inFlight = /* @__PURE__ */ new Map();
|
|
1873
1978
|
function syncSecrets(options) {
|
|
@@ -2093,7 +2198,7 @@ async function pushEnvToSecrets(options) {
|
|
|
2093
2198
|
};
|
|
2094
2199
|
}
|
|
2095
2200
|
async function sharedImportedNames(rootDir, manifestFilePath) {
|
|
2096
|
-
if (
|
|
2201
|
+
if (path8.resolve(manifestFilePath) !== path8.resolve(manifestPath(rootDir))) {
|
|
2097
2202
|
return /* @__PURE__ */ new Set();
|
|
2098
2203
|
}
|
|
2099
2204
|
try {
|
|
@@ -2156,7 +2261,7 @@ function isSyncDisabledByEnv() {
|
|
|
2156
2261
|
}
|
|
2157
2262
|
async function readLocalState(rootDir) {
|
|
2158
2263
|
try {
|
|
2159
|
-
const raw = await
|
|
2264
|
+
const raw = await fs5.promises.readFile(localStatePath(rootDir), "utf8");
|
|
2160
2265
|
const parsed = JSON.parse(raw);
|
|
2161
2266
|
if (parsed && typeof parsed === "object" && typeof parsed.salt === "string" && parsed.secrets && typeof parsed.secrets === "object") {
|
|
2162
2267
|
return {
|
|
@@ -2170,8 +2275,8 @@ async function readLocalState(rootDir) {
|
|
|
2170
2275
|
}
|
|
2171
2276
|
async function writeLocalState(rootDir, state) {
|
|
2172
2277
|
const file = localStatePath(rootDir);
|
|
2173
|
-
await
|
|
2174
|
-
await
|
|
2278
|
+
await fs5.promises.mkdir(path8.dirname(file), { recursive: true });
|
|
2279
|
+
await fs5.promises.writeFile(
|
|
2175
2280
|
file,
|
|
2176
2281
|
JSON.stringify(state, null, 2) + "\n",
|
|
2177
2282
|
"utf8"
|
|
@@ -2197,7 +2302,7 @@ function getGitEmail() {
|
|
|
2197
2302
|
}
|
|
2198
2303
|
|
|
2199
2304
|
// src/cli/secrets.ts
|
|
2200
|
-
var BAR =
|
|
2305
|
+
var BAR = dim4("\u2503");
|
|
2201
2306
|
var DEV_SYNC_TIMEOUT_MS = 1e4;
|
|
2202
2307
|
function registerSecretsCommands(program) {
|
|
2203
2308
|
const secrets = program.command("secrets").description(
|
|
@@ -2237,7 +2342,7 @@ function registerSecretsCommands(program) {
|
|
|
2237
2342
|
}
|
|
2238
2343
|
async function secretsInit(opts) {
|
|
2239
2344
|
const rootDir = process.cwd();
|
|
2240
|
-
const target = opts.manifest ?
|
|
2345
|
+
const target = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
|
|
2241
2346
|
if (await readManifest(target)) {
|
|
2242
2347
|
console.log(
|
|
2243
2348
|
`${BAR} ${yellow("secrets:")} manifest already exists at ${rel(rootDir, target)}`
|
|
@@ -2258,41 +2363,41 @@ async function secretsInit(opts) {
|
|
|
2258
2363
|
await writeManifest(target, manifest);
|
|
2259
2364
|
const addedGitignore = await ensureRootGitignored(rootDir);
|
|
2260
2365
|
console.log();
|
|
2261
|
-
console.log(`${BAR} ${
|
|
2366
|
+
console.log(`${BAR} ${green2("secrets:")} created ${rel(rootDir, target)}`);
|
|
2262
2367
|
if (addedGitignore) {
|
|
2263
|
-
console.log(`${BAR} added ${
|
|
2368
|
+
console.log(`${BAR} added ${dim4(".root/")} to .gitignore`);
|
|
2264
2369
|
}
|
|
2265
2370
|
await warnIfEnvNotIgnored(rootDir);
|
|
2266
2371
|
console.log(
|
|
2267
|
-
`${BAR} ${
|
|
2372
|
+
`${BAR} ${dim4("next: `root secrets set <NAME>` to store a value")}`
|
|
2268
2373
|
);
|
|
2269
2374
|
console.log();
|
|
2270
2375
|
}
|
|
2271
2376
|
async function secretsSet(name, opts) {
|
|
2272
2377
|
const rootDir = process.cwd();
|
|
2273
|
-
const manifestFilePath = opts.manifest ?
|
|
2378
|
+
const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
|
|
2274
2379
|
const secretValue = await readSecretValue(name);
|
|
2275
2380
|
if (!secretValue) {
|
|
2276
2381
|
throw new Error("no value provided on stdin");
|
|
2277
2382
|
}
|
|
2278
2383
|
await setSecret({ rootDir, manifestFilePath, name, value: secretValue });
|
|
2279
|
-
console.log(`${BAR} ${
|
|
2384
|
+
console.log(`${BAR} ${green2("secrets:")} set ${name}`);
|
|
2280
2385
|
console.log(
|
|
2281
|
-
`${BAR} ${
|
|
2386
|
+
`${BAR} ${dim4(`commit ${rel(rootDir, manifestFilePath)} to share this change`)}`
|
|
2282
2387
|
);
|
|
2283
2388
|
}
|
|
2284
2389
|
async function secretsRm(name, opts) {
|
|
2285
2390
|
const rootDir = process.cwd();
|
|
2286
|
-
const manifestFilePath = opts.manifest ?
|
|
2391
|
+
const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
|
|
2287
2392
|
await removeSecret({ rootDir, manifestFilePath, name });
|
|
2288
|
-
console.log(`${BAR} ${
|
|
2393
|
+
console.log(`${BAR} ${green2("secrets:")} removed ${name}`);
|
|
2289
2394
|
console.log(
|
|
2290
|
-
`${BAR} ${
|
|
2395
|
+
`${BAR} ${dim4(`commit ${rel(rootDir, manifestFilePath)} to share this change`)}`
|
|
2291
2396
|
);
|
|
2292
2397
|
}
|
|
2293
2398
|
async function secretsPush(opts) {
|
|
2294
2399
|
const rootDir = process.cwd();
|
|
2295
|
-
const manifestFilePath = opts.manifest ?
|
|
2400
|
+
const manifestFilePath = opts.manifest ? path9.resolve(rootDir, opts.manifest) : manifestPath(rootDir);
|
|
2296
2401
|
const only = opts.keys ? opts.keys.split(",").map((k) => k.trim()).filter(Boolean) : void 0;
|
|
2297
2402
|
const confirm = opts.yes ? void 0 : async (names, gsmKey) => {
|
|
2298
2403
|
if (!process.stdin.isTTY) {
|
|
@@ -2302,7 +2407,7 @@ async function secretsPush(opts) {
|
|
|
2302
2407
|
}
|
|
2303
2408
|
console.log();
|
|
2304
2409
|
console.log(
|
|
2305
|
-
`${BAR} ${
|
|
2410
|
+
`${BAR} ${green2("secrets:")} push ${names.length} value(s) from .env to "${gsmKey}":`
|
|
2306
2411
|
);
|
|
2307
2412
|
for (const name of names) {
|
|
2308
2413
|
console.log(`${BAR} ${name}`);
|
|
@@ -2345,13 +2450,13 @@ async function secretsStatus() {
|
|
|
2345
2450
|
}
|
|
2346
2451
|
console.log();
|
|
2347
2452
|
console.log(
|
|
2348
|
-
`${BAR} ${
|
|
2453
|
+
`${BAR} ${green2("secrets:")} ${resolved.site.gsmKey} ${dim4(`(${resolved.site.gcpProjectId})`)}`
|
|
2349
2454
|
);
|
|
2350
2455
|
if (resolved.shared) {
|
|
2351
|
-
console.log(`${BAR} imports ${
|
|
2456
|
+
console.log(`${BAR} imports ${dim4(resolved.shared.gsmKey)}`);
|
|
2352
2457
|
}
|
|
2353
2458
|
if (keys.length === 0) {
|
|
2354
|
-
console.log(`${BAR} ${
|
|
2459
|
+
console.log(`${BAR} ${dim4("no managed keys yet")}`);
|
|
2355
2460
|
}
|
|
2356
2461
|
for (const key of keys) {
|
|
2357
2462
|
console.log(`${BAR} ${formatStatus(key)}`);
|
|
@@ -2379,15 +2484,15 @@ async function syncSecretsOnDev(rootDir) {
|
|
|
2379
2484
|
function formatStatus(key) {
|
|
2380
2485
|
switch (key.kind) {
|
|
2381
2486
|
case "in-sync":
|
|
2382
|
-
return `${
|
|
2487
|
+
return `${green2("\u2713")} ${key.name}`;
|
|
2383
2488
|
case "remote-newer":
|
|
2384
|
-
return `${yellow("\u2193")} ${key.name} ${
|
|
2489
|
+
return `${yellow("\u2193")} ${key.name} ${dim4("(update available \u2014 run `root secrets sync`)")}`;
|
|
2385
2490
|
case "locally-edited":
|
|
2386
|
-
return `${
|
|
2491
|
+
return `${dim4("\u2022")} ${key.name} ${dim4("(locally edited)")}`;
|
|
2387
2492
|
case "conflict":
|
|
2388
|
-
return `${yellow("!")} ${key.name} ${
|
|
2493
|
+
return `${yellow("!")} ${key.name} ${dim4("(changed locally & remotely)")}`;
|
|
2389
2494
|
case "not-pulled":
|
|
2390
|
-
return `${yellow("\u2193")} ${key.name} ${
|
|
2495
|
+
return `${yellow("\u2193")} ${key.name} ${dim4("(not pulled yet)")}`;
|
|
2391
2496
|
default:
|
|
2392
2497
|
return key.name;
|
|
2393
2498
|
}
|
|
@@ -2399,13 +2504,13 @@ function printSyncSummary(result, opts = {}) {
|
|
|
2399
2504
|
}
|
|
2400
2505
|
const parts = [];
|
|
2401
2506
|
if (result.changed.length) {
|
|
2402
|
-
parts.push(
|
|
2507
|
+
parts.push(green2(`${result.changed.length} updated`));
|
|
2403
2508
|
}
|
|
2404
2509
|
if (result.removed.length) {
|
|
2405
2510
|
parts.push(`${result.removed.length} removed`);
|
|
2406
2511
|
}
|
|
2407
2512
|
if (result.kept.length) {
|
|
2408
|
-
parts.push(
|
|
2513
|
+
parts.push(dim4(`${result.kept.length} local`));
|
|
2409
2514
|
}
|
|
2410
2515
|
if (result.conflicts.length) {
|
|
2411
2516
|
parts.push(yellow(`${result.conflicts.length} conflict`));
|
|
@@ -2415,22 +2520,22 @@ function printSyncSummary(result, opts = {}) {
|
|
|
2415
2520
|
}
|
|
2416
2521
|
console.log();
|
|
2417
2522
|
console.log(
|
|
2418
|
-
`${BAR} ${
|
|
2523
|
+
`${BAR} ${green2("secrets:")} ${parts.length ? parts.join(", ") : "up to date"}`
|
|
2419
2524
|
);
|
|
2420
2525
|
for (const name of result.changed) {
|
|
2421
|
-
console.log(`${BAR} ${
|
|
2526
|
+
console.log(`${BAR} ${green2("+")} ${name}`);
|
|
2422
2527
|
}
|
|
2423
2528
|
for (const name of result.removed) {
|
|
2424
|
-
console.log(`${BAR} ${
|
|
2529
|
+
console.log(`${BAR} ${dim4("-")} ${name} ${dim4("(removed)")}`);
|
|
2425
2530
|
}
|
|
2426
2531
|
for (const name of result.overwritten) {
|
|
2427
2532
|
console.log(
|
|
2428
|
-
`${BAR} ${yellow("!")} ${name} ${
|
|
2533
|
+
`${BAR} ${yellow("!")} ${name} ${dim4("(local value replaced)")}`
|
|
2429
2534
|
);
|
|
2430
2535
|
}
|
|
2431
2536
|
for (const name of result.conflicts) {
|
|
2432
2537
|
console.log(
|
|
2433
|
-
`${BAR} ${yellow("!")} ${name} ${
|
|
2538
|
+
`${BAR} ${yellow("!")} ${name} ${dim4(
|
|
2434
2539
|
"(changed locally & remotely; keeping yours \u2014 `root secrets pull` to take remote)"
|
|
2435
2540
|
)}`
|
|
2436
2541
|
);
|
|
@@ -2452,28 +2557,28 @@ function printPushResult(result, rootDir, manifestFilePath) {
|
|
|
2452
2557
|
console.log(`${BAR} ${yellow("secrets:")} nothing to push`);
|
|
2453
2558
|
} else {
|
|
2454
2559
|
console.log(
|
|
2455
|
-
`${BAR} ${
|
|
2560
|
+
`${BAR} ${green2("secrets:")} pushed ${result.pushed.length} value(s) to "${result.gsmKey}"`
|
|
2456
2561
|
);
|
|
2457
2562
|
for (const name of result.pushed) {
|
|
2458
|
-
console.log(`${BAR} ${
|
|
2563
|
+
console.log(`${BAR} ${green2("+")} ${name}`);
|
|
2459
2564
|
}
|
|
2460
2565
|
}
|
|
2461
2566
|
for (const skip of result.skipped) {
|
|
2462
|
-
console.log(`${BAR} ${
|
|
2567
|
+
console.log(`${BAR} ${dim4("-")} ${skip.name} ${dim4(`(${skip.reason})`)}`);
|
|
2463
2568
|
}
|
|
2464
2569
|
if (result.pushed.length > 0) {
|
|
2465
2570
|
console.log(
|
|
2466
|
-
`${BAR} ${
|
|
2571
|
+
`${BAR} ${dim4(`commit ${rel(rootDir, manifestFilePath)} to share`)}`
|
|
2467
2572
|
);
|
|
2468
2573
|
}
|
|
2469
2574
|
console.log();
|
|
2470
2575
|
}
|
|
2471
2576
|
async function ensureRootGitignored(rootDir) {
|
|
2472
2577
|
const gitRoot = await gitToplevel(rootDir) ?? rootDir;
|
|
2473
|
-
const gitignore =
|
|
2578
|
+
const gitignore = path9.join(gitRoot, ".gitignore");
|
|
2474
2579
|
let content = "";
|
|
2475
2580
|
try {
|
|
2476
|
-
content = await
|
|
2581
|
+
content = await fs6.promises.readFile(gitignore, "utf8");
|
|
2477
2582
|
} catch {
|
|
2478
2583
|
}
|
|
2479
2584
|
const lines = content.split(/\r?\n/).map((line) => line.trim());
|
|
@@ -2481,7 +2586,7 @@ async function ensureRootGitignored(rootDir) {
|
|
|
2481
2586
|
return false;
|
|
2482
2587
|
}
|
|
2483
2588
|
const prefix = content && !content.endsWith("\n") ? "\n" : "";
|
|
2484
|
-
await
|
|
2589
|
+
await fs6.promises.writeFile(gitignore, `${content}${prefix}.root/
|
|
2485
2590
|
`, "utf8");
|
|
2486
2591
|
return true;
|
|
2487
2592
|
}
|
|
@@ -2489,7 +2594,7 @@ async function warnIfEnvNotIgnored(rootDir) {
|
|
|
2489
2594
|
const ignored = await isPathGitIgnored(rootDir, ".env");
|
|
2490
2595
|
if (ignored === false) {
|
|
2491
2596
|
console.log(
|
|
2492
|
-
`${BAR} ${yellow("warning:")} ${
|
|
2597
|
+
`${BAR} ${yellow("warning:")} ${dim4(".env is not git-ignored \u2014 add it to .gitignore")}`
|
|
2493
2598
|
);
|
|
2494
2599
|
}
|
|
2495
2600
|
}
|
|
@@ -2609,7 +2714,7 @@ function withTimeout(promise, ms) {
|
|
|
2609
2714
|
});
|
|
2610
2715
|
}
|
|
2611
2716
|
function rel(rootDir, filePath) {
|
|
2612
|
-
return
|
|
2717
|
+
return path9.relative(rootDir, filePath) || path9.basename(filePath);
|
|
2613
2718
|
}
|
|
2614
2719
|
function firstLine(text) {
|
|
2615
2720
|
return String(text).split("\n")[0];
|
|
@@ -2626,11 +2731,11 @@ function action(fn) {
|
|
|
2626
2731
|
}
|
|
2627
2732
|
|
|
2628
2733
|
// src/cli/startup/startup-tasks.ts
|
|
2629
|
-
import
|
|
2630
|
-
import
|
|
2734
|
+
import os2 from "node:os";
|
|
2735
|
+
import path10 from "node:path";
|
|
2631
2736
|
|
|
2632
2737
|
// src/cli/startup/check-version.ts
|
|
2633
|
-
import { dim as
|
|
2738
|
+
import { dim as dim5, green as green3, yellow as yellow2 } from "kleur/colors";
|
|
2634
2739
|
var PACKAGE_NAME = "@blinkk/root";
|
|
2635
2740
|
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2636
2741
|
var REGISTRY_TIMEOUT_MS = 3e3;
|
|
@@ -2701,16 +2806,16 @@ function parseVersion(version) {
|
|
|
2701
2806
|
return [toInt(parts[0]), toInt(parts[1]), toInt(parts[2])];
|
|
2702
2807
|
}
|
|
2703
2808
|
function printUpdateNotice(current, latest) {
|
|
2704
|
-
const bar =
|
|
2809
|
+
const bar = dim5("\u2503");
|
|
2705
2810
|
const label = yellow2(`Update available for ${PACKAGE_NAME}:`);
|
|
2706
2811
|
console.log();
|
|
2707
|
-
console.log(`${bar} ${label} ${
|
|
2812
|
+
console.log(`${bar} ${label} ${dim5(current)} \u2192 ${green3(latest)}`);
|
|
2708
2813
|
console.log();
|
|
2709
2814
|
}
|
|
2710
2815
|
|
|
2711
2816
|
// src/cli/startup/startup-tasks.ts
|
|
2712
2817
|
var STARTUP_TASKS = [checkVersionTask];
|
|
2713
|
-
var STATE_FILE =
|
|
2818
|
+
var STATE_FILE = path10.join(os2.homedir(), ".root", "startup-tasks.json");
|
|
2714
2819
|
async function runStartupTasks(ctx) {
|
|
2715
2820
|
try {
|
|
2716
2821
|
const state = await readState();
|
|
@@ -2761,13 +2866,13 @@ async function writeState(state) {
|
|
|
2761
2866
|
}
|
|
2762
2867
|
|
|
2763
2868
|
// src/cli/dev.ts
|
|
2764
|
-
var
|
|
2869
|
+
var __dirname4 = path11.dirname(fileURLToPath4(import.meta.url));
|
|
2765
2870
|
var DEV_SERVER_404_LOG_IGNORE_PATHS = /* @__PURE__ */ new Set([
|
|
2766
2871
|
"/.well-known/appspecific/com.chrome.devtools.json"
|
|
2767
2872
|
]);
|
|
2768
2873
|
async function dev(rootProjectDir, options) {
|
|
2769
2874
|
process.env.NODE_ENV = "development";
|
|
2770
|
-
const rootDir =
|
|
2875
|
+
const rootDir = path11.resolve(rootProjectDir || process.cwd());
|
|
2771
2876
|
const defaultPort = parseInt(process.env.PORT || "4007");
|
|
2772
2877
|
const host = options?.host || "localhost";
|
|
2773
2878
|
const port = await findOpenPort(defaultPort, defaultPort + 10);
|
|
@@ -2783,19 +2888,19 @@ async function dev(rootProjectDir, options) {
|
|
|
2783
2888
|
const basePath = rootConfig.base || "";
|
|
2784
2889
|
const homePagePath = rootConfig.server?.homePagePath || basePath;
|
|
2785
2890
|
console.log();
|
|
2786
|
-
console.log(`${
|
|
2787
|
-
console.log(`${
|
|
2891
|
+
console.log(`${dim6("\u2503")} project: ${rootDir}`);
|
|
2892
|
+
console.log(`${dim6("\u2503")} server: http://${host}:${port}${homePagePath}`);
|
|
2788
2893
|
if (testCmsEnabled(rootConfig)) {
|
|
2789
|
-
console.log(`${
|
|
2894
|
+
console.log(`${dim6("\u2503")} cms: http://${host}:${port}/cms/`);
|
|
2790
2895
|
}
|
|
2791
|
-
console.log(`${
|
|
2896
|
+
console.log(`${dim6("\u2503")} mode: development`);
|
|
2792
2897
|
console.log();
|
|
2793
2898
|
currentServer = server.listen(port, host);
|
|
2794
2899
|
const rootConfigDependencies = server.get(
|
|
2795
2900
|
"rootConfigDependencies"
|
|
2796
2901
|
);
|
|
2797
2902
|
const dependencies = [
|
|
2798
|
-
|
|
2903
|
+
path11.resolve(rootDir, "root.config.ts"),
|
|
2799
2904
|
...rootConfigDependencies
|
|
2800
2905
|
];
|
|
2801
2906
|
viteServer.watcher.add(dependencies);
|
|
@@ -2803,7 +2908,7 @@ async function dev(rootProjectDir, options) {
|
|
|
2803
2908
|
if (dependencies.includes(file)) {
|
|
2804
2909
|
console.log(
|
|
2805
2910
|
`
|
|
2806
|
-
${
|
|
2911
|
+
${dim6("\u2503")} root.config.ts changed. restarting server...`
|
|
2807
2912
|
);
|
|
2808
2913
|
await restart();
|
|
2809
2914
|
}
|
|
@@ -2823,7 +2928,7 @@ ${dim5("\u2503")} root.config.ts changed. restarting server...`
|
|
|
2823
2928
|
await start2();
|
|
2824
2929
|
}
|
|
2825
2930
|
async function createDevServer(options) {
|
|
2826
|
-
const rootDir =
|
|
2931
|
+
const rootDir = path11.resolve(options?.rootDir || process.cwd());
|
|
2827
2932
|
const { rootConfig, dependencies } = await loadRootConfigWithDeps(rootDir, {
|
|
2828
2933
|
command: "dev"
|
|
2829
2934
|
});
|
|
@@ -2838,6 +2943,7 @@ async function createDevServer(options) {
|
|
|
2838
2943
|
});
|
|
2839
2944
|
server.set("viteServer", viteServer);
|
|
2840
2945
|
server.use(rootProjectMiddleware({ rootConfig }));
|
|
2946
|
+
server.use(securityHeadersMiddleware({ rootConfig }));
|
|
2841
2947
|
server.use(viteMiddleware);
|
|
2842
2948
|
server.use(hooksMiddleware());
|
|
2843
2949
|
const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
|
|
@@ -2859,7 +2965,7 @@ async function createDevServer(options) {
|
|
|
2859
2965
|
if (rootConfig.server?.headers) {
|
|
2860
2966
|
server.use(headersMiddleware({ rootConfig }));
|
|
2861
2967
|
}
|
|
2862
|
-
const publicDir =
|
|
2968
|
+
const publicDir = path11.join(rootDir, "public");
|
|
2863
2969
|
if (await dirExists(publicDir)) {
|
|
2864
2970
|
server.use(rootPublicDirMiddleware({ publicDir, viteServer }));
|
|
2865
2971
|
}
|
|
@@ -2887,10 +2993,10 @@ async function createViteMiddleware(options) {
|
|
|
2887
2993
|
return sourceFile.relPath;
|
|
2888
2994
|
});
|
|
2889
2995
|
const bundleScripts = [];
|
|
2890
|
-
if (await isDirectory(
|
|
2891
|
-
const bundleFiles = await
|
|
2996
|
+
if (await isDirectory(path11.join(rootDir, "bundles"))) {
|
|
2997
|
+
const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
|
|
2892
2998
|
bundleFiles.forEach((file) => {
|
|
2893
|
-
const parts =
|
|
2999
|
+
const parts = path11.parse(file);
|
|
2894
3000
|
if (isJsFile(parts.base)) {
|
|
2895
3001
|
bundleScripts.push(file);
|
|
2896
3002
|
}
|
|
@@ -2907,7 +3013,7 @@ async function createViteMiddleware(options) {
|
|
|
2907
3013
|
optimizeDeps
|
|
2908
3014
|
});
|
|
2909
3015
|
function isInElementsDir(changedFilePath) {
|
|
2910
|
-
const filePath =
|
|
3016
|
+
const filePath = path11.resolve(changedFilePath);
|
|
2911
3017
|
const elementsDirs = getElementsDirs(rootConfig, pods);
|
|
2912
3018
|
return elementsDirs.some((dirPath) => filePath.startsWith(dirPath));
|
|
2913
3019
|
}
|
|
@@ -2926,7 +3032,7 @@ async function createViteMiddleware(options) {
|
|
|
2926
3032
|
const viteMiddleware = async (req, res, next) => {
|
|
2927
3033
|
try {
|
|
2928
3034
|
req.viteServer = viteServer;
|
|
2929
|
-
const renderModulePath =
|
|
3035
|
+
const renderModulePath = path11.resolve(__dirname4, "./render.js");
|
|
2930
3036
|
const render = await viteServer.ssrLoadModule(
|
|
2931
3037
|
renderModulePath
|
|
2932
3038
|
);
|
|
@@ -2950,7 +3056,7 @@ function rootPublicDirMiddleware(options) {
|
|
|
2950
3056
|
handler = sirv(publicDir, sirvOptions);
|
|
2951
3057
|
}, 1e3);
|
|
2952
3058
|
function isInPublicDir(changedFilePath) {
|
|
2953
|
-
const filePath =
|
|
3059
|
+
const filePath = path11.resolve(changedFilePath);
|
|
2954
3060
|
return filePath.startsWith(publicDir);
|
|
2955
3061
|
}
|
|
2956
3062
|
const watcher = options.viteServer.watcher;
|
|
@@ -2982,7 +3088,7 @@ function rootDevServer404Middleware() {
|
|
|
2982
3088
|
}
|
|
2983
3089
|
if (req.renderer) {
|
|
2984
3090
|
const url = req.path;
|
|
2985
|
-
const ext =
|
|
3091
|
+
const ext = path11.extname(url);
|
|
2986
3092
|
if (!ext) {
|
|
2987
3093
|
const renderer = req.renderer;
|
|
2988
3094
|
const data = await renderer.renderDevServer404(req);
|
|
@@ -3000,7 +3106,7 @@ function rootDevServer500Middleware() {
|
|
|
3000
3106
|
console.error(String(err.stack || err));
|
|
3001
3107
|
if (req.renderer) {
|
|
3002
3108
|
const url = req.path;
|
|
3003
|
-
const ext =
|
|
3109
|
+
const ext = path11.extname(url);
|
|
3004
3110
|
if (!ext) {
|
|
3005
3111
|
const renderer = req.renderer;
|
|
3006
3112
|
const data = await renderer.renderDevServer500(req, err);
|
|
@@ -3026,7 +3132,7 @@ function debounce(fn, timeout) {
|
|
|
3026
3132
|
|
|
3027
3133
|
// src/cli/gae-deploy.ts
|
|
3028
3134
|
import { execSync } from "node:child_process";
|
|
3029
|
-
import
|
|
3135
|
+
import fs7 from "node:fs";
|
|
3030
3136
|
import yaml from "js-yaml";
|
|
3031
3137
|
async function gaeDeploy(appDir, options) {
|
|
3032
3138
|
if (!appDir) {
|
|
@@ -3040,10 +3146,10 @@ async function gaeDeploy(appDir, options) {
|
|
|
3040
3146
|
}
|
|
3041
3147
|
process.chdir(appDir);
|
|
3042
3148
|
const appYamlPath = "app.yaml";
|
|
3043
|
-
if (!
|
|
3149
|
+
if (!fs7.existsSync(appYamlPath)) {
|
|
3044
3150
|
throw new Error(`[gae-deplopy] Missing: ${appYamlPath}`);
|
|
3045
3151
|
}
|
|
3046
|
-
const appYaml = yaml.load(
|
|
3152
|
+
const appYaml = yaml.load(fs7.readFileSync(appYamlPath, "utf8"));
|
|
3047
3153
|
const service = appYaml.service;
|
|
3048
3154
|
if (!service) {
|
|
3049
3155
|
throw new Error(
|
|
@@ -3069,7 +3175,7 @@ async function gaeDeploy(appDir, options) {
|
|
|
3069
3175
|
{ stdio: "inherit" }
|
|
3070
3176
|
);
|
|
3071
3177
|
if (backupAppYaml) {
|
|
3072
|
-
|
|
3178
|
+
fs7.copyFileSync(backupAppYaml, "app.yaml");
|
|
3073
3179
|
}
|
|
3074
3180
|
if (options?.healthcheckUrl) {
|
|
3075
3181
|
const healthcheckPassed = await testHealth(
|
|
@@ -3156,8 +3262,8 @@ function testIsEnvPlaceholder(envValue) {
|
|
|
3156
3262
|
}
|
|
3157
3263
|
function updateAppYamlEnv(appYamlPath, appYaml) {
|
|
3158
3264
|
const backupAppYaml = `${appYamlPath}.bak`;
|
|
3159
|
-
|
|
3160
|
-
let content =
|
|
3265
|
+
fs7.copyFileSync(appYamlPath, backupAppYaml);
|
|
3266
|
+
let content = fs7.readFileSync(appYamlPath, "utf8");
|
|
3161
3267
|
const envVars = appYaml.env_variables;
|
|
3162
3268
|
Object.entries(envVars).forEach(([envVar, envValue]) => {
|
|
3163
3269
|
if (testIsEnvPlaceholder(envValue)) {
|
|
@@ -3170,7 +3276,7 @@ function updateAppYamlEnv(appYamlPath, appYaml) {
|
|
|
3170
3276
|
}
|
|
3171
3277
|
}
|
|
3172
3278
|
});
|
|
3173
|
-
|
|
3279
|
+
fs7.writeFileSync(appYamlPath, content, "utf8");
|
|
3174
3280
|
return backupAppYaml;
|
|
3175
3281
|
}
|
|
3176
3282
|
function getTimestamp() {
|
|
@@ -3194,33 +3300,33 @@ function testManagedVersion(service, appInfo, prefix) {
|
|
|
3194
3300
|
}
|
|
3195
3301
|
|
|
3196
3302
|
// src/cli/preview.ts
|
|
3197
|
-
import
|
|
3198
|
-
import compression from "compression";
|
|
3303
|
+
import path12 from "node:path";
|
|
3199
3304
|
import cookieParser2 from "cookie-parser";
|
|
3200
3305
|
import { default as express2 } from "express";
|
|
3201
|
-
import { dim as
|
|
3306
|
+
import { dim as dim7 } from "kleur/colors";
|
|
3202
3307
|
import sirv2 from "sirv";
|
|
3203
3308
|
async function preview(rootProjectDir, options) {
|
|
3204
3309
|
process.env.NODE_ENV = "development";
|
|
3205
|
-
const rootDir =
|
|
3310
|
+
const rootDir = path12.resolve(rootProjectDir || process.cwd());
|
|
3206
3311
|
const server = await createPreviewServer({ rootDir });
|
|
3207
3312
|
const port = parseInt(process.env.PORT || "4007");
|
|
3208
3313
|
const host = options?.host || "localhost";
|
|
3209
3314
|
console.log();
|
|
3210
|
-
console.log(`${
|
|
3211
|
-
console.log(`${
|
|
3212
|
-
console.log(`${
|
|
3315
|
+
console.log(`${dim7("\u2503")} project: ${rootDir}`);
|
|
3316
|
+
console.log(`${dim7("\u2503")} server: http://${host}:${port}`);
|
|
3317
|
+
console.log(`${dim7("\u2503")} mode: preview`);
|
|
3213
3318
|
console.log();
|
|
3214
3319
|
server.listen(port, host);
|
|
3215
3320
|
}
|
|
3216
3321
|
async function createPreviewServer(options) {
|
|
3217
3322
|
const rootDir = options.rootDir;
|
|
3218
3323
|
const rootConfig = await loadBundledConfig(rootDir, { command: "preview" });
|
|
3219
|
-
const distDir =
|
|
3324
|
+
const distDir = path12.join(rootDir, "dist");
|
|
3220
3325
|
const server = express2();
|
|
3221
3326
|
server.disable("x-powered-by");
|
|
3222
|
-
server.use(
|
|
3327
|
+
server.use(compressionMiddleware());
|
|
3223
3328
|
server.use(rootProjectMiddleware({ rootConfig }));
|
|
3329
|
+
server.use(securityHeadersMiddleware({ rootConfig }));
|
|
3224
3330
|
server.use(await rootPreviewRendererMiddleware({ rootConfig, distDir }));
|
|
3225
3331
|
server.use(hooksMiddleware());
|
|
3226
3332
|
const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
|
|
@@ -3242,7 +3348,7 @@ async function createPreviewServer(options) {
|
|
|
3242
3348
|
if (rootConfig.server?.headers) {
|
|
3243
3349
|
server.use(headersMiddleware({ rootConfig }));
|
|
3244
3350
|
}
|
|
3245
|
-
const publicDir =
|
|
3351
|
+
const publicDir = path12.join(distDir, "html");
|
|
3246
3352
|
server.use(sirv2(publicDir, { dev: false }));
|
|
3247
3353
|
server.use(trailingSlashMiddleware({ rootConfig }));
|
|
3248
3354
|
server.use(rootPreviewServerMiddleware());
|
|
@@ -3261,14 +3367,14 @@ async function createPreviewServer(options) {
|
|
|
3261
3367
|
}
|
|
3262
3368
|
async function rootPreviewRendererMiddleware(options) {
|
|
3263
3369
|
const { distDir, rootConfig } = options;
|
|
3264
|
-
const render = await import(
|
|
3265
|
-
const manifestPath2 =
|
|
3370
|
+
const render = await import(path12.join(distDir, "server/render.js"));
|
|
3371
|
+
const manifestPath2 = path12.join(distDir, ".root/manifest.json");
|
|
3266
3372
|
if (!await fileExists(manifestPath2)) {
|
|
3267
3373
|
throw new Error(
|
|
3268
3374
|
`could not find ${manifestPath2}. run \`root build\` before \`root preview\`.`
|
|
3269
3375
|
);
|
|
3270
3376
|
}
|
|
3271
|
-
const elementGraphJsonPath =
|
|
3377
|
+
const elementGraphJsonPath = path12.join(distDir, ".root/elements.json");
|
|
3272
3378
|
if (!await fileExists(elementGraphJsonPath)) {
|
|
3273
3379
|
throw new Error(
|
|
3274
3380
|
`could not find ${elementGraphJsonPath}. run \`root build\` before \`root preview\`.`
|
|
@@ -3308,7 +3414,7 @@ function rootPreviewServer404Middleware() {
|
|
|
3308
3414
|
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
3309
3415
|
if (req.renderer) {
|
|
3310
3416
|
const url = req.path;
|
|
3311
|
-
const ext =
|
|
3417
|
+
const ext = path12.extname(url);
|
|
3312
3418
|
if (!ext) {
|
|
3313
3419
|
const renderer = req.renderer;
|
|
3314
3420
|
const data = await renderer.render404({ currentPath: url });
|
|
@@ -3326,7 +3432,7 @@ function rootPreviewServer500Middleware() {
|
|
|
3326
3432
|
console.error(String(err.stack || err));
|
|
3327
3433
|
if (req.renderer) {
|
|
3328
3434
|
const url = req.path;
|
|
3329
|
-
const ext =
|
|
3435
|
+
const ext = path12.extname(url);
|
|
3330
3436
|
if (!ext) {
|
|
3331
3437
|
const renderer = req.renderer;
|
|
3332
3438
|
const data = await renderer.renderDevServer500(req, err);
|
|
@@ -3340,33 +3446,33 @@ function rootPreviewServer500Middleware() {
|
|
|
3340
3446
|
}
|
|
3341
3447
|
|
|
3342
3448
|
// src/cli/start.ts
|
|
3343
|
-
import
|
|
3344
|
-
import compression2 from "compression";
|
|
3449
|
+
import path13 from "node:path";
|
|
3345
3450
|
import cookieParser3 from "cookie-parser";
|
|
3346
3451
|
import { default as express3 } from "express";
|
|
3347
|
-
import { dim as
|
|
3452
|
+
import { dim as dim8 } from "kleur/colors";
|
|
3348
3453
|
import sirv3 from "sirv";
|
|
3349
3454
|
async function start(rootProjectDir, options) {
|
|
3350
3455
|
process.env.NODE_ENV = "production";
|
|
3351
|
-
const rootDir =
|
|
3456
|
+
const rootDir = path13.resolve(rootProjectDir || process.cwd());
|
|
3352
3457
|
const server = await createProdServer({ rootDir });
|
|
3353
3458
|
const port = parseInt(process.env.PORT || "4007");
|
|
3354
3459
|
const host = options?.host || "localhost";
|
|
3355
3460
|
console.log();
|
|
3356
|
-
console.log(`${
|
|
3357
|
-
console.log(`${
|
|
3358
|
-
console.log(`${
|
|
3461
|
+
console.log(`${dim8("\u2503")} project: ${rootDir}`);
|
|
3462
|
+
console.log(`${dim8("\u2503")} server: http://${host}:${port}`);
|
|
3463
|
+
console.log(`${dim8("\u2503")} mode: production`);
|
|
3359
3464
|
console.log();
|
|
3360
3465
|
server.listen(port, host);
|
|
3361
3466
|
}
|
|
3362
3467
|
async function createProdServer(options) {
|
|
3363
3468
|
const rootDir = options.rootDir;
|
|
3364
3469
|
const rootConfig = await loadBundledConfig(rootDir, { command: "start" });
|
|
3365
|
-
const distDir =
|
|
3470
|
+
const distDir = path13.join(rootDir, "dist");
|
|
3366
3471
|
const server = express3();
|
|
3367
3472
|
server.disable("x-powered-by");
|
|
3368
|
-
server.use(
|
|
3473
|
+
server.use(compressionMiddleware());
|
|
3369
3474
|
server.use(rootProjectMiddleware({ rootConfig }));
|
|
3475
|
+
server.use(securityHeadersMiddleware({ rootConfig }));
|
|
3370
3476
|
server.use(await rootProdRendererMiddleware({ rootConfig, distDir }));
|
|
3371
3477
|
server.use(hooksMiddleware());
|
|
3372
3478
|
const sessionCookieSecret = getSessionCookieSecret(rootConfig, rootDir);
|
|
@@ -3388,7 +3494,7 @@ async function createProdServer(options) {
|
|
|
3388
3494
|
if (rootConfig.server?.headers) {
|
|
3389
3495
|
server.use(headersMiddleware({ rootConfig }));
|
|
3390
3496
|
}
|
|
3391
|
-
const publicDir =
|
|
3497
|
+
const publicDir = path13.join(distDir, "html");
|
|
3392
3498
|
server.use(sirv3(publicDir, { dev: false }));
|
|
3393
3499
|
server.use(trailingSlashMiddleware({ rootConfig }));
|
|
3394
3500
|
server.use(rootProdServerMiddleware());
|
|
@@ -3407,14 +3513,14 @@ async function createProdServer(options) {
|
|
|
3407
3513
|
}
|
|
3408
3514
|
async function rootProdRendererMiddleware(options) {
|
|
3409
3515
|
const { distDir, rootConfig } = options;
|
|
3410
|
-
const render = await import(
|
|
3411
|
-
const manifestPath2 =
|
|
3516
|
+
const render = await import(path13.join(distDir, "server/render.js"));
|
|
3517
|
+
const manifestPath2 = path13.join(distDir, ".root/manifest.json");
|
|
3412
3518
|
if (!await fileExists(manifestPath2)) {
|
|
3413
3519
|
throw new Error(
|
|
3414
3520
|
`could not find ${manifestPath2}. run \`root build\` before \`root start\`.`
|
|
3415
3521
|
);
|
|
3416
3522
|
}
|
|
3417
|
-
const elementGraphJsonPath =
|
|
3523
|
+
const elementGraphJsonPath = path13.join(distDir, ".root/elements.json");
|
|
3418
3524
|
if (!await fileExists(elementGraphJsonPath)) {
|
|
3419
3525
|
throw new Error(
|
|
3420
3526
|
`could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
|
|
@@ -3454,7 +3560,7 @@ function rootProdServer404Middleware() {
|
|
|
3454
3560
|
console.error(`\u2753 404 ${req.originalUrl}`);
|
|
3455
3561
|
if (req.renderer) {
|
|
3456
3562
|
const url = req.path;
|
|
3457
|
-
const ext =
|
|
3563
|
+
const ext = path13.extname(url);
|
|
3458
3564
|
if (!ext) {
|
|
3459
3565
|
const renderer = req.renderer;
|
|
3460
3566
|
const data = await renderer.render404({ currentPath: url });
|
|
@@ -3472,7 +3578,7 @@ function rootProdServer500Middleware() {
|
|
|
3472
3578
|
console.error(String(err.stack || err));
|
|
3473
3579
|
if (req.renderer) {
|
|
3474
3580
|
const url = req.path;
|
|
3475
|
-
const ext =
|
|
3581
|
+
const ext = path13.extname(url);
|
|
3476
3582
|
if (!ext) {
|
|
3477
3583
|
const renderer = req.renderer;
|
|
3478
3584
|
const data = await renderer.renderError(err);
|
|
@@ -3513,11 +3619,21 @@ var CliRunner = class {
|
|
|
3513
3619
|
"-c, --concurrency <num>",
|
|
3514
3620
|
"number of files to build concurrently",
|
|
3515
3621
|
"10"
|
|
3622
|
+
).option(
|
|
3623
|
+
"--threads [num]",
|
|
3624
|
+
'renders pages using worker threads; pass a number for exactly N workers, or omit the value (or pass "auto") to pick based on cpu cores and page count'
|
|
3516
3625
|
).option(
|
|
3517
3626
|
"--filter <urlPathRegex>",
|
|
3518
3627
|
'builds the url paths that match the given regex, e.g. "/products/.*"',
|
|
3519
3628
|
""
|
|
3520
|
-
).
|
|
3629
|
+
).addOption(
|
|
3630
|
+
new Option(
|
|
3631
|
+
"--log <mode>",
|
|
3632
|
+
'build log output: "progress" (default) shows a progress indicator and a final summary, "verbose" prints one line per output file, "quiet" prints only the final summary'
|
|
3633
|
+
).choices(["progress", "verbose", "quiet"])
|
|
3634
|
+
).action(
|
|
3635
|
+
(rootProjectDir, options, cmd) => build(rootProjectDir, cmd.optsWithGlobals())
|
|
3636
|
+
);
|
|
3521
3637
|
program.command("codegen [type] [name]").description("generates boilerplate code").option("--out <outdir>", "output dir").action(codegen);
|
|
3522
3638
|
program.command("create-package [path]").alias("package").description(
|
|
3523
3639
|
"creates a standalone npm package for deployment to various hosting services"
|
|
@@ -3579,4 +3695,4 @@ export {
|
|
|
3579
3695
|
createProdServer,
|
|
3580
3696
|
CliRunner
|
|
3581
3697
|
};
|
|
3582
|
-
//# sourceMappingURL=chunk-
|
|
3698
|
+
//# sourceMappingURL=chunk-GK3TDYUY.js.map
|