@jsenv/core 27.0.0-alpha.82 → 27.0.0-alpha.85
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/js/event_source_client.js +208 -4
- package/dist/js/s.js +2 -2
- package/dist/main.js +1430 -615
- package/dist/s.js +2 -2
- package/dist/s.js.map +2 -1
- package/package.json +6 -2
- package/src/build/build.js +5 -8
- package/src/build/build_urls_generator.js +1 -2
- package/src/build/inject_global_version_mappings.js +4 -4
- package/src/build/inject_service_worker_urls.js +2 -2
- package/src/build/resync_ressource_hints.js +17 -18
- package/src/build/start_build_server.js +33 -26
- package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +1 -2
- package/src/dev/plugins/toolbar/client/util/fetching.js +1 -1
- package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -3
- package/src/dev/start_dev_server.js +38 -30
- package/src/execute/runtimes/browsers/from_playwright.js +5 -4
- package/src/execute/runtimes/node/node_process.js +2 -2
- package/src/helpers/command/command.js +73 -0
- package/src/helpers/event_source/event_source.js +197 -0
- package/src/helpers/event_source/sse_service.js +53 -0
- package/src/helpers/worker_reload.js +57 -0
- package/src/omega/compat/runtime_compat.js +2 -1
- package/src/omega/kitchen.js +4 -1
- package/src/omega/server/user_agent.js +2 -1
- package/src/omega/url_graph/sort_by_dependencies.js +27 -0
- package/src/omega/url_graph/url_info_transformations.js +24 -14
- package/src/plugins/autoreload/dev_sse/client/event_source_client.js +1 -1
- package/src/plugins/autoreload/dev_sse/client/reload.js +6 -3
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +3 -3
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +1 -1
- package/src/plugins/bundling/css/bundle_css.js +4 -4
- package/src/plugins/bundling/js_module/bundle_js_module.js +86 -67
- package/src/plugins/commonjs_globals/jsenv_plugin_commonjs_globals.js +2 -2
- package/src/plugins/file_urls/jsenv_plugin_file_urls.js +4 -5
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +62 -74
- package/src/plugins/import_meta_hot/html_hot_dependencies.js +9 -15
- package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +3 -3
- package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +2 -2
- package/src/plugins/importmap/jsenv_plugin_importmap.js +25 -27
- package/src/plugins/inject_globals/inject_globals.js +4 -4
- package/src/plugins/inline/jsenv_plugin_data_urls.js +1 -1
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +41 -43
- package/src/plugins/inline/jsenv_plugin_js_inline_content.js +4 -4
- package/src/plugins/minification/css/minify_css.js +1 -1
- package/src/plugins/transpilation/as_js_classic/client/s.js +2 -2
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +2 -4
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +45 -67
- package/src/plugins/transpilation/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +2 -3
- package/src/plugins/transpilation/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +3 -4
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +1 -1
- package/src/plugins/transpilation/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +2 -3
- package/src/plugins/transpilation/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +2 -3
- package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +1 -1
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +1 -1
- package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +2 -1
- package/src/plugins/url_analysis/css/css_urls.js +2 -3
- package/src/plugins/url_analysis/html/html_urls.js +98 -113
- package/src/plugins/url_analysis/js/js_urls.js +3 -2
- package/src/test/coverage/babel_plugin_instrument.js +82 -0
- package/src/test/coverage/coverage_reporter_html_directory.js +36 -0
- package/src/test/coverage/coverage_reporter_json_file.js +22 -0
- package/src/test/coverage/coverage_reporter_text_log.js +19 -0
- package/src/test/coverage/empty_coverage_factory.js +52 -0
- package/src/test/coverage/file_by_file_coverage.js +25 -0
- package/src/test/coverage/istanbul_coverage_composition.js +28 -0
- package/src/test/coverage/istanbul_coverage_map_from_coverage.js +16 -0
- package/src/test/coverage/list_files_not_covered.js +15 -0
- package/src/test/coverage/missing_coverage.js +41 -0
- package/src/test/coverage/report_to_coverage.js +196 -0
- package/src/test/coverage/v8_and_istanbul.js +37 -0
- package/src/test/coverage/v8_coverage_composition.js +24 -0
- package/src/test/coverage/v8_coverage_from_directory.js +87 -0
- package/src/test/coverage/v8_coverage_to_istanbul.js +99 -0
- package/src/test/execute_plan.js +2 -2
- package/src/test/execute_test_plan.js +3 -3
package/dist/main.js
CHANGED
|
@@ -1,56 +1,89 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { registerFileLifecycle, readFileSync as readFileSync$1, bufferToEtag, writeFileSync, ensureWindowsDriveLetter, collectFiles, assertAndNormalizeDirectoryUrl, registerDirectoryLifecycle, writeFile, ensureEmptyDirectory, writeDirectory } from "@jsenv/filesystem";
|
|
3
|
-
import {
|
|
1
|
+
import { createSSERoom, timeStart, fetchFileSystem, composeTwoResponses, serveDirectory, startServer, pluginCORS, jsenvAccessControlAllowedHeaders, pluginServerTiming, pluginRequestWaitingCheck, composeServices, findFreePort } from "@jsenv/server";
|
|
2
|
+
import { registerFileLifecycle, readFileSync as readFileSync$1, bufferToEtag, writeFileSync, ensureWindowsDriveLetter, collectFiles, assertAndNormalizeDirectoryUrl, registerDirectoryLifecycle, writeFile, readFile, readDirectory, ensureEmptyDirectory, writeDirectory } from "@jsenv/filesystem";
|
|
3
|
+
import { createCallbackListNotifiedOnce, createCallbackList, Abort, raceProcessTeardownEvents, raceCallbacks } from "@jsenv/abort";
|
|
4
|
+
import { createDetailedMessage, createLogger, createTaskLog, loggerToLevels, byteAsFileSize, ANSI, msAsDuration, msAsEllapsedTime, byteAsMemoryUsage, UNICODE, createLog, startSpinner, distributePercentages } from "@jsenv/log";
|
|
4
5
|
import { urlToRelativeUrl, generateInlineContentUrl, ensurePathnameTrailingSlash, urlIsInsideOf, urlToFilename, DATA_URL, injectQueryParams, injectQueryParamsIntoSpecifier, fileSystemPathToUrl, urlToFileSystemPath, isFileSystemPath, normalizeUrl, stringifyUrlSite, setUrlFilename, moveUrl, getCallerPosition, resolveUrl, resolveDirectoryUrl, asUrlWithoutSearch, asUrlUntilPathname, urlToBasename, urlToExtension } from "@jsenv/urls";
|
|
5
|
-
import {
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { workerData, Worker } from "node:worker_threads";
|
|
6
8
|
import { URL_META } from "@jsenv/url-meta";
|
|
7
|
-
import { parseHtmlString, stringifyHtmlAst,
|
|
8
|
-
import {
|
|
9
|
-
import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js";
|
|
10
|
-
import { applyPostCss } from "@jsenv/utils/css_ast/apply_post_css.js";
|
|
11
|
-
import { postCssPluginUrlVisitor } from "@jsenv/utils/css_ast/postcss_plugin_url_visitor.js";
|
|
12
|
-
import { parseJsUrls } from "@jsenv/utils/js_ast/parse_js_urls.js";
|
|
9
|
+
import { parseHtmlString, stringifyHtmlAst, visitHtmlNodes, getHtmlNodeAttribute, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, findHtmlNode, getHtmlNodeText, removeHtmlNode, setHtmlNodeText, analyzeScriptNode, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode } from "@jsenv/ast";
|
|
10
|
+
import { createMagicSource, composeTwoSourcemaps, sourcemapConverter, SOURCEMAP, generateSourcemapFileUrl, generateSourcemapDataUrl } from "@jsenv/sourcemap";
|
|
13
11
|
import { resolveImport, normalizeImportMap, composeTwoImportMaps } from "@jsenv/importmap";
|
|
14
12
|
import { applyNodeEsmResolution, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, applyFileSystemMagicResolution, getExtensionsToTry } from "@jsenv/node-esm-resolution";
|
|
15
13
|
import { statSync, realpathSync, readdirSync, readFileSync, existsSync } from "node:fs";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { JS_QUOTES } from "@jsenv/utils/string/js_quotes.js";
|
|
19
|
-
import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js";
|
|
20
|
-
import { transpileWithParcel, minifyWithParcel } from "@jsenv/utils/css_ast/parcel_css.js";
|
|
14
|
+
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
|
|
15
|
+
import { JS_QUOTES } from "@jsenv/utils/src/string/js_quotes.js";
|
|
21
16
|
import { createRequire } from "node:module";
|
|
22
|
-
import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_composition_v3.js";
|
|
23
17
|
import babelParser from "@babel/parser";
|
|
24
|
-
import { findHighestVersion } from "@jsenv/utils/semantic_versioning/highest_version.js";
|
|
25
|
-
import { injectImport } from "@jsenv/utils/js_ast/babel_utils.js";
|
|
26
|
-
import { sortByDependencies } from "@jsenv/utils/graph/sort_by_dependencies.js";
|
|
27
|
-
import { applyRollupPlugins } from "@jsenv/utils/js_ast/apply_rollup_plugins.js";
|
|
28
|
-
import { sourcemapConverter } from "@jsenv/utils/sourcemap/sourcemap_converter.js";
|
|
29
|
-
import { createCallbackList, createCallbackListNotifiedOnce, Abort, raceCallbacks, raceProcessTeardownEvents } from "@jsenv/abort";
|
|
30
|
-
import { createSSEService } from "@jsenv/utils/event_source/sse_service.js";
|
|
31
|
-
import { timeStart, fetchFileSystem, composeTwoResponses, serveDirectory, startServer, pluginCORS, jsenvAccessControlAllowedHeaders, pluginServerTiming, pluginRequestWaitingCheck, composeServices, findFreePort } from "@jsenv/server";
|
|
32
|
-
import { SOURCEMAP, generateSourcemapUrl, sourcemapToBase64Url } from "@jsenv/utils/sourcemap/sourcemap_utils.js";
|
|
18
|
+
import { findHighestVersion } from "@jsenv/utils/src/semantic_versioning/highest_version.js";
|
|
33
19
|
import { validateResponseIntegrity } from "@jsenv/integrity";
|
|
34
20
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
|
|
35
|
-
import { memoizeByFirstArgument } from "@jsenv/utils/memoize/memoize_by_first_argument.js";
|
|
36
|
-
import { generateCoverageJsonFile } from "@jsenv/utils/coverage/coverage_reporter_json_file.js";
|
|
37
|
-
import { generateCoverageHtmlDirectory } from "@jsenv/utils/coverage/coverage_reporter_html_directory.js";
|
|
38
|
-
import { generateCoverageTextLog } from "@jsenv/utils/coverage/coverage_reporter_text_log.js";
|
|
21
|
+
import { memoizeByFirstArgument } from "@jsenv/utils/src/memoize/memoize_by_first_argument.js";
|
|
39
22
|
import { memoryUsage } from "node:process";
|
|
40
23
|
import wrapAnsi from "wrap-ansi";
|
|
41
24
|
import stripAnsi from "strip-ansi";
|
|
42
25
|
import cuid from "cuid";
|
|
43
|
-
import { babelPluginInstrument } from "@jsenv/utils/coverage/babel_plugin_instrument.js";
|
|
44
|
-
import { reportToCoverage } from "@jsenv/utils/coverage/report_to_coverage.js";
|
|
45
26
|
import v8 from "node:v8";
|
|
46
27
|
import { runInNewContext, Script } from "node:vm";
|
|
47
|
-
import { memoize } from "@jsenv/utils/memoize/memoize.js";
|
|
48
|
-
import {
|
|
49
|
-
import { composeTwoFileByFileIstanbulCoverages } from "@jsenv/utils/coverage/istanbul_coverage_composition.js";
|
|
50
|
-
import { escapeRegexpSpecialChars } from "@jsenv/utils/string/escape_regexp_special_chars.js";
|
|
28
|
+
import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
|
|
29
|
+
import { escapeRegexpSpecialChars } from "@jsenv/utils/src/string/escape_regexp_special_chars.js";
|
|
51
30
|
import { fork } from "node:child_process";
|
|
52
31
|
import { uneval } from "@jsenv/uneval";
|
|
53
|
-
import { createVersionGenerator } from "@jsenv/utils/versioning/version_generator.js";
|
|
32
|
+
import { createVersionGenerator } from "@jsenv/utils/src/versioning/version_generator.js";
|
|
33
|
+
|
|
34
|
+
const createReloadableWorker = (workerFileUrl, options = {}) => {
|
|
35
|
+
const workerFilePath = fileURLToPath(workerFileUrl);
|
|
36
|
+
const isPrimary = !workerData || workerData.workerFilePath !== workerFilePath;
|
|
37
|
+
let worker;
|
|
38
|
+
|
|
39
|
+
const terminate = async () => {
|
|
40
|
+
if (worker) {
|
|
41
|
+
let _worker = worker;
|
|
42
|
+
worker = null;
|
|
43
|
+
const exitPromise = new Promise(resolve => {
|
|
44
|
+
_worker.once("exit", resolve);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
_worker.terminate();
|
|
48
|
+
|
|
49
|
+
await exitPromise;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const load = async () => {
|
|
54
|
+
if (!isPrimary) {
|
|
55
|
+
throw new Error(`worker can be loaded from primary file only`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
worker = new Worker(workerFilePath, { ...options,
|
|
59
|
+
workerData: { ...options.workerData,
|
|
60
|
+
workerFilePath
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
worker.once("error", error => {
|
|
64
|
+
console.error(error);
|
|
65
|
+
});
|
|
66
|
+
await new Promise(resolve => {
|
|
67
|
+
worker.once("online", resolve);
|
|
68
|
+
});
|
|
69
|
+
worker.once("exit", () => {
|
|
70
|
+
worker = null;
|
|
71
|
+
});
|
|
72
|
+
return worker;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const reload = async () => {
|
|
76
|
+
await terminate();
|
|
77
|
+
await load();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
isPrimary,
|
|
82
|
+
load,
|
|
83
|
+
reload,
|
|
84
|
+
terminate
|
|
85
|
+
};
|
|
86
|
+
};
|
|
54
87
|
|
|
55
88
|
const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
56
89
|
const url = urlInfo.originalUrl;
|
|
@@ -74,9 +107,14 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
74
107
|
column,
|
|
75
108
|
originalLine,
|
|
76
109
|
originalColumn,
|
|
77
|
-
|
|
78
|
-
|
|
110
|
+
node,
|
|
111
|
+
attributeName,
|
|
112
|
+
specifier
|
|
79
113
|
}) => {
|
|
114
|
+
const {
|
|
115
|
+
crossorigin,
|
|
116
|
+
integrity
|
|
117
|
+
} = readFetchMetas(node);
|
|
80
118
|
const isRessourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(subtype);
|
|
81
119
|
const [reference] = referenceUtils.found({
|
|
82
120
|
type,
|
|
@@ -86,10 +124,14 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
86
124
|
specifier,
|
|
87
125
|
specifierLine: line,
|
|
88
126
|
specifierColumn: column,
|
|
89
|
-
isRessourceHint
|
|
127
|
+
isRessourceHint,
|
|
128
|
+
crossorigin,
|
|
129
|
+
integrity
|
|
90
130
|
});
|
|
91
131
|
actions.push(async () => {
|
|
92
|
-
|
|
132
|
+
setHtmlNodeAttributes(node, {
|
|
133
|
+
[attributeName]: await referenceUtils.readGeneratedSpecifier(reference)
|
|
134
|
+
});
|
|
93
135
|
});
|
|
94
136
|
}
|
|
95
137
|
});
|
|
@@ -103,6 +145,24 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
103
145
|
content: stringifyHtmlAst(htmlAst)
|
|
104
146
|
};
|
|
105
147
|
};
|
|
148
|
+
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"];
|
|
149
|
+
const integrityCompatibleTagNames = ["script", "link", "img", "source"];
|
|
150
|
+
|
|
151
|
+
const readFetchMetas = node => {
|
|
152
|
+
const meta = {};
|
|
153
|
+
|
|
154
|
+
if (crossOriginCompatibleTagNames.includes(node.nodeName)) {
|
|
155
|
+
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
156
|
+
meta.crossorigin = crossorigin;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
160
|
+
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
161
|
+
meta.integrity = integrity;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return meta;
|
|
165
|
+
};
|
|
106
166
|
|
|
107
167
|
const visitHtmlUrls = ({
|
|
108
168
|
url,
|
|
@@ -114,18 +174,18 @@ const visitHtmlUrls = ({
|
|
|
114
174
|
subtype,
|
|
115
175
|
expectedType,
|
|
116
176
|
node,
|
|
117
|
-
|
|
177
|
+
attributeName,
|
|
118
178
|
specifier
|
|
119
179
|
}) => {
|
|
120
|
-
const generatedFromInlineContent =
|
|
180
|
+
const generatedFromInlineContent = getHtmlNodeAttribute(node, "generated-from-inline-content") !== undefined;
|
|
121
181
|
let position;
|
|
122
182
|
|
|
123
183
|
if (generatedFromInlineContent) {
|
|
124
184
|
// when generated from inline content,
|
|
125
185
|
// line, column is not "src" nor "generated-from-src" but "original-position"
|
|
126
|
-
position =
|
|
186
|
+
position = getHtmlNodePosition(node);
|
|
127
187
|
} else {
|
|
128
|
-
position =
|
|
188
|
+
position = getHtmlNodeAttributePosition(node, attributeName);
|
|
129
189
|
}
|
|
130
190
|
|
|
131
191
|
const {
|
|
@@ -141,19 +201,68 @@ const visitHtmlUrls = ({
|
|
|
141
201
|
column,
|
|
142
202
|
// originalLine, originalColumn
|
|
143
203
|
specifier,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// srcGeneratedFromInlineContent
|
|
147
|
-
...readFetchMetas(node)
|
|
204
|
+
node,
|
|
205
|
+
attributeName
|
|
148
206
|
});
|
|
149
207
|
};
|
|
150
208
|
|
|
151
|
-
const
|
|
209
|
+
const visitAttributeAsUrlSpecifier = ({
|
|
210
|
+
node,
|
|
211
|
+
attributeName,
|
|
212
|
+
...rest
|
|
213
|
+
}) => {
|
|
214
|
+
const value = getHtmlNodeAttribute(node, attributeName);
|
|
215
|
+
|
|
216
|
+
if (value) {
|
|
217
|
+
const generatedBy = getHtmlNodeAttribute(node, "generated-by");
|
|
218
|
+
|
|
219
|
+
if (generatedBy !== undefined) {
|
|
220
|
+
// during build the importmap is inlined
|
|
221
|
+
// and shoud not be considered as a dependency anymore
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
addDependency({ ...rest,
|
|
226
|
+
node,
|
|
227
|
+
attributeName,
|
|
228
|
+
specifier: attributeName === "generated-from-src" || attributeName === "generated-from-href" ? new URL(value, url).href : value
|
|
229
|
+
});
|
|
230
|
+
} else if (attributeName === "src") {
|
|
231
|
+
visitAttributeAsUrlSpecifier({ ...rest,
|
|
232
|
+
node,
|
|
233
|
+
attributeName: "generated-from-src"
|
|
234
|
+
});
|
|
235
|
+
} else if (attributeName === "href") {
|
|
236
|
+
visitAttributeAsUrlSpecifier({ ...rest,
|
|
237
|
+
node,
|
|
238
|
+
attributeName: "generated-from-href"
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const visitSrcset = ({
|
|
244
|
+
type,
|
|
245
|
+
node
|
|
246
|
+
}) => {
|
|
247
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
248
|
+
|
|
249
|
+
if (srcset) {
|
|
250
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
251
|
+
srcCandidates.forEach(srcCandidate => {
|
|
252
|
+
addDependency({
|
|
253
|
+
type,
|
|
254
|
+
node,
|
|
255
|
+
attributeName: "srcset",
|
|
256
|
+
specifier: srcCandidate.specifier
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
visitHtmlNodes(htmlAst, {
|
|
152
263
|
link: node => {
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const typeAttribute = getHtmlNodeAttributeByName(node, "type");
|
|
156
|
-
const type = typeAttribute ? typeAttribute.value : undefined;
|
|
264
|
+
const rel = getHtmlNodeAttribute(node, "rel");
|
|
265
|
+
const type = getHtmlNodeAttribute(node, "type");
|
|
157
266
|
visitAttributeAsUrlSpecifier({
|
|
158
267
|
type: "link_href",
|
|
159
268
|
subtype: rel,
|
|
@@ -169,15 +278,16 @@ const visitHtmlUrls = ({
|
|
|
169
278
|
},
|
|
170
279
|
// style: () => {},
|
|
171
280
|
script: node => {
|
|
172
|
-
const
|
|
281
|
+
const type = getHtmlNodeAttribute(node, "type");
|
|
282
|
+
const expectedType = {
|
|
283
|
+
"undefined": "js_classic",
|
|
284
|
+
"text/javascript": "js_classic",
|
|
285
|
+
"module": "js_module",
|
|
286
|
+
"importmap": "importmap"
|
|
287
|
+
}[type];
|
|
173
288
|
visitAttributeAsUrlSpecifier({
|
|
174
289
|
type: "script_src",
|
|
175
|
-
expectedType
|
|
176
|
-
"undefined": "js_classic",
|
|
177
|
-
"text/javascript": "js_classic",
|
|
178
|
-
"module": "js_module",
|
|
179
|
-
"importmap": "importmap"
|
|
180
|
-
}[typeAttributeNode ? typeAttributeNode.value : undefined],
|
|
290
|
+
expectedType,
|
|
181
291
|
node,
|
|
182
292
|
attributeName: "src"
|
|
183
293
|
});
|
|
@@ -233,102 +343,9 @@ const visitHtmlUrls = ({
|
|
|
233
343
|
attributeName: "href"
|
|
234
344
|
});
|
|
235
345
|
}
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const visitAttributeAsUrlSpecifier = ({
|
|
239
|
-
type,
|
|
240
|
-
subtype,
|
|
241
|
-
expectedType,
|
|
242
|
-
node,
|
|
243
|
-
attributeName
|
|
244
|
-
}) => {
|
|
245
|
-
const attribute = getHtmlNodeAttributeByName(node, attributeName);
|
|
246
|
-
const value = attribute ? attribute.value : undefined;
|
|
247
|
-
|
|
248
|
-
if (value) {
|
|
249
|
-
const generatedBy = getHtmlNodeAttributeByName(node, "generated-by");
|
|
250
|
-
|
|
251
|
-
if (generatedBy) {
|
|
252
|
-
// during build the importmap is inlined
|
|
253
|
-
// and shoud not be considered as a dependency anymore
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
addDependency({
|
|
258
|
-
type,
|
|
259
|
-
subtype,
|
|
260
|
-
expectedType,
|
|
261
|
-
node,
|
|
262
|
-
attribute,
|
|
263
|
-
specifier: attributeName === "generated-from-src" || attributeName === "generated-from-href" ? new URL(value, url).href : value
|
|
264
|
-
});
|
|
265
|
-
} else if (attributeName === "src") {
|
|
266
|
-
visitAttributeAsUrlSpecifier({
|
|
267
|
-
type,
|
|
268
|
-
subtype,
|
|
269
|
-
expectedType,
|
|
270
|
-
node,
|
|
271
|
-
attributeName: "generated-from-src"
|
|
272
|
-
});
|
|
273
|
-
} else if (attributeName === "href") {
|
|
274
|
-
visitAttributeAsUrlSpecifier({
|
|
275
|
-
type,
|
|
276
|
-
subtype,
|
|
277
|
-
expectedType,
|
|
278
|
-
node,
|
|
279
|
-
attributeName: "generated-from-href"
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const visitSrcset = ({
|
|
285
|
-
type,
|
|
286
|
-
node
|
|
287
|
-
}) => {
|
|
288
|
-
const srcsetAttribute = getHtmlNodeAttributeByName(node, "srcset");
|
|
289
|
-
const srcset = srcsetAttribute ? srcsetAttribute.value : undefined;
|
|
290
|
-
|
|
291
|
-
if (srcset) {
|
|
292
|
-
const srcCandidates = htmlAttributeSrcSet.parse(srcset);
|
|
293
|
-
srcCandidates.forEach(srcCandidate => {
|
|
294
|
-
addDependency({
|
|
295
|
-
type,
|
|
296
|
-
node,
|
|
297
|
-
attribute: srcsetAttribute,
|
|
298
|
-
specifier: srcCandidate.specifier
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
visitHtmlAst(htmlAst, node => {
|
|
305
|
-
const visitor = visitors[node.nodeName];
|
|
306
|
-
|
|
307
|
-
if (visitor) {
|
|
308
|
-
visitor(node);
|
|
309
|
-
}
|
|
310
346
|
});
|
|
311
347
|
};
|
|
312
348
|
|
|
313
|
-
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"];
|
|
314
|
-
const integrityCompatibleTagNames = ["script", "link", "img", "source"];
|
|
315
|
-
|
|
316
|
-
const readFetchMetas = node => {
|
|
317
|
-
const meta = {};
|
|
318
|
-
|
|
319
|
-
if (crossOriginCompatibleTagNames.includes(node.nodeName)) {
|
|
320
|
-
const crossoriginAttribute = getHtmlNodeAttributeByName(node, "crossorigin");
|
|
321
|
-
meta.crossorigin = crossoriginAttribute ? crossoriginAttribute.value : undefined;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (integrityCompatibleTagNames.includes(node.nodeName)) {
|
|
325
|
-
const integrityAttribute = getHtmlNodeAttributeByName(node, "integrity");
|
|
326
|
-
meta.integrity = integrityAttribute ? integrityAttribute.value : undefined;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return meta;
|
|
330
|
-
};
|
|
331
|
-
|
|
332
349
|
/*
|
|
333
350
|
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
334
351
|
*/
|
|
@@ -704,14 +721,14 @@ const jsenvPluginImportmap = () => {
|
|
|
704
721
|
transformUrlContent: {
|
|
705
722
|
html: async (htmlUrlInfo, context) => {
|
|
706
723
|
const htmlAst = parseHtmlString(htmlUrlInfo.content);
|
|
707
|
-
const importmap =
|
|
724
|
+
const importmap = findHtmlNode(htmlAst, node => {
|
|
708
725
|
if (node.nodeName !== "script") {
|
|
709
726
|
return false;
|
|
710
727
|
}
|
|
711
728
|
|
|
712
|
-
const
|
|
729
|
+
const type = getHtmlNodeAttribute(node, "type");
|
|
713
730
|
|
|
714
|
-
if (
|
|
731
|
+
if (type === undefined || type !== "importmap") {
|
|
715
732
|
return false;
|
|
716
733
|
}
|
|
717
734
|
|
|
@@ -730,7 +747,7 @@ const jsenvPluginImportmap = () => {
|
|
|
730
747
|
lineEnd,
|
|
731
748
|
columnEnd,
|
|
732
749
|
isOriginal
|
|
733
|
-
} =
|
|
750
|
+
} = getHtmlNodePosition(importmap, {
|
|
734
751
|
preferOriginal: true
|
|
735
752
|
});
|
|
736
753
|
const inlineImportmapUrl = generateInlineContentUrl({
|
|
@@ -753,9 +770,9 @@ const jsenvPluginImportmap = () => {
|
|
|
753
770
|
await context.cook(inlineImportmapUrlInfo, {
|
|
754
771
|
reference: inlineImportmapReference
|
|
755
772
|
});
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
773
|
+
setHtmlNodeText(importmap, inlineImportmapUrlInfo.content);
|
|
774
|
+
setHtmlNodeAttributes(importmap, {
|
|
775
|
+
"generated-by": "jsenv:importmap"
|
|
759
776
|
});
|
|
760
777
|
onHtmlImportmapParsed(JSON.parse(inlineImportmapUrlInfo.content), htmlUrlInfo.url);
|
|
761
778
|
};
|
|
@@ -772,11 +789,11 @@ const jsenvPluginImportmap = () => {
|
|
|
772
789
|
reference: importmapReference
|
|
773
790
|
});
|
|
774
791
|
onHtmlImportmapParsed(JSON.parse(importmapUrlInfo.content), htmlUrlInfo.url);
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
792
|
+
setHtmlNodeText(importmap, importmapUrlInfo.content);
|
|
793
|
+
setHtmlNodeAttributes(importmap, {
|
|
794
|
+
"src": undefined,
|
|
795
|
+
"generated-by": "jsenv:importmap",
|
|
796
|
+
"generated-from-src": src
|
|
780
797
|
});
|
|
781
798
|
const {
|
|
782
799
|
line,
|
|
@@ -784,7 +801,7 @@ const jsenvPluginImportmap = () => {
|
|
|
784
801
|
lineEnd,
|
|
785
802
|
columnEnd,
|
|
786
803
|
isOriginal
|
|
787
|
-
} =
|
|
804
|
+
} = getHtmlNodePosition(importmap, {
|
|
788
805
|
preferOriginal: true
|
|
789
806
|
});
|
|
790
807
|
const inlineImportmapUrl = generateInlineContentUrl({
|
|
@@ -805,16 +822,15 @@ const jsenvPluginImportmap = () => {
|
|
|
805
822
|
});
|
|
806
823
|
};
|
|
807
824
|
|
|
808
|
-
const
|
|
809
|
-
const src = srcAttribute ? srcAttribute.value : undefined;
|
|
825
|
+
const src = getHtmlNodeAttribute(importmap, "src");
|
|
810
826
|
|
|
811
827
|
if (src) {
|
|
812
828
|
await handleImportmapWithSrc(importmap, src);
|
|
813
829
|
} else {
|
|
814
|
-
const
|
|
830
|
+
const htmlNodeText = getHtmlNodeText(importmap);
|
|
815
831
|
|
|
816
|
-
if (
|
|
817
|
-
await handleInlineImportmap(importmap,
|
|
832
|
+
if (htmlNodeText) {
|
|
833
|
+
await handleInlineImportmap(importmap, htmlNodeText);
|
|
818
834
|
}
|
|
819
835
|
} // once this plugin knows the importmap, it will use it
|
|
820
836
|
// to map imports. These import specifiers will be normalized
|
|
@@ -1063,7 +1079,7 @@ const jsenvPluginUrlVersion = () => {
|
|
|
1063
1079
|
const jsenvPluginFileUrls = ({
|
|
1064
1080
|
magicExtensions = ["inherit", ".js"],
|
|
1065
1081
|
magicDirectoryIndex = true,
|
|
1066
|
-
|
|
1082
|
+
preserveSymlinks = false,
|
|
1067
1083
|
directoryReferenceAllowed = false
|
|
1068
1084
|
}) => {
|
|
1069
1085
|
return [{
|
|
@@ -1118,7 +1134,7 @@ const jsenvPluginFileUrls = ({
|
|
|
1118
1134
|
if (foundADirectory && directoryReferenceAllowed) {
|
|
1119
1135
|
reference.data.foundADirectory = true;
|
|
1120
1136
|
const directoryFacadeUrl = urlObject.href;
|
|
1121
|
-
const directoryUrlRaw =
|
|
1137
|
+
const directoryUrlRaw = preserveSymlinks ? directoryFacadeUrl : resolveSymlink(directoryFacadeUrl);
|
|
1122
1138
|
const directoryUrl = `${directoryUrlRaw}${search}${hash}`;
|
|
1123
1139
|
return directoryUrl;
|
|
1124
1140
|
}
|
|
@@ -1137,7 +1153,7 @@ const jsenvPluginFileUrls = ({
|
|
|
1137
1153
|
|
|
1138
1154
|
reference.data.foundADirectory = filesystemResolution.isDirectory;
|
|
1139
1155
|
const fileFacadeUrl = filesystemResolution.url;
|
|
1140
|
-
const fileUrlRaw =
|
|
1156
|
+
const fileUrlRaw = preserveSymlinks ? fileFacadeUrl : resolveSymlink(fileFacadeUrl);
|
|
1141
1157
|
const fileUrl = `${fileUrlRaw}${search}${hash}`;
|
|
1142
1158
|
return fileUrl;
|
|
1143
1159
|
}
|
|
@@ -1257,13 +1273,9 @@ const jsenvPluginHtmlInlineContent = ({
|
|
|
1257
1273
|
const actions = [];
|
|
1258
1274
|
|
|
1259
1275
|
const handleInlineStyle = node => {
|
|
1260
|
-
|
|
1261
|
-
return;
|
|
1262
|
-
}
|
|
1276
|
+
const htmlNodeText = getHtmlNodeText(node);
|
|
1263
1277
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
if (!textNode) {
|
|
1278
|
+
if (!htmlNodeText) {
|
|
1267
1279
|
return;
|
|
1268
1280
|
}
|
|
1269
1281
|
|
|
@@ -1274,7 +1286,7 @@ const jsenvPluginHtmlInlineContent = ({
|
|
|
1274
1286
|
lineEnd,
|
|
1275
1287
|
columnEnd,
|
|
1276
1288
|
isOriginal
|
|
1277
|
-
} =
|
|
1289
|
+
} = getHtmlNodePosition(node, {
|
|
1278
1290
|
preferOriginal: true
|
|
1279
1291
|
});
|
|
1280
1292
|
const inlineStyleUrl = generateInlineContentUrl({
|
|
@@ -1296,55 +1308,47 @@ const jsenvPluginHtmlInlineContent = ({
|
|
|
1296
1308
|
specifierColumn: column,
|
|
1297
1309
|
specifier: inlineStyleUrl,
|
|
1298
1310
|
contentType: "text/css",
|
|
1299
|
-
content:
|
|
1311
|
+
content: htmlNodeText
|
|
1300
1312
|
});
|
|
1301
1313
|
await context.cook(inlineStyleUrlInfo, {
|
|
1302
1314
|
reference: inlineStyleReference
|
|
1303
1315
|
});
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1316
|
+
setHtmlNodeText(node, inlineStyleUrlInfo.content);
|
|
1317
|
+
setHtmlNodeAttributes(node, {
|
|
1318
|
+
"generated-by": "jsenv:html_inline_content"
|
|
1307
1319
|
});
|
|
1308
1320
|
});
|
|
1309
1321
|
};
|
|
1310
1322
|
|
|
1311
1323
|
const handleInlineScript = node => {
|
|
1312
|
-
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1324
|
+
const htmlNodeText = getHtmlNodeText(node);
|
|
1315
1325
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
if (!textNode) {
|
|
1326
|
+
if (!htmlNodeText) {
|
|
1319
1327
|
return;
|
|
1320
1328
|
} // If the inline script was already handled by an other plugin, ignore it
|
|
1321
1329
|
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
1322
1330
|
// - we want to avoid cooking twice a script during build
|
|
1323
1331
|
|
|
1324
1332
|
|
|
1325
|
-
const generatedBy =
|
|
1333
|
+
const generatedBy = getHtmlNodeAttribute(node, "generated-by");
|
|
1326
1334
|
|
|
1327
|
-
if (generatedBy) {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1335
|
+
if (generatedBy === "jsenv:as_js_classic_html" && !analyzeConvertedScripts) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1333
1338
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
}
|
|
1339
|
+
if (generatedBy === "jsenv:html_supervisor") {
|
|
1340
|
+
return;
|
|
1337
1341
|
}
|
|
1338
1342
|
|
|
1339
1343
|
actions.push(async () => {
|
|
1340
|
-
const scriptCategory =
|
|
1344
|
+
const scriptCategory = analyzeScriptNode(node);
|
|
1341
1345
|
const {
|
|
1342
1346
|
line,
|
|
1343
1347
|
column,
|
|
1344
1348
|
lineEnd,
|
|
1345
1349
|
columnEnd,
|
|
1346
1350
|
isOriginal
|
|
1347
|
-
} =
|
|
1351
|
+
} = getHtmlNodePosition(node, {
|
|
1348
1352
|
preferOriginal: true
|
|
1349
1353
|
}); // from MDN about [type] attribute:
|
|
1350
1354
|
// "Any other value: The embedded content is treated as a data block
|
|
@@ -1380,21 +1384,25 @@ const jsenvPluginHtmlInlineContent = ({
|
|
|
1380
1384
|
isOriginalPosition: isOriginal,
|
|
1381
1385
|
specifier: inlineScriptUrl,
|
|
1382
1386
|
contentType,
|
|
1383
|
-
content:
|
|
1387
|
+
content: htmlNodeText
|
|
1384
1388
|
});
|
|
1385
1389
|
await context.cook(inlineScriptUrlInfo, {
|
|
1386
1390
|
reference: inlineScriptReference
|
|
1387
1391
|
});
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1392
|
+
setHtmlNodeText(node, inlineScriptUrlInfo.content);
|
|
1393
|
+
setHtmlNodeAttributes(node, {
|
|
1394
|
+
"generated-by": "jsenv:html_inline_content"
|
|
1391
1395
|
});
|
|
1392
1396
|
});
|
|
1393
1397
|
};
|
|
1394
1398
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1399
|
+
visitHtmlNodes(htmlAst, {
|
|
1400
|
+
style: node => {
|
|
1401
|
+
handleInlineStyle(node);
|
|
1402
|
+
},
|
|
1403
|
+
script: node => {
|
|
1404
|
+
handleInlineScript(node);
|
|
1405
|
+
}
|
|
1398
1406
|
});
|
|
1399
1407
|
|
|
1400
1408
|
if (actions.length === 0) {
|
|
@@ -1934,15 +1942,15 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
1934
1942
|
const htmlAst = parseHtmlString(content);
|
|
1935
1943
|
const scriptsToSupervise = [];
|
|
1936
1944
|
|
|
1937
|
-
const handleInlineScript = (node,
|
|
1938
|
-
const scriptCategory =
|
|
1945
|
+
const handleInlineScript = (node, htmlNodeText) => {
|
|
1946
|
+
const scriptCategory = analyzeScriptNode(node);
|
|
1939
1947
|
const {
|
|
1940
1948
|
line,
|
|
1941
1949
|
column,
|
|
1942
1950
|
lineEnd,
|
|
1943
1951
|
columnEnd,
|
|
1944
1952
|
isOriginal
|
|
1945
|
-
} =
|
|
1953
|
+
} = getHtmlNodePosition(node, {
|
|
1946
1954
|
preferOriginal: true
|
|
1947
1955
|
});
|
|
1948
1956
|
let inlineScriptUrl = generateInlineContentUrl({
|
|
@@ -1964,7 +1972,7 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
1964
1972
|
specifierColumn: column,
|
|
1965
1973
|
specifier: inlineScriptUrl,
|
|
1966
1974
|
contentType: "text/javascript",
|
|
1967
|
-
content:
|
|
1975
|
+
content: htmlNodeText
|
|
1968
1976
|
});
|
|
1969
1977
|
removeHtmlNodeText(node);
|
|
1970
1978
|
scriptsToSupervise.push({
|
|
@@ -1975,21 +1983,19 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
1975
1983
|
});
|
|
1976
1984
|
};
|
|
1977
1985
|
|
|
1978
|
-
const handleScriptWithSrc = (node,
|
|
1979
|
-
const scriptCategory =
|
|
1980
|
-
const
|
|
1981
|
-
const
|
|
1982
|
-
const
|
|
1983
|
-
const
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
const async = asyncAttribute ? asyncAttribute.value : undefined;
|
|
1988
|
-
removeHtmlNodeAttributeByName(node, "src");
|
|
1986
|
+
const handleScriptWithSrc = (node, src) => {
|
|
1987
|
+
const scriptCategory = analyzeScriptNode(node);
|
|
1988
|
+
const integrity = getHtmlNodeAttribute(node, "integrity");
|
|
1989
|
+
const crossorigin = getHtmlNodeAttribute(node, "crossorigin") !== undefined;
|
|
1990
|
+
const defer = getHtmlNodeAttribute(node, "defer") !== undefined;
|
|
1991
|
+
const async = getHtmlNodeAttribute(node, "async") !== undefined;
|
|
1992
|
+
setHtmlNodeAttributes(node, {
|
|
1993
|
+
src: undefined
|
|
1994
|
+
});
|
|
1989
1995
|
scriptsToSupervise.push({
|
|
1990
1996
|
node,
|
|
1991
1997
|
type: scriptCategory,
|
|
1992
|
-
src
|
|
1998
|
+
src,
|
|
1993
1999
|
defer,
|
|
1994
2000
|
async,
|
|
1995
2001
|
integrity,
|
|
@@ -1997,41 +2003,39 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
1997
2003
|
});
|
|
1998
2004
|
};
|
|
1999
2005
|
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
const scriptCategory = parseScriptNode(node);
|
|
2006
|
+
visitHtmlNodes(htmlAst, {
|
|
2007
|
+
script: node => {
|
|
2008
|
+
const scriptCategory = analyzeScriptNode(node);
|
|
2006
2009
|
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
+
if (scriptCategory !== "classic" && scriptCategory !== "module") {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2010
2013
|
|
|
2011
|
-
|
|
2014
|
+
const injectedBy = getHtmlNodeAttribute(node, "injected-by");
|
|
2012
2015
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
+
if (injectedBy !== undefined) {
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2016
2019
|
|
|
2017
|
-
|
|
2020
|
+
const noHtmlSupervisor = getHtmlNodeAttribute(node, "no-html-supervisor");
|
|
2018
2021
|
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
+
if (noHtmlSupervisor !== undefined) {
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2022
2025
|
|
|
2023
|
-
|
|
2026
|
+
const htmlNodeText = getHtmlNodeText(node);
|
|
2024
2027
|
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2028
|
+
if (htmlNodeText) {
|
|
2029
|
+
handleInlineScript(node, htmlNodeText);
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2029
2032
|
|
|
2030
|
-
|
|
2033
|
+
const src = getHtmlNodeAttribute(node, "src");
|
|
2031
2034
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
+
if (src) {
|
|
2036
|
+
handleScriptWithSrc(node, src);
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2035
2039
|
}
|
|
2036
2040
|
});
|
|
2037
2041
|
const [htmlSupervisorInstallerFileReference] = referenceUtils.inject({
|
|
@@ -2039,7 +2043,7 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
2039
2043
|
expectedType: "js_module",
|
|
2040
2044
|
specifier: htmlSupervisorInstallerFileUrl
|
|
2041
2045
|
});
|
|
2042
|
-
|
|
2046
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
2043
2047
|
"tagName": "script",
|
|
2044
2048
|
"type": "module",
|
|
2045
2049
|
"textContent": `
|
|
@@ -2055,7 +2059,7 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
2055
2059
|
expectedType: "js_classic",
|
|
2056
2060
|
specifier: htmlSupervisorSetupFileUrl
|
|
2057
2061
|
});
|
|
2058
|
-
|
|
2062
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
2059
2063
|
"tagName": "script",
|
|
2060
2064
|
"src": htmlSupervisorSetupFileReference.generatedSpecifier,
|
|
2061
2065
|
"injected-by": "jsenv:html_supervisor"
|
|
@@ -2070,20 +2074,24 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
2070
2074
|
integrity,
|
|
2071
2075
|
crossorigin
|
|
2072
2076
|
}) => {
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2077
|
+
setHtmlNodeText(node, generateCodeToSuperviseScript({
|
|
2078
|
+
type,
|
|
2079
|
+
src,
|
|
2080
|
+
isInline,
|
|
2081
|
+
defer,
|
|
2082
|
+
async,
|
|
2083
|
+
integrity,
|
|
2084
|
+
crossorigin,
|
|
2085
|
+
htmlSupervisorInstallerSpecifier: htmlSupervisorInstallerFileReference.generatedSpecifier
|
|
2086
|
+
}));
|
|
2087
|
+
setHtmlNodeAttributes(node, {
|
|
2088
|
+
"generated-by": "jsenv:html_supervisor",
|
|
2089
|
+
...(src ? {
|
|
2090
|
+
"generated-from-src": src
|
|
2091
|
+
} : {}),
|
|
2092
|
+
...(isInline ? {
|
|
2093
|
+
"generated-from-inline-content": ""
|
|
2094
|
+
} : {})
|
|
2087
2095
|
});
|
|
2088
2096
|
});
|
|
2089
2097
|
const htmlModified = stringifyHtmlAst(htmlAst);
|
|
@@ -2698,12 +2706,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2698
2706
|
const classicScriptNodes = [];
|
|
2699
2707
|
|
|
2700
2708
|
const visitLinkNodes = node => {
|
|
2701
|
-
|
|
2702
|
-
return;
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
const relAttribute = getHtmlNodeAttributeByName(node, "rel");
|
|
2706
|
-
const rel = relAttribute ? relAttribute.value : undefined;
|
|
2709
|
+
const rel = getHtmlNodeAttribute(node, "rel");
|
|
2707
2710
|
|
|
2708
2711
|
if (rel === "modulepreload") {
|
|
2709
2712
|
modulePreloadNodes.push(node);
|
|
@@ -2711,8 +2714,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2711
2714
|
}
|
|
2712
2715
|
|
|
2713
2716
|
if (rel === "preload") {
|
|
2714
|
-
const
|
|
2715
|
-
const asValue = asAttribute ? asAttribute.value : undefined;
|
|
2717
|
+
const asValue = getHtmlNodeAttribute(node, "as");
|
|
2716
2718
|
|
|
2717
2719
|
if (asValue === "script") {
|
|
2718
2720
|
preloadAsScriptNodes.push(node);
|
|
@@ -2723,12 +2725,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2723
2725
|
};
|
|
2724
2726
|
|
|
2725
2727
|
const visitScriptNodes = node => {
|
|
2726
|
-
|
|
2727
|
-
return;
|
|
2728
|
-
}
|
|
2729
|
-
|
|
2730
|
-
const typeAttribute = getHtmlNodeAttributeByName(node, "type");
|
|
2731
|
-
const type = typeAttribute ? typeAttribute.value : undefined;
|
|
2728
|
+
const type = getHtmlNodeAttribute(node, "type");
|
|
2732
2729
|
|
|
2733
2730
|
if (type === "module") {
|
|
2734
2731
|
moduleScriptNodes.push(node);
|
|
@@ -2741,9 +2738,13 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2741
2738
|
}
|
|
2742
2739
|
};
|
|
2743
2740
|
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2741
|
+
visitHtmlNodes(htmlAst, {
|
|
2742
|
+
link: node => {
|
|
2743
|
+
visitLinkNodes(node);
|
|
2744
|
+
},
|
|
2745
|
+
script: node => {
|
|
2746
|
+
visitScriptNodes(node);
|
|
2747
|
+
}
|
|
2747
2748
|
});
|
|
2748
2749
|
const actions = [];
|
|
2749
2750
|
const jsModuleUrls = [];
|
|
@@ -2785,10 +2786,10 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2785
2786
|
};
|
|
2786
2787
|
|
|
2787
2788
|
classicScriptNodes.forEach(classicScriptNode => {
|
|
2788
|
-
const
|
|
2789
|
+
const src = getHtmlNodeAttribute(classicScriptNode, "src");
|
|
2789
2790
|
|
|
2790
|
-
if (
|
|
2791
|
-
const reference = urlInfo.references.find(ref => ref.generatedSpecifier ===
|
|
2791
|
+
if (src !== undefined) {
|
|
2792
|
+
const reference = urlInfo.references.find(ref => ref.generatedSpecifier === src && ref.type === "script_src");
|
|
2792
2793
|
const urlObject = new URL(reference.url);
|
|
2793
2794
|
|
|
2794
2795
|
if (urlObject.searchParams.has("as_js_classic")) {
|
|
@@ -2807,10 +2808,10 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2807
2808
|
}
|
|
2808
2809
|
});
|
|
2809
2810
|
moduleScriptNodes.forEach(moduleScriptNode => {
|
|
2810
|
-
const
|
|
2811
|
+
const src = getHtmlNodeAttribute(moduleScriptNode, "src");
|
|
2811
2812
|
|
|
2812
|
-
if (
|
|
2813
|
-
const reference = urlInfo.references.find(ref => ref.generatedSpecifier ===
|
|
2813
|
+
if (src !== undefined) {
|
|
2814
|
+
const reference = urlInfo.references.find(ref => ref.generatedSpecifier === src && ref.type === "script_src" && ref.expectedType === "js_module");
|
|
2814
2815
|
jsModuleUrls.push(reference.url);
|
|
2815
2816
|
|
|
2816
2817
|
if (shouldTransformScriptTypeModule) {
|
|
@@ -2818,8 +2819,10 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2818
2819
|
const [newReference] = await getReferenceAsJsClassic(reference, {
|
|
2819
2820
|
cookIt: true
|
|
2820
2821
|
});
|
|
2821
|
-
|
|
2822
|
-
|
|
2822
|
+
setHtmlNodeAttributes(moduleScriptNode, {
|
|
2823
|
+
type: undefined,
|
|
2824
|
+
src: newReference.generatedSpecifier
|
|
2825
|
+
});
|
|
2823
2826
|
});
|
|
2824
2827
|
}
|
|
2825
2828
|
|
|
@@ -2827,7 +2830,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2827
2830
|
}
|
|
2828
2831
|
|
|
2829
2832
|
if (shouldTransformScriptTypeModule) {
|
|
2830
|
-
const
|
|
2833
|
+
const htmlNodeText = getHtmlNodeText(moduleScriptNode);
|
|
2831
2834
|
actions.push(async () => {
|
|
2832
2835
|
const {
|
|
2833
2836
|
line,
|
|
@@ -2835,7 +2838,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2835
2838
|
lineEnd,
|
|
2836
2839
|
columnEnd,
|
|
2837
2840
|
isOriginal
|
|
2838
|
-
} =
|
|
2841
|
+
} = getHtmlNodePosition(moduleScriptNode, {
|
|
2839
2842
|
preferOriginal: true
|
|
2840
2843
|
});
|
|
2841
2844
|
let inlineScriptUrl = generateInlineContentUrl({
|
|
@@ -2858,15 +2861,15 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2858
2861
|
specifierColumn: column,
|
|
2859
2862
|
specifier: inlineScriptUrl,
|
|
2860
2863
|
contentType: "text/javascript",
|
|
2861
|
-
content:
|
|
2864
|
+
content: htmlNodeText
|
|
2862
2865
|
});
|
|
2863
2866
|
const [, newUrlInfo] = await getReferenceAsJsClassic(inlineReference, {
|
|
2864
2867
|
cookIt: true
|
|
2865
2868
|
});
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2869
|
+
setHtmlNodeText(moduleScriptNode, newUrlInfo.content);
|
|
2870
|
+
setHtmlNodeAttributes(moduleScriptNode, {
|
|
2871
|
+
"type": undefined,
|
|
2872
|
+
"generated-by": "jsenv:as_js_classic_html"
|
|
2870
2873
|
});
|
|
2871
2874
|
});
|
|
2872
2875
|
}
|
|
@@ -2874,8 +2877,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2874
2877
|
|
|
2875
2878
|
if (shouldTransformScriptTypeModule) {
|
|
2876
2879
|
preloadAsScriptNodes.forEach(preloadAsScriptNode => {
|
|
2877
|
-
const
|
|
2878
|
-
const href = hrefAttribute.value;
|
|
2880
|
+
const href = getHtmlNodeAttribute(preloadAsScriptNode, "href");
|
|
2879
2881
|
const reference = urlInfo.references.find(ref => ref.generatedSpecifier === href && ref.type === "link_href" && ref.expectedType === undefined);
|
|
2880
2882
|
const expectedScriptType = jsModuleUrls.includes(reference.url) ? "module" : "classic";
|
|
2881
2883
|
|
|
@@ -2890,16 +2892,15 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2890
2892
|
[newReference] = await getReferenceAsJsClassic(reference);
|
|
2891
2893
|
}
|
|
2892
2894
|
|
|
2893
|
-
|
|
2894
|
-
href: newReference.generatedSpecifier
|
|
2895
|
+
setHtmlNodeAttributes(preloadAsScriptNode, {
|
|
2896
|
+
href: newReference.generatedSpecifier,
|
|
2897
|
+
crossorigin: undefined
|
|
2895
2898
|
});
|
|
2896
|
-
removeHtmlNodeAttributeByName(preloadAsScriptNode, "crossorigin");
|
|
2897
2899
|
});
|
|
2898
2900
|
}
|
|
2899
2901
|
});
|
|
2900
2902
|
modulePreloadNodes.forEach(modulePreloadNode => {
|
|
2901
|
-
const
|
|
2902
|
-
const href = hrefAttribute.value;
|
|
2903
|
+
const href = getHtmlNodeAttribute(modulePreloadNode, "href");
|
|
2903
2904
|
const reference = urlInfo.references.find(ref => ref.generatedSpecifier === href && ref.type === "link_href" && ref.expectedType === "js_module");
|
|
2904
2905
|
actions.push(async () => {
|
|
2905
2906
|
let newReference;
|
|
@@ -2910,7 +2911,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2910
2911
|
[newReference] = await getReferenceAsJsClassic(reference);
|
|
2911
2912
|
}
|
|
2912
2913
|
|
|
2913
|
-
|
|
2914
|
+
setHtmlNodeAttributes(modulePreloadNode, {
|
|
2914
2915
|
rel: "preload",
|
|
2915
2916
|
as: "script",
|
|
2916
2917
|
href: newReference.generatedSpecifier
|
|
@@ -2934,7 +2935,7 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
2934
2935
|
expectedType: "js_classic",
|
|
2935
2936
|
specifier: systemJsClientFileUrl
|
|
2936
2937
|
});
|
|
2937
|
-
|
|
2938
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
2938
2939
|
"tagName": "script",
|
|
2939
2940
|
"src": systemJsReference.generatedSpecifier,
|
|
2940
2941
|
"injected-by": "jsenv:as_js_classic_html"
|
|
@@ -4013,7 +4014,7 @@ const babelPluginBabelHelpersAsJsenvImports = (babel, {
|
|
|
4013
4014
|
}
|
|
4014
4015
|
|
|
4015
4016
|
const babelHelperImportSpecifier = getBabelHelperFileUrl(name);
|
|
4016
|
-
const helper =
|
|
4017
|
+
const helper = injectJsImport({
|
|
4017
4018
|
programPath: file.path,
|
|
4018
4019
|
from: getImportSpecifier(babelHelperImportSpecifier),
|
|
4019
4020
|
nameHint: `_${name}`,
|
|
@@ -4116,7 +4117,7 @@ const babelPluginNewStylesheetAsJsenvImport = (babel, {
|
|
|
4116
4117
|
});
|
|
4117
4118
|
|
|
4118
4119
|
if (usesNewStylesheet) {
|
|
4119
|
-
|
|
4120
|
+
injectJsImport({
|
|
4120
4121
|
programPath,
|
|
4121
4122
|
from: getImportSpecifier(newStylesheetClientFileUrl),
|
|
4122
4123
|
sideEffect: true
|
|
@@ -4181,7 +4182,7 @@ const babelPluginGlobalThisAsJsenvImport = (babel, {
|
|
|
4181
4182
|
} = path; // we should do this once, tree shaking will remote it but still
|
|
4182
4183
|
|
|
4183
4184
|
if (node.name === "globalThis") {
|
|
4184
|
-
|
|
4185
|
+
injectJsImport({
|
|
4185
4186
|
programPath: path.scope.getProgramParent().path,
|
|
4186
4187
|
from: getImportSpecifier(globalThisClientFileUrl),
|
|
4187
4188
|
sideEffect: true
|
|
@@ -4215,7 +4216,7 @@ const babelPluginRegeneratorRuntimeAsJsenvImport = (babel, {
|
|
|
4215
4216
|
} = path;
|
|
4216
4217
|
|
|
4217
4218
|
if (node.name === "regeneratorRuntime") {
|
|
4218
|
-
|
|
4219
|
+
injectJsImport({
|
|
4219
4220
|
programPath: path.scope.getProgramParent().path,
|
|
4220
4221
|
from: getImportSpecifier(regeneratorRuntimeClientFileUrl),
|
|
4221
4222
|
sideEffect: true
|
|
@@ -4459,6 +4460,39 @@ const jsenvPluginNodeRuntime = ({
|
|
|
4459
4460
|
};
|
|
4460
4461
|
};
|
|
4461
4462
|
|
|
4463
|
+
const sortByDependencies = nodes => {
|
|
4464
|
+
const visited = [];
|
|
4465
|
+
const sorted = [];
|
|
4466
|
+
const circular = [];
|
|
4467
|
+
|
|
4468
|
+
const visit = url => {
|
|
4469
|
+
const isSorted = sorted.includes(url);
|
|
4470
|
+
|
|
4471
|
+
if (isSorted) {
|
|
4472
|
+
return;
|
|
4473
|
+
}
|
|
4474
|
+
|
|
4475
|
+
const isVisited = visited.includes(url);
|
|
4476
|
+
|
|
4477
|
+
if (isVisited) {
|
|
4478
|
+
circular.push(url);
|
|
4479
|
+
sorted.push(url);
|
|
4480
|
+
} else {
|
|
4481
|
+
visited.push(url);
|
|
4482
|
+
nodes[url].dependencies.forEach(dependencyUrl => {
|
|
4483
|
+
visit(dependencyUrl);
|
|
4484
|
+
});
|
|
4485
|
+
sorted.push(url);
|
|
4486
|
+
}
|
|
4487
|
+
};
|
|
4488
|
+
|
|
4489
|
+
Object.keys(nodes).forEach(url => {
|
|
4490
|
+
visit(url);
|
|
4491
|
+
});
|
|
4492
|
+
sorted.circular = circular;
|
|
4493
|
+
return sorted;
|
|
4494
|
+
};
|
|
4495
|
+
|
|
4462
4496
|
/*
|
|
4463
4497
|
* Each @import found in css is replaced by the file content
|
|
4464
4498
|
* - There is no need to worry about urls (such as background-image: url())
|
|
@@ -4676,85 +4710,20 @@ const bundleJsModule = async ({
|
|
|
4676
4710
|
});
|
|
4677
4711
|
return jsModuleBundleUrlInfos;
|
|
4678
4712
|
};
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
logger,
|
|
4713
|
+
|
|
4714
|
+
const rollupPluginJsenv = ({
|
|
4715
|
+
// logger,
|
|
4682
4716
|
rootDirectoryUrl,
|
|
4683
4717
|
buildDirectoryUrl,
|
|
4684
4718
|
urlGraph,
|
|
4685
4719
|
jsModuleUrlInfos,
|
|
4686
|
-
runtimeCompat,
|
|
4687
4720
|
sourcemaps,
|
|
4688
4721
|
include,
|
|
4689
|
-
babelHelpersChunk
|
|
4722
|
+
babelHelpersChunk,
|
|
4723
|
+
resultRef
|
|
4690
4724
|
}) => {
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
};
|
|
4694
|
-
|
|
4695
|
-
try {
|
|
4696
|
-
await applyRollupPlugins({
|
|
4697
|
-
rollupPlugins: [rollupPluginJsenv({
|
|
4698
|
-
signal,
|
|
4699
|
-
logger,
|
|
4700
|
-
rootDirectoryUrl,
|
|
4701
|
-
buildDirectoryUrl,
|
|
4702
|
-
urlGraph,
|
|
4703
|
-
jsModuleUrlInfos,
|
|
4704
|
-
runtimeCompat,
|
|
4705
|
-
sourcemaps,
|
|
4706
|
-
include,
|
|
4707
|
-
babelHelpersChunk,
|
|
4708
|
-
resultRef
|
|
4709
|
-
})],
|
|
4710
|
-
inputOptions: {
|
|
4711
|
-
input: [],
|
|
4712
|
-
onwarn: warning => {
|
|
4713
|
-
if (warning.code === "CIRCULAR_DEPENDENCY") {
|
|
4714
|
-
return;
|
|
4715
|
-
}
|
|
4716
|
-
|
|
4717
|
-
if (warning.code === "THIS_IS_UNDEFINED" && pathToFileURL(warning.id).href === globalThisClientFileUrl) {
|
|
4718
|
-
return;
|
|
4719
|
-
}
|
|
4720
|
-
|
|
4721
|
-
if (warning.code === "EVAL") {
|
|
4722
|
-
// ideally we should disable only for jsenv files
|
|
4723
|
-
return;
|
|
4724
|
-
}
|
|
4725
|
-
|
|
4726
|
-
logger.warn(String(warning));
|
|
4727
|
-
}
|
|
4728
|
-
}
|
|
4729
|
-
});
|
|
4730
|
-
return resultRef.current;
|
|
4731
|
-
} catch (e) {
|
|
4732
|
-
if (e.code === "MISSING_EXPORT") {
|
|
4733
|
-
const detailedMessage = createDetailedMessage(e.message, {
|
|
4734
|
-
frame: e.frame
|
|
4735
|
-
});
|
|
4736
|
-
throw new Error(detailedMessage, {
|
|
4737
|
-
cause: e
|
|
4738
|
-
});
|
|
4739
|
-
}
|
|
4740
|
-
|
|
4741
|
-
throw e;
|
|
4742
|
-
}
|
|
4743
|
-
};
|
|
4744
|
-
|
|
4745
|
-
const rollupPluginJsenv = ({
|
|
4746
|
-
// logger,
|
|
4747
|
-
rootDirectoryUrl,
|
|
4748
|
-
buildDirectoryUrl,
|
|
4749
|
-
urlGraph,
|
|
4750
|
-
jsModuleUrlInfos,
|
|
4751
|
-
sourcemaps,
|
|
4752
|
-
include,
|
|
4753
|
-
babelHelpersChunk,
|
|
4754
|
-
resultRef
|
|
4755
|
-
}) => {
|
|
4756
|
-
let _rollupEmitFile = () => {
|
|
4757
|
-
throw new Error("not implemented");
|
|
4725
|
+
let _rollupEmitFile = () => {
|
|
4726
|
+
throw new Error("not implemented");
|
|
4758
4727
|
};
|
|
4759
4728
|
|
|
4760
4729
|
const emitChunk = chunk => {
|
|
@@ -4966,6 +4935,91 @@ const rollupPluginJsenv = ({
|
|
|
4966
4935
|
};
|
|
4967
4936
|
};
|
|
4968
4937
|
|
|
4938
|
+
const buildWithRollup = async ({
|
|
4939
|
+
signal,
|
|
4940
|
+
logger,
|
|
4941
|
+
rootDirectoryUrl,
|
|
4942
|
+
buildDirectoryUrl,
|
|
4943
|
+
urlGraph,
|
|
4944
|
+
jsModuleUrlInfos,
|
|
4945
|
+
runtimeCompat,
|
|
4946
|
+
sourcemaps,
|
|
4947
|
+
include,
|
|
4948
|
+
babelHelpersChunk
|
|
4949
|
+
}) => {
|
|
4950
|
+
const resultRef = {
|
|
4951
|
+
current: null
|
|
4952
|
+
};
|
|
4953
|
+
|
|
4954
|
+
try {
|
|
4955
|
+
await applyRollupPlugins({
|
|
4956
|
+
rollupPlugins: [rollupPluginJsenv({
|
|
4957
|
+
signal,
|
|
4958
|
+
logger,
|
|
4959
|
+
rootDirectoryUrl,
|
|
4960
|
+
buildDirectoryUrl,
|
|
4961
|
+
urlGraph,
|
|
4962
|
+
jsModuleUrlInfos,
|
|
4963
|
+
runtimeCompat,
|
|
4964
|
+
sourcemaps,
|
|
4965
|
+
include,
|
|
4966
|
+
babelHelpersChunk,
|
|
4967
|
+
resultRef
|
|
4968
|
+
})],
|
|
4969
|
+
inputOptions: {
|
|
4970
|
+
input: [],
|
|
4971
|
+
onwarn: warning => {
|
|
4972
|
+
if (warning.code === "CIRCULAR_DEPENDENCY") {
|
|
4973
|
+
return;
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
if (warning.code === "THIS_IS_UNDEFINED" && pathToFileURL(warning.id).href === globalThisClientFileUrl) {
|
|
4977
|
+
return;
|
|
4978
|
+
}
|
|
4979
|
+
|
|
4980
|
+
if (warning.code === "EVAL") {
|
|
4981
|
+
// ideally we should disable only for jsenv files
|
|
4982
|
+
return;
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
logger.warn(String(warning));
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4988
|
+
});
|
|
4989
|
+
return resultRef.current;
|
|
4990
|
+
} catch (e) {
|
|
4991
|
+
if (e.code === "MISSING_EXPORT") {
|
|
4992
|
+
const detailedMessage = createDetailedMessage(e.message, {
|
|
4993
|
+
frame: e.frame
|
|
4994
|
+
});
|
|
4995
|
+
throw new Error(detailedMessage, {
|
|
4996
|
+
cause: e
|
|
4997
|
+
});
|
|
4998
|
+
}
|
|
4999
|
+
|
|
5000
|
+
throw e;
|
|
5001
|
+
}
|
|
5002
|
+
};
|
|
5003
|
+
|
|
5004
|
+
const applyRollupPlugins = async ({
|
|
5005
|
+
rollupPlugins,
|
|
5006
|
+
inputOptions = {},
|
|
5007
|
+
outputOptions = {}
|
|
5008
|
+
}) => {
|
|
5009
|
+
const {
|
|
5010
|
+
rollup
|
|
5011
|
+
} = await import("rollup");
|
|
5012
|
+
const {
|
|
5013
|
+
importAssertions
|
|
5014
|
+
} = await import("acorn-import-assertions");
|
|
5015
|
+
const rollupReturnValue = await rollup({ ...inputOptions,
|
|
5016
|
+
plugins: rollupPlugins,
|
|
5017
|
+
acornInjectPlugins: [importAssertions, ...(inputOptions.acornInjectPlugins || [])]
|
|
5018
|
+
});
|
|
5019
|
+
const rollupOutputArray = await rollupReturnValue.generate(outputOptions);
|
|
5020
|
+
return rollupOutputArray;
|
|
5021
|
+
};
|
|
5022
|
+
|
|
4969
5023
|
const willBeInsideJsDirectory = ({
|
|
4970
5024
|
chunkInfo,
|
|
4971
5025
|
fileUrlConverter,
|
|
@@ -5208,8 +5262,7 @@ const collectHotDataFromHtmlAst = htmlAst => {
|
|
|
5208
5262
|
attributeName,
|
|
5209
5263
|
hotAccepted
|
|
5210
5264
|
}) => {
|
|
5211
|
-
const
|
|
5212
|
-
const value = attribute ? attribute.value : undefined;
|
|
5265
|
+
const value = getHtmlNodeAttribute(node, attributeName);
|
|
5213
5266
|
|
|
5214
5267
|
if (value) {
|
|
5215
5268
|
onSpecifier({
|
|
@@ -5256,11 +5309,10 @@ const collectHotDataFromHtmlAst = htmlAst => {
|
|
|
5256
5309
|
}
|
|
5257
5310
|
|
|
5258
5311
|
if (nodeNamesWithSrcset.includes(node.nodeName)) {
|
|
5259
|
-
const
|
|
5260
|
-
const srcset = srcsetAttribute ? srcsetAttribute.value : undefined;
|
|
5312
|
+
const srcset = getHtmlNodeAttribute(node, "srcset");
|
|
5261
5313
|
|
|
5262
5314
|
if (srcset) {
|
|
5263
|
-
const srcCandidates =
|
|
5315
|
+
const srcCandidates = parseSrcSet(srcset);
|
|
5264
5316
|
srcCandidates.forEach(srcCandidate => {
|
|
5265
5317
|
onSpecifier({
|
|
5266
5318
|
node,
|
|
@@ -5301,15 +5353,15 @@ const nodeNamesWithSrcset = ["img", "source"];
|
|
|
5301
5353
|
|
|
5302
5354
|
const getNodeContext = node => {
|
|
5303
5355
|
const context = {};
|
|
5304
|
-
const
|
|
5356
|
+
const hotAccept = getHtmlNodeAttribute(node, "hot-accept");
|
|
5305
5357
|
|
|
5306
|
-
if (
|
|
5358
|
+
if (hotAccept !== undefined) {
|
|
5307
5359
|
context.hotAccepted = true;
|
|
5308
5360
|
}
|
|
5309
5361
|
|
|
5310
|
-
const
|
|
5362
|
+
const hotDecline = getHtmlNodeAttribute(node, "hot-decline");
|
|
5311
5363
|
|
|
5312
|
-
if (
|
|
5364
|
+
if (hotDecline !== undefined) {
|
|
5313
5365
|
context.hotAccepted = false;
|
|
5314
5366
|
}
|
|
5315
5367
|
|
|
@@ -5322,7 +5374,7 @@ const htmlNodeCanHotReload = node => {
|
|
|
5322
5374
|
isStylesheet,
|
|
5323
5375
|
isRessourceHint,
|
|
5324
5376
|
rel
|
|
5325
|
-
} =
|
|
5377
|
+
} = analyzeLinkNode(node);
|
|
5326
5378
|
|
|
5327
5379
|
if (isStylesheet) {
|
|
5328
5380
|
// stylesheets can be hot replaced by default
|
|
@@ -5622,7 +5674,7 @@ const jsenvPluginDevSSEClient = () => {
|
|
|
5622
5674
|
expectedType: "js_module",
|
|
5623
5675
|
specifier: eventSourceClientFileUrl
|
|
5624
5676
|
});
|
|
5625
|
-
|
|
5677
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
5626
5678
|
"tagName": "script",
|
|
5627
5679
|
"type": "module",
|
|
5628
5680
|
"src": eventSourceClientReference.generatedSpecifier,
|
|
@@ -5637,6 +5689,60 @@ const jsenvPluginDevSSEClient = () => {
|
|
|
5637
5689
|
};
|
|
5638
5690
|
};
|
|
5639
5691
|
|
|
5692
|
+
const createSSEService = ({
|
|
5693
|
+
serverEventCallbackList
|
|
5694
|
+
}) => {
|
|
5695
|
+
const destroyCallbackList = createCallbackListNotifiedOnce();
|
|
5696
|
+
const cache = [];
|
|
5697
|
+
const sseRoomLimit = 100;
|
|
5698
|
+
|
|
5699
|
+
const getOrCreateSSERoom = request => {
|
|
5700
|
+
const htmlFileRelativeUrl = request.ressource.slice(1);
|
|
5701
|
+
const cacheEntry = cache.find(cacheEntryCandidate => cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl);
|
|
5702
|
+
|
|
5703
|
+
if (cacheEntry) {
|
|
5704
|
+
return cacheEntry.sseRoom;
|
|
5705
|
+
}
|
|
5706
|
+
|
|
5707
|
+
const sseRoom = createSSERoom({
|
|
5708
|
+
retryDuration: 2000,
|
|
5709
|
+
historyLength: 100,
|
|
5710
|
+
welcomeEventEnabled: true,
|
|
5711
|
+
effect: () => {
|
|
5712
|
+
return serverEventCallbackList.add(event => {
|
|
5713
|
+
sseRoom.sendEvent(event);
|
|
5714
|
+
});
|
|
5715
|
+
}
|
|
5716
|
+
});
|
|
5717
|
+
const removeSSECleanupCallback = destroyCallbackList.add(() => {
|
|
5718
|
+
removeSSECleanupCallback();
|
|
5719
|
+
sseRoom.close();
|
|
5720
|
+
});
|
|
5721
|
+
cache.push({
|
|
5722
|
+
htmlFileRelativeUrl,
|
|
5723
|
+
sseRoom,
|
|
5724
|
+
cleanup: () => {
|
|
5725
|
+
removeSSECleanupCallback();
|
|
5726
|
+
sseRoom.close();
|
|
5727
|
+
}
|
|
5728
|
+
});
|
|
5729
|
+
|
|
5730
|
+
if (cache.length >= sseRoomLimit) {
|
|
5731
|
+
const firstCacheEntry = cache.shift();
|
|
5732
|
+
firstCacheEntry.cleanup();
|
|
5733
|
+
}
|
|
5734
|
+
|
|
5735
|
+
return sseRoom;
|
|
5736
|
+
};
|
|
5737
|
+
|
|
5738
|
+
return {
|
|
5739
|
+
getOrCreateSSERoom,
|
|
5740
|
+
destroy: () => {
|
|
5741
|
+
destroyCallbackList.notify();
|
|
5742
|
+
}
|
|
5743
|
+
};
|
|
5744
|
+
};
|
|
5745
|
+
|
|
5640
5746
|
const jsenvPluginDevSSEServer = ({
|
|
5641
5747
|
rootDirectoryUrl,
|
|
5642
5748
|
urlGraph,
|
|
@@ -6608,13 +6714,27 @@ const createUrlInfoTransformer = ({
|
|
|
6608
6714
|
const sourcemapsEnabled = sourcemaps === "inline" || sourcemaps === "file" || sourcemaps === "programmatic";
|
|
6609
6715
|
|
|
6610
6716
|
const normalizeSourcemap = (urlInfo, sourcemap) => {
|
|
6717
|
+
let {
|
|
6718
|
+
sources
|
|
6719
|
+
} = sourcemap;
|
|
6720
|
+
|
|
6721
|
+
if (sources) {
|
|
6722
|
+
sources = sources.map(source => {
|
|
6723
|
+
if (source && isFileSystemPath(source)) {
|
|
6724
|
+
return String(pathToFileURL(source));
|
|
6725
|
+
}
|
|
6726
|
+
|
|
6727
|
+
return source;
|
|
6728
|
+
});
|
|
6729
|
+
}
|
|
6730
|
+
|
|
6611
6731
|
const wantSourcesContent = // for inline content (<script> insdide html)
|
|
6612
6732
|
// chrome won't be able to fetch the file as it does not exists
|
|
6613
6733
|
// so sourcemap must contain sources
|
|
6614
|
-
sourcemapsSourcesContent || urlInfo.isInline ||
|
|
6734
|
+
sourcemapsSourcesContent || urlInfo.isInline || sources && sources.some(source => !source || !source.startsWith("file:"));
|
|
6615
6735
|
|
|
6616
|
-
if (
|
|
6617
|
-
sourcemap.sources =
|
|
6736
|
+
if (sources && sources.length > 1) {
|
|
6737
|
+
sourcemap.sources = sources.map(source => new URL(source, urlInfo.originalUrl).href);
|
|
6618
6738
|
|
|
6619
6739
|
if (!wantSourcesContent) {
|
|
6620
6740
|
sourcemap.sourcesContent = undefined;
|
|
@@ -6650,7 +6770,7 @@ const createUrlInfoTransformer = ({
|
|
|
6650
6770
|
// but otherwise it's generatedUrl to be inside .jsenv/ directory
|
|
6651
6771
|
|
|
6652
6772
|
|
|
6653
|
-
urlInfo.sourcemapGeneratedUrl =
|
|
6773
|
+
urlInfo.sourcemapGeneratedUrl = generateSourcemapFileUrl(urlInfo.generatedUrl);
|
|
6654
6774
|
const [sourcemapReference, sourcemapUrlInfo] = injectSourcemapPlaceholder({
|
|
6655
6775
|
urlInfo,
|
|
6656
6776
|
specifier: urlInfo.sourcemapGeneratedUrl
|
|
@@ -6756,7 +6876,7 @@ const createUrlInfoTransformer = ({
|
|
|
6756
6876
|
sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
|
|
6757
6877
|
|
|
6758
6878
|
if (sourcemaps === "inline") {
|
|
6759
|
-
sourcemapReference.generatedSpecifier =
|
|
6879
|
+
sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
|
|
6760
6880
|
}
|
|
6761
6881
|
|
|
6762
6882
|
if (sourcemaps === "file" || sourcemaps === "inline") {
|
|
@@ -7661,6 +7781,8 @@ const memoizeCook = cook => {
|
|
|
7661
7781
|
const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
|
|
7662
7782
|
if (reference.shouldHandle) {
|
|
7663
7783
|
urlInfo.shouldHandle = true;
|
|
7784
|
+
} else {
|
|
7785
|
+
urlInfo.shouldHandle = false;
|
|
7664
7786
|
}
|
|
7665
7787
|
|
|
7666
7788
|
urlInfo.originalUrl = urlInfo.originalUrl || reference.url;
|
|
@@ -8295,7 +8417,7 @@ const jsenvPluginExplorer = ({
|
|
|
8295
8417
|
|
|
8296
8418
|
const startDevServer = async ({
|
|
8297
8419
|
signal = new AbortController().signal,
|
|
8298
|
-
handleSIGINT,
|
|
8420
|
+
handleSIGINT = true,
|
|
8299
8421
|
logLevel = "info",
|
|
8300
8422
|
omegaServerLogLevel = "warn",
|
|
8301
8423
|
port = 3456,
|
|
@@ -8315,9 +8437,9 @@ const startDevServer = async ({
|
|
|
8315
8437
|
devServerMainFile = getCallerPosition().url,
|
|
8316
8438
|
// force disable server autoreload when this code is executed:
|
|
8317
8439
|
// - inside a forked child process
|
|
8318
|
-
// -
|
|
8319
|
-
//
|
|
8320
|
-
devServerAutoreload = typeof process.send !== "function" && !
|
|
8440
|
+
// - debugged by vscode
|
|
8441
|
+
// otherwise we get net:ERR_CONNECTION_REFUSED
|
|
8442
|
+
devServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
|
|
8321
8443
|
clientFiles = {
|
|
8322
8444
|
"./src/": true,
|
|
8323
8445
|
"./test/": true
|
|
@@ -8349,198 +8471,882 @@ const startDevServer = async ({
|
|
|
8349
8471
|
test: {
|
|
8350
8472
|
"./test/**/*.test.html": true
|
|
8351
8473
|
}
|
|
8352
|
-
},
|
|
8353
|
-
// toolbar = false,
|
|
8354
|
-
writeGeneratedFiles = true
|
|
8474
|
+
},
|
|
8475
|
+
// toolbar = false,
|
|
8476
|
+
writeGeneratedFiles = true
|
|
8477
|
+
}) => {
|
|
8478
|
+
const logger = createLogger({
|
|
8479
|
+
logLevel
|
|
8480
|
+
});
|
|
8481
|
+
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
|
|
8482
|
+
const operation = Abort.startOperation();
|
|
8483
|
+
operation.addAbortSignal(signal);
|
|
8484
|
+
|
|
8485
|
+
if (handleSIGINT) {
|
|
8486
|
+
operation.addAbortSource(abort => {
|
|
8487
|
+
return raceProcessTeardownEvents({
|
|
8488
|
+
SIGINT: true
|
|
8489
|
+
}, abort);
|
|
8490
|
+
});
|
|
8491
|
+
}
|
|
8492
|
+
|
|
8493
|
+
if (port === 0) {
|
|
8494
|
+
port = await findFreePort(port, {
|
|
8495
|
+
signal: operation.signal
|
|
8496
|
+
});
|
|
8497
|
+
}
|
|
8498
|
+
|
|
8499
|
+
const reloadableWorker = createReloadableWorker(devServerMainFile);
|
|
8500
|
+
|
|
8501
|
+
if (devServerAutoreload && reloadableWorker.isPrimary) {
|
|
8502
|
+
const devServerFileChangeCallback = ({
|
|
8503
|
+
relativeUrl,
|
|
8504
|
+
event
|
|
8505
|
+
}) => {
|
|
8506
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href;
|
|
8507
|
+
logger.info(`file ${event} ${url} -> restarting server...`);
|
|
8508
|
+
reloadableWorker.reload();
|
|
8509
|
+
};
|
|
8510
|
+
|
|
8511
|
+
const stopWatchingDevServerFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
8512
|
+
watchPatterns: {
|
|
8513
|
+
[devServerMainFile]: true,
|
|
8514
|
+
...devServerFiles
|
|
8515
|
+
},
|
|
8516
|
+
cooldownBetweenFileEvents,
|
|
8517
|
+
keepProcessAlive: false,
|
|
8518
|
+
recursive: true,
|
|
8519
|
+
added: ({
|
|
8520
|
+
relativeUrl
|
|
8521
|
+
}) => {
|
|
8522
|
+
devServerFileChangeCallback({
|
|
8523
|
+
relativeUrl,
|
|
8524
|
+
event: "added"
|
|
8525
|
+
});
|
|
8526
|
+
},
|
|
8527
|
+
updated: ({
|
|
8528
|
+
relativeUrl
|
|
8529
|
+
}) => {
|
|
8530
|
+
devServerFileChangeCallback({
|
|
8531
|
+
relativeUrl,
|
|
8532
|
+
event: "modified"
|
|
8533
|
+
});
|
|
8534
|
+
},
|
|
8535
|
+
removed: ({
|
|
8536
|
+
relativeUrl
|
|
8537
|
+
}) => {
|
|
8538
|
+
devServerFileChangeCallback({
|
|
8539
|
+
relativeUrl,
|
|
8540
|
+
event: "removed"
|
|
8541
|
+
});
|
|
8542
|
+
}
|
|
8543
|
+
});
|
|
8544
|
+
operation.addAbortCallback(() => {
|
|
8545
|
+
stopWatchingDevServerFiles();
|
|
8546
|
+
reloadableWorker.terminate();
|
|
8547
|
+
});
|
|
8548
|
+
const worker = await reloadableWorker.load();
|
|
8549
|
+
|
|
8550
|
+
if (!keepProcessAlive) {
|
|
8551
|
+
worker.unref();
|
|
8552
|
+
}
|
|
8553
|
+
|
|
8554
|
+
return {
|
|
8555
|
+
origin: `${protocol}://127.0.0.1:${port}`,
|
|
8556
|
+
stop: () => {
|
|
8557
|
+
stopWatchingDevServerFiles();
|
|
8558
|
+
reloadableWorker.terminate();
|
|
8559
|
+
}
|
|
8560
|
+
};
|
|
8561
|
+
}
|
|
8562
|
+
|
|
8563
|
+
const startDevServerTask = createTaskLog("start dev server", {
|
|
8564
|
+
disabled: !loggerToLevels(logger).info
|
|
8565
|
+
});
|
|
8566
|
+
const clientFileChangeCallbackList = [];
|
|
8567
|
+
const clientFilesPruneCallbackList = [];
|
|
8568
|
+
|
|
8569
|
+
const clientFileChangeCallback = ({
|
|
8570
|
+
relativeUrl,
|
|
8571
|
+
event
|
|
8572
|
+
}) => {
|
|
8573
|
+
const url = new URL(relativeUrl, rootDirectoryUrl).href;
|
|
8574
|
+
clientFileChangeCallbackList.forEach(callback => {
|
|
8575
|
+
callback({
|
|
8576
|
+
url,
|
|
8577
|
+
event
|
|
8578
|
+
});
|
|
8579
|
+
});
|
|
8580
|
+
};
|
|
8581
|
+
|
|
8582
|
+
const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
8583
|
+
watchPatterns: clientFiles,
|
|
8584
|
+
cooldownBetweenFileEvents,
|
|
8585
|
+
keepProcessAlive: false,
|
|
8586
|
+
recursive: true,
|
|
8587
|
+
added: ({
|
|
8588
|
+
relativeUrl
|
|
8589
|
+
}) => {
|
|
8590
|
+
clientFileChangeCallback({
|
|
8591
|
+
event: "added",
|
|
8592
|
+
relativeUrl
|
|
8593
|
+
});
|
|
8594
|
+
},
|
|
8595
|
+
updated: ({
|
|
8596
|
+
relativeUrl
|
|
8597
|
+
}) => {
|
|
8598
|
+
clientFileChangeCallback({
|
|
8599
|
+
event: "modified",
|
|
8600
|
+
relativeUrl
|
|
8601
|
+
});
|
|
8602
|
+
},
|
|
8603
|
+
removed: ({
|
|
8604
|
+
relativeUrl
|
|
8605
|
+
}) => {
|
|
8606
|
+
clientFileChangeCallback({
|
|
8607
|
+
event: "removed",
|
|
8608
|
+
relativeUrl
|
|
8609
|
+
});
|
|
8610
|
+
}
|
|
8611
|
+
});
|
|
8612
|
+
const urlGraph = createUrlGraph({
|
|
8613
|
+
clientFileChangeCallbackList,
|
|
8614
|
+
clientFilesPruneCallbackList
|
|
8615
|
+
});
|
|
8616
|
+
const kitchen = createKitchen({
|
|
8617
|
+
signal,
|
|
8618
|
+
logger,
|
|
8619
|
+
rootDirectoryUrl,
|
|
8620
|
+
urlGraph,
|
|
8621
|
+
scenario: "dev",
|
|
8622
|
+
runtimeCompat,
|
|
8623
|
+
sourcemaps,
|
|
8624
|
+
writeGeneratedFiles,
|
|
8625
|
+
plugins: [...plugins, ...getCorePlugins({
|
|
8626
|
+
rootDirectoryUrl,
|
|
8627
|
+
urlGraph,
|
|
8628
|
+
scenario: "dev",
|
|
8629
|
+
runtimeCompat,
|
|
8630
|
+
urlAnalysis,
|
|
8631
|
+
htmlSupervisor,
|
|
8632
|
+
nodeEsmResolution,
|
|
8633
|
+
fileSystemMagicResolution,
|
|
8634
|
+
transpilation,
|
|
8635
|
+
clientAutoreload,
|
|
8636
|
+
clientFileChangeCallbackList,
|
|
8637
|
+
clientFilesPruneCallbackList
|
|
8638
|
+
}), jsenvPluginExplorer({
|
|
8639
|
+
groups: explorerGroups
|
|
8640
|
+
}) // ...(toolbar ? [jsenvPluginToolbar(toolbar)] : []),
|
|
8641
|
+
]
|
|
8642
|
+
});
|
|
8643
|
+
const server = await startOmegaServer({
|
|
8644
|
+
logLevel: omegaServerLogLevel,
|
|
8645
|
+
keepProcessAlive,
|
|
8646
|
+
listenAnyIp,
|
|
8647
|
+
port,
|
|
8648
|
+
protocol,
|
|
8649
|
+
http2,
|
|
8650
|
+
certificate,
|
|
8651
|
+
privateKey,
|
|
8652
|
+
rootDirectoryUrl,
|
|
8653
|
+
urlGraph,
|
|
8654
|
+
kitchen,
|
|
8655
|
+
scenario: "dev"
|
|
8656
|
+
});
|
|
8657
|
+
startDevServerTask.done();
|
|
8658
|
+
logger.info(``);
|
|
8659
|
+
Object.keys(server.origins).forEach(key => {
|
|
8660
|
+
logger.info(`- ${server.origins[key]}`);
|
|
8661
|
+
});
|
|
8662
|
+
logger.info(``);
|
|
8663
|
+
server.addEffect(() => {
|
|
8664
|
+
return () => {
|
|
8665
|
+
kitchen.pluginController.callHooks("destroy", {});
|
|
8666
|
+
};
|
|
8667
|
+
});
|
|
8668
|
+
return {
|
|
8669
|
+
origin: server.origin,
|
|
8670
|
+
stop: () => {
|
|
8671
|
+
stopWatchingClientFiles();
|
|
8672
|
+
server.stop();
|
|
8673
|
+
}
|
|
8674
|
+
};
|
|
8675
|
+
};
|
|
8676
|
+
|
|
8677
|
+
const generateCoverageJsonFile = async ({
|
|
8678
|
+
coverage,
|
|
8679
|
+
coverageJsonFileUrl,
|
|
8680
|
+
coverageJsonFileLog,
|
|
8681
|
+
logger
|
|
8682
|
+
}) => {
|
|
8683
|
+
const coverageAsText = JSON.stringify(coverage, null, " ");
|
|
8684
|
+
|
|
8685
|
+
if (coverageJsonFileLog) {
|
|
8686
|
+
logger.info(`-> ${urlToFileSystemPath(coverageJsonFileUrl)} (${byteAsFileSize(Buffer.byteLength(coverageAsText))})`);
|
|
8687
|
+
}
|
|
8688
|
+
|
|
8689
|
+
await writeFile(coverageJsonFileUrl, coverageAsText);
|
|
8690
|
+
};
|
|
8691
|
+
|
|
8692
|
+
const istanbulCoverageMapFromCoverage = coverage => {
|
|
8693
|
+
const {
|
|
8694
|
+
createCoverageMap
|
|
8695
|
+
} = requireFromJsenv("istanbul-lib-coverage");
|
|
8696
|
+
const coverageAdjusted = {};
|
|
8697
|
+
Object.keys(coverage).forEach(key => {
|
|
8698
|
+
coverageAdjusted[key.slice(2)] = { ...coverage[key],
|
|
8699
|
+
path: key.slice(2)
|
|
8700
|
+
};
|
|
8701
|
+
});
|
|
8702
|
+
const coverageMap = createCoverageMap(coverageAdjusted);
|
|
8703
|
+
return coverageMap;
|
|
8704
|
+
};
|
|
8705
|
+
|
|
8706
|
+
const generateCoverageHtmlDirectory = async (coverage, {
|
|
8707
|
+
rootDirectoryUrl,
|
|
8708
|
+
coverageHtmlDirectoryRelativeUrl,
|
|
8709
|
+
coverageSkipEmpty,
|
|
8710
|
+
coverageSkipFull
|
|
8711
|
+
}) => {
|
|
8712
|
+
const libReport = requireFromJsenv("istanbul-lib-report");
|
|
8713
|
+
const reports = requireFromJsenv("istanbul-reports");
|
|
8714
|
+
const context = libReport.createContext({
|
|
8715
|
+
dir: urlToFileSystemPath(rootDirectoryUrl),
|
|
8716
|
+
coverageMap: istanbulCoverageMapFromCoverage(coverage),
|
|
8717
|
+
sourceFinder: path => {
|
|
8718
|
+
return readFileSync(urlToFileSystemPath(resolveUrl(path, rootDirectoryUrl)), "utf8");
|
|
8719
|
+
}
|
|
8720
|
+
});
|
|
8721
|
+
const report = reports.create("html", {
|
|
8722
|
+
skipEmpty: coverageSkipEmpty,
|
|
8723
|
+
skipFull: coverageSkipFull,
|
|
8724
|
+
subdir: coverageHtmlDirectoryRelativeUrl
|
|
8725
|
+
});
|
|
8726
|
+
report.execute(context);
|
|
8727
|
+
};
|
|
8728
|
+
|
|
8729
|
+
const generateCoverageTextLog = (coverage, {
|
|
8730
|
+
coverageSkipEmpty,
|
|
8731
|
+
coverageSkipFull
|
|
8732
|
+
}) => {
|
|
8733
|
+
const libReport = requireFromJsenv("istanbul-lib-report");
|
|
8734
|
+
const reports = requireFromJsenv("istanbul-reports");
|
|
8735
|
+
const context = libReport.createContext({
|
|
8736
|
+
coverageMap: istanbulCoverageMapFromCoverage(coverage)
|
|
8737
|
+
});
|
|
8738
|
+
const report = reports.create("text", {
|
|
8739
|
+
skipEmpty: coverageSkipEmpty,
|
|
8740
|
+
skipFull: coverageSkipFull
|
|
8741
|
+
});
|
|
8742
|
+
report.execute(context);
|
|
8743
|
+
};
|
|
8744
|
+
|
|
8745
|
+
const babelPluginInstrument = (api, {
|
|
8746
|
+
rootDirectoryUrl,
|
|
8747
|
+
useInlineSourceMaps = false,
|
|
8748
|
+
coverageConfig = {
|
|
8749
|
+
"./**/*": true
|
|
8750
|
+
}
|
|
8751
|
+
}) => {
|
|
8752
|
+
const {
|
|
8753
|
+
programVisitor
|
|
8754
|
+
} = requireFromJsenv("istanbul-lib-instrument");
|
|
8755
|
+
const {
|
|
8756
|
+
types
|
|
8757
|
+
} = api;
|
|
8758
|
+
const associations = URL_META.resolveAssociations({
|
|
8759
|
+
cover: coverageConfig
|
|
8760
|
+
}, rootDirectoryUrl);
|
|
8761
|
+
|
|
8762
|
+
const shouldInstrument = url => {
|
|
8763
|
+
return URL_META.applyAssociations({
|
|
8764
|
+
url,
|
|
8765
|
+
associations
|
|
8766
|
+
}).cover;
|
|
8767
|
+
};
|
|
8768
|
+
|
|
8769
|
+
return {
|
|
8770
|
+
name: "transform-instrument",
|
|
8771
|
+
visitor: {
|
|
8772
|
+
Program: {
|
|
8773
|
+
enter(path) {
|
|
8774
|
+
const {
|
|
8775
|
+
file
|
|
8776
|
+
} = this;
|
|
8777
|
+
const {
|
|
8778
|
+
opts
|
|
8779
|
+
} = file;
|
|
8780
|
+
|
|
8781
|
+
if (!opts.sourceFileName) {
|
|
8782
|
+
console.warn(`cannot instrument file when "sourceFileName" option is not set`);
|
|
8783
|
+
return;
|
|
8784
|
+
}
|
|
8785
|
+
|
|
8786
|
+
const fileUrl = fileSystemPathToUrl(opts.sourceFileName);
|
|
8787
|
+
|
|
8788
|
+
if (!shouldInstrument(fileUrl)) {
|
|
8789
|
+
return;
|
|
8790
|
+
}
|
|
8791
|
+
|
|
8792
|
+
this.__dv__ = null;
|
|
8793
|
+
let inputSourceMap;
|
|
8794
|
+
|
|
8795
|
+
if (useInlineSourceMaps) {
|
|
8796
|
+
// https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
|
|
8797
|
+
inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
|
|
8798
|
+
} else {
|
|
8799
|
+
inputSourceMap = opts.inputSourceMap;
|
|
8800
|
+
}
|
|
8801
|
+
|
|
8802
|
+
this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
|
|
8803
|
+
coverageVariable: "__coverage__",
|
|
8804
|
+
inputSourceMap
|
|
8805
|
+
});
|
|
8806
|
+
|
|
8807
|
+
this.__dv__.enter(path);
|
|
8808
|
+
},
|
|
8809
|
+
|
|
8810
|
+
exit(path) {
|
|
8811
|
+
if (!this.__dv__) {
|
|
8812
|
+
return;
|
|
8813
|
+
}
|
|
8814
|
+
|
|
8815
|
+
const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
|
|
8816
|
+
|
|
8817
|
+
|
|
8818
|
+
this.file.metadata.coverage = object.fileCoverage;
|
|
8819
|
+
}
|
|
8820
|
+
|
|
8821
|
+
}
|
|
8822
|
+
}
|
|
8823
|
+
};
|
|
8824
|
+
};
|
|
8825
|
+
|
|
8826
|
+
const visitNodeV8Directory = async ({
|
|
8827
|
+
logger,
|
|
8828
|
+
signal,
|
|
8829
|
+
NODE_V8_COVERAGE,
|
|
8830
|
+
onV8Coverage,
|
|
8831
|
+
maxMsWaitingForNodeToWriteCoverageFile = 2000
|
|
8832
|
+
}) => {
|
|
8833
|
+
const operation = Abort.startOperation();
|
|
8834
|
+
operation.addAbortSignal(signal);
|
|
8835
|
+
|
|
8836
|
+
const tryReadDirectory = async () => {
|
|
8837
|
+
const dirContent = await readDirectory(NODE_V8_COVERAGE);
|
|
8838
|
+
|
|
8839
|
+
if (dirContent.length > 0) {
|
|
8840
|
+
return dirContent;
|
|
8841
|
+
}
|
|
8842
|
+
|
|
8843
|
+
logger.warn(`v8 coverage directory is empty at ${NODE_V8_COVERAGE}`);
|
|
8844
|
+
return dirContent;
|
|
8845
|
+
};
|
|
8846
|
+
|
|
8847
|
+
try {
|
|
8848
|
+
operation.throwIfAborted();
|
|
8849
|
+
const dirContent = await tryReadDirectory();
|
|
8850
|
+
const coverageDirectoryUrl = assertAndNormalizeDirectoryUrl(NODE_V8_COVERAGE);
|
|
8851
|
+
await dirContent.reduce(async (previous, dirEntry) => {
|
|
8852
|
+
operation.throwIfAborted();
|
|
8853
|
+
await previous;
|
|
8854
|
+
const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl);
|
|
8855
|
+
|
|
8856
|
+
const tryReadJsonFile = async (timeSpentTrying = 0) => {
|
|
8857
|
+
const fileContent = await readFile(dirEntryUrl, {
|
|
8858
|
+
as: "string"
|
|
8859
|
+
});
|
|
8860
|
+
|
|
8861
|
+
if (fileContent === "") {
|
|
8862
|
+
if (timeSpentTrying < 400) {
|
|
8863
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
8864
|
+
return tryReadJsonFile(timeSpentTrying + 200);
|
|
8865
|
+
}
|
|
8866
|
+
|
|
8867
|
+
console.warn(`Coverage JSON file is empty at ${dirEntryUrl}`);
|
|
8868
|
+
return null;
|
|
8869
|
+
}
|
|
8870
|
+
|
|
8871
|
+
try {
|
|
8872
|
+
const fileAsJson = JSON.parse(fileContent);
|
|
8873
|
+
return fileAsJson;
|
|
8874
|
+
} catch (e) {
|
|
8875
|
+
if (timeSpentTrying < maxMsWaitingForNodeToWriteCoverageFile) {
|
|
8876
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
8877
|
+
return tryReadJsonFile(timeSpentTrying + 200);
|
|
8878
|
+
}
|
|
8879
|
+
|
|
8880
|
+
console.warn(createDetailedMessage(`Error while reading coverage file`, {
|
|
8881
|
+
"error stack": e.stack,
|
|
8882
|
+
"file": dirEntryUrl
|
|
8883
|
+
}));
|
|
8884
|
+
return null;
|
|
8885
|
+
}
|
|
8886
|
+
};
|
|
8887
|
+
|
|
8888
|
+
const fileContent = await tryReadJsonFile();
|
|
8889
|
+
|
|
8890
|
+
if (fileContent) {
|
|
8891
|
+
onV8Coverage(fileContent);
|
|
8892
|
+
}
|
|
8893
|
+
}, Promise.resolve());
|
|
8894
|
+
} finally {
|
|
8895
|
+
await operation.end();
|
|
8896
|
+
}
|
|
8897
|
+
};
|
|
8898
|
+
const filterV8Coverage = (v8Coverage, {
|
|
8899
|
+
urlShouldBeCovered
|
|
8900
|
+
}) => {
|
|
8901
|
+
const v8CoverageFiltered = { ...v8Coverage,
|
|
8902
|
+
result: v8Coverage.result.filter(fileReport => urlShouldBeCovered(fileReport.url))
|
|
8903
|
+
};
|
|
8904
|
+
return v8CoverageFiltered;
|
|
8905
|
+
};
|
|
8906
|
+
|
|
8907
|
+
const composeTwoV8Coverages = (firstV8Coverage, secondV8Coverage) => {
|
|
8908
|
+
if (secondV8Coverage.result.length === 0) {
|
|
8909
|
+
return firstV8Coverage;
|
|
8910
|
+
} // eslint-disable-next-line import/no-unresolved
|
|
8911
|
+
|
|
8912
|
+
|
|
8913
|
+
const {
|
|
8914
|
+
mergeProcessCovs
|
|
8915
|
+
} = requireFromJsenv("@c88/v8-coverage"); // "mergeProcessCovs" do not preserves source-map-cache during the merge
|
|
8916
|
+
// so we store sourcemap cache now
|
|
8917
|
+
|
|
8918
|
+
const sourceMapCache = {};
|
|
8919
|
+
|
|
8920
|
+
const visit = coverageReport => {
|
|
8921
|
+
if (coverageReport["source-map-cache"]) {
|
|
8922
|
+
Object.assign(sourceMapCache, coverageReport["source-map-cache"]);
|
|
8923
|
+
}
|
|
8924
|
+
};
|
|
8925
|
+
|
|
8926
|
+
visit(firstV8Coverage);
|
|
8927
|
+
visit(secondV8Coverage);
|
|
8928
|
+
const v8Coverage = mergeProcessCovs([firstV8Coverage, secondV8Coverage]);
|
|
8929
|
+
v8Coverage["source-map-cache"] = sourceMapCache;
|
|
8930
|
+
return v8Coverage;
|
|
8931
|
+
};
|
|
8932
|
+
|
|
8933
|
+
const composeTwoFileByFileIstanbulCoverages = (firstFileByFileIstanbulCoverage, secondFileByFileIstanbulCoverage) => {
|
|
8934
|
+
const fileByFileIstanbulCoverage = {};
|
|
8935
|
+
Object.keys(firstFileByFileIstanbulCoverage).forEach(key => {
|
|
8936
|
+
fileByFileIstanbulCoverage[key] = firstFileByFileIstanbulCoverage[key];
|
|
8937
|
+
});
|
|
8938
|
+
Object.keys(secondFileByFileIstanbulCoverage).forEach(key => {
|
|
8939
|
+
const firstCoverage = firstFileByFileIstanbulCoverage[key];
|
|
8940
|
+
const secondCoverage = secondFileByFileIstanbulCoverage[key];
|
|
8941
|
+
fileByFileIstanbulCoverage[key] = firstCoverage ? merge(firstCoverage, secondCoverage) : secondCoverage;
|
|
8942
|
+
});
|
|
8943
|
+
return fileByFileIstanbulCoverage;
|
|
8944
|
+
};
|
|
8945
|
+
|
|
8946
|
+
const merge = (firstIstanbulCoverage, secondIstanbulCoverage) => {
|
|
8947
|
+
const {
|
|
8948
|
+
createFileCoverage
|
|
8949
|
+
} = requireFromJsenv("istanbul-lib-coverage");
|
|
8950
|
+
const istanbulFileCoverageObject = createFileCoverage(firstIstanbulCoverage);
|
|
8951
|
+
istanbulFileCoverageObject.merge(secondIstanbulCoverage);
|
|
8952
|
+
const istanbulCoverage = istanbulFileCoverageObject.toJSON();
|
|
8953
|
+
return istanbulCoverage;
|
|
8954
|
+
};
|
|
8955
|
+
|
|
8956
|
+
const v8CoverageToIstanbul = async (v8Coverage, {
|
|
8957
|
+
signal
|
|
8958
|
+
}) => {
|
|
8959
|
+
const operation = Abort.startOperation();
|
|
8960
|
+
operation.addAbortSignal(signal);
|
|
8961
|
+
|
|
8962
|
+
try {
|
|
8963
|
+
const v8ToIstanbul = requireFromJsenv("v8-to-istanbul");
|
|
8964
|
+
const sourcemapCache = v8Coverage["source-map-cache"];
|
|
8965
|
+
let istanbulCoverageComposed = null;
|
|
8966
|
+
await v8Coverage.result.reduce(async (previous, fileV8Coverage) => {
|
|
8967
|
+
operation.throwIfAborted();
|
|
8968
|
+
await previous;
|
|
8969
|
+
const {
|
|
8970
|
+
source
|
|
8971
|
+
} = fileV8Coverage;
|
|
8972
|
+
let sources; // when v8 coverage comes from playwright (chromium) v8Coverage.source is set
|
|
8973
|
+
|
|
8974
|
+
if (typeof source === "string") {
|
|
8975
|
+
sources = {
|
|
8976
|
+
source
|
|
8977
|
+
};
|
|
8978
|
+
} // when v8 coverage comes from Node.js, the source can be read from sourcemapCache
|
|
8979
|
+
else if (sourcemapCache) {
|
|
8980
|
+
sources = sourcesFromSourceMapCache(fileV8Coverage.url, sourcemapCache);
|
|
8981
|
+
}
|
|
8982
|
+
|
|
8983
|
+
const path = urlToFileSystemPath(fileV8Coverage.url);
|
|
8984
|
+
const converter = v8ToIstanbul(path, // wrapperLength is undefined we don't need it
|
|
8985
|
+
// https://github.com/istanbuljs/v8-to-istanbul/blob/2b54bc97c5edf8a37b39a171ec29134ba9bfd532/lib/v8-to-istanbul.js#L27
|
|
8986
|
+
undefined, sources);
|
|
8987
|
+
await converter.load();
|
|
8988
|
+
converter.applyCoverage(fileV8Coverage.functions);
|
|
8989
|
+
const istanbulCoverage = converter.toIstanbul();
|
|
8990
|
+
istanbulCoverageComposed = istanbulCoverageComposed ? composeTwoFileByFileIstanbulCoverages(istanbulCoverageComposed, istanbulCoverage) : istanbulCoverage;
|
|
8991
|
+
}, Promise.resolve());
|
|
8992
|
+
|
|
8993
|
+
if (!istanbulCoverageComposed) {
|
|
8994
|
+
return {};
|
|
8995
|
+
}
|
|
8996
|
+
|
|
8997
|
+
istanbulCoverageComposed = markAsConvertedFromV8(istanbulCoverageComposed);
|
|
8998
|
+
return istanbulCoverageComposed;
|
|
8999
|
+
} finally {
|
|
9000
|
+
await operation.end();
|
|
9001
|
+
}
|
|
9002
|
+
};
|
|
9003
|
+
|
|
9004
|
+
const markAsConvertedFromV8 = fileByFileCoverage => {
|
|
9005
|
+
const fileByFileMarked = {};
|
|
9006
|
+
Object.keys(fileByFileCoverage).forEach(key => {
|
|
9007
|
+
const fileCoverage = fileByFileCoverage[key];
|
|
9008
|
+
fileByFileMarked[key] = { ...fileCoverage,
|
|
9009
|
+
fromV8: true
|
|
9010
|
+
};
|
|
9011
|
+
});
|
|
9012
|
+
return fileByFileMarked;
|
|
9013
|
+
};
|
|
9014
|
+
|
|
9015
|
+
const sourcesFromSourceMapCache = (url, sourceMapCache) => {
|
|
9016
|
+
const sourceMapAndLineLengths = sourceMapCache[url];
|
|
9017
|
+
|
|
9018
|
+
if (!sourceMapAndLineLengths) {
|
|
9019
|
+
return {};
|
|
9020
|
+
}
|
|
9021
|
+
|
|
9022
|
+
const {
|
|
9023
|
+
data,
|
|
9024
|
+
lineLengths
|
|
9025
|
+
} = sourceMapAndLineLengths; // See: https://github.com/nodejs/node/pull/34305
|
|
9026
|
+
|
|
9027
|
+
if (!data) {
|
|
9028
|
+
return undefined;
|
|
9029
|
+
}
|
|
9030
|
+
|
|
9031
|
+
const sources = {
|
|
9032
|
+
sourcemap: data,
|
|
9033
|
+
...(lineLengths ? {
|
|
9034
|
+
source: sourcesFromLineLengths(lineLengths)
|
|
9035
|
+
} : {})
|
|
9036
|
+
};
|
|
9037
|
+
return sources;
|
|
9038
|
+
};
|
|
9039
|
+
|
|
9040
|
+
const sourcesFromLineLengths = lineLengths => {
|
|
9041
|
+
let source = "";
|
|
9042
|
+
lineLengths.forEach(length => {
|
|
9043
|
+
source += `${"".padEnd(length, ".")}\n`;
|
|
9044
|
+
});
|
|
9045
|
+
return source;
|
|
9046
|
+
};
|
|
9047
|
+
|
|
9048
|
+
const composeV8AndIstanbul = (v8FileByFileCoverage, istanbulFileByFileCoverage, {
|
|
9049
|
+
coverageV8ConflictWarning
|
|
9050
|
+
}) => {
|
|
9051
|
+
const fileByFileCoverage = {};
|
|
9052
|
+
const v8Files = Object.keys(v8FileByFileCoverage);
|
|
9053
|
+
const istanbulFiles = Object.keys(istanbulFileByFileCoverage);
|
|
9054
|
+
v8Files.forEach(key => {
|
|
9055
|
+
fileByFileCoverage[key] = v8FileByFileCoverage[key];
|
|
9056
|
+
});
|
|
9057
|
+
istanbulFiles.forEach(key => {
|
|
9058
|
+
const v8Coverage = v8FileByFileCoverage[key];
|
|
9059
|
+
|
|
9060
|
+
if (v8Coverage) {
|
|
9061
|
+
if (coverageV8ConflictWarning) {
|
|
9062
|
+
console.warn(createDetailedMessage(`Coverage conflict on "${key}", found two coverage that cannot be merged together: v8 and istanbul. The istanbul coverage will be ignored.`, {
|
|
9063
|
+
details: `This happens when a file is executed on a runtime using v8 coverage (node or chromium) and on runtime using istanbul coverage (firefox or webkit)`,
|
|
9064
|
+
suggestion: "You can disable this warning with coverageV8ConflictWarning: false"
|
|
9065
|
+
}));
|
|
9066
|
+
}
|
|
9067
|
+
|
|
9068
|
+
fileByFileCoverage[key] = v8Coverage;
|
|
9069
|
+
} else {
|
|
9070
|
+
fileByFileCoverage[key] = istanbulFileByFileCoverage[key];
|
|
9071
|
+
}
|
|
9072
|
+
});
|
|
9073
|
+
return fileByFileCoverage;
|
|
9074
|
+
};
|
|
9075
|
+
|
|
9076
|
+
const normalizeFileByFileCoveragePaths = (fileByFileCoverage, rootDirectoryUrl) => {
|
|
9077
|
+
const fileByFileNormalized = {};
|
|
9078
|
+
Object.keys(fileByFileCoverage).forEach(key => {
|
|
9079
|
+
const fileCoverage = fileByFileCoverage[key];
|
|
9080
|
+
const {
|
|
9081
|
+
path
|
|
9082
|
+
} = fileCoverage;
|
|
9083
|
+
const url = isFileSystemPath(path) ? fileSystemPathToUrl(path) : new URL(path, rootDirectoryUrl).href;
|
|
9084
|
+
const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl);
|
|
9085
|
+
fileByFileNormalized[`./${relativeUrl}`] = { ...fileCoverage,
|
|
9086
|
+
path: `./${relativeUrl}`
|
|
9087
|
+
};
|
|
9088
|
+
});
|
|
9089
|
+
return fileByFileNormalized;
|
|
9090
|
+
};
|
|
9091
|
+
|
|
9092
|
+
const listRelativeFileUrlToCover = async ({
|
|
9093
|
+
signal,
|
|
9094
|
+
rootDirectoryUrl,
|
|
9095
|
+
coverageConfig
|
|
9096
|
+
}) => {
|
|
9097
|
+
const matchingFileResultArray = await collectFiles({
|
|
9098
|
+
signal,
|
|
9099
|
+
directoryUrl: rootDirectoryUrl,
|
|
9100
|
+
associations: {
|
|
9101
|
+
cover: coverageConfig
|
|
9102
|
+
},
|
|
9103
|
+
predicate: ({
|
|
9104
|
+
cover
|
|
9105
|
+
}) => cover
|
|
9106
|
+
});
|
|
9107
|
+
return matchingFileResultArray.map(({
|
|
9108
|
+
relativeUrl
|
|
9109
|
+
}) => relativeUrl);
|
|
9110
|
+
};
|
|
9111
|
+
|
|
9112
|
+
const relativeUrlToEmptyCoverage = async (relativeUrl, {
|
|
9113
|
+
signal,
|
|
9114
|
+
rootDirectoryUrl
|
|
9115
|
+
}) => {
|
|
9116
|
+
const operation = Abort.startOperation();
|
|
9117
|
+
operation.addAbortSignal(signal);
|
|
9118
|
+
|
|
9119
|
+
try {
|
|
9120
|
+
const fileUrl = resolveUrl(relativeUrl, rootDirectoryUrl);
|
|
9121
|
+
const content = await readFile(fileUrl, {
|
|
9122
|
+
as: "string"
|
|
9123
|
+
});
|
|
9124
|
+
operation.throwIfAborted();
|
|
9125
|
+
const {
|
|
9126
|
+
metadata
|
|
9127
|
+
} = await applyBabelPlugins({
|
|
9128
|
+
babelPlugins: [[babelPluginInstrument, {
|
|
9129
|
+
rootDirectoryUrl
|
|
9130
|
+
}]],
|
|
9131
|
+
urlInfo: {
|
|
9132
|
+
originalUrl: fileUrl,
|
|
9133
|
+
content
|
|
9134
|
+
}
|
|
9135
|
+
});
|
|
9136
|
+
const {
|
|
9137
|
+
coverage
|
|
9138
|
+
} = metadata;
|
|
9139
|
+
|
|
9140
|
+
if (!coverage) {
|
|
9141
|
+
throw new Error(`missing coverage for file`);
|
|
9142
|
+
} // https://github.com/gotwarlost/istanbul/blob/bc84c315271a5dd4d39bcefc5925cfb61a3d174a/lib/command/common/run-with-cover.js#L229
|
|
9143
|
+
|
|
9144
|
+
|
|
9145
|
+
Object.keys(coverage.s).forEach(function (key) {
|
|
9146
|
+
coverage.s[key] = 0;
|
|
9147
|
+
});
|
|
9148
|
+
return coverage;
|
|
9149
|
+
} catch (e) {
|
|
9150
|
+
if (e && e.code === "PARSE_ERROR") {
|
|
9151
|
+
// return an empty coverage for that file when
|
|
9152
|
+
// it contains a syntax error
|
|
9153
|
+
return createEmptyCoverage(relativeUrl);
|
|
9154
|
+
}
|
|
9155
|
+
|
|
9156
|
+
throw e;
|
|
9157
|
+
} finally {
|
|
9158
|
+
await operation.end();
|
|
9159
|
+
}
|
|
9160
|
+
};
|
|
9161
|
+
|
|
9162
|
+
const createEmptyCoverage = relativeUrl => {
|
|
9163
|
+
const {
|
|
9164
|
+
createFileCoverage
|
|
9165
|
+
} = requireFromJsenv("istanbul-lib-coverage");
|
|
9166
|
+
return createFileCoverage(relativeUrl).toJSON();
|
|
9167
|
+
};
|
|
9168
|
+
|
|
9169
|
+
const getMissingFileByFileCoverage = async ({
|
|
9170
|
+
signal,
|
|
9171
|
+
rootDirectoryUrl,
|
|
9172
|
+
coverageConfig,
|
|
9173
|
+
fileByFileCoverage
|
|
8355
9174
|
}) => {
|
|
8356
|
-
const
|
|
8357
|
-
logLevel
|
|
8358
|
-
});
|
|
8359
|
-
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
|
|
8360
|
-
const reloadableProcess = await initReloadableProcess({
|
|
9175
|
+
const relativeUrlsToCover = await listRelativeFileUrlToCover({
|
|
8361
9176
|
signal,
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
enabled: true,
|
|
8365
|
-
logLevel: "warn",
|
|
8366
|
-
fileToRestart: devServerMainFile
|
|
8367
|
-
} : {
|
|
8368
|
-
enabled: false
|
|
8369
|
-
})
|
|
9177
|
+
rootDirectoryUrl,
|
|
9178
|
+
coverageConfig
|
|
8370
9179
|
});
|
|
9180
|
+
const relativeUrlsMissing = relativeUrlsToCover.filter(relativeUrlToCover => Object.keys(fileByFileCoverage).every(key => {
|
|
9181
|
+
return key !== `./${relativeUrlToCover}`;
|
|
9182
|
+
}));
|
|
9183
|
+
const operation = Abort.startOperation();
|
|
9184
|
+
operation.addAbortSignal(signal);
|
|
9185
|
+
const missingFileByFileCoverage = {};
|
|
9186
|
+
await relativeUrlsMissing.reduce(async (previous, relativeUrlMissing) => {
|
|
9187
|
+
operation.throwIfAborted();
|
|
9188
|
+
await previous;
|
|
9189
|
+
await operation.withSignal(async signal => {
|
|
9190
|
+
const emptyCoverage = await relativeUrlToEmptyCoverage(relativeUrlMissing, {
|
|
9191
|
+
signal,
|
|
9192
|
+
rootDirectoryUrl
|
|
9193
|
+
});
|
|
9194
|
+
missingFileByFileCoverage[`./${relativeUrlMissing}`] = emptyCoverage;
|
|
9195
|
+
});
|
|
9196
|
+
}, Promise.resolve());
|
|
9197
|
+
return missingFileByFileCoverage;
|
|
9198
|
+
};
|
|
8371
9199
|
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
9200
|
+
const reportToCoverage = async (report, {
|
|
9201
|
+
signal,
|
|
9202
|
+
logger,
|
|
9203
|
+
rootDirectoryUrl,
|
|
9204
|
+
coverageConfig,
|
|
9205
|
+
coverageIncludeMissing,
|
|
9206
|
+
urlShouldBeCovered,
|
|
9207
|
+
coverageForceIstanbul,
|
|
9208
|
+
coverageV8ConflictWarning
|
|
9209
|
+
}) => {
|
|
9210
|
+
// collect v8 and istanbul coverage from executions
|
|
9211
|
+
let {
|
|
9212
|
+
v8Coverage,
|
|
9213
|
+
fileByFileIstanbulCoverage
|
|
9214
|
+
} = await getCoverageFromReport({
|
|
9215
|
+
signal,
|
|
9216
|
+
report,
|
|
9217
|
+
onMissing: ({
|
|
9218
|
+
file,
|
|
9219
|
+
executionResult,
|
|
9220
|
+
executionName
|
|
8376
9221
|
}) => {
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
9222
|
+
// several reasons not to have coverage here:
|
|
9223
|
+
// 1. the file we executed did not import an instrumented file.
|
|
9224
|
+
// - a test file without import
|
|
9225
|
+
// - a test file importing only file excluded from coverage
|
|
9226
|
+
// - a coverDescription badly configured so that we don't realize
|
|
9227
|
+
// a file should be covered
|
|
9228
|
+
// 2. the file we wanted to executed timedout
|
|
9229
|
+
// - infinite loop
|
|
9230
|
+
// - too extensive operation
|
|
9231
|
+
// - a badly configured or too low allocatedMs for that execution.
|
|
9232
|
+
// 3. the file we wanted to execute contains syntax-error
|
|
9233
|
+
// in any scenario we are fine because
|
|
9234
|
+
// coverDescription will generate empty coverage for files
|
|
9235
|
+
// that were suppose to be coverage but were not.
|
|
9236
|
+
if (executionResult.status === "completed" && executionResult.runtimeName !== "node" && !process.env.NODE_V8_COVERAGE) {
|
|
9237
|
+
logger.warn(`No execution.coverageFileUrl from execution named "${executionName}" of ${file}`);
|
|
8382
9238
|
}
|
|
8383
|
-
}
|
|
9239
|
+
}
|
|
9240
|
+
});
|
|
8384
9241
|
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
added: ({
|
|
8394
|
-
relativeUrl
|
|
8395
|
-
}) => {
|
|
8396
|
-
devServerFileChangeCallback({
|
|
8397
|
-
relativeUrl,
|
|
8398
|
-
event: "added"
|
|
8399
|
-
});
|
|
8400
|
-
},
|
|
8401
|
-
updated: ({
|
|
8402
|
-
relativeUrl
|
|
8403
|
-
}) => {
|
|
8404
|
-
devServerFileChangeCallback({
|
|
8405
|
-
relativeUrl,
|
|
8406
|
-
event: "modified"
|
|
8407
|
-
});
|
|
8408
|
-
},
|
|
8409
|
-
removed: ({
|
|
8410
|
-
relativeUrl
|
|
8411
|
-
}) => {
|
|
8412
|
-
devServerFileChangeCallback({
|
|
8413
|
-
relativeUrl,
|
|
8414
|
-
event: "removed"
|
|
9242
|
+
if (!coverageForceIstanbul && process.env.NODE_V8_COVERAGE) {
|
|
9243
|
+
await visitNodeV8Directory({
|
|
9244
|
+
logger,
|
|
9245
|
+
signal,
|
|
9246
|
+
NODE_V8_COVERAGE: process.env.NODE_V8_COVERAGE,
|
|
9247
|
+
onV8Coverage: nodeV8Coverage => {
|
|
9248
|
+
const nodeV8CoverageLight = filterV8Coverage(nodeV8Coverage, {
|
|
9249
|
+
urlShouldBeCovered
|
|
8415
9250
|
});
|
|
9251
|
+
v8Coverage = v8Coverage ? composeTwoV8Coverages(v8Coverage, nodeV8CoverageLight) : nodeV8CoverageLight;
|
|
8416
9252
|
}
|
|
8417
9253
|
});
|
|
8418
|
-
|
|
8419
|
-
unregisterDevServerFilesWatcher();
|
|
8420
|
-
});
|
|
8421
|
-
return {
|
|
8422
|
-
origin: `${protocol}://127.0.0.1:${port}`,
|
|
8423
|
-
stop: () => {
|
|
8424
|
-
unregisterDevServerFilesWatcher();
|
|
8425
|
-
reloadableProcess.stop();
|
|
8426
|
-
}
|
|
8427
|
-
};
|
|
8428
|
-
}
|
|
9254
|
+
} // try to merge v8 with istanbul, if any
|
|
8429
9255
|
|
|
8430
|
-
const startDevServerTask = createTaskLog("start dev server", {
|
|
8431
|
-
disabled: !loggerToLevels(logger).info
|
|
8432
|
-
});
|
|
8433
|
-
const clientFileChangeCallbackList = [];
|
|
8434
|
-
const clientFilesPruneCallbackList = [];
|
|
8435
9256
|
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
clientFileChangeCallbackList.forEach(callback => {
|
|
8442
|
-
callback({
|
|
8443
|
-
url,
|
|
8444
|
-
event
|
|
8445
|
-
});
|
|
9257
|
+
let fileByFileCoverage;
|
|
9258
|
+
|
|
9259
|
+
if (v8Coverage) {
|
|
9260
|
+
let v8FileByFileCoverage = await v8CoverageToIstanbul(v8Coverage, {
|
|
9261
|
+
signal
|
|
8446
9262
|
});
|
|
8447
|
-
|
|
9263
|
+
v8FileByFileCoverage = normalizeFileByFileCoveragePaths(v8FileByFileCoverage, rootDirectoryUrl);
|
|
8448
9264
|
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
recursive: true,
|
|
8454
|
-
added: ({
|
|
8455
|
-
relativeUrl
|
|
8456
|
-
}) => {
|
|
8457
|
-
clientFileChangeCallback({
|
|
8458
|
-
event: "added",
|
|
8459
|
-
relativeUrl
|
|
8460
|
-
});
|
|
8461
|
-
},
|
|
8462
|
-
updated: ({
|
|
8463
|
-
relativeUrl
|
|
8464
|
-
}) => {
|
|
8465
|
-
clientFileChangeCallback({
|
|
8466
|
-
event: "modified",
|
|
8467
|
-
relativeUrl
|
|
8468
|
-
});
|
|
8469
|
-
},
|
|
8470
|
-
removed: ({
|
|
8471
|
-
relativeUrl
|
|
8472
|
-
}) => {
|
|
8473
|
-
clientFileChangeCallback({
|
|
8474
|
-
event: "removed",
|
|
8475
|
-
relativeUrl
|
|
9265
|
+
if (fileByFileIstanbulCoverage) {
|
|
9266
|
+
fileByFileIstanbulCoverage = normalizeFileByFileCoveragePaths(fileByFileIstanbulCoverage, rootDirectoryUrl);
|
|
9267
|
+
fileByFileCoverage = composeV8AndIstanbul(v8FileByFileCoverage, fileByFileIstanbulCoverage, {
|
|
9268
|
+
coverageV8ConflictWarning
|
|
8476
9269
|
});
|
|
9270
|
+
} else {
|
|
9271
|
+
fileByFileCoverage = v8FileByFileCoverage;
|
|
8477
9272
|
}
|
|
8478
|
-
}
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
sourcemaps,
|
|
8491
|
-
writeGeneratedFiles,
|
|
8492
|
-
plugins: [...plugins, ...getCorePlugins({
|
|
9273
|
+
} // get istanbul only
|
|
9274
|
+
else if (fileByFileIstanbulCoverage) {
|
|
9275
|
+
fileByFileCoverage = normalizeFileByFileCoveragePaths(fileByFileIstanbulCoverage, rootDirectoryUrl);
|
|
9276
|
+
} // no coverage found in execution (or zero file where executed)
|
|
9277
|
+
else {
|
|
9278
|
+
fileByFileCoverage = {};
|
|
9279
|
+
} // now add coverage for file not covered
|
|
9280
|
+
|
|
9281
|
+
|
|
9282
|
+
if (coverageIncludeMissing) {
|
|
9283
|
+
const missingFileByFileCoverage = await getMissingFileByFileCoverage({
|
|
9284
|
+
signal,
|
|
8493
9285
|
rootDirectoryUrl,
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
9286
|
+
coverageConfig,
|
|
9287
|
+
fileByFileCoverage
|
|
9288
|
+
});
|
|
9289
|
+
Object.assign(fileByFileCoverage, normalizeFileByFileCoveragePaths(missingFileByFileCoverage, rootDirectoryUrl));
|
|
9290
|
+
}
|
|
9291
|
+
|
|
9292
|
+
return fileByFileCoverage;
|
|
9293
|
+
};
|
|
9294
|
+
|
|
9295
|
+
const getCoverageFromReport = async ({
|
|
9296
|
+
signal,
|
|
9297
|
+
report,
|
|
9298
|
+
onMissing
|
|
9299
|
+
}) => {
|
|
9300
|
+
const operation = Abort.startOperation();
|
|
9301
|
+
operation.addAbortSignal(signal);
|
|
9302
|
+
|
|
9303
|
+
try {
|
|
9304
|
+
let v8Coverage;
|
|
9305
|
+
let fileByFileIstanbulCoverage; // collect v8 and istanbul coverage from executions
|
|
9306
|
+
|
|
9307
|
+
await Object.keys(report).reduce(async (previous, file) => {
|
|
9308
|
+
operation.throwIfAborted();
|
|
9309
|
+
await previous;
|
|
9310
|
+
const executionResultForFile = report[file];
|
|
9311
|
+
await Object.keys(executionResultForFile).reduce(async (previous, executionName) => {
|
|
9312
|
+
operation.throwIfAborted();
|
|
9313
|
+
await previous;
|
|
9314
|
+
const executionResultForFileOnRuntime = executionResultForFile[executionName];
|
|
9315
|
+
const {
|
|
9316
|
+
coverageFileUrl
|
|
9317
|
+
} = executionResultForFileOnRuntime;
|
|
9318
|
+
|
|
9319
|
+
if (!coverageFileUrl) {
|
|
9320
|
+
onMissing({
|
|
9321
|
+
executionName,
|
|
9322
|
+
file,
|
|
9323
|
+
executionResult: executionResultForFileOnRuntime
|
|
9324
|
+
});
|
|
9325
|
+
return;
|
|
9326
|
+
}
|
|
9327
|
+
|
|
9328
|
+
const executionCoverage = await readFile(coverageFileUrl, {
|
|
9329
|
+
as: "json"
|
|
9330
|
+
});
|
|
9331
|
+
|
|
9332
|
+
if (isV8Coverage(executionCoverage)) {
|
|
9333
|
+
v8Coverage = v8Coverage ? composeTwoV8Coverages(v8Coverage, executionCoverage) : executionCoverage;
|
|
9334
|
+
} else {
|
|
9335
|
+
fileByFileIstanbulCoverage = fileByFileIstanbulCoverage ? composeTwoFileByFileIstanbulCoverages(fileByFileIstanbulCoverage, executionCoverage) : executionCoverage;
|
|
9336
|
+
}
|
|
9337
|
+
}, Promise.resolve());
|
|
9338
|
+
}, Promise.resolve());
|
|
9339
|
+
return {
|
|
9340
|
+
v8Coverage,
|
|
9341
|
+
fileByFileIstanbulCoverage
|
|
8533
9342
|
};
|
|
8534
|
-
}
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
stop: () => {
|
|
8538
|
-
stopWatchingClientFiles();
|
|
8539
|
-
server.stop();
|
|
8540
|
-
}
|
|
8541
|
-
};
|
|
9343
|
+
} finally {
|
|
9344
|
+
await operation.end();
|
|
9345
|
+
}
|
|
8542
9346
|
};
|
|
8543
9347
|
|
|
9348
|
+
const isV8Coverage = coverage => Boolean(coverage.result);
|
|
9349
|
+
|
|
8544
9350
|
const run = async ({
|
|
8545
9351
|
signal = new AbortController().signal,
|
|
8546
9352
|
logger,
|
|
@@ -11540,7 +12346,7 @@ const injectors = {
|
|
|
11540
12346
|
const htmlAst = parseHtmlString(urlInfo.content, {
|
|
11541
12347
|
storeOriginalPositions: false
|
|
11542
12348
|
});
|
|
11543
|
-
|
|
12349
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
11544
12350
|
"tagName": "script",
|
|
11545
12351
|
"textContent": generateClientCodeForVersionMappings(versionMappings, {
|
|
11546
12352
|
globalName: "window"
|
|
@@ -11668,15 +12474,12 @@ const resyncRessourceHints = async ({
|
|
|
11668
12474
|
});
|
|
11669
12475
|
const actions = [];
|
|
11670
12476
|
|
|
11671
|
-
const visitLinkWithHref = (linkNode,
|
|
11672
|
-
const href = hrefAttribute.value;
|
|
11673
|
-
|
|
12477
|
+
const visitLinkWithHref = (linkNode, href) => {
|
|
11674
12478
|
if (!href || href.startsWith("data:")) {
|
|
11675
12479
|
return;
|
|
11676
12480
|
}
|
|
11677
12481
|
|
|
11678
|
-
const
|
|
11679
|
-
const rel = relAttribute ? relAttribute.value : undefined;
|
|
12482
|
+
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
11680
12483
|
const isRessourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
|
|
11681
12484
|
|
|
11682
12485
|
if (!isRessourceHint) {
|
|
@@ -11720,22 +12523,20 @@ const resyncRessourceHints = async ({
|
|
|
11720
12523
|
}
|
|
11721
12524
|
|
|
11722
12525
|
actions.push(() => {
|
|
11723
|
-
|
|
12526
|
+
setHtmlNodeAttributes(linkNode, {
|
|
12527
|
+
href: urlInfo.data.buildUrlSpecifier
|
|
12528
|
+
});
|
|
11724
12529
|
});
|
|
11725
12530
|
};
|
|
11726
12531
|
|
|
11727
|
-
|
|
11728
|
-
|
|
11729
|
-
|
|
11730
|
-
}
|
|
12532
|
+
visitHtmlNodes(htmlAst, {
|
|
12533
|
+
link: node => {
|
|
12534
|
+
const href = getHtmlNodeAttribute(node, "href");
|
|
11731
12535
|
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
return;
|
|
12536
|
+
if (href !== undefined) {
|
|
12537
|
+
visitLinkWithHref(node, href);
|
|
12538
|
+
}
|
|
11736
12539
|
}
|
|
11737
|
-
|
|
11738
|
-
visitLinkWithHref(node, hrefAttribute);
|
|
11739
12540
|
});
|
|
11740
12541
|
|
|
11741
12542
|
if (actions.length) {
|
|
@@ -12300,7 +13101,7 @@ build ${entryPointKeys.length} entry points`);
|
|
|
12300
13101
|
|
|
12301
13102
|
if (reference.type === "sourcemap_comment") {
|
|
12302
13103
|
// inherit parent build url
|
|
12303
|
-
return
|
|
13104
|
+
return generateSourcemapFileUrl(reference.parentUrl);
|
|
12304
13105
|
} // files generated during the final graph:
|
|
12305
13106
|
// - sourcemaps
|
|
12306
13107
|
// const finalUrlInfo = finalGraph.getUrlInfo(url)
|
|
@@ -13026,6 +13827,7 @@ const startBuildServer = async ({
|
|
|
13026
13827
|
ip,
|
|
13027
13828
|
port = 9779,
|
|
13028
13829
|
services = {},
|
|
13830
|
+
keepProcessAlive = true,
|
|
13029
13831
|
rootDirectoryUrl,
|
|
13030
13832
|
buildDirectoryUrl,
|
|
13031
13833
|
mainBuildFileUrl = "/index.html",
|
|
@@ -13036,9 +13838,9 @@ const startBuildServer = async ({
|
|
|
13036
13838
|
buildServerMainFile = getCallerPosition().url,
|
|
13037
13839
|
// force disable server autoreload when this code is executed:
|
|
13038
13840
|
// - inside a forked child process
|
|
13039
|
-
// -
|
|
13040
|
-
//
|
|
13041
|
-
buildServerAutoreload = typeof process.send !== "function" && !
|
|
13841
|
+
// - debugged by vscode
|
|
13842
|
+
// otherwise we get net:ERR_CONNECTION_REFUSED
|
|
13843
|
+
buildServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
|
|
13042
13844
|
cooldownBetweenFileEvents
|
|
13043
13845
|
}) => {
|
|
13044
13846
|
const logger = createLogger({
|
|
@@ -13046,19 +13848,26 @@ const startBuildServer = async ({
|
|
|
13046
13848
|
});
|
|
13047
13849
|
rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
|
|
13048
13850
|
buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl);
|
|
13049
|
-
const
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13851
|
+
const operation = Abort.startOperation();
|
|
13852
|
+
operation.addAbortSignal(signal);
|
|
13853
|
+
|
|
13854
|
+
if (handleSIGINT) {
|
|
13855
|
+
operation.addAbortSource(abort => {
|
|
13856
|
+
return raceProcessTeardownEvents({
|
|
13857
|
+
SIGINT: true
|
|
13858
|
+
}, abort);
|
|
13859
|
+
});
|
|
13860
|
+
}
|
|
13861
|
+
|
|
13862
|
+
if (port === 0) {
|
|
13863
|
+
port = await findFreePort(port, {
|
|
13864
|
+
signal: operation.signal
|
|
13865
|
+
});
|
|
13866
|
+
}
|
|
13060
13867
|
|
|
13061
|
-
|
|
13868
|
+
const reloadableWorker = createReloadableWorker(buildServerMainFile);
|
|
13869
|
+
|
|
13870
|
+
if (buildServerAutoreload && reloadableWorker.isPrimary) {
|
|
13062
13871
|
const buildServerFileChangeCallback = ({
|
|
13063
13872
|
relativeUrl,
|
|
13064
13873
|
event
|
|
@@ -13067,7 +13876,7 @@ const startBuildServer = async ({
|
|
|
13067
13876
|
|
|
13068
13877
|
if (buildServerAutoreload) {
|
|
13069
13878
|
logger.info(`file ${event} ${url} -> restarting server...`);
|
|
13070
|
-
|
|
13879
|
+
reloadableWorker.reload();
|
|
13071
13880
|
}
|
|
13072
13881
|
};
|
|
13073
13882
|
|
|
@@ -13104,19 +13913,25 @@ const startBuildServer = async ({
|
|
|
13104
13913
|
});
|
|
13105
13914
|
}
|
|
13106
13915
|
});
|
|
13107
|
-
|
|
13916
|
+
operation.addAbortCallback(() => {
|
|
13108
13917
|
stopWatchingBuildServerFiles();
|
|
13918
|
+
reloadableWorker.terminate();
|
|
13109
13919
|
});
|
|
13920
|
+
const worker = await reloadableWorker.load();
|
|
13921
|
+
|
|
13922
|
+
if (!keepProcessAlive) {
|
|
13923
|
+
worker.unref();
|
|
13924
|
+
}
|
|
13925
|
+
|
|
13110
13926
|
return {
|
|
13111
13927
|
origin: `${protocol}://127.0.0.1:${port}`,
|
|
13112
13928
|
stop: () => {
|
|
13113
13929
|
stopWatchingBuildServerFiles();
|
|
13114
|
-
|
|
13930
|
+
reloadableWorker.terminate();
|
|
13115
13931
|
}
|
|
13116
13932
|
};
|
|
13117
13933
|
}
|
|
13118
13934
|
|
|
13119
|
-
signal = reloadableProcess.signal;
|
|
13120
13935
|
const startBuildServerTask = createTaskLog("start build server", {
|
|
13121
13936
|
disabled: !loggerToLevels(logger).info
|
|
13122
13937
|
});
|
|
@@ -13365,7 +14180,7 @@ const globalInjectorOnHtml = async (urlInfo, globals) => {
|
|
|
13365
14180
|
globals,
|
|
13366
14181
|
isWebWorker: false
|
|
13367
14182
|
});
|
|
13368
|
-
|
|
14183
|
+
injectScriptNodeAsEarlyAsPossible(htmlAst, createHtmlNode({
|
|
13369
14184
|
"tagName": "script",
|
|
13370
14185
|
"textContent": clientCode,
|
|
13371
14186
|
"injected-by": "jsenv:inject_globals"
|