@jsenv/core 40.0.10 → 40.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/build.js +1792 -1101
- package/dist/client/autoreload/autoreload.js +1 -27
- package/dist/jsenv_core_node_modules.js +2045 -0
- package/dist/jsenv_core_packages.js +9397 -5830
- package/dist/start_build_server/start_build_server.js +4 -2
- package/dist/start_dev_server/start_dev_server.js +228 -70
- package/package.json +16 -15
- package/src/build/build.js +1084 -560
- package/src/build/build_content_report.js +377 -0
- package/src/build/build_params.js +1 -4
- package/src/build/build_specifier_manager.js +70 -21
- package/src/build/build_urls_generator.js +29 -28
- package/src/kitchen/fetched_content_compliance.js +2 -2
- package/src/kitchen/kitchen.js +1 -1
- package/src/plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js +20 -5
- package/src/plugins/plugins.js +5 -2
- package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +3 -4
- package/src/plugins/reference_analysis/jsenv_plugin_reference_analysis.js +1 -4
- package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +56 -34
- package/src/plugins/resolution_node_esm/node_esm_resolver.js +132 -11
- package/src/build/jsenv_plugin_subbuilds.js +0 -76
- package/src/kitchen/url_graph/url_graph_report.js +0 -202
- /package/dist/client/{server_events_client → server_events}/server_events_client.js +0 -0
package/src/build/build.js
CHANGED
|
@@ -21,19 +21,43 @@ import { parseHtml, stringifyHtmlAst } from "@jsenv/ast";
|
|
|
21
21
|
import {
|
|
22
22
|
assertAndNormalizeDirectoryUrl,
|
|
23
23
|
clearDirectorySync,
|
|
24
|
+
compareFileUrls,
|
|
24
25
|
ensureEmptyDirectory,
|
|
25
26
|
lookupPackageDirectory,
|
|
26
27
|
writeFileSync,
|
|
27
28
|
} from "@jsenv/filesystem";
|
|
28
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
ANSI,
|
|
31
|
+
createDynamicLog,
|
|
32
|
+
createLogger,
|
|
33
|
+
createTaskLog,
|
|
34
|
+
humanizeDuration,
|
|
35
|
+
humanizeMemory,
|
|
36
|
+
UNICODE,
|
|
37
|
+
} from "@jsenv/humanize";
|
|
38
|
+
import { applyNodeEsmResolution } from "@jsenv/node-esm-resolution";
|
|
39
|
+
import {
|
|
40
|
+
startMonitoringCpuUsage,
|
|
41
|
+
startMonitoringMemoryUsage,
|
|
42
|
+
} from "@jsenv/os-metrics";
|
|
29
43
|
import { jsenvPluginBundling } from "@jsenv/plugin-bundling";
|
|
30
44
|
import { jsenvPluginMinification } from "@jsenv/plugin-minification";
|
|
31
45
|
import { jsenvPluginJsModuleFallback } from "@jsenv/plugin-transpilation";
|
|
32
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
browserDefaultRuntimeCompat,
|
|
48
|
+
inferRuntimeCompatFromClosestPackage,
|
|
49
|
+
nodeDefaultRuntimeCompat,
|
|
50
|
+
} from "@jsenv/runtime-compat";
|
|
51
|
+
import {
|
|
52
|
+
urlIsInsideOf,
|
|
53
|
+
urlToBasename,
|
|
54
|
+
urlToExtension,
|
|
55
|
+
urlToRelativeUrl,
|
|
56
|
+
} from "@jsenv/urls";
|
|
57
|
+
import { memoryUsage as processMemoryUsage } from "node:process";
|
|
33
58
|
import { watchSourceFiles } from "../helpers/watch_source_files.js";
|
|
34
59
|
import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
|
|
35
60
|
import { createKitchen } from "../kitchen/kitchen.js";
|
|
36
|
-
import { createUrlGraphSummary } from "../kitchen/url_graph/url_graph_report.js";
|
|
37
61
|
import { GRAPH_VISITOR } from "../kitchen/url_graph/url_graph_visitor.js";
|
|
38
62
|
import { jsenvPluginDirectoryReferenceEffect } from "../plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js";
|
|
39
63
|
import { jsenvPluginInlining } from "../plugins/inlining/jsenv_plugin_inlining.js";
|
|
@@ -43,15 +67,12 @@ import {
|
|
|
43
67
|
} from "../plugins/plugin_controller.js";
|
|
44
68
|
import { getCorePlugins } from "../plugins/plugins.js";
|
|
45
69
|
import { jsenvPluginReferenceAnalysis } from "../plugins/reference_analysis/jsenv_plugin_reference_analysis.js";
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
getDefaultBase,
|
|
49
|
-
logsDefault,
|
|
50
|
-
} from "./build_params.js";
|
|
70
|
+
import { renderBuildDoneLog } from "./build_content_report.js";
|
|
71
|
+
import { defaultRuntimeCompat, logsDefault } from "./build_params.js";
|
|
51
72
|
import { createBuildSpecifierManager } from "./build_specifier_manager.js";
|
|
73
|
+
import { createBuildUrlsGenerator } from "./build_urls_generator.js";
|
|
52
74
|
import { jsenvPluginLineBreakNormalization } from "./jsenv_plugin_line_break_normalization.js";
|
|
53
75
|
import { jsenvPluginMappings } from "./jsenv_plugin_mappings.js";
|
|
54
|
-
import { jsenvPluginSubbuilds } from "./jsenv_plugin_subbuilds.js";
|
|
55
76
|
|
|
56
77
|
/**
|
|
57
78
|
* Generate an optimized version of source files into a directory.
|
|
@@ -66,8 +87,8 @@ import { jsenvPluginSubbuilds } from "./jsenv_plugin_subbuilds.js";
|
|
|
66
87
|
* Keys are relative to sourceDirectoryUrl
|
|
67
88
|
* @param {object} params.runtimeCompat
|
|
68
89
|
* Code generated will be compatible with these runtimes
|
|
69
|
-
* @param {string} [params.assetsDirectory
|
|
70
|
-
* Directory where asset files will be written
|
|
90
|
+
* @param {string} [params.assetsDirectory]
|
|
91
|
+
* Directory where asset files will be written. By default sibling to the entry build file.
|
|
71
92
|
* @param {string|url} [params.base=""]
|
|
72
93
|
* Urls in build file contents will be prefixed with this string
|
|
73
94
|
* @param {boolean|object} [params.bundling=true]
|
|
@@ -89,54 +110,29 @@ import { jsenvPluginSubbuilds } from "./jsenv_plugin_subbuilds.js";
|
|
|
89
110
|
* Map build file paths without versioning to versioned file paths
|
|
90
111
|
*/
|
|
91
112
|
export const build = async ({
|
|
92
|
-
signal = new AbortController().signal,
|
|
93
|
-
handleSIGINT = true,
|
|
94
|
-
logs = logsDefault,
|
|
95
113
|
sourceDirectoryUrl,
|
|
96
114
|
buildDirectoryUrl,
|
|
97
115
|
entryPoints = {},
|
|
98
|
-
|
|
99
|
-
runtimeCompat = defaultRuntimeCompat,
|
|
100
|
-
base = getDefaultBase(runtimeCompat),
|
|
101
|
-
ignore,
|
|
102
|
-
|
|
103
|
-
mappings,
|
|
104
|
-
subbuilds = [],
|
|
105
|
-
plugins = [],
|
|
106
|
-
referenceAnalysis = {},
|
|
107
|
-
nodeEsmResolution,
|
|
108
|
-
magicExtensions,
|
|
109
|
-
magicDirectoryIndex,
|
|
110
|
-
directoryReferenceEffect,
|
|
111
|
-
scenarioPlaceholders,
|
|
112
|
-
injections,
|
|
113
|
-
transpilation = {},
|
|
114
|
-
bundling = true,
|
|
115
|
-
minification = !runtimeCompat.node,
|
|
116
|
-
versioning = !runtimeCompat.node,
|
|
117
|
-
versioningMethod = "search_param", // "filename", "search_param"
|
|
118
|
-
versioningViaImportmap = true,
|
|
119
|
-
versionLength = 8,
|
|
120
|
-
lineBreakNormalization = process.platform === "win32",
|
|
116
|
+
logs,
|
|
121
117
|
|
|
122
|
-
sourceFilesConfig = {},
|
|
123
|
-
cooldownBetweenFileEvents,
|
|
124
|
-
watch = false,
|
|
125
|
-
http = false,
|
|
126
|
-
|
|
127
|
-
buildDirectoryCleanPatterns = {
|
|
128
|
-
"**/*": true,
|
|
129
|
-
},
|
|
130
|
-
sourcemaps = "none",
|
|
131
|
-
sourcemapsSourcesContent,
|
|
132
|
-
writeOnFileSystem = true,
|
|
133
118
|
outDirectoryUrl,
|
|
134
|
-
|
|
135
|
-
assetManifestFileRelativeUrl = "asset-manifest.json",
|
|
119
|
+
buildDirectoryCleanPatterns = { "**/*": true },
|
|
136
120
|
returnBuildInlineContents,
|
|
137
121
|
returnBuildManifest,
|
|
122
|
+
returnBuildFileVersions,
|
|
123
|
+
signal = new AbortController().signal,
|
|
124
|
+
handleSIGINT = true,
|
|
125
|
+
|
|
126
|
+
writeOnFileSystem = true,
|
|
127
|
+
|
|
128
|
+
watch = false,
|
|
129
|
+
sourceFilesConfig = {},
|
|
130
|
+
cooldownBetweenFileEvents,
|
|
131
|
+
|
|
138
132
|
...rest
|
|
139
133
|
}) => {
|
|
134
|
+
const entryPointArray = [];
|
|
135
|
+
|
|
140
136
|
// param validation
|
|
141
137
|
{
|
|
142
138
|
const unexpectedParamNames = Object.keys(rest);
|
|
@@ -145,88 +141,166 @@ export const build = async ({
|
|
|
145
141
|
`${unexpectedParamNames.join(",")}: there is no such param`,
|
|
146
142
|
);
|
|
147
143
|
}
|
|
148
|
-
//
|
|
144
|
+
// source and build directory
|
|
149
145
|
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const unexpectedLogsKeys = Object.keys(logs).filter(
|
|
154
|
-
(key) => !Object.hasOwn(logsDefault, key),
|
|
146
|
+
sourceDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
147
|
+
sourceDirectoryUrl,
|
|
148
|
+
"sourceDirectoryUrl",
|
|
155
149
|
);
|
|
156
|
-
|
|
150
|
+
buildDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
151
|
+
buildDirectoryUrl,
|
|
152
|
+
"buildDirectoryUrl",
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
// entry points
|
|
156
|
+
{
|
|
157
|
+
if (typeof entryPoints !== "object" || entryPoints === null) {
|
|
157
158
|
throw new TypeError(
|
|
158
|
-
|
|
159
|
+
`The value "${entryPoints}" for "entryPoints" is invalid: it must be an object.`,
|
|
159
160
|
);
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
162
|
+
const keys = Object.keys(entryPoints);
|
|
163
|
+
const isSingleEntryPoint = keys.length === 1;
|
|
164
|
+
for (const key of keys) {
|
|
165
|
+
// key (sourceRelativeUrl)
|
|
166
|
+
let sourceUrl;
|
|
167
|
+
let runtimeType;
|
|
168
|
+
{
|
|
169
|
+
if (isBareSpecifier(key)) {
|
|
170
|
+
const packageConditions = ["development", "node", "import"];
|
|
171
|
+
try {
|
|
172
|
+
const { url, type } = applyNodeEsmResolution({
|
|
173
|
+
conditions: packageConditions,
|
|
174
|
+
parentUrl: sourceDirectoryUrl,
|
|
175
|
+
specifier: key,
|
|
176
|
+
});
|
|
177
|
+
if (type === "field:browser") {
|
|
178
|
+
runtimeType = "browser";
|
|
179
|
+
}
|
|
180
|
+
sourceUrl = url;
|
|
181
|
+
} catch (e) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`The key "${key}" in "entryPoints" is invalid: it cannot be resolved.`,
|
|
184
|
+
{ cause: e },
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
if (!key.startsWith("./")) {
|
|
189
|
+
throw new TypeError(
|
|
190
|
+
`The key "${key}" in "entryPoints" is invalid: it must start with "./".`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
sourceUrl = new URL(key, sourceDirectoryUrl).href;
|
|
196
|
+
} catch {
|
|
197
|
+
throw new TypeError(
|
|
198
|
+
`The key "${key}" in "entryPoints" is invalid: it must be a relative url.`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (!urlIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
`The key "${key}" in "entryPoints" is invalid: it must be inside the source directory at ${sourceDirectoryUrl}.`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!runtimeType) {
|
|
209
|
+
const ext = urlToExtension(sourceUrl);
|
|
210
|
+
if (ext === ".html" || ext === ".css") {
|
|
211
|
+
runtimeType = "browser";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
182
214
|
}
|
|
183
|
-
}
|
|
184
|
-
} else if (outDirectoryUrl) {
|
|
185
|
-
outDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
186
|
-
outDirectoryUrl,
|
|
187
|
-
"outDirectoryUrl",
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
215
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
216
|
+
// value (entryPointParams)
|
|
217
|
+
const value = entryPoints[key];
|
|
218
|
+
{
|
|
219
|
+
if (value === null || typeof value !== "object") {
|
|
220
|
+
throw new TypeError(
|
|
221
|
+
`The value "${value}" in "entryPoints" is invalid: it must be an object.`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const forEntryPointOrEmpty = isSingleEntryPoint
|
|
225
|
+
? ""
|
|
226
|
+
: ` for entry point "${key}"`;
|
|
227
|
+
const unexpectedEntryPointParamNames = Object.keys(value).filter(
|
|
228
|
+
(key) => !Object.hasOwn(entryPointDefaultParams, key),
|
|
229
|
+
);
|
|
230
|
+
if (unexpectedEntryPointParamNames.length) {
|
|
231
|
+
throw new TypeError(
|
|
232
|
+
`The value${forEntryPointOrEmpty} contains unknown keys: ${unexpectedEntryPointParamNames.join(",")}.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
const { versioningMethod } = value;
|
|
236
|
+
if (versioningMethod !== undefined) {
|
|
237
|
+
if (!["filename", "search_param"].includes(versioningMethod)) {
|
|
238
|
+
throw new TypeError(
|
|
239
|
+
`The versioningMethod "${versioningMethod}"${forEntryPointOrEmpty} is invalid: it must be "filename" or "search_param".`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const { buildRelativeUrl } = value;
|
|
244
|
+
if (buildRelativeUrl !== undefined) {
|
|
245
|
+
let buildUrl;
|
|
246
|
+
try {
|
|
247
|
+
buildUrl = new URL(buildRelativeUrl, buildDirectoryUrl);
|
|
248
|
+
} catch {
|
|
249
|
+
throw new TypeError(
|
|
250
|
+
`The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be a relative url.`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
`The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be inside the build directory at ${buildDirectoryUrl}.`,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const { runtimeCompat } = value;
|
|
260
|
+
if (runtimeCompat !== undefined) {
|
|
261
|
+
if (runtimeCompat === null || typeof runtimeCompat !== "object") {
|
|
262
|
+
throw new TypeError(
|
|
263
|
+
`The runtimeCompat "${runtimeCompat}"${forEntryPointOrEmpty} is invalid: it must be an object.`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
entryPointArray.push({
|
|
270
|
+
key,
|
|
271
|
+
sourceUrl,
|
|
272
|
+
sourceRelativeUrl: `./${urlToRelativeUrl(sourceUrl, sourceDirectoryUrl)}`,
|
|
273
|
+
params: { ...value },
|
|
274
|
+
runtimeType,
|
|
275
|
+
});
|
|
200
276
|
}
|
|
201
|
-
|
|
202
|
-
|
|
277
|
+
}
|
|
278
|
+
// logs
|
|
279
|
+
if (logs === undefined) {
|
|
280
|
+
logs = logsDefault;
|
|
281
|
+
} else {
|
|
282
|
+
if (typeof logs !== "object") {
|
|
203
283
|
throw new TypeError(
|
|
204
|
-
`
|
|
284
|
+
`The value "${logs}" is invalid for param logs: it must be an object.`,
|
|
205
285
|
);
|
|
206
286
|
}
|
|
207
|
-
|
|
287
|
+
const unexpectedLogsKeys = Object.keys(logs).filter(
|
|
288
|
+
(key) => !Object.hasOwn(logsDefault, key),
|
|
289
|
+
);
|
|
290
|
+
if (unexpectedLogsKeys.length > 0) {
|
|
208
291
|
throw new TypeError(
|
|
209
|
-
`
|
|
292
|
+
`The param logs have unknown params: ${unexpectedLogsKeys.join(",")}.`,
|
|
210
293
|
);
|
|
211
294
|
}
|
|
212
|
-
});
|
|
213
|
-
if (!["filename", "search_param"].includes(versioningMethod)) {
|
|
214
|
-
throw new TypeError(
|
|
215
|
-
`versioningMethod must be "filename" or "search_param", got ${versioning}`,
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
if (bundling === true) {
|
|
219
|
-
bundling = {};
|
|
220
295
|
}
|
|
221
|
-
if (
|
|
222
|
-
|
|
296
|
+
if (outDirectoryUrl !== undefined) {
|
|
297
|
+
outDirectoryUrl = assertAndNormalizeDirectoryUrl(
|
|
298
|
+
outDirectoryUrl,
|
|
299
|
+
"outDirectoryUrl",
|
|
300
|
+
);
|
|
223
301
|
}
|
|
224
302
|
}
|
|
225
303
|
|
|
226
|
-
if (assetsDirectory && assetsDirectory[assetsDirectory.length - 1] !== "/") {
|
|
227
|
-
assetsDirectory = `${assetsDirectory}/`;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
304
|
const operation = Abort.startOperation();
|
|
231
305
|
operation.addAbortSignal(signal);
|
|
232
306
|
if (handleSIGINT) {
|
|
@@ -240,464 +314,340 @@ export const build = async ({
|
|
|
240
314
|
});
|
|
241
315
|
}
|
|
242
316
|
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
317
|
+
const cpuMonitoring = startMonitoringCpuUsage();
|
|
318
|
+
operation.addEndCallback(cpuMonitoring.stop);
|
|
319
|
+
const [processCpuUsageMonitoring] = cpuMonitoring;
|
|
320
|
+
const memoryMonitoring = startMonitoringMemoryUsage();
|
|
321
|
+
const [processMemoryUsageMonitoring] = memoryMonitoring;
|
|
322
|
+
const interval = setInterval(() => {
|
|
323
|
+
processCpuUsageMonitoring.measure();
|
|
324
|
+
processMemoryUsageMonitoring.measure();
|
|
325
|
+
}, 500).unref();
|
|
326
|
+
operation.addEndCallback(() => {
|
|
327
|
+
clearInterval(interval);
|
|
328
|
+
});
|
|
252
329
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
sourcemapsSourcesContent,
|
|
295
|
-
outDirectoryUrl: outDirectoryUrl
|
|
296
|
-
? new URL("craft/", outDirectoryUrl)
|
|
297
|
-
: undefined,
|
|
330
|
+
const logLevel = logs.level;
|
|
331
|
+
const logger = createLogger({ logLevel });
|
|
332
|
+
const animatedLogEnabled =
|
|
333
|
+
logs.animated &&
|
|
334
|
+
// canEraseProcessStdout
|
|
335
|
+
process.stdout.isTTY &&
|
|
336
|
+
// if there is an error during execution npm will mess up the output
|
|
337
|
+
// (happens when npm runs several command in a workspace)
|
|
338
|
+
// so we enable hot replace only when !process.exitCode (no error so far)
|
|
339
|
+
process.exitCode !== 1;
|
|
340
|
+
let startBuildLogs = () => {};
|
|
341
|
+
|
|
342
|
+
const renderEntyPointBuildDoneLog = (
|
|
343
|
+
entryBuildInfo,
|
|
344
|
+
{ sourceUrlToLog, buildUrlToLog },
|
|
345
|
+
) => {
|
|
346
|
+
let content = "";
|
|
347
|
+
content += `${UNICODE.OK} ${ANSI.color(sourceUrlToLog, ANSI.GREY)} ${ANSI.color("->", ANSI.GREY)} ${ANSI.color(buildUrlToLog, "")}`;
|
|
348
|
+
// content += " ";
|
|
349
|
+
// content += ANSI.color("(", ANSI.GREY);
|
|
350
|
+
// content += ANSI.color(
|
|
351
|
+
// humanizeDuration(entryBuildInfo.duration, { short: true }),
|
|
352
|
+
// ANSI.GREY,
|
|
353
|
+
// );
|
|
354
|
+
// content += ANSI.color(")", ANSI.GREY);
|
|
355
|
+
content += "\n";
|
|
356
|
+
return content;
|
|
357
|
+
};
|
|
358
|
+
const renderBuildEndLog = ({ duration, buildFileContents }) => {
|
|
359
|
+
// tell how many files are generated in build directory
|
|
360
|
+
// tell the repartition?
|
|
361
|
+
// this is not really useful for single build right?
|
|
362
|
+
|
|
363
|
+
processCpuUsageMonitoring.end();
|
|
364
|
+
processMemoryUsageMonitoring.end();
|
|
365
|
+
|
|
366
|
+
return renderBuildDoneLog({
|
|
367
|
+
duration,
|
|
368
|
+
buildFileContents,
|
|
369
|
+
processCpuUsage: processCpuUsageMonitoring.info,
|
|
370
|
+
processMemoryUsage: processMemoryUsageMonitoring.info,
|
|
298
371
|
});
|
|
372
|
+
};
|
|
299
373
|
|
|
300
|
-
|
|
374
|
+
if (animatedLogEnabled) {
|
|
375
|
+
startBuildLogs = () => {
|
|
376
|
+
const startMs = Date.now();
|
|
377
|
+
let dynamicLog = createDynamicLog();
|
|
378
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
379
|
+
let frameIndex = 0;
|
|
380
|
+
let oneWrite = false;
|
|
381
|
+
const memoryHeapUsedAtStart = processMemoryUsage().heapUsed;
|
|
382
|
+
const renderDynamicLog = () => {
|
|
383
|
+
frameIndex = frameIndex === frames.length - 1 ? 0 : frameIndex + 1;
|
|
384
|
+
let dynamicLogContent = "";
|
|
385
|
+
dynamicLogContent += `${frames[frameIndex]} `;
|
|
386
|
+
dynamicLogContent += `building ${entryPointArray.length} entry points`;
|
|
301
387
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
388
|
+
const msEllapsed = Date.now() - startMs;
|
|
389
|
+
const infos = [];
|
|
390
|
+
const duration = humanizeDuration(msEllapsed, {
|
|
391
|
+
short: true,
|
|
392
|
+
decimals: 0,
|
|
393
|
+
rounded: false,
|
|
394
|
+
});
|
|
395
|
+
infos.push(ANSI.color(duration, ANSI.GREY));
|
|
396
|
+
let memoryUsageColor = ANSI.GREY;
|
|
397
|
+
const memoryHeapUsed = processMemoryUsage().heapUsed;
|
|
398
|
+
if (memoryHeapUsed > 2.5 * memoryHeapUsedAtStart) {
|
|
399
|
+
memoryUsageColor = ANSI.YELLOW;
|
|
400
|
+
} else if (memoryHeapUsed > 1.5 * memoryHeapUsedAtStart) {
|
|
401
|
+
memoryUsageColor = null;
|
|
402
|
+
}
|
|
403
|
+
const memoryHeapUsedFormatted = humanizeMemory(memoryHeapUsed, {
|
|
404
|
+
short: true,
|
|
405
|
+
decimals: 0,
|
|
406
|
+
});
|
|
407
|
+
infos.push(ANSI.color(memoryHeapUsedFormatted, memoryUsageColor));
|
|
408
|
+
|
|
409
|
+
const infoFormatted = infos.join(ANSI.color(`/`, ANSI.GREY));
|
|
410
|
+
dynamicLogContent += ` ${ANSI.color(
|
|
411
|
+
"[",
|
|
412
|
+
ANSI.GREY,
|
|
413
|
+
)}${infoFormatted}${ANSI.color("]", ANSI.GREY)}`;
|
|
414
|
+
|
|
415
|
+
if (oneWrite) {
|
|
416
|
+
dynamicLogContent = `\n${dynamicLogContent}`;
|
|
417
|
+
}
|
|
418
|
+
dynamicLogContent = `${dynamicLogContent}\n`;
|
|
419
|
+
return dynamicLogContent;
|
|
420
|
+
};
|
|
421
|
+
dynamicLog.update(renderDynamicLog());
|
|
422
|
+
const interval = setInterval(() => {
|
|
423
|
+
dynamicLog.update(renderDynamicLog());
|
|
424
|
+
}, 150).unref();
|
|
425
|
+
signal.addEventListener("abort", () => {
|
|
426
|
+
clearInterval(interval);
|
|
427
|
+
});
|
|
428
|
+
return {
|
|
429
|
+
onEntryPointBuildStart: (
|
|
430
|
+
entryBuildInfo,
|
|
431
|
+
{ sourceUrlToLog, buildUrlToLog },
|
|
432
|
+
) => {
|
|
433
|
+
return () => {
|
|
434
|
+
oneWrite = true;
|
|
435
|
+
dynamicLog.clearDuringFunctionCall((write) => {
|
|
436
|
+
const log = renderEntyPointBuildDoneLog(entryBuildInfo, {
|
|
437
|
+
sourceUrlToLog,
|
|
438
|
+
buildUrlToLog,
|
|
439
|
+
});
|
|
440
|
+
write(log);
|
|
441
|
+
}, renderDynamicLog());
|
|
320
442
|
};
|
|
321
443
|
},
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return result;
|
|
444
|
+
onBuildEnd: ({ buildFileContents, duration }) => {
|
|
445
|
+
clearInterval(interval);
|
|
446
|
+
dynamicLog.update("");
|
|
447
|
+
dynamicLog.destroy();
|
|
448
|
+
dynamicLog = null;
|
|
449
|
+
logger.info("");
|
|
450
|
+
logger.info(renderBuildEndLog({ duration, buildFileContents }));
|
|
330
451
|
},
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
} else {
|
|
455
|
+
startBuildLogs = () => {
|
|
456
|
+
if (entryPointArray.length === 1) {
|
|
457
|
+
const [singleEntryPoint] = entryPointArray;
|
|
458
|
+
logger.info(`building ${singleEntryPoint.key}`);
|
|
459
|
+
} else {
|
|
460
|
+
logger.info(`building ${entryPointArray.length} entry points`);
|
|
461
|
+
}
|
|
462
|
+
logger.info("");
|
|
463
|
+
return {
|
|
464
|
+
onEntryPointBuildStart: (
|
|
465
|
+
entryBuildInfo,
|
|
466
|
+
{ sourceUrlToLog, buildUrlToLog },
|
|
467
|
+
) => {
|
|
468
|
+
return () => {
|
|
469
|
+
logger.info(
|
|
470
|
+
renderEntyPointBuildDoneLog(entryBuildInfo, {
|
|
471
|
+
sourceUrlToLog,
|
|
472
|
+
buildUrlToLog,
|
|
473
|
+
}),
|
|
474
|
+
);
|
|
475
|
+
};
|
|
348
476
|
},
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
rawKitchen,
|
|
357
|
-
);
|
|
358
|
-
rawKitchen.setPluginController(rawPluginController);
|
|
477
|
+
onBuildEnd: ({ buildFileContents, duration }) => {
|
|
478
|
+
logger.info("");
|
|
479
|
+
logger.info(renderBuildEndLog({ duration, buildFileContents }));
|
|
480
|
+
},
|
|
481
|
+
};
|
|
482
|
+
};
|
|
483
|
+
}
|
|
359
484
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
});
|
|
378
|
-
});
|
|
379
|
-
await rawRootUrlInfo.cookDependencies({
|
|
380
|
-
operation: buildOperation,
|
|
381
|
-
});
|
|
382
|
-
} catch (e) {
|
|
383
|
-
generateSourceGraph.fail();
|
|
384
|
-
throw e;
|
|
385
|
-
}
|
|
386
|
-
generateSourceGraph.done();
|
|
485
|
+
// we want to start building the entry point that are deeper
|
|
486
|
+
// - they are more likely to be small
|
|
487
|
+
// - they are more likely to be referenced by highter files that will depend on them
|
|
488
|
+
entryPointArray.sort((a, b) => {
|
|
489
|
+
return compareFileUrls(a.sourceUrl, b.sourceUrl);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
const packageDirectoryUrl = lookupPackageDirectory(sourceDirectoryUrl);
|
|
493
|
+
if (outDirectoryUrl === undefined) {
|
|
494
|
+
if (
|
|
495
|
+
process.env.CAPTURING_SIDE_EFFECTS ||
|
|
496
|
+
(!import.meta.build &&
|
|
497
|
+
urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl))
|
|
498
|
+
) {
|
|
499
|
+
outDirectoryUrl = new URL("../.jsenv_b/", sourceDirectoryUrl).href;
|
|
500
|
+
} else if (packageDirectoryUrl) {
|
|
501
|
+
outDirectoryUrl = `${packageDirectoryUrl}.jsenv/`;
|
|
387
502
|
}
|
|
503
|
+
}
|
|
504
|
+
let rootPackageDirectoryUrl = packageDirectoryUrl;
|
|
505
|
+
if (packageDirectoryUrl) {
|
|
506
|
+
const parentPackageDirectoryUrl = lookupPackageDirectory(
|
|
507
|
+
new URL("../", packageDirectoryUrl),
|
|
508
|
+
);
|
|
509
|
+
if (parentPackageDirectoryUrl) {
|
|
510
|
+
rootPackageDirectoryUrl = parentPackageDirectoryUrl;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
388
513
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
// - no external plugin
|
|
395
|
-
// - no plugin putting reference.mustIgnore on https urls
|
|
396
|
-
// At this stage it's only about redirecting urls to the build directory
|
|
397
|
-
// consequently only a subset or urls are supported
|
|
398
|
-
supportedProtocols: ["file:", "data:", "virtual:", "ignore:"],
|
|
399
|
-
ignore,
|
|
400
|
-
ignoreProtocol: "remove",
|
|
401
|
-
build: true,
|
|
402
|
-
runtimeCompat,
|
|
403
|
-
initialContext: contextSharedDuringBuild,
|
|
404
|
-
sourcemaps,
|
|
405
|
-
sourcemapsComment: "relative",
|
|
406
|
-
sourcemapsSourcesContent,
|
|
407
|
-
outDirectoryUrl: outDirectoryUrl
|
|
408
|
-
? new URL("shape/", outDirectoryUrl)
|
|
409
|
-
: undefined,
|
|
410
|
-
});
|
|
411
|
-
const buildSpecifierManager = createBuildSpecifierManager({
|
|
412
|
-
rawKitchen,
|
|
413
|
-
finalKitchen,
|
|
414
|
-
logger,
|
|
514
|
+
const runBuild = async ({ signal }) => {
|
|
515
|
+
const startDate = Date.now();
|
|
516
|
+
const { onBuildEnd, onEntryPointBuildStart } = startBuildLogs();
|
|
517
|
+
|
|
518
|
+
const buildUrlsGenerator = createBuildUrlsGenerator({
|
|
415
519
|
sourceDirectoryUrl,
|
|
416
520
|
buildDirectoryUrl,
|
|
417
|
-
base,
|
|
418
|
-
assetsDirectory,
|
|
419
|
-
|
|
420
|
-
versioning,
|
|
421
|
-
versioningMethod,
|
|
422
|
-
versionLength,
|
|
423
|
-
canUseImportmap:
|
|
424
|
-
versioningViaImportmap &&
|
|
425
|
-
entryUrls.every((finalEntryUrl) => {
|
|
426
|
-
const entryUrlInfo = rawKitchen.graph.getUrlInfo(finalEntryUrl);
|
|
427
|
-
return entryUrlInfo.type === "html";
|
|
428
|
-
}) &&
|
|
429
|
-
rawKitchen.context.isSupportedOnCurrentClients("importmap"),
|
|
430
521
|
});
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
"optimizeUrlContent",
|
|
451
|
-
urlInfo,
|
|
452
|
-
(optimizeReturnValue) => {
|
|
453
|
-
urlInfo.mutateContent(optimizeReturnValue);
|
|
454
|
-
},
|
|
455
|
-
);
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
buildSpecifierManager.jsenvPluginMoveToBuildDirectory,
|
|
459
|
-
]);
|
|
460
|
-
const finalPluginController = createPluginController(
|
|
461
|
-
finalPluginStore,
|
|
462
|
-
finalKitchen,
|
|
463
|
-
{
|
|
464
|
-
initialPuginsMeta: rawKitchen.pluginController.pluginsMeta,
|
|
465
|
-
},
|
|
466
|
-
);
|
|
467
|
-
finalKitchen.setPluginController(finalPluginController);
|
|
468
|
-
|
|
469
|
-
const bundlers = {};
|
|
470
|
-
bundle: {
|
|
471
|
-
for (const plugin of rawKitchen.pluginController.activePlugins) {
|
|
472
|
-
const bundle = plugin.bundle;
|
|
473
|
-
if (!bundle) {
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
if (typeof bundle !== "object") {
|
|
477
|
-
throw new Error(
|
|
478
|
-
`bundle must be an object, found "${bundle}" on plugin named "${plugin.name}"`,
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
for (const type of Object.keys(bundle)) {
|
|
482
|
-
const bundleFunction = bundle[type];
|
|
483
|
-
if (!bundleFunction) {
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
const bundlerForThatType = bundlers[type];
|
|
487
|
-
if (bundlerForThatType) {
|
|
488
|
-
// first plugin to define a bundle hook wins
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
bundlers[type] = {
|
|
492
|
-
plugin,
|
|
493
|
-
bundleFunction: bundle[type],
|
|
494
|
-
urlInfoMap: new Map(),
|
|
495
|
-
};
|
|
522
|
+
|
|
523
|
+
let someEntryPointUseNode = false;
|
|
524
|
+
for (const entryPoint of entryPointArray) {
|
|
525
|
+
let { runtimeCompat } = entryPoint.params;
|
|
526
|
+
if (runtimeCompat === undefined) {
|
|
527
|
+
const runtimeCompatFromPackage = inferRuntimeCompatFromClosestPackage(
|
|
528
|
+
entryPoint.sourceUrl,
|
|
529
|
+
{
|
|
530
|
+
runtimeType: entryPoint.runtimeType,
|
|
531
|
+
},
|
|
532
|
+
);
|
|
533
|
+
if (runtimeCompatFromPackage) {
|
|
534
|
+
entryPoint.params.runtimeCompat = runtimeCompat =
|
|
535
|
+
runtimeCompatFromPackage;
|
|
536
|
+
} else {
|
|
537
|
+
entryPoint.params.runtimeCompat = runtimeCompat =
|
|
538
|
+
entryPoint.runtimeType === "browser"
|
|
539
|
+
? browserDefaultRuntimeCompat
|
|
540
|
+
: nodeDefaultRuntimeCompat;
|
|
496
541
|
}
|
|
497
542
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
if (bundler) {
|
|
501
|
-
bundler.urlInfoMap.set(rawUrlInfo.url, rawUrlInfo);
|
|
502
|
-
}
|
|
503
|
-
};
|
|
504
|
-
// ignore unused urls thanks to "forEachUrlInfoStronglyReferenced"
|
|
505
|
-
// it avoid bundling things that are not actually used
|
|
506
|
-
// happens for:
|
|
507
|
-
// - js import assertions
|
|
508
|
-
// - conversion to js classic using ?as_js_classic or ?js_module_fallback
|
|
509
|
-
GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
|
|
510
|
-
rawKitchen.graph.rootUrlInfo,
|
|
511
|
-
(rawUrlInfo) => {
|
|
512
|
-
if (rawUrlInfo.isEntryPoint) {
|
|
513
|
-
addToBundlerIfAny(rawUrlInfo);
|
|
514
|
-
}
|
|
515
|
-
if (rawUrlInfo.type === "html") {
|
|
516
|
-
for (const referenceToOther of rawUrlInfo.referenceToOthersSet) {
|
|
517
|
-
if (
|
|
518
|
-
referenceToOther.isResourceHint &&
|
|
519
|
-
referenceToOther.expectedType === "js_module"
|
|
520
|
-
) {
|
|
521
|
-
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
522
|
-
if (
|
|
523
|
-
referencedUrlInfo &&
|
|
524
|
-
// something else than the resource hint is using this url
|
|
525
|
-
referencedUrlInfo.referenceFromOthersSet.size > 0
|
|
526
|
-
) {
|
|
527
|
-
addToBundlerIfAny(referencedUrlInfo);
|
|
528
|
-
continue;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
if (referenceToOther.isWeak) {
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
535
|
-
if (referencedUrlInfo.isInline) {
|
|
536
|
-
if (referencedUrlInfo.type !== "js_module") {
|
|
537
|
-
continue;
|
|
538
|
-
}
|
|
539
|
-
addToBundlerIfAny(referencedUrlInfo);
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
|
-
addToBundlerIfAny(referencedUrlInfo);
|
|
543
|
-
}
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
// File referenced with
|
|
547
|
-
// - new URL("./file.js", import.meta.url)
|
|
548
|
-
// - import.meta.resolve("./file.js")
|
|
549
|
-
// are entry points that should be bundled
|
|
550
|
-
// For instance we will bundle service worker/workers detected like this
|
|
551
|
-
if (rawUrlInfo.type === "js_module") {
|
|
552
|
-
for (const referenceToOther of rawUrlInfo.referenceToOthersSet) {
|
|
553
|
-
if (
|
|
554
|
-
referenceToOther.type === "js_url" ||
|
|
555
|
-
referenceToOther.subtype === "import_meta_resolve"
|
|
556
|
-
) {
|
|
557
|
-
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
558
|
-
let isAlreadyBundled = false;
|
|
559
|
-
for (const referenceFromOther of referencedUrlInfo.referenceFromOthersSet) {
|
|
560
|
-
if (referenceFromOther.url === referencedUrlInfo.url) {
|
|
561
|
-
if (
|
|
562
|
-
referenceFromOther.subtype === "import_dynamic" ||
|
|
563
|
-
referenceFromOther.type === "script"
|
|
564
|
-
) {
|
|
565
|
-
isAlreadyBundled = true;
|
|
566
|
-
break;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
if (!isAlreadyBundled) {
|
|
571
|
-
addToBundlerIfAny(referencedUrlInfo);
|
|
572
|
-
}
|
|
573
|
-
continue;
|
|
574
|
-
}
|
|
575
|
-
if (referenceToOther.type === "js_inline_content") {
|
|
576
|
-
// we should bundle it too right?
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
},
|
|
581
|
-
);
|
|
582
|
-
for (const type of Object.keys(bundlers)) {
|
|
583
|
-
const bundler = bundlers[type];
|
|
584
|
-
const urlInfosToBundle = Array.from(bundler.urlInfoMap.values());
|
|
585
|
-
if (urlInfosToBundle.length === 0) {
|
|
586
|
-
continue;
|
|
587
|
-
}
|
|
588
|
-
const bundleTask = createBuildTask(`bundle "${type}"`);
|
|
589
|
-
try {
|
|
590
|
-
await buildSpecifierManager.applyBundling({
|
|
591
|
-
bundler,
|
|
592
|
-
urlInfosToBundle,
|
|
593
|
-
});
|
|
594
|
-
} catch (e) {
|
|
595
|
-
bundleTask.fail();
|
|
596
|
-
throw e;
|
|
597
|
-
}
|
|
598
|
-
bundleTask.done();
|
|
543
|
+
if (!someEntryPointUseNode && "node" in runtimeCompat) {
|
|
544
|
+
someEntryPointUseNode = true;
|
|
599
545
|
}
|
|
600
546
|
}
|
|
601
547
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
entryUrls.forEach((entryUrl) => {
|
|
612
|
-
finalRootUrlInfo.dependencies.found({
|
|
613
|
-
trace: { message: `entryPoint` },
|
|
614
|
-
isEntryPoint: true,
|
|
615
|
-
type: "entry_point",
|
|
616
|
-
specifier: entryUrl,
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
});
|
|
620
|
-
await finalRootUrlInfo.cookDependencies({
|
|
621
|
-
operation: buildOperation,
|
|
622
|
-
});
|
|
623
|
-
} catch (e) {
|
|
624
|
-
generateBuildGraph.fail();
|
|
625
|
-
throw e;
|
|
548
|
+
const entryBuildInfoMap = new Map();
|
|
549
|
+
let entryPointIndex = 0;
|
|
550
|
+
const entryOutDirSet = new Set();
|
|
551
|
+
for (const entryPoint of entryPointArray) {
|
|
552
|
+
let entryOutDirCandidate = `entry_${urlToBasename(entryPoint.sourceRelativeUrl)}/`;
|
|
553
|
+
let entryInteger = 1;
|
|
554
|
+
while (entryOutDirSet.has(entryOutDirCandidate)) {
|
|
555
|
+
entryInteger++;
|
|
556
|
+
entryOutDirCandidate = `entry_${urlToBasename(entryPoint.sourceRelativeUrl)}_${entryInteger}/`;
|
|
626
557
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
558
|
+
const entryOutDirname = entryOutDirCandidate;
|
|
559
|
+
entryOutDirSet.add(entryOutDirname);
|
|
560
|
+
const entryOutDirectoryUrl = new URL(entryOutDirname, outDirectoryUrl);
|
|
561
|
+
const { entryReference, buildEntryPoint } = await prepareEntryPointBuild(
|
|
562
|
+
{
|
|
563
|
+
signal,
|
|
564
|
+
sourceDirectoryUrl,
|
|
565
|
+
buildDirectoryUrl,
|
|
566
|
+
outDirectoryUrl: entryOutDirectoryUrl,
|
|
567
|
+
sourceRelativeUrl: entryPoint.sourceRelativeUrl,
|
|
568
|
+
buildUrlsGenerator,
|
|
569
|
+
someEntryPointUseNode,
|
|
570
|
+
},
|
|
571
|
+
entryPoint.params,
|
|
572
|
+
);
|
|
573
|
+
const entryPointBuildRelativeUrl = entryPoint.params.buildRelativeUrl;
|
|
574
|
+
const entryBuildInfo = {
|
|
575
|
+
index: entryPointIndex,
|
|
576
|
+
entryReference,
|
|
577
|
+
entryUrlInfo: entryReference.urlInfo,
|
|
578
|
+
buildRelativeUrl: entryPointBuildRelativeUrl,
|
|
579
|
+
buildFileContents: undefined,
|
|
580
|
+
buildFileVersions: undefined,
|
|
581
|
+
buildInlineContents: undefined,
|
|
582
|
+
buildManifest: undefined,
|
|
583
|
+
duration: null,
|
|
584
|
+
buildEntryPoint: () => {
|
|
585
|
+
const sourceUrl = new URL(
|
|
586
|
+
entryPoint.sourceRelativeUrl,
|
|
587
|
+
sourceDirectoryUrl,
|
|
588
|
+
);
|
|
589
|
+
const buildUrl = new URL(
|
|
590
|
+
entryPointBuildRelativeUrl,
|
|
591
|
+
buildDirectoryUrl,
|
|
592
|
+
);
|
|
593
|
+
const sourceUrlToLog = rootPackageDirectoryUrl
|
|
594
|
+
? urlToRelativeUrl(sourceUrl, rootPackageDirectoryUrl)
|
|
595
|
+
: entryPoint.key;
|
|
596
|
+
const buildUrlToLog = rootPackageDirectoryUrl
|
|
597
|
+
? urlToRelativeUrl(buildUrl, rootPackageDirectoryUrl)
|
|
598
|
+
: entryPointBuildRelativeUrl;
|
|
632
599
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
600
|
+
const entryPointBuildStartMs = Date.now();
|
|
601
|
+
const onEntryPointBuildEnd = onEntryPointBuildStart(entryBuildInfo, {
|
|
602
|
+
sourceUrlToLog,
|
|
603
|
+
buildUrlToLog,
|
|
604
|
+
});
|
|
605
|
+
const promise = (async () => {
|
|
606
|
+
const result = await buildEntryPoint({
|
|
607
|
+
getOtherEntryBuildInfo: (url) => {
|
|
608
|
+
if (url === entryReference.url) {
|
|
609
|
+
return null;
|
|
610
|
+
}
|
|
611
|
+
const otherEntryBuildInfo = entryBuildInfoMap.get(url);
|
|
612
|
+
if (!otherEntryBuildInfo) {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
return otherEntryBuildInfo;
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
entryBuildInfo.buildFileContents = result.buildFileContents;
|
|
619
|
+
entryBuildInfo.buildFileVersions = result.buildFileVersions;
|
|
620
|
+
entryBuildInfo.buildInlineContents = result.buildInlineContents;
|
|
621
|
+
entryBuildInfo.buildManifest = result.buildManifest;
|
|
622
|
+
entryBuildInfo.duration = Date.now() - entryPointBuildStartMs;
|
|
623
|
+
onEntryPointBuildEnd();
|
|
624
|
+
})();
|
|
625
|
+
entryBuildInfo.promise = promise;
|
|
626
|
+
return promise;
|
|
627
|
+
},
|
|
636
628
|
};
|
|
629
|
+
entryBuildInfoMap.set(entryReference.url, entryBuildInfo);
|
|
630
|
+
entryPointIndex++;
|
|
631
|
+
}
|
|
637
632
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
* - Used to remove resource hint targeting an url that is no longer used:
|
|
645
|
-
* - because of bundlings
|
|
646
|
-
* - because of import assertions transpilation (file is inlined into JS)
|
|
647
|
-
*/
|
|
648
|
-
resync_resource_hints: {
|
|
649
|
-
buildSpecifierManager.prepareResyncResourceHints({
|
|
650
|
-
registerHtmlRefine,
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
mutate_html: {
|
|
655
|
-
GRAPH_VISITOR.forEach(finalKitchen.graph, (urlInfo) => {
|
|
656
|
-
if (!urlInfo.url.startsWith("file:")) {
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
if (urlInfo.type !== "html") {
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
const htmlAst = parseHtml({
|
|
663
|
-
html: urlInfo.content,
|
|
664
|
-
url: urlInfo.url,
|
|
665
|
-
storeOriginalPositions: false,
|
|
666
|
-
});
|
|
667
|
-
for (const htmlRefine of htmlRefineSet) {
|
|
668
|
-
const htmlMutationCallbackSet = new Set();
|
|
669
|
-
const registerHtmlMutation = (callback) => {
|
|
670
|
-
htmlMutationCallbackSet.add(callback);
|
|
671
|
-
};
|
|
672
|
-
htmlRefine(htmlAst, { registerHtmlMutation });
|
|
673
|
-
for (const htmlMutationCallback of htmlMutationCallbackSet) {
|
|
674
|
-
htmlMutationCallback();
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
// cleanup jsenv attributes from html as a last step
|
|
678
|
-
urlInfo.content = stringifyHtmlAst(htmlAst, {
|
|
679
|
-
cleanupJsenvAttributes: true,
|
|
680
|
-
cleanupPositionAttributes: true,
|
|
681
|
-
});
|
|
682
|
-
});
|
|
683
|
-
}
|
|
633
|
+
const promises = [];
|
|
634
|
+
for (const [, entryBuildInfo] of entryBuildInfoMap) {
|
|
635
|
+
const promise = entryBuildInfo.buildEntryPoint();
|
|
636
|
+
promises.push(promise);
|
|
637
|
+
}
|
|
638
|
+
await Promise.all(promises);
|
|
684
639
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
}
|
|
640
|
+
const buildFileContents = {};
|
|
641
|
+
const buildFileVersions = {};
|
|
642
|
+
const buildInlineContents = {};
|
|
643
|
+
const buildManifest = {};
|
|
644
|
+
for (const [, entryBuildInfo] of entryBuildInfoMap) {
|
|
645
|
+
Object.assign(buildFileContents, entryBuildInfo.buildFileContents);
|
|
646
|
+
Object.assign(buildFileVersions, entryBuildInfo.buildFileVersions);
|
|
647
|
+
Object.assign(buildInlineContents, entryBuildInfo.buildInlineContents);
|
|
648
|
+
Object.assign(buildManifest, entryBuildInfo.buildManifest);
|
|
696
649
|
}
|
|
697
|
-
const { buildFileContents, buildInlineContents, buildManifest } =
|
|
698
|
-
buildSpecifierManager.getBuildInfo();
|
|
699
650
|
if (writeOnFileSystem) {
|
|
700
|
-
const writingFiles = createBuildTask("write files in build directory");
|
|
701
651
|
clearDirectorySync(buildDirectoryUrl, buildDirectoryCleanPatterns);
|
|
702
652
|
const buildRelativeUrls = Object.keys(buildFileContents);
|
|
703
653
|
buildRelativeUrls.forEach((buildRelativeUrl) => {
|
|
@@ -706,23 +656,17 @@ build ${entryPointKeys.length} entry points`);
|
|
|
706
656
|
buildFileContents[buildRelativeUrl],
|
|
707
657
|
);
|
|
708
658
|
});
|
|
709
|
-
if (versioning && assetManifest && Object.keys(buildManifest).length) {
|
|
710
|
-
writeFileSync(
|
|
711
|
-
new URL(assetManifestFileRelativeUrl, buildDirectoryUrl),
|
|
712
|
-
JSON.stringify(buildManifest, null, " "),
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
writingFiles.done();
|
|
716
659
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
660
|
+
onBuildEnd({
|
|
661
|
+
buildFileContents,
|
|
662
|
+
buildInlineContents,
|
|
663
|
+
buildManifest,
|
|
664
|
+
duration: Date.now() - startDate,
|
|
665
|
+
});
|
|
722
666
|
return {
|
|
723
667
|
...(returnBuildInlineContents ? { buildInlineContents } : {}),
|
|
724
668
|
...(returnBuildManifest ? { buildManifest } : {}),
|
|
725
|
-
...(
|
|
669
|
+
...(returnBuildFileVersions ? { buildFileVersions } : {}),
|
|
726
670
|
};
|
|
727
671
|
};
|
|
728
672
|
|
|
@@ -730,7 +674,6 @@ build ${entryPointKeys.length} entry points`);
|
|
|
730
674
|
try {
|
|
731
675
|
const result = await runBuild({
|
|
732
676
|
signal: operation.signal,
|
|
733
|
-
logLevel: logs.level,
|
|
734
677
|
});
|
|
735
678
|
return result;
|
|
736
679
|
} finally {
|
|
@@ -802,3 +745,584 @@ build ${entryPointKeys.length} entry points`);
|
|
|
802
745
|
await firstBuildPromise;
|
|
803
746
|
return stopWatchingSourceFiles;
|
|
804
747
|
};
|
|
748
|
+
|
|
749
|
+
const entryPointDefaultParams = {
|
|
750
|
+
buildRelativeUrl: undefined,
|
|
751
|
+
runtimeCompat: defaultRuntimeCompat,
|
|
752
|
+
plugins: [],
|
|
753
|
+
mappings: undefined,
|
|
754
|
+
assetsDirectory: undefined,
|
|
755
|
+
base: undefined,
|
|
756
|
+
ignore: undefined,
|
|
757
|
+
|
|
758
|
+
bundling: true,
|
|
759
|
+
minification: true,
|
|
760
|
+
versioning: true,
|
|
761
|
+
|
|
762
|
+
referenceAnalysis: {},
|
|
763
|
+
nodeEsmResolution: undefined,
|
|
764
|
+
packageConditions: undefined,
|
|
765
|
+
magicExtensions: undefined,
|
|
766
|
+
magicDirectoryIndex: undefined,
|
|
767
|
+
directoryReferenceEffect: undefined,
|
|
768
|
+
scenarioPlaceholders: undefined,
|
|
769
|
+
injections: undefined,
|
|
770
|
+
transpilation: {},
|
|
771
|
+
|
|
772
|
+
versioningMethod: "search_param", // "filename", "search_param"
|
|
773
|
+
versioningViaImportmap: true,
|
|
774
|
+
versionLength: 8,
|
|
775
|
+
lineBreakNormalization: process.platform === "win32",
|
|
776
|
+
|
|
777
|
+
http: false,
|
|
778
|
+
|
|
779
|
+
sourcemaps: "none",
|
|
780
|
+
sourcemapsSourcesContent: undefined,
|
|
781
|
+
assetManifest: false,
|
|
782
|
+
assetManifestFileRelativeUrl: "asset-manifest.json",
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const prepareEntryPointBuild = async (
|
|
786
|
+
{
|
|
787
|
+
signal,
|
|
788
|
+
sourceDirectoryUrl,
|
|
789
|
+
buildDirectoryUrl,
|
|
790
|
+
sourceRelativeUrl,
|
|
791
|
+
outDirectoryUrl,
|
|
792
|
+
buildUrlsGenerator,
|
|
793
|
+
someEntryPointUseNode,
|
|
794
|
+
},
|
|
795
|
+
entryPointParams,
|
|
796
|
+
) => {
|
|
797
|
+
let {
|
|
798
|
+
buildRelativeUrl,
|
|
799
|
+
runtimeCompat,
|
|
800
|
+
plugins,
|
|
801
|
+
mappings,
|
|
802
|
+
assetsDirectory,
|
|
803
|
+
base,
|
|
804
|
+
ignore,
|
|
805
|
+
|
|
806
|
+
bundling,
|
|
807
|
+
minification,
|
|
808
|
+
versioning,
|
|
809
|
+
|
|
810
|
+
referenceAnalysis,
|
|
811
|
+
nodeEsmResolution,
|
|
812
|
+
packageConditions,
|
|
813
|
+
magicExtensions,
|
|
814
|
+
magicDirectoryIndex,
|
|
815
|
+
directoryReferenceEffect,
|
|
816
|
+
scenarioPlaceholders,
|
|
817
|
+
injections,
|
|
818
|
+
transpilation,
|
|
819
|
+
|
|
820
|
+
versioningMethod,
|
|
821
|
+
versioningViaImportmap,
|
|
822
|
+
versionLength,
|
|
823
|
+
lineBreakNormalization,
|
|
824
|
+
|
|
825
|
+
http,
|
|
826
|
+
|
|
827
|
+
sourcemaps,
|
|
828
|
+
sourcemapsSourcesContent,
|
|
829
|
+
assetManifest,
|
|
830
|
+
assetManifestFileRelativeUrl,
|
|
831
|
+
} = {
|
|
832
|
+
...entryPointDefaultParams,
|
|
833
|
+
...entryPointParams,
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// param defaults and normalization
|
|
837
|
+
{
|
|
838
|
+
if (entryPointParams.buildRelativeUrl === undefined) {
|
|
839
|
+
buildRelativeUrl = entryPointParams.buildRelativeUrl = sourceRelativeUrl;
|
|
840
|
+
}
|
|
841
|
+
const buildUrl = new URL(buildRelativeUrl, buildDirectoryUrl);
|
|
842
|
+
entryPointParams.buildRelativeUrl = buildRelativeUrl = urlToRelativeUrl(
|
|
843
|
+
buildUrl,
|
|
844
|
+
buildDirectoryUrl,
|
|
845
|
+
);
|
|
846
|
+
if (entryPointParams.assetsDirectory === undefined) {
|
|
847
|
+
const entryBuildUrl = new URL(buildRelativeUrl, buildDirectoryUrl).href;
|
|
848
|
+
const entryBuildRelativeUrl = urlToRelativeUrl(
|
|
849
|
+
entryBuildUrl,
|
|
850
|
+
buildDirectoryUrl,
|
|
851
|
+
);
|
|
852
|
+
if (entryBuildRelativeUrl.includes("/")) {
|
|
853
|
+
const assetDirectoryUrl = new URL("./", entryBuildUrl);
|
|
854
|
+
assetsDirectory = urlToRelativeUrl(
|
|
855
|
+
assetDirectoryUrl,
|
|
856
|
+
buildDirectoryUrl,
|
|
857
|
+
);
|
|
858
|
+
} else {
|
|
859
|
+
assetsDirectory = "";
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (
|
|
863
|
+
assetsDirectory &&
|
|
864
|
+
assetsDirectory[assetsDirectory.length - 1] !== "/"
|
|
865
|
+
) {
|
|
866
|
+
assetsDirectory = `${assetsDirectory}/`;
|
|
867
|
+
}
|
|
868
|
+
if (entryPointParams.base === undefined) {
|
|
869
|
+
base = someEntryPointUseNode ? "./" : "/";
|
|
870
|
+
}
|
|
871
|
+
if (entryPointParams.bundling === undefined) {
|
|
872
|
+
bundling = true;
|
|
873
|
+
}
|
|
874
|
+
if (bundling === true) {
|
|
875
|
+
bundling = {};
|
|
876
|
+
}
|
|
877
|
+
if (entryPointParams.minification === undefined) {
|
|
878
|
+
minification = !someEntryPointUseNode;
|
|
879
|
+
}
|
|
880
|
+
if (minification === true) {
|
|
881
|
+
minification = {};
|
|
882
|
+
}
|
|
883
|
+
if (entryPointParams.versioning === undefined) {
|
|
884
|
+
versioning = !someEntryPointUseNode;
|
|
885
|
+
}
|
|
886
|
+
if (entryPointParams.versioningMethod === undefined) {
|
|
887
|
+
versioningMethod = entryPointDefaultParams.versioningMethod;
|
|
888
|
+
}
|
|
889
|
+
if (entryPointParams.assetManifest === undefined) {
|
|
890
|
+
assetManifest = versioningMethod === "filename";
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const buildOperation = Abort.startOperation();
|
|
895
|
+
buildOperation.addAbortSignal(signal);
|
|
896
|
+
|
|
897
|
+
const explicitJsModuleConversion =
|
|
898
|
+
sourceRelativeUrl.includes("?js_module_fallback") ||
|
|
899
|
+
sourceRelativeUrl.includes("?as_js_classic");
|
|
900
|
+
const contextSharedDuringBuild = {
|
|
901
|
+
buildStep: "craft",
|
|
902
|
+
buildDirectoryUrl,
|
|
903
|
+
assetsDirectory,
|
|
904
|
+
versioning,
|
|
905
|
+
versioningViaImportmap,
|
|
906
|
+
};
|
|
907
|
+
const rawKitchen = createKitchen({
|
|
908
|
+
signal,
|
|
909
|
+
logLevel: "warn",
|
|
910
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
911
|
+
ignore,
|
|
912
|
+
// during first pass (craft) we keep "ignore:" when a reference is ignored
|
|
913
|
+
// so that the second pass (shape) properly ignore those urls
|
|
914
|
+
ignoreProtocol: "keep",
|
|
915
|
+
build: true,
|
|
916
|
+
runtimeCompat,
|
|
917
|
+
initialContext: contextSharedDuringBuild,
|
|
918
|
+
sourcemaps,
|
|
919
|
+
sourcemapsSourcesContent,
|
|
920
|
+
outDirectoryUrl: outDirectoryUrl
|
|
921
|
+
? new URL("craft/", outDirectoryUrl)
|
|
922
|
+
: undefined,
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
let _getOtherEntryBuildInfo;
|
|
926
|
+
const rawPluginStore = createPluginStore([
|
|
927
|
+
...(mappings ? [jsenvPluginMappings(mappings)] : []),
|
|
928
|
+
{
|
|
929
|
+
name: "jsenv:other_entry_point_build_during_craft",
|
|
930
|
+
fetchUrlContent: async (urlInfo) => {
|
|
931
|
+
if (!_getOtherEntryBuildInfo) {
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
const otherEntryBuildInfo = _getOtherEntryBuildInfo(urlInfo.url);
|
|
935
|
+
if (!otherEntryBuildInfo) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
urlInfo.otherEntryBuildInfo = otherEntryBuildInfo;
|
|
939
|
+
return {
|
|
940
|
+
type: "entry_build", // this ensure the rest of jsenv do not try to scan or modify the content
|
|
941
|
+
content: "", // we don't know yet the content it will be known later
|
|
942
|
+
filenameHint: otherEntryBuildInfo.entryUrlInfo.filenameHint,
|
|
943
|
+
};
|
|
944
|
+
},
|
|
945
|
+
},
|
|
946
|
+
...plugins,
|
|
947
|
+
...(bundling ? [jsenvPluginBundling(bundling)] : []),
|
|
948
|
+
...(minification ? [jsenvPluginMinification(minification)] : []),
|
|
949
|
+
...getCorePlugins({
|
|
950
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
951
|
+
runtimeCompat,
|
|
952
|
+
referenceAnalysis,
|
|
953
|
+
nodeEsmResolution,
|
|
954
|
+
packageConditions,
|
|
955
|
+
magicExtensions,
|
|
956
|
+
magicDirectoryIndex,
|
|
957
|
+
directoryReferenceEffect,
|
|
958
|
+
injections,
|
|
959
|
+
transpilation: {
|
|
960
|
+
babelHelpersAsImport: !explicitJsModuleConversion,
|
|
961
|
+
...transpilation,
|
|
962
|
+
jsModuleFallback: false,
|
|
963
|
+
},
|
|
964
|
+
inlining: false,
|
|
965
|
+
http,
|
|
966
|
+
scenarioPlaceholders,
|
|
967
|
+
}),
|
|
968
|
+
]);
|
|
969
|
+
const rawPluginController = createPluginController(
|
|
970
|
+
rawPluginStore,
|
|
971
|
+
rawKitchen,
|
|
972
|
+
);
|
|
973
|
+
rawKitchen.setPluginController(rawPluginController);
|
|
974
|
+
|
|
975
|
+
const rawRootUrlInfo = rawKitchen.graph.rootUrlInfo;
|
|
976
|
+
let entryReference;
|
|
977
|
+
await rawRootUrlInfo.dependencies.startCollecting(() => {
|
|
978
|
+
entryReference = rawRootUrlInfo.dependencies.found({
|
|
979
|
+
trace: { message: `"${sourceRelativeUrl}" from "entryPoints"` },
|
|
980
|
+
isEntryPoint: true,
|
|
981
|
+
type: "entry_point",
|
|
982
|
+
specifier: sourceRelativeUrl,
|
|
983
|
+
filenameHint: buildRelativeUrl,
|
|
984
|
+
});
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
return {
|
|
988
|
+
entryReference,
|
|
989
|
+
buildEntryPoint: async ({ getOtherEntryBuildInfo }) => {
|
|
990
|
+
craft: {
|
|
991
|
+
_getOtherEntryBuildInfo = getOtherEntryBuildInfo;
|
|
992
|
+
if (outDirectoryUrl) {
|
|
993
|
+
await ensureEmptyDirectory(new URL(`craft/`, outDirectoryUrl));
|
|
994
|
+
}
|
|
995
|
+
await rawRootUrlInfo.cookDependencies({ operation: buildOperation });
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
const finalKitchen = createKitchen({
|
|
999
|
+
name: "shape",
|
|
1000
|
+
logLevel: "warn",
|
|
1001
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
1002
|
+
// here most plugins are not there
|
|
1003
|
+
// - no external plugin
|
|
1004
|
+
// - no plugin putting reference.mustIgnore on https urls
|
|
1005
|
+
// At this stage it's only about redirecting urls to the build directory
|
|
1006
|
+
// consequently only a subset or urls are supported
|
|
1007
|
+
supportedProtocols: ["file:", "data:", "virtual:", "ignore:"],
|
|
1008
|
+
ignore,
|
|
1009
|
+
ignoreProtocol: "remove",
|
|
1010
|
+
build: true,
|
|
1011
|
+
runtimeCompat,
|
|
1012
|
+
initialContext: contextSharedDuringBuild,
|
|
1013
|
+
sourcemaps,
|
|
1014
|
+
sourcemapsComment: "relative",
|
|
1015
|
+
sourcemapsSourcesContent,
|
|
1016
|
+
outDirectoryUrl: outDirectoryUrl
|
|
1017
|
+
? new URL("shape/", outDirectoryUrl)
|
|
1018
|
+
: undefined,
|
|
1019
|
+
});
|
|
1020
|
+
const buildSpecifierManager = createBuildSpecifierManager({
|
|
1021
|
+
rawKitchen,
|
|
1022
|
+
finalKitchen,
|
|
1023
|
+
logger: createLogger({ logLevel: "warn" }),
|
|
1024
|
+
sourceDirectoryUrl,
|
|
1025
|
+
buildDirectoryUrl,
|
|
1026
|
+
base,
|
|
1027
|
+
assetsDirectory,
|
|
1028
|
+
buildUrlsGenerator,
|
|
1029
|
+
|
|
1030
|
+
versioning,
|
|
1031
|
+
versioningMethod,
|
|
1032
|
+
versionLength,
|
|
1033
|
+
canUseImportmap:
|
|
1034
|
+
versioningViaImportmap &&
|
|
1035
|
+
rawKitchen.graph.getUrlInfo(entryReference.url).type === "html" &&
|
|
1036
|
+
rawKitchen.context.isSupportedOnCurrentClients("importmap"),
|
|
1037
|
+
});
|
|
1038
|
+
const finalPluginStore = createPluginStore([
|
|
1039
|
+
jsenvPluginReferenceAnalysis({
|
|
1040
|
+
...referenceAnalysis,
|
|
1041
|
+
fetchInlineUrls: false,
|
|
1042
|
+
// inlineContent: false,
|
|
1043
|
+
}),
|
|
1044
|
+
jsenvPluginDirectoryReferenceEffect(directoryReferenceEffect, {
|
|
1045
|
+
rootDirectoryUrl: sourceDirectoryUrl,
|
|
1046
|
+
}),
|
|
1047
|
+
...(lineBreakNormalization
|
|
1048
|
+
? [jsenvPluginLineBreakNormalization()]
|
|
1049
|
+
: []),
|
|
1050
|
+
jsenvPluginJsModuleFallback({
|
|
1051
|
+
remapImportSpecifier: (specifier, parentUrl) => {
|
|
1052
|
+
return buildSpecifierManager.remapPlaceholder(specifier, parentUrl);
|
|
1053
|
+
},
|
|
1054
|
+
}),
|
|
1055
|
+
jsenvPluginInlining(),
|
|
1056
|
+
{
|
|
1057
|
+
name: "jsenv:optimize",
|
|
1058
|
+
appliesDuring: "build",
|
|
1059
|
+
transformUrlContent: async (urlInfo) => {
|
|
1060
|
+
await rawKitchen.pluginController.callAsyncHooks(
|
|
1061
|
+
"optimizeUrlContent",
|
|
1062
|
+
urlInfo,
|
|
1063
|
+
(optimizeReturnValue) => {
|
|
1064
|
+
urlInfo.mutateContent(optimizeReturnValue);
|
|
1065
|
+
},
|
|
1066
|
+
);
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
1069
|
+
buildSpecifierManager.jsenvPluginMoveToBuildDirectory,
|
|
1070
|
+
]);
|
|
1071
|
+
const finalPluginController = createPluginController(
|
|
1072
|
+
finalPluginStore,
|
|
1073
|
+
finalKitchen,
|
|
1074
|
+
{
|
|
1075
|
+
initialPuginsMeta: rawKitchen.pluginController.pluginsMeta,
|
|
1076
|
+
},
|
|
1077
|
+
);
|
|
1078
|
+
finalKitchen.setPluginController(finalPluginController);
|
|
1079
|
+
|
|
1080
|
+
bundle: {
|
|
1081
|
+
const bundlerMap = new Map();
|
|
1082
|
+
for (const plugin of rawKitchen.pluginController.activePlugins) {
|
|
1083
|
+
const bundle = plugin.bundle;
|
|
1084
|
+
if (!bundle) {
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
if (typeof bundle !== "object") {
|
|
1088
|
+
throw new Error(
|
|
1089
|
+
`bundle must be an object, found "${bundle}" on plugin named "${plugin.name}"`,
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
for (const type of Object.keys(bundle)) {
|
|
1093
|
+
const bundleFunction = bundle[type];
|
|
1094
|
+
if (!bundleFunction) {
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
if (bundlerMap.has(type)) {
|
|
1098
|
+
// first plugin to define a bundle hook wins
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
bundlerMap.set(type, {
|
|
1102
|
+
plugin,
|
|
1103
|
+
bundleFunction: bundle[type],
|
|
1104
|
+
urlInfoMap: new Map(),
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
if (bundlerMap.size === 0) {
|
|
1109
|
+
break bundle;
|
|
1110
|
+
}
|
|
1111
|
+
const addToBundlerIfAny = (rawUrlInfo) => {
|
|
1112
|
+
const bundler = bundlerMap.get(rawUrlInfo.type);
|
|
1113
|
+
if (bundler) {
|
|
1114
|
+
bundler.urlInfoMap.set(rawUrlInfo.url, rawUrlInfo);
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
// ignore unused urls thanks to "forEachUrlInfoStronglyReferenced"
|
|
1118
|
+
// it avoid bundling things that are not actually used
|
|
1119
|
+
// happens for:
|
|
1120
|
+
// - js import assertions
|
|
1121
|
+
// - conversion to js classic using ?as_js_classic or ?js_module_fallback
|
|
1122
|
+
GRAPH_VISITOR.forEachUrlInfoStronglyReferenced(
|
|
1123
|
+
rawKitchen.graph.rootUrlInfo,
|
|
1124
|
+
(rawUrlInfo) => {
|
|
1125
|
+
if (rawUrlInfo.isEntryPoint) {
|
|
1126
|
+
addToBundlerIfAny(rawUrlInfo);
|
|
1127
|
+
}
|
|
1128
|
+
if (rawUrlInfo.type === "html") {
|
|
1129
|
+
for (const referenceToOther of rawUrlInfo.referenceToOthersSet) {
|
|
1130
|
+
if (
|
|
1131
|
+
referenceToOther.isResourceHint &&
|
|
1132
|
+
referenceToOther.expectedType === "js_module"
|
|
1133
|
+
) {
|
|
1134
|
+
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
1135
|
+
if (
|
|
1136
|
+
referencedUrlInfo &&
|
|
1137
|
+
// something else than the resource hint is using this url
|
|
1138
|
+
referencedUrlInfo.referenceFromOthersSet.size > 0
|
|
1139
|
+
) {
|
|
1140
|
+
addToBundlerIfAny(referencedUrlInfo);
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (referenceToOther.isWeak) {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
1148
|
+
if (referencedUrlInfo.isInline) {
|
|
1149
|
+
if (referencedUrlInfo.type !== "js_module") {
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
addToBundlerIfAny(referencedUrlInfo);
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
addToBundlerIfAny(referencedUrlInfo);
|
|
1156
|
+
}
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
// File referenced with
|
|
1160
|
+
// - new URL("./file.js", import.meta.url)
|
|
1161
|
+
// - import.meta.resolve("./file.js")
|
|
1162
|
+
// are entry points that should be bundled
|
|
1163
|
+
// For instance we will bundle service worker/workers detected like this
|
|
1164
|
+
if (rawUrlInfo.type === "js_module") {
|
|
1165
|
+
for (const referenceToOther of rawUrlInfo.referenceToOthersSet) {
|
|
1166
|
+
if (
|
|
1167
|
+
referenceToOther.type === "js_url" ||
|
|
1168
|
+
referenceToOther.subtype === "import_meta_resolve"
|
|
1169
|
+
) {
|
|
1170
|
+
const referencedUrlInfo = referenceToOther.urlInfo;
|
|
1171
|
+
let isAlreadyBundled = false;
|
|
1172
|
+
for (const referenceFromOther of referencedUrlInfo.referenceFromOthersSet) {
|
|
1173
|
+
if (referenceFromOther.url === referencedUrlInfo.url) {
|
|
1174
|
+
if (
|
|
1175
|
+
referenceFromOther.subtype === "import_dynamic" ||
|
|
1176
|
+
referenceFromOther.type === "script"
|
|
1177
|
+
) {
|
|
1178
|
+
isAlreadyBundled = true;
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (!isAlreadyBundled) {
|
|
1184
|
+
addToBundlerIfAny(referencedUrlInfo);
|
|
1185
|
+
}
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
if (referenceToOther.type === "js_inline_content") {
|
|
1189
|
+
// we should bundle it too right?
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
},
|
|
1194
|
+
);
|
|
1195
|
+
for (const [, bundler] of bundlerMap) {
|
|
1196
|
+
const urlInfosToBundle = Array.from(bundler.urlInfoMap.values());
|
|
1197
|
+
if (urlInfosToBundle.length === 0) {
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
await buildSpecifierManager.applyBundling({
|
|
1201
|
+
bundler,
|
|
1202
|
+
urlInfosToBundle,
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
shape: {
|
|
1208
|
+
finalKitchen.context.buildStep = "shape";
|
|
1209
|
+
if (outDirectoryUrl) {
|
|
1210
|
+
await ensureEmptyDirectory(new URL(`shape/`, outDirectoryUrl));
|
|
1211
|
+
}
|
|
1212
|
+
const finalRootUrlInfo = finalKitchen.graph.rootUrlInfo;
|
|
1213
|
+
await finalRootUrlInfo.dependencies.startCollecting(() => {
|
|
1214
|
+
finalRootUrlInfo.dependencies.found({
|
|
1215
|
+
trace: { message: `entryPoint` },
|
|
1216
|
+
isEntryPoint: true,
|
|
1217
|
+
type: "entry_point",
|
|
1218
|
+
specifier: entryReference.url,
|
|
1219
|
+
});
|
|
1220
|
+
});
|
|
1221
|
+
await finalRootUrlInfo.cookDependencies({
|
|
1222
|
+
operation: buildOperation,
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
refine: {
|
|
1227
|
+
finalKitchen.context.buildStep = "refine";
|
|
1228
|
+
|
|
1229
|
+
const htmlRefineSet = new Set();
|
|
1230
|
+
const registerHtmlRefine = (htmlRefine) => {
|
|
1231
|
+
htmlRefineSet.add(htmlRefine);
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
replace_placeholders: {
|
|
1235
|
+
await buildSpecifierManager.replacePlaceholders();
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/*
|
|
1239
|
+
* Update <link rel="preload"> and friends after build (once we know everything)
|
|
1240
|
+
* - Used to remove resource hint targeting an url that is no longer used:
|
|
1241
|
+
* - because of bundlings
|
|
1242
|
+
* - because of import assertions transpilation (file is inlined into JS)
|
|
1243
|
+
*/
|
|
1244
|
+
resync_resource_hints: {
|
|
1245
|
+
buildSpecifierManager.prepareResyncResourceHints({
|
|
1246
|
+
registerHtmlRefine,
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
mutate_html: {
|
|
1251
|
+
GRAPH_VISITOR.forEach(finalKitchen.graph, (urlInfo) => {
|
|
1252
|
+
if (!urlInfo.url.startsWith("file:")) {
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
if (urlInfo.type !== "html") {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
const htmlAst = parseHtml({
|
|
1259
|
+
html: urlInfo.content,
|
|
1260
|
+
url: urlInfo.url,
|
|
1261
|
+
storeOriginalPositions: false,
|
|
1262
|
+
});
|
|
1263
|
+
for (const htmlRefine of htmlRefineSet) {
|
|
1264
|
+
const htmlMutationCallbackSet = new Set();
|
|
1265
|
+
const registerHtmlMutation = (callback) => {
|
|
1266
|
+
htmlMutationCallbackSet.add(callback);
|
|
1267
|
+
};
|
|
1268
|
+
htmlRefine(htmlAst, { registerHtmlMutation });
|
|
1269
|
+
for (const htmlMutationCallback of htmlMutationCallbackSet) {
|
|
1270
|
+
htmlMutationCallback();
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
// cleanup jsenv attributes from html as a last step
|
|
1274
|
+
urlInfo.content = stringifyHtmlAst(htmlAst, {
|
|
1275
|
+
cleanupJsenvAttributes: true,
|
|
1276
|
+
cleanupPositionAttributes: true,
|
|
1277
|
+
});
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
inject_urls_in_service_workers: {
|
|
1282
|
+
const inject =
|
|
1283
|
+
buildSpecifierManager.prepareServiceWorkerUrlInjection();
|
|
1284
|
+
if (inject) {
|
|
1285
|
+
await inject();
|
|
1286
|
+
buildOperation.throwIfAborted();
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
const {
|
|
1291
|
+
buildFileContents,
|
|
1292
|
+
buildFileVersions,
|
|
1293
|
+
buildInlineContents,
|
|
1294
|
+
buildManifest,
|
|
1295
|
+
} = buildSpecifierManager.getBuildInfo();
|
|
1296
|
+
if (versioning && assetManifest && Object.keys(buildManifest).length) {
|
|
1297
|
+
buildFileContents[assetManifestFileRelativeUrl] = JSON.stringify(
|
|
1298
|
+
buildManifest,
|
|
1299
|
+
null,
|
|
1300
|
+
" ",
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
return {
|
|
1304
|
+
buildFileContents,
|
|
1305
|
+
buildFileVersions,
|
|
1306
|
+
buildInlineContents,
|
|
1307
|
+
buildManifest,
|
|
1308
|
+
};
|
|
1309
|
+
},
|
|
1310
|
+
};
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
const isBareSpecifier = (specifier) => {
|
|
1314
|
+
if (
|
|
1315
|
+
specifier[0] === "/" ||
|
|
1316
|
+
specifier.startsWith("./") ||
|
|
1317
|
+
specifier.startsWith("../")
|
|
1318
|
+
) {
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
try {
|
|
1322
|
+
// eslint-disable-next-line no-new
|
|
1323
|
+
new URL(specifier);
|
|
1324
|
+
return false;
|
|
1325
|
+
} catch {
|
|
1326
|
+
return true;
|
|
1327
|
+
}
|
|
1328
|
+
};
|