@jsenv/core 27.8.0 → 28.0.1
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/autoreload.js +2 -2
- package/dist/js/html_supervisor_installer.js +3 -3
- package/dist/js/server_events_client.js +1 -1
- package/dist/main.js +520 -469
- package/package.json +2 -2
- package/readme.md +1 -1
- package/src/build/build.js +8 -8
- package/src/build/{resync_ressource_hints.js → resync_resource_hints.js} +10 -12
- package/src/build/start_build_server.js +6 -9
- package/src/dev/start_dev_server.js +2 -2
- package/src/execute/execute.js +14 -52
- package/src/execute/runtimes/browsers/from_playwright.js +19 -8
- package/src/main.js +3 -0
- package/src/omega/kitchen.js +5 -5
- package/src/omega/omega_server.js +2 -2
- package/src/omega/server/file_service.js +3 -3
- package/src/omega/url_graph/url_graph_load.js +4 -4
- package/src/omega/url_graph.js +3 -3
- package/src/ping_server.js +30 -0
- package/src/plugins/autoreload/client/reload.js +2 -2
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -1
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +3 -3
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
- package/src/plugins/explorer/jsenv_plugin_explorer.js +1 -1
- package/src/plugins/html_supervisor/client/error_formatter.js +3 -3
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +5 -5
- package/src/plugins/import_meta_hot/html_hot_dependencies.js +4 -4
- package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +1 -9
- package/src/plugins/plugin_controller.js +2 -2
- package/src/plugins/server_events/client/server_events_client.js +1 -1
- package/src/plugins/toolbar/jsenv_plugin_toolbar.js +1 -1
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +2 -2
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +3 -3
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -0
- package/src/plugins/url_analysis/html/html_urls.js +2 -2
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +1 -1
- package/src/test/execute_plan.js +15 -68
- package/src/test/execute_test_plan.js +4 -26
package/dist/main.js
CHANGED
|
@@ -12,10 +12,10 @@ import { createMagicSource, composeTwoSourcemaps, getOriginalPosition, sourcemap
|
|
|
12
12
|
import { parseHtmlString, stringifyHtmlAst, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, getHtmlNodeText, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode } from "@jsenv/ast";
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import babelParser from "@babel/parser";
|
|
15
|
+
import net, { createServer, isIP } from "node:net";
|
|
15
16
|
import http from "node:http";
|
|
16
17
|
import cluster from "node:cluster";
|
|
17
18
|
import { performance as performance$1 } from "node:perf_hooks";
|
|
18
|
-
import net, { createServer } from "node:net";
|
|
19
19
|
import { Readable, Stream, Writable } from "node:stream";
|
|
20
20
|
import { Http2ServerResponse } from "node:http2";
|
|
21
21
|
import { lookup } from "node:dns";
|
|
@@ -94,7 +94,7 @@ const urlToScheme$1 = url => {
|
|
|
94
94
|
return scheme;
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
const
|
|
97
|
+
const urlToResource = url => {
|
|
98
98
|
const scheme = urlToScheme$1(url);
|
|
99
99
|
|
|
100
100
|
if (scheme === "file") {
|
|
@@ -115,25 +115,25 @@ const urlToRessource$1 = url => {
|
|
|
115
115
|
};
|
|
116
116
|
|
|
117
117
|
const urlToPathname$1 = url => {
|
|
118
|
-
const
|
|
119
|
-
const pathname =
|
|
118
|
+
const resource = urlToResource(url);
|
|
119
|
+
const pathname = resourceToPathname(resource);
|
|
120
120
|
return pathname;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
-
const
|
|
124
|
-
const searchSeparatorIndex =
|
|
123
|
+
const resourceToPathname = resource => {
|
|
124
|
+
const searchSeparatorIndex = resource.indexOf("?");
|
|
125
125
|
|
|
126
126
|
if (searchSeparatorIndex > -1) {
|
|
127
|
-
return
|
|
127
|
+
return resource.slice(0, searchSeparatorIndex);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
const hashIndex =
|
|
130
|
+
const hashIndex = resource.indexOf("#");
|
|
131
131
|
|
|
132
132
|
if (hashIndex > -1) {
|
|
133
|
-
return
|
|
133
|
+
return resource.slice(0, hashIndex);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
return
|
|
136
|
+
return resource;
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
const urlToFilename$1 = url => {
|
|
@@ -616,8 +616,8 @@ const urlToRelativeUrl = (url, baseUrl) => {
|
|
|
616
616
|
} = urlObject;
|
|
617
617
|
|
|
618
618
|
if (pathname === "/") {
|
|
619
|
-
const
|
|
620
|
-
return
|
|
619
|
+
const baseUrlResourceWithoutLeadingSlash = baseUrlObject.pathname.slice(1);
|
|
620
|
+
return baseUrlResourceWithoutLeadingSlash;
|
|
621
621
|
}
|
|
622
622
|
|
|
623
623
|
const basePathname = baseUrlObject.pathname;
|
|
@@ -2006,10 +2006,10 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
|
|
|
2006
2006
|
return `file:///${driveLetter}:${afterProtocol}`;
|
|
2007
2007
|
};
|
|
2008
2008
|
|
|
2009
|
-
const extractDriveLetter =
|
|
2009
|
+
const extractDriveLetter = resource => {
|
|
2010
2010
|
// we still have the windows drive letter
|
|
2011
|
-
if (/[a-zA-Z]/.test(
|
|
2012
|
-
return
|
|
2011
|
+
if (/[a-zA-Z]/.test(resource[1]) && resource[2] === ":") {
|
|
2012
|
+
return resource[1];
|
|
2013
2013
|
}
|
|
2014
2014
|
|
|
2015
2015
|
return null;
|
|
@@ -2136,7 +2136,7 @@ const createWatcher = (sourcePath, options) => {
|
|
|
2136
2136
|
return watcher;
|
|
2137
2137
|
};
|
|
2138
2138
|
|
|
2139
|
-
const
|
|
2139
|
+
const trackResources = () => {
|
|
2140
2140
|
const callbackArray = [];
|
|
2141
2141
|
|
|
2142
2142
|
const registerCleanupCallback = callback => {
|
|
@@ -2244,7 +2244,7 @@ const registerDirectoryLifecycle = (source, {
|
|
|
2244
2244
|
return watch;
|
|
2245
2245
|
};
|
|
2246
2246
|
|
|
2247
|
-
const tracker =
|
|
2247
|
+
const tracker = trackResources();
|
|
2248
2248
|
const infoMap = new Map();
|
|
2249
2249
|
|
|
2250
2250
|
const readEntryInfo = url => {
|
|
@@ -2380,7 +2380,7 @@ const registerDirectoryLifecycle = (source, {
|
|
|
2380
2380
|
|
|
2381
2381
|
if (entryInfo.type !== previousInfo.type) {
|
|
2382
2382
|
// it existed and was replaced by something else
|
|
2383
|
-
// we don't handle this as an update. We rather say the
|
|
2383
|
+
// we don't handle this as an update. We rather say the resource
|
|
2384
2384
|
// is lost and something else is found (call removed() then added())
|
|
2385
2385
|
handleEntryLost(previousInfo);
|
|
2386
2386
|
handleEntryFound(entryInfo);
|
|
@@ -2591,7 +2591,7 @@ const registerFileLifecycle = (source, {
|
|
|
2591
2591
|
}
|
|
2592
2592
|
}
|
|
2593
2593
|
|
|
2594
|
-
const tracker =
|
|
2594
|
+
const tracker = trackResources();
|
|
2595
2595
|
|
|
2596
2596
|
const handleFileFound = ({
|
|
2597
2597
|
existent
|
|
@@ -4014,10 +4014,10 @@ const createUrlGraph = ({
|
|
|
4014
4014
|
}
|
|
4015
4015
|
|
|
4016
4016
|
references.forEach(reference => {
|
|
4017
|
-
if (reference.
|
|
4018
|
-
//
|
|
4017
|
+
if (reference.isResourceHint) {
|
|
4018
|
+
// resource hint are a special kind of reference.
|
|
4019
4019
|
// They are a sort of weak reference to an url.
|
|
4020
|
-
// We ignore them so that url referenced only by
|
|
4020
|
+
// We ignore them so that url referenced only by resource hints
|
|
4021
4021
|
// have url.dependents.size === 0 and can be considered as not used
|
|
4022
4022
|
// It means html won't consider url referenced solely
|
|
4023
4023
|
// by <link> as dependency and it's fine
|
|
@@ -4243,7 +4243,7 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
4243
4243
|
crossorigin,
|
|
4244
4244
|
integrity
|
|
4245
4245
|
} = readFetchMetas(node);
|
|
4246
|
-
const
|
|
4246
|
+
const isResourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(subtype);
|
|
4247
4247
|
const [reference] = referenceUtils.found({
|
|
4248
4248
|
type,
|
|
4249
4249
|
expectedType,
|
|
@@ -4252,7 +4252,7 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
|
|
|
4252
4252
|
specifier,
|
|
4253
4253
|
specifierLine: line,
|
|
4254
4254
|
specifierColumn: column,
|
|
4255
|
-
|
|
4255
|
+
isResourceHint,
|
|
4256
4256
|
crossorigin,
|
|
4257
4257
|
integrity
|
|
4258
4258
|
});
|
|
@@ -4669,7 +4669,7 @@ const jsenvPluginUrlAnalysis = ({
|
|
|
4669
4669
|
return;
|
|
4670
4670
|
}
|
|
4671
4671
|
|
|
4672
|
-
if (reference.specifier[0] === "#" && // For Html, css and in general "#" refer to a
|
|
4672
|
+
if (reference.specifier[0] === "#" && // For Html, css and in general "#" refer to a resource in the page
|
|
4673
4673
|
// so that urls must be kept intact
|
|
4674
4674
|
// However for js import specifiers they have a different meaning and we want
|
|
4675
4675
|
// to resolve them (https://nodejs.org/api/packages.html#imports for instance)
|
|
@@ -5825,10 +5825,10 @@ const jsenvPluginAsJsClassicHtml = ({
|
|
|
5825
5825
|
const convertedUrls = [];
|
|
5826
5826
|
|
|
5827
5827
|
const getReferenceAsJsClassic = async (reference, {
|
|
5828
|
-
// we don't cook
|
|
5829
|
-
// because they might refer to
|
|
5828
|
+
// we don't cook resource hints
|
|
5829
|
+
// because they might refer to resource that will be modified during build
|
|
5830
5830
|
// It also means something else HAVE to reference that url in order to cook it
|
|
5831
|
-
// so that the preload is deleted by "
|
|
5831
|
+
// so that the preload is deleted by "resync_resource_hints.js" otherwise
|
|
5832
5832
|
cookIt = false
|
|
5833
5833
|
} = {}) => {
|
|
5834
5834
|
const newReferenceProps = {
|
|
@@ -10451,7 +10451,7 @@ const jsenvPluginAsJsClassicConversion = ({
|
|
|
10451
10451
|
// - import specifier (static/dynamic import + re-export)
|
|
10452
10452
|
// - url specifier when inside System.register/_context.import()
|
|
10453
10453
|
// (because it's the transpiled equivalent of static and dynamic imports)
|
|
10454
|
-
// And not other references otherwise we could try to transform inline
|
|
10454
|
+
// And not other references otherwise we could try to transform inline resources
|
|
10455
10455
|
// or specifiers inside new URL()...
|
|
10456
10456
|
js_import_export: propagateJsClassicSearchParam,
|
|
10457
10457
|
js_url_specifier: (reference, context) => {
|
|
@@ -10468,7 +10468,7 @@ const jsenvPluginAsJsClassicConversion = ({
|
|
|
10468
10468
|
context,
|
|
10469
10469
|
searchParam: "as_js_classic",
|
|
10470
10470
|
// override the expectedType to "js_module"
|
|
10471
|
-
// because when there is ?as_js_classic it means the underlying
|
|
10471
|
+
// because when there is ?as_js_classic it means the underlying resource
|
|
10472
10472
|
// is a js_module
|
|
10473
10473
|
expectedType: "js_module"
|
|
10474
10474
|
});
|
|
@@ -11531,26 +11531,26 @@ const getParentUrl = url => {
|
|
|
11531
11531
|
if (url.startsWith("file://")) {
|
|
11532
11532
|
// With node.js new URL('../', 'file:///C:/').href
|
|
11533
11533
|
// returns "file:///C:/" instead of "file:///"
|
|
11534
|
-
const
|
|
11535
|
-
const slashLastIndex =
|
|
11534
|
+
const resource = url.slice("file://".length);
|
|
11535
|
+
const slashLastIndex = resource.lastIndexOf("/");
|
|
11536
11536
|
|
|
11537
11537
|
if (slashLastIndex === -1) {
|
|
11538
11538
|
return url;
|
|
11539
11539
|
}
|
|
11540
11540
|
|
|
11541
|
-
const lastCharIndex =
|
|
11541
|
+
const lastCharIndex = resource.length - 1;
|
|
11542
11542
|
|
|
11543
11543
|
if (slashLastIndex === lastCharIndex) {
|
|
11544
|
-
const slashBeforeLastIndex =
|
|
11544
|
+
const slashBeforeLastIndex = resource.lastIndexOf("/", slashLastIndex - 1);
|
|
11545
11545
|
|
|
11546
11546
|
if (slashBeforeLastIndex === -1) {
|
|
11547
11547
|
return url;
|
|
11548
11548
|
}
|
|
11549
11549
|
|
|
11550
|
-
return `file://${
|
|
11550
|
+
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
11551
11551
|
}
|
|
11552
11552
|
|
|
11553
|
-
return `file://${
|
|
11553
|
+
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
11554
11554
|
}
|
|
11555
11555
|
|
|
11556
11556
|
return new URL(url.endsWith("/") ? "../" : "./", url).href;
|
|
@@ -13190,7 +13190,7 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
13190
13190
|
name: "jsenv:html_supervisor",
|
|
13191
13191
|
appliesDuring: "dev",
|
|
13192
13192
|
serve: async (request, context) => {
|
|
13193
|
-
if (request.
|
|
13193
|
+
if (request.pathname.startsWith("/__get_code_frame__/")) {
|
|
13194
13194
|
const {
|
|
13195
13195
|
pathname,
|
|
13196
13196
|
searchParams
|
|
@@ -13249,8 +13249,8 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
13249
13249
|
};
|
|
13250
13250
|
}
|
|
13251
13251
|
|
|
13252
|
-
if (request.
|
|
13253
|
-
const file = request.
|
|
13252
|
+
if (request.pathname.startsWith("/__get_error_cause__/")) {
|
|
13253
|
+
const file = request.pathname.slice("/__get_error_cause__/".length);
|
|
13254
13254
|
|
|
13255
13255
|
if (!file) {
|
|
13256
13256
|
return {
|
|
@@ -13309,8 +13309,8 @@ const jsenvPluginHtmlSupervisor = ({
|
|
|
13309
13309
|
};
|
|
13310
13310
|
}
|
|
13311
13311
|
|
|
13312
|
-
if (request.
|
|
13313
|
-
const file = request.
|
|
13312
|
+
if (request.pathname.startsWith("/__open_in_editor__/")) {
|
|
13313
|
+
const file = request.pathname.slice("/__open_in_editor__/".length);
|
|
13314
13314
|
|
|
13315
13315
|
if (!file) {
|
|
13316
13316
|
return {
|
|
@@ -13742,7 +13742,6 @@ const jsenvPluginImportMetaScenarios = () => {
|
|
|
13742
13742
|
});
|
|
13743
13743
|
const {
|
|
13744
13744
|
dev = [],
|
|
13745
|
-
test = [],
|
|
13746
13745
|
build = []
|
|
13747
13746
|
} = metadata.importMetaScenarios;
|
|
13748
13747
|
const replacements = [];
|
|
@@ -13759,9 +13758,6 @@ const jsenvPluginImportMetaScenarios = () => {
|
|
|
13759
13758
|
dev.forEach(path => {
|
|
13760
13759
|
replace(path, "undefined");
|
|
13761
13760
|
});
|
|
13762
|
-
test.forEach(path => {
|
|
13763
|
-
replace(path, context.scenarios.test ? "true" : "undefined");
|
|
13764
|
-
});
|
|
13765
13761
|
build.forEach(path => {
|
|
13766
13762
|
replace(path, "true");
|
|
13767
13763
|
});
|
|
@@ -13773,12 +13769,6 @@ const jsenvPluginImportMetaScenarios = () => {
|
|
|
13773
13769
|
dev.forEach(path => {
|
|
13774
13770
|
replace(path, "true");
|
|
13775
13771
|
});
|
|
13776
|
-
|
|
13777
|
-
if (context.scenarios.test) {
|
|
13778
|
-
test.forEach(path => {
|
|
13779
|
-
replace(path, "true");
|
|
13780
|
-
});
|
|
13781
|
-
}
|
|
13782
13772
|
}
|
|
13783
13773
|
|
|
13784
13774
|
const magicSource = createMagicSource(urlInfo.content);
|
|
@@ -14062,6 +14052,87 @@ export default inlineContent.text`,
|
|
|
14062
14052
|
return [asJsonModule, asCssModule, asTextModule];
|
|
14063
14053
|
};
|
|
14064
14054
|
|
|
14055
|
+
const babelPluginInstrument = (api, {
|
|
14056
|
+
rootDirectoryUrl,
|
|
14057
|
+
useInlineSourceMaps = false,
|
|
14058
|
+
coverageConfig = {
|
|
14059
|
+
"./**/*": true
|
|
14060
|
+
}
|
|
14061
|
+
}) => {
|
|
14062
|
+
const {
|
|
14063
|
+
programVisitor
|
|
14064
|
+
} = requireFromJsenv("istanbul-lib-instrument");
|
|
14065
|
+
const {
|
|
14066
|
+
types
|
|
14067
|
+
} = api;
|
|
14068
|
+
const associations = URL_META.resolveAssociations({
|
|
14069
|
+
cover: coverageConfig
|
|
14070
|
+
}, rootDirectoryUrl);
|
|
14071
|
+
|
|
14072
|
+
const shouldInstrument = url => {
|
|
14073
|
+
return URL_META.applyAssociations({
|
|
14074
|
+
url,
|
|
14075
|
+
associations
|
|
14076
|
+
}).cover;
|
|
14077
|
+
};
|
|
14078
|
+
|
|
14079
|
+
return {
|
|
14080
|
+
name: "transform-instrument",
|
|
14081
|
+
visitor: {
|
|
14082
|
+
Program: {
|
|
14083
|
+
enter(path) {
|
|
14084
|
+
const {
|
|
14085
|
+
file
|
|
14086
|
+
} = this;
|
|
14087
|
+
const {
|
|
14088
|
+
opts
|
|
14089
|
+
} = file;
|
|
14090
|
+
|
|
14091
|
+
if (!opts.sourceFileName) {
|
|
14092
|
+
console.warn(`cannot instrument file when "sourceFileName" option is not set`);
|
|
14093
|
+
return;
|
|
14094
|
+
}
|
|
14095
|
+
|
|
14096
|
+
const fileUrl = fileSystemPathToUrl$1(opts.sourceFileName);
|
|
14097
|
+
|
|
14098
|
+
if (!shouldInstrument(fileUrl)) {
|
|
14099
|
+
return;
|
|
14100
|
+
}
|
|
14101
|
+
|
|
14102
|
+
this.__dv__ = null;
|
|
14103
|
+
let inputSourceMap;
|
|
14104
|
+
|
|
14105
|
+
if (useInlineSourceMaps) {
|
|
14106
|
+
// https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
|
|
14107
|
+
inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
|
|
14108
|
+
} else {
|
|
14109
|
+
inputSourceMap = opts.inputSourceMap;
|
|
14110
|
+
}
|
|
14111
|
+
|
|
14112
|
+
this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
|
|
14113
|
+
coverageVariable: "__coverage__",
|
|
14114
|
+
inputSourceMap
|
|
14115
|
+
});
|
|
14116
|
+
|
|
14117
|
+
this.__dv__.enter(path);
|
|
14118
|
+
},
|
|
14119
|
+
|
|
14120
|
+
exit(path) {
|
|
14121
|
+
if (!this.__dv__) {
|
|
14122
|
+
return;
|
|
14123
|
+
}
|
|
14124
|
+
|
|
14125
|
+
const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
|
|
14126
|
+
|
|
14127
|
+
|
|
14128
|
+
this.file.metadata.coverage = object.fileCoverage;
|
|
14129
|
+
}
|
|
14130
|
+
|
|
14131
|
+
}
|
|
14132
|
+
}
|
|
14133
|
+
};
|
|
14134
|
+
};
|
|
14135
|
+
|
|
14065
14136
|
const versionFromValue = value => {
|
|
14066
14137
|
if (typeof value === "number") {
|
|
14067
14138
|
return numberToVersion(value);
|
|
@@ -15243,6 +15314,17 @@ const jsenvPluginBabel = ({
|
|
|
15243
15314
|
getImportSpecifier
|
|
15244
15315
|
});
|
|
15245
15316
|
|
|
15317
|
+
if (context.scenarios.dev) {
|
|
15318
|
+
const requestHeaders = context.request.headers;
|
|
15319
|
+
|
|
15320
|
+
if (requestHeaders["x-coverage-instanbul"]) {
|
|
15321
|
+
babelPluginStructure["transform-instrument"] = [babelPluginInstrument, {
|
|
15322
|
+
rootDirectoryUrl: context.rootDirectoryUrl,
|
|
15323
|
+
coverageConfig: JSON.parse(requestHeaders["x-coverage-instanbul"])
|
|
15324
|
+
}];
|
|
15325
|
+
}
|
|
15326
|
+
}
|
|
15327
|
+
|
|
15246
15328
|
if (getCustomBabelPlugins) {
|
|
15247
15329
|
Object.assign(babelPluginStructure, getCustomBabelPlugins(context));
|
|
15248
15330
|
}
|
|
@@ -16315,7 +16397,7 @@ const htmlNodeCanHotReload = node => {
|
|
|
16315
16397
|
if (node.nodeName === "link") {
|
|
16316
16398
|
const {
|
|
16317
16399
|
isStylesheet,
|
|
16318
|
-
|
|
16400
|
+
isResourceHint,
|
|
16319
16401
|
rel
|
|
16320
16402
|
} = analyzeLinkNode(node);
|
|
16321
16403
|
|
|
@@ -16324,9 +16406,9 @@ const htmlNodeCanHotReload = node => {
|
|
|
16324
16406
|
return true;
|
|
16325
16407
|
}
|
|
16326
16408
|
|
|
16327
|
-
if (
|
|
16328
|
-
// for
|
|
16329
|
-
// but we won't do anything (if the
|
|
16409
|
+
if (isResourceHint) {
|
|
16410
|
+
// for resource hints html will be notified the underlying resource has changed
|
|
16411
|
+
// but we won't do anything (if the resource is deleted we should?)
|
|
16330
16412
|
return true;
|
|
16331
16413
|
}
|
|
16332
16414
|
|
|
@@ -16561,10 +16643,7 @@ import.meta.hot = createImportMetaHot(import.meta.url)
|
|
|
16561
16643
|
const jsenvPluginHmr = () => {
|
|
16562
16644
|
return {
|
|
16563
16645
|
name: "jsenv:hmr",
|
|
16564
|
-
appliesDuring:
|
|
16565
|
-
dev: true,
|
|
16566
|
-
test: false
|
|
16567
|
-
},
|
|
16646
|
+
appliesDuring: "dev",
|
|
16568
16647
|
redirectUrl: reference => {
|
|
16569
16648
|
const urlObject = new URL(reference.url);
|
|
16570
16649
|
|
|
@@ -16607,10 +16686,7 @@ const jsenvPluginAutoreloadClient = () => {
|
|
|
16607
16686
|
const autoreloadClientFileUrl = new URL("./js/autoreload.js", import.meta.url).href;
|
|
16608
16687
|
return {
|
|
16609
16688
|
name: "jsenv:autoreload_client",
|
|
16610
|
-
appliesDuring:
|
|
16611
|
-
dev: true,
|
|
16612
|
-
test: false
|
|
16613
|
-
},
|
|
16689
|
+
appliesDuring: "dev",
|
|
16614
16690
|
transformUrlContent: {
|
|
16615
16691
|
html: (htmlUrlInfo, context) => {
|
|
16616
16692
|
const htmlAst = parseHtmlString(htmlUrlInfo.content);
|
|
@@ -16640,10 +16716,7 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
16640
16716
|
}) => {
|
|
16641
16717
|
return {
|
|
16642
16718
|
name: "jsenv:autoreload_server",
|
|
16643
|
-
appliesDuring:
|
|
16644
|
-
dev: true,
|
|
16645
|
-
test: false
|
|
16646
|
-
},
|
|
16719
|
+
appliesDuring: "dev",
|
|
16647
16720
|
serverEvents: {
|
|
16648
16721
|
reload: ({
|
|
16649
16722
|
sendServerEvent,
|
|
@@ -16805,7 +16878,7 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
16805
16878
|
firstUrlInfo
|
|
16806
16879
|
}) => {
|
|
16807
16880
|
const mainHotUpdate = propagateUpdate(firstUrlInfo);
|
|
16808
|
-
const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => formatUrlForClient(prunedUrlInfo.url))}`; // now check if we can hot update the main
|
|
16881
|
+
const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => formatUrlForClient(prunedUrlInfo.url))}`; // now check if we can hot update the main resource
|
|
16809
16882
|
// then if we can hot update all dependencies
|
|
16810
16883
|
|
|
16811
16884
|
if (mainHotUpdate.declined) {
|
|
@@ -16852,7 +16925,7 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
16852
16925
|
rootDirectoryUrl,
|
|
16853
16926
|
urlGraph
|
|
16854
16927
|
}) => {
|
|
16855
|
-
if (request.
|
|
16928
|
+
if (request.pathname === "/__graph__") {
|
|
16856
16929
|
const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl));
|
|
16857
16930
|
return {
|
|
16858
16931
|
status: 200,
|
|
@@ -16922,7 +16995,7 @@ const jsenvPluginExplorer = ({
|
|
|
16922
16995
|
serve: async (request, {
|
|
16923
16996
|
rootDirectoryUrl
|
|
16924
16997
|
}) => {
|
|
16925
|
-
if (request.
|
|
16998
|
+
if (request.pathname !== "/") {
|
|
16926
16999
|
return null;
|
|
16927
17000
|
}
|
|
16928
17001
|
|
|
@@ -17896,7 +17969,7 @@ const nodeStreamToObservable = nodeStream => {
|
|
|
17896
17969
|
// safe measure, ensure the readable stream gets
|
|
17897
17970
|
// used in the next ${readableStreamLifetimeInSeconds} otherwise destroys it
|
|
17898
17971
|
const timeout = setTimeout(() => {
|
|
17899
|
-
process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release
|
|
17972
|
+
process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release resources`, {
|
|
17900
17973
|
CODE: "READABLE_STREAM_TIMEOUT",
|
|
17901
17974
|
// url is for http client request
|
|
17902
17975
|
detail: `path: ${nodeStream.path}, fd: ${nodeStream.fd}, url: ${nodeStream.url}`
|
|
@@ -17976,8 +18049,8 @@ const fromNodeRequest = (nodeRequest, {
|
|
|
17976
18049
|
signal,
|
|
17977
18050
|
http2: Boolean(nodeRequest.stream),
|
|
17978
18051
|
origin: requestOrigin,
|
|
17979
|
-
...
|
|
17980
|
-
|
|
18052
|
+
...getPropertiesFromResource({
|
|
18053
|
+
resource: nodeRequest.url,
|
|
17981
18054
|
baseUrl: requestOrigin
|
|
17982
18055
|
}),
|
|
17983
18056
|
method: nodeRequest.method,
|
|
@@ -17986,13 +18059,13 @@ const fromNodeRequest = (nodeRequest, {
|
|
|
17986
18059
|
});
|
|
17987
18060
|
};
|
|
17988
18061
|
const applyRedirectionToRequest = (request, {
|
|
17989
|
-
|
|
18062
|
+
resource,
|
|
17990
18063
|
pathname,
|
|
17991
18064
|
...rest
|
|
17992
18065
|
}) => {
|
|
17993
18066
|
return { ...request,
|
|
17994
|
-
...(
|
|
17995
|
-
|
|
18067
|
+
...(resource ? getPropertiesFromResource({
|
|
18068
|
+
resource,
|
|
17996
18069
|
baseUrl: request.url
|
|
17997
18070
|
}) : pathname ? getPropertiesFromPathname({
|
|
17998
18071
|
pathname,
|
|
@@ -18002,16 +18075,16 @@ const applyRedirectionToRequest = (request, {
|
|
|
18002
18075
|
};
|
|
18003
18076
|
};
|
|
18004
18077
|
|
|
18005
|
-
const
|
|
18006
|
-
|
|
18078
|
+
const getPropertiesFromResource = ({
|
|
18079
|
+
resource,
|
|
18007
18080
|
baseUrl
|
|
18008
18081
|
}) => {
|
|
18009
|
-
const urlObject = new URL(
|
|
18082
|
+
const urlObject = new URL(resource, baseUrl);
|
|
18010
18083
|
let pathname = urlObject.pathname;
|
|
18011
18084
|
return {
|
|
18012
18085
|
url: String(urlObject),
|
|
18013
18086
|
pathname,
|
|
18014
|
-
|
|
18087
|
+
resource
|
|
18015
18088
|
};
|
|
18016
18089
|
};
|
|
18017
18090
|
|
|
@@ -18019,8 +18092,8 @@ const getPropertiesFromPathname = ({
|
|
|
18019
18092
|
pathname,
|
|
18020
18093
|
baseUrl
|
|
18021
18094
|
}) => {
|
|
18022
|
-
return
|
|
18023
|
-
|
|
18095
|
+
return getPropertiesFromResource({
|
|
18096
|
+
resource: `${pathname}${new URL(baseUrl).search}`,
|
|
18024
18097
|
baseUrl
|
|
18025
18098
|
});
|
|
18026
18099
|
};
|
|
@@ -18048,11 +18121,11 @@ const createPushRequest = (request, {
|
|
|
18048
18121
|
const getHeadersInheritedByPushRequest = request => {
|
|
18049
18122
|
const headersInherited = { ...request.headers
|
|
18050
18123
|
}; // mtime sent by the client in request headers concerns the main request
|
|
18051
|
-
// Time remains valid for request to other
|
|
18124
|
+
// Time remains valid for request to other resources so we keep it
|
|
18052
18125
|
// in child requests
|
|
18053
18126
|
// delete childHeaders["if-modified-since"]
|
|
18054
18127
|
// eTag sent by the client in request headers concerns the main request
|
|
18055
|
-
// A request made to an other
|
|
18128
|
+
// A request made to an other resource must not inherit the eTag
|
|
18056
18129
|
|
|
18057
18130
|
delete headersInherited["if-none-match"];
|
|
18058
18131
|
return headersInherited;
|
|
@@ -18367,101 +18440,12 @@ const statusIsClientError = status => status >= 400 && status < 500;
|
|
|
18367
18440
|
|
|
18368
18441
|
const statusIsServerError = status => status >= 500 && status < 600;
|
|
18369
18442
|
|
|
18370
|
-
const applyDnsResolution = async (hostname, {
|
|
18371
|
-
verbatim = false
|
|
18372
|
-
} = {}) => {
|
|
18373
|
-
const dnsResolution = await new Promise((resolve, reject) => {
|
|
18374
|
-
lookup(hostname, {
|
|
18375
|
-
verbatim
|
|
18376
|
-
}, (error, address, family) => {
|
|
18377
|
-
if (error) {
|
|
18378
|
-
reject(error);
|
|
18379
|
-
} else {
|
|
18380
|
-
resolve({
|
|
18381
|
-
address,
|
|
18382
|
-
family
|
|
18383
|
-
});
|
|
18384
|
-
}
|
|
18385
|
-
});
|
|
18386
|
-
});
|
|
18387
|
-
return dnsResolution;
|
|
18388
|
-
};
|
|
18389
|
-
|
|
18390
|
-
const getServerOrigins = async ({
|
|
18391
|
-
protocol,
|
|
18392
|
-
host,
|
|
18393
|
-
port
|
|
18394
|
-
}) => {
|
|
18395
|
-
const isLocal = LOOPBACK_HOSTNAMES.includes(host);
|
|
18396
|
-
const localhostDnsResolution = await applyDnsResolution("localhost");
|
|
18397
|
-
const localOrigin = createServerOrigin({
|
|
18398
|
-
protocol,
|
|
18399
|
-
hostname: localhostDnsResolution.address === "127.0.0.1" ? "localhost" : "127.0.0.1",
|
|
18400
|
-
port
|
|
18401
|
-
});
|
|
18402
|
-
|
|
18403
|
-
if (isLocal) {
|
|
18404
|
-
return {
|
|
18405
|
-
local: localOrigin
|
|
18406
|
-
};
|
|
18407
|
-
}
|
|
18408
|
-
|
|
18409
|
-
const isAnyIp = WILDCARD_HOSTNAMES.includes(host);
|
|
18410
|
-
const networkOrigin = createServerOrigin({
|
|
18411
|
-
protocol,
|
|
18412
|
-
hostname: isAnyIp ? getExternalIp() : host,
|
|
18413
|
-
port
|
|
18414
|
-
});
|
|
18415
|
-
return {
|
|
18416
|
-
local: localOrigin,
|
|
18417
|
-
network: networkOrigin
|
|
18418
|
-
};
|
|
18419
|
-
};
|
|
18420
|
-
const LOOPBACK_HOSTNAMES = ["localhost", "127.0.0.1", "::1", "0000:0000:0000:0000:0000:0000:0000:0001"];
|
|
18421
|
-
const WILDCARD_HOSTNAMES = [undefined, "0.0.0.0", "::", "0000:0000:0000:0000:0000:0000:0000:0000"];
|
|
18422
|
-
|
|
18423
|
-
const createServerOrigin = ({
|
|
18424
|
-
protocol,
|
|
18425
|
-
hostname,
|
|
18426
|
-
port
|
|
18427
|
-
}) => {
|
|
18428
|
-
const url = new URL("https://127.0.0.1:80");
|
|
18429
|
-
url.protocol = protocol;
|
|
18430
|
-
url.hostname = hostname;
|
|
18431
|
-
url.port = port;
|
|
18432
|
-
return url.origin;
|
|
18433
|
-
};
|
|
18434
|
-
|
|
18435
|
-
const getExternalIp = () => {
|
|
18436
|
-
const networkInterfaceMap = networkInterfaces();
|
|
18437
|
-
let internalIPV4NetworkAddress;
|
|
18438
|
-
Object.keys(networkInterfaceMap).find(key => {
|
|
18439
|
-
const networkAddressArray = networkInterfaceMap[key];
|
|
18440
|
-
return networkAddressArray.find(networkAddress => {
|
|
18441
|
-
if (networkAddress.internal) return false;
|
|
18442
|
-
if (!isIpV4(networkAddress)) return false;
|
|
18443
|
-
internalIPV4NetworkAddress = networkAddress;
|
|
18444
|
-
return true;
|
|
18445
|
-
});
|
|
18446
|
-
});
|
|
18447
|
-
return internalIPV4NetworkAddress ? internalIPV4NetworkAddress.address : null;
|
|
18448
|
-
};
|
|
18449
|
-
|
|
18450
|
-
const isIpV4 = networkAddress => {
|
|
18451
|
-
// node 18+
|
|
18452
|
-
if (typeof networkAddress.family === "number") {
|
|
18453
|
-
return networkAddress.family === 4;
|
|
18454
|
-
}
|
|
18455
|
-
|
|
18456
|
-
return networkAddress.family === "IPv4";
|
|
18457
|
-
};
|
|
18458
|
-
|
|
18459
18443
|
const listen = async ({
|
|
18460
18444
|
signal = new AbortController().signal,
|
|
18461
18445
|
server,
|
|
18462
18446
|
port,
|
|
18463
18447
|
portHint,
|
|
18464
|
-
|
|
18448
|
+
hostname
|
|
18465
18449
|
}) => {
|
|
18466
18450
|
const listeningOperation = Abort.startOperation();
|
|
18467
18451
|
|
|
@@ -18472,7 +18456,7 @@ const listen = async ({
|
|
|
18472
18456
|
listeningOperation.throwIfAborted();
|
|
18473
18457
|
port = await findFreePort(portHint, {
|
|
18474
18458
|
signal: listeningOperation.signal,
|
|
18475
|
-
|
|
18459
|
+
hostname
|
|
18476
18460
|
});
|
|
18477
18461
|
}
|
|
18478
18462
|
|
|
@@ -18480,7 +18464,7 @@ const listen = async ({
|
|
|
18480
18464
|
port = await startListening({
|
|
18481
18465
|
server,
|
|
18482
18466
|
port,
|
|
18483
|
-
|
|
18467
|
+
hostname
|
|
18484
18468
|
});
|
|
18485
18469
|
listeningOperation.addAbortCallback(() => stopListening(server));
|
|
18486
18470
|
listeningOperation.throwIfAborted();
|
|
@@ -18492,7 +18476,7 @@ const listen = async ({
|
|
|
18492
18476
|
|
|
18493
18477
|
const findFreePort = async (initialPort = 1, {
|
|
18494
18478
|
signal = new AbortController().signal,
|
|
18495
|
-
|
|
18479
|
+
hostname = "127.0.0.1",
|
|
18496
18480
|
min = 1,
|
|
18497
18481
|
max = 65534,
|
|
18498
18482
|
next = port => port + 1
|
|
@@ -18514,27 +18498,27 @@ const findFreePort = async (initialPort = 1, {
|
|
|
18514
18498
|
const nextPort = next(port);
|
|
18515
18499
|
|
|
18516
18500
|
if (nextPort > max) {
|
|
18517
|
-
throw new Error(`${
|
|
18501
|
+
throw new Error(`${hostname} has no available port between ${min} and ${max}`);
|
|
18518
18502
|
}
|
|
18519
18503
|
|
|
18520
|
-
return testUntil(nextPort,
|
|
18504
|
+
return testUntil(nextPort, hostname);
|
|
18521
18505
|
};
|
|
18522
18506
|
|
|
18523
|
-
const freePort = await testUntil(initialPort,
|
|
18507
|
+
const freePort = await testUntil(initialPort, hostname);
|
|
18524
18508
|
return freePort;
|
|
18525
18509
|
} finally {
|
|
18526
18510
|
await findFreePortOperation.end();
|
|
18527
18511
|
}
|
|
18528
18512
|
};
|
|
18529
18513
|
|
|
18530
|
-
const portIsFree = async (port,
|
|
18514
|
+
const portIsFree = async (port, hostname) => {
|
|
18531
18515
|
const server = createServer();
|
|
18532
18516
|
|
|
18533
18517
|
try {
|
|
18534
18518
|
await startListening({
|
|
18535
18519
|
server,
|
|
18536
18520
|
port,
|
|
18537
|
-
|
|
18521
|
+
hostname
|
|
18538
18522
|
});
|
|
18539
18523
|
} catch (error) {
|
|
18540
18524
|
if (error && error.code === "EADDRINUSE") {
|
|
@@ -18555,7 +18539,7 @@ const portIsFree = async (port, host) => {
|
|
|
18555
18539
|
const startListening = ({
|
|
18556
18540
|
server,
|
|
18557
18541
|
port,
|
|
18558
|
-
|
|
18542
|
+
hostname
|
|
18559
18543
|
}) => {
|
|
18560
18544
|
return new Promise((resolve, reject) => {
|
|
18561
18545
|
server.on("error", reject);
|
|
@@ -18564,7 +18548,7 @@ const startListening = ({
|
|
|
18564
18548
|
// https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
|
|
18565
18549
|
resolve(server.address().port);
|
|
18566
18550
|
});
|
|
18567
|
-
server.listen(port,
|
|
18551
|
+
server.listen(port, hostname);
|
|
18568
18552
|
});
|
|
18569
18553
|
};
|
|
18570
18554
|
|
|
@@ -18803,6 +18787,134 @@ const STOP_REASON_PROCESS_BEFORE_EXIT = createReason("process before exit");
|
|
|
18803
18787
|
const STOP_REASON_PROCESS_EXIT = createReason("process exit");
|
|
18804
18788
|
const STOP_REASON_NOT_SPECIFIED = createReason("not specified");
|
|
18805
18789
|
|
|
18790
|
+
const createIpGetters = () => {
|
|
18791
|
+
const networkAddresses = [];
|
|
18792
|
+
const networkInterfaceMap = networkInterfaces();
|
|
18793
|
+
|
|
18794
|
+
for (const key of Object.keys(networkInterfaceMap)) {
|
|
18795
|
+
for (const networkAddress of networkInterfaceMap[key]) {
|
|
18796
|
+
networkAddresses.push(networkAddress);
|
|
18797
|
+
}
|
|
18798
|
+
}
|
|
18799
|
+
|
|
18800
|
+
return {
|
|
18801
|
+
getFirstInternalIp: ({
|
|
18802
|
+
preferIpv6
|
|
18803
|
+
}) => {
|
|
18804
|
+
const isPref = preferIpv6 ? isIpV6 : isIpV4;
|
|
18805
|
+
let firstInternalIp;
|
|
18806
|
+
|
|
18807
|
+
for (const networkAddress of networkAddresses) {
|
|
18808
|
+
if (networkAddress.internal) {
|
|
18809
|
+
firstInternalIp = networkAddress.address;
|
|
18810
|
+
|
|
18811
|
+
if (isPref(networkAddress)) {
|
|
18812
|
+
break;
|
|
18813
|
+
}
|
|
18814
|
+
}
|
|
18815
|
+
}
|
|
18816
|
+
|
|
18817
|
+
return firstInternalIp;
|
|
18818
|
+
},
|
|
18819
|
+
getFirstExternalIp: ({
|
|
18820
|
+
preferIpv6
|
|
18821
|
+
}) => {
|
|
18822
|
+
const isPref = preferIpv6 ? isIpV6 : isIpV4;
|
|
18823
|
+
let firstExternalIp;
|
|
18824
|
+
|
|
18825
|
+
for (const networkAddress of networkAddresses) {
|
|
18826
|
+
if (!networkAddress.internal) {
|
|
18827
|
+
firstExternalIp = networkAddress.address;
|
|
18828
|
+
|
|
18829
|
+
if (isPref(networkAddress)) {
|
|
18830
|
+
break;
|
|
18831
|
+
}
|
|
18832
|
+
}
|
|
18833
|
+
}
|
|
18834
|
+
|
|
18835
|
+
return firstExternalIp;
|
|
18836
|
+
}
|
|
18837
|
+
};
|
|
18838
|
+
};
|
|
18839
|
+
|
|
18840
|
+
const isIpV4 = networkAddress => {
|
|
18841
|
+
// node 18.5
|
|
18842
|
+
if (typeof networkAddress.family === "number") {
|
|
18843
|
+
return networkAddress.family === 4;
|
|
18844
|
+
}
|
|
18845
|
+
|
|
18846
|
+
return networkAddress.family === "IPv4";
|
|
18847
|
+
};
|
|
18848
|
+
|
|
18849
|
+
const isIpV6 = networkAddress => !isIpV4(networkAddress);
|
|
18850
|
+
|
|
18851
|
+
const parseHostname = hostname => {
|
|
18852
|
+
if (hostname === "0.0.0.0") {
|
|
18853
|
+
return {
|
|
18854
|
+
type: "ip",
|
|
18855
|
+
label: "unspecified",
|
|
18856
|
+
version: 4
|
|
18857
|
+
};
|
|
18858
|
+
}
|
|
18859
|
+
|
|
18860
|
+
if (hostname === "::" || hostname === "0000:0000:0000:0000:0000:0000:0000:0000") {
|
|
18861
|
+
return {
|
|
18862
|
+
type: "ip",
|
|
18863
|
+
label: "unspecified",
|
|
18864
|
+
version: 6
|
|
18865
|
+
};
|
|
18866
|
+
}
|
|
18867
|
+
|
|
18868
|
+
if (hostname === "127.0.0.1") {
|
|
18869
|
+
return {
|
|
18870
|
+
type: "ip",
|
|
18871
|
+
label: "loopback",
|
|
18872
|
+
version: 4
|
|
18873
|
+
};
|
|
18874
|
+
}
|
|
18875
|
+
|
|
18876
|
+
if (hostname === "::1" || hostname === "0000:0000:0000:0000:0000:0000:0000:0001") {
|
|
18877
|
+
return {
|
|
18878
|
+
type: "ip",
|
|
18879
|
+
label: "loopback",
|
|
18880
|
+
version: 6
|
|
18881
|
+
};
|
|
18882
|
+
}
|
|
18883
|
+
|
|
18884
|
+
const ipVersion = isIP(hostname);
|
|
18885
|
+
|
|
18886
|
+
if (ipVersion === 0) {
|
|
18887
|
+
return {
|
|
18888
|
+
type: "hostname"
|
|
18889
|
+
};
|
|
18890
|
+
}
|
|
18891
|
+
|
|
18892
|
+
return {
|
|
18893
|
+
type: "ip",
|
|
18894
|
+
version: ipVersion
|
|
18895
|
+
};
|
|
18896
|
+
};
|
|
18897
|
+
|
|
18898
|
+
const applyDnsResolution = async (hostname, {
|
|
18899
|
+
verbatim = false
|
|
18900
|
+
} = {}) => {
|
|
18901
|
+
const dnsResolution = await new Promise((resolve, reject) => {
|
|
18902
|
+
lookup(hostname, {
|
|
18903
|
+
verbatim
|
|
18904
|
+
}, (error, address, family) => {
|
|
18905
|
+
if (error) {
|
|
18906
|
+
reject(error);
|
|
18907
|
+
} else {
|
|
18908
|
+
resolve({
|
|
18909
|
+
address,
|
|
18910
|
+
family
|
|
18911
|
+
});
|
|
18912
|
+
}
|
|
18913
|
+
});
|
|
18914
|
+
});
|
|
18915
|
+
return dnsResolution;
|
|
18916
|
+
};
|
|
18917
|
+
|
|
18806
18918
|
const startServer = async ({
|
|
18807
18919
|
signal = new AbortController().signal,
|
|
18808
18920
|
logLevel,
|
|
@@ -18814,7 +18926,8 @@ const startServer = async ({
|
|
|
18814
18926
|
redirectHttpToHttps,
|
|
18815
18927
|
allowHttpRequestOnHttps = false,
|
|
18816
18928
|
acceptAnyIp = false,
|
|
18817
|
-
|
|
18929
|
+
preferIpv6,
|
|
18930
|
+
hostname = "localhost",
|
|
18818
18931
|
port = 0,
|
|
18819
18932
|
// assign a random available port
|
|
18820
18933
|
portHint,
|
|
@@ -18839,11 +18952,15 @@ const startServer = async ({
|
|
|
18839
18952
|
requestWaitingMs
|
|
18840
18953
|
}) => {
|
|
18841
18954
|
warn(createDetailedMessage$1(`still no response found for request after ${requestWaitingMs} ms`, {
|
|
18842
|
-
"request url":
|
|
18955
|
+
"request url": request.url,
|
|
18843
18956
|
"request headers": JSON.stringify(request.headers, null, " ")
|
|
18844
18957
|
}));
|
|
18845
18958
|
}
|
|
18846
18959
|
} = {}) => {
|
|
18960
|
+
const logger = createLogger({
|
|
18961
|
+
logLevel
|
|
18962
|
+
});
|
|
18963
|
+
|
|
18847
18964
|
if (protocol !== "http" && protocol !== "https") {
|
|
18848
18965
|
throw new Error(`protocol must be http or https, got ${protocol}`);
|
|
18849
18966
|
}
|
|
@@ -18862,10 +18979,6 @@ const startServer = async ({
|
|
|
18862
18979
|
throw new Error(`http2 needs "https" but protocol is "${protocol}"`);
|
|
18863
18980
|
}
|
|
18864
18981
|
|
|
18865
|
-
const logger = createLogger({
|
|
18866
|
-
logLevel
|
|
18867
|
-
});
|
|
18868
|
-
|
|
18869
18982
|
if (redirectHttpToHttps === undefined && protocol === "https" && !allowHttpRequestOnHttps) {
|
|
18870
18983
|
redirectHttpToHttps = true;
|
|
18871
18984
|
}
|
|
@@ -18898,6 +19011,10 @@ const startServer = async ({
|
|
|
18898
19011
|
let nodeServer;
|
|
18899
19012
|
const startServerOperation = Abort.startOperation();
|
|
18900
19013
|
const stopCallbackList = createCallbackListNotifiedOnce();
|
|
19014
|
+
const serverOrigins = {
|
|
19015
|
+
local: "" // favors hostname when possible
|
|
19016
|
+
|
|
19017
|
+
};
|
|
18901
19018
|
|
|
18902
19019
|
try {
|
|
18903
19020
|
startServerOperation.addAbortSignal(signal);
|
|
@@ -18925,12 +19042,85 @@ const startServer = async ({
|
|
|
18925
19042
|
nodeServer.unref();
|
|
18926
19043
|
}
|
|
18927
19044
|
|
|
19045
|
+
const createOrigin = hostname => {
|
|
19046
|
+
if (isIP(hostname) === 6) {
|
|
19047
|
+
return `${protocol}://[${hostname}]`;
|
|
19048
|
+
}
|
|
19049
|
+
|
|
19050
|
+
return `${protocol}://${hostname}`;
|
|
19051
|
+
};
|
|
19052
|
+
|
|
19053
|
+
const ipGetters = createIpGetters();
|
|
19054
|
+
let hostnameToListen;
|
|
19055
|
+
|
|
19056
|
+
if (acceptAnyIp) {
|
|
19057
|
+
const firstInternalIp = ipGetters.getFirstInternalIp({
|
|
19058
|
+
preferIpv6
|
|
19059
|
+
});
|
|
19060
|
+
serverOrigins.local = createOrigin(firstInternalIp);
|
|
19061
|
+
serverOrigins.localip = createOrigin(firstInternalIp);
|
|
19062
|
+
const firstExternalIp = ipGetters.getFirstExternalIp({
|
|
19063
|
+
preferIpv6
|
|
19064
|
+
});
|
|
19065
|
+
serverOrigins.externalip = createOrigin(firstExternalIp);
|
|
19066
|
+
hostnameToListen = preferIpv6 ? "::" : "0.0.0.0";
|
|
19067
|
+
} else {
|
|
19068
|
+
hostnameToListen = hostname;
|
|
19069
|
+
}
|
|
19070
|
+
|
|
19071
|
+
const hostnameInfo = parseHostname(hostname);
|
|
19072
|
+
|
|
19073
|
+
if (hostnameInfo.type === "ip") {
|
|
19074
|
+
if (acceptAnyIp) {
|
|
19075
|
+
throw new Error(`hostname cannot be an ip when acceptAnyIp is enabled, got ${hostname}`);
|
|
19076
|
+
}
|
|
19077
|
+
|
|
19078
|
+
preferIpv6 = hostnameInfo.version === 6;
|
|
19079
|
+
const firstInternalIp = ipGetters.getFirstInternalIp({
|
|
19080
|
+
preferIpv6
|
|
19081
|
+
});
|
|
19082
|
+
serverOrigins.local = createOrigin(firstInternalIp);
|
|
19083
|
+
serverOrigins.localip = createOrigin(firstInternalIp);
|
|
19084
|
+
|
|
19085
|
+
if (hostnameInfo.label === "unspecified") {
|
|
19086
|
+
const firstExternalIp = ipGetters.getFirstExternalIp({
|
|
19087
|
+
preferIpv6
|
|
19088
|
+
});
|
|
19089
|
+
serverOrigins.externalip = createOrigin(firstExternalIp);
|
|
19090
|
+
} else if (hostnameInfo.label === "loopback") {} else {
|
|
19091
|
+
serverOrigins.local = createOrigin(hostname);
|
|
19092
|
+
}
|
|
19093
|
+
} else {
|
|
19094
|
+
const hostnameDnsResolution = await applyDnsResolution(hostname, {
|
|
19095
|
+
verbatim: true
|
|
19096
|
+
});
|
|
19097
|
+
|
|
19098
|
+
if (hostnameDnsResolution) {
|
|
19099
|
+
const hostnameIp = hostnameDnsResolution.address;
|
|
19100
|
+
serverOrigins.localip = createOrigin(hostnameIp);
|
|
19101
|
+
serverOrigins.local = createOrigin(hostname);
|
|
19102
|
+
} else {
|
|
19103
|
+
const firstInternalIp = ipGetters.getFirstInternalIp({
|
|
19104
|
+
preferIpv6
|
|
19105
|
+
}); // fallback to internal ip because there is no ip
|
|
19106
|
+
// associated to this hostname on operating system (in hosts file)
|
|
19107
|
+
|
|
19108
|
+
hostname = firstInternalIp;
|
|
19109
|
+
hostnameToListen = firstInternalIp;
|
|
19110
|
+
serverOrigins.local = createOrigin(firstInternalIp);
|
|
19111
|
+
}
|
|
19112
|
+
}
|
|
19113
|
+
|
|
18928
19114
|
port = await listen({
|
|
18929
19115
|
signal: startServerOperation.signal,
|
|
18930
19116
|
server: nodeServer,
|
|
18931
19117
|
port,
|
|
18932
19118
|
portHint,
|
|
18933
|
-
|
|
19119
|
+
hostname: hostnameToListen
|
|
19120
|
+
}); // normalize origins (remove :80 when port is 80 for instance)
|
|
19121
|
+
|
|
19122
|
+
Object.keys(serverOrigins).forEach(key => {
|
|
19123
|
+
serverOrigins[key] = new URL(`${serverOrigins[key]}:${port}`).origin;
|
|
18934
19124
|
});
|
|
18935
19125
|
serviceController.callHooks("serverListening", {
|
|
18936
19126
|
port
|
|
@@ -18941,12 +19131,23 @@ const startServer = async ({
|
|
|
18941
19131
|
startServerOperation.throwIfAborted();
|
|
18942
19132
|
} finally {
|
|
18943
19133
|
await startServerOperation.end();
|
|
18944
|
-
} //
|
|
19134
|
+
} // the main server origin
|
|
19135
|
+
// - when protocol is http
|
|
19136
|
+
// node-fetch do not apply local dns resolution to map localhost back to 127.0.0.1
|
|
19137
|
+
// despites localhost being mapped so we prefer to use the internal ip
|
|
19138
|
+
// (127.0.0.1)
|
|
19139
|
+
// - when protocol is https
|
|
19140
|
+
// using the hostname becomes important because the certificate is generated
|
|
19141
|
+
// for hostnames, not for ips
|
|
19142
|
+
// so we prefer https://locahost or https://local_hostname
|
|
19143
|
+
// over the ip
|
|
19144
|
+
|
|
19145
|
+
|
|
19146
|
+
const serverOrigin = serverOrigins.local; // now the server is started (listening) it cannot be aborted anymore
|
|
18945
19147
|
// (otherwise an AbortError is thrown to the code calling "startServer")
|
|
18946
19148
|
// we can proceed to create a stop function to stop it gacefully
|
|
18947
19149
|
// and add a request handler
|
|
18948
19150
|
|
|
18949
|
-
|
|
18950
19151
|
stopCallbackList.add(({
|
|
18951
19152
|
reason
|
|
18952
19153
|
}) => {
|
|
@@ -18984,12 +19185,6 @@ const startServer = async ({
|
|
|
18984
19185
|
};
|
|
18985
19186
|
|
|
18986
19187
|
status = "opened";
|
|
18987
|
-
const serverOrigins = await getServerOrigins({
|
|
18988
|
-
protocol,
|
|
18989
|
-
host,
|
|
18990
|
-
port
|
|
18991
|
-
});
|
|
18992
|
-
const serverOrigin = serverOrigins.local;
|
|
18993
19188
|
const removeConnectionErrorListener = listenServerConnectionError(nodeServer, onError);
|
|
18994
19189
|
stopCallbackList.add(removeConnectionErrorListener);
|
|
18995
19190
|
const connectionsTracker = trackServerPendingConnections(nodeServer, {
|
|
@@ -19181,7 +19376,7 @@ const startServer = async ({
|
|
|
19181
19376
|
const onPushStreamError = e => {
|
|
19182
19377
|
addRequestLog(requestNode, {
|
|
19183
19378
|
type: "error",
|
|
19184
|
-
value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.
|
|
19379
|
+
value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.resource}`, {
|
|
19185
19380
|
"error stack": e.stack
|
|
19186
19381
|
})
|
|
19187
19382
|
});
|
|
@@ -19285,7 +19480,7 @@ const startServer = async ({
|
|
|
19285
19480
|
|
|
19286
19481
|
addRequestLog(requestNode, {
|
|
19287
19482
|
type: "info",
|
|
19288
|
-
value: request.parent ? `Push ${request.
|
|
19483
|
+
value: request.parent ? `Push ${request.resource}` : `${request.method} ${request.url}`
|
|
19289
19484
|
});
|
|
19290
19485
|
|
|
19291
19486
|
const warn = value => {
|
|
@@ -19609,7 +19804,7 @@ const startServer = async ({
|
|
|
19609
19804
|
let websocketServer = new WebSocketServer({
|
|
19610
19805
|
noServer: true
|
|
19611
19806
|
});
|
|
19612
|
-
const websocketOrigin = protocol === "https" ? `wss://${
|
|
19807
|
+
const websocketOrigin = protocol === "https" ? `wss://${hostname}:${port}` : `ws://${hostname}:${port}`;
|
|
19613
19808
|
server.websocketOrigin = websocketOrigin;
|
|
19614
19809
|
|
|
19615
19810
|
const upgradeCallback = (nodeRequest, socket, head) => {
|
|
@@ -19650,6 +19845,7 @@ const startServer = async ({
|
|
|
19650
19845
|
Object.assign(server, {
|
|
19651
19846
|
getStatus: () => status,
|
|
19652
19847
|
port,
|
|
19848
|
+
hostname,
|
|
19653
19849
|
origin: serverOrigin,
|
|
19654
19850
|
origins: serverOrigins,
|
|
19655
19851
|
nodeServer,
|
|
@@ -20102,7 +20298,7 @@ const fetchFileSystem = async (filesystemUrl, {
|
|
|
20102
20298
|
|
|
20103
20299
|
rootDirectoryUrl = rootDirectoryUrlString;
|
|
20104
20300
|
} // here you might be tempted to add || cacheControl === 'no-cache'
|
|
20105
|
-
// but no-cache means
|
|
20301
|
+
// but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
|
|
20106
20302
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
|
|
20107
20303
|
|
|
20108
20304
|
|
|
@@ -20243,7 +20439,7 @@ const getClientCacheResponse = async ({
|
|
|
20243
20439
|
sourceUrl
|
|
20244
20440
|
}) => {
|
|
20245
20441
|
// here you might be tempted to add || headers["cache-control"] === "no-cache"
|
|
20246
|
-
// but no-cache means
|
|
20442
|
+
// but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
|
|
20247
20443
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
|
|
20248
20444
|
if (headers["cache-control"] === "no-store" || // let's disable it on no-cache too
|
|
20249
20445
|
headers["cache-control"] === "no-cache") {
|
|
@@ -20951,8 +21147,8 @@ const flattenAndFilterPlugins = (plugins, {
|
|
|
20951
21147
|
}
|
|
20952
21148
|
|
|
20953
21149
|
if (typeof appliesDuring === "string") {
|
|
20954
|
-
if (!["dev", "
|
|
20955
|
-
throw new Error(`"appliesDuring" must be "dev"
|
|
21150
|
+
if (!["dev", "build"].includes(appliesDuring)) {
|
|
21151
|
+
throw new Error(`"appliesDuring" must be "dev" or "build", got ${appliesDuring}`);
|
|
20956
21152
|
}
|
|
20957
21153
|
|
|
20958
21154
|
if (scenarios[appliesDuring]) {
|
|
@@ -21644,7 +21840,7 @@ const validateResponseIntegrity = ({
|
|
|
21644
21840
|
return true;
|
|
21645
21841
|
}
|
|
21646
21842
|
|
|
21647
|
-
const error = new Error(`Integrity validation failed for
|
|
21843
|
+
const error = new Error(`Integrity validation failed for resource "${url}". The integrity found for this resource is "${strongestAlgo}-${actualBase64Value}"`);
|
|
21648
21844
|
error.code = "EINTEGRITY";
|
|
21649
21845
|
error.algorithm = strongestAlgo;
|
|
21650
21846
|
error.found = actualBase64Value;
|
|
@@ -21756,7 +21952,7 @@ const createKitchen = ({
|
|
|
21756
21952
|
isEntryPoint = false,
|
|
21757
21953
|
isInline = false,
|
|
21758
21954
|
injected = false,
|
|
21759
|
-
|
|
21955
|
+
isResourceHint = false,
|
|
21760
21956
|
content,
|
|
21761
21957
|
contentType,
|
|
21762
21958
|
assert,
|
|
@@ -21794,8 +21990,8 @@ const createKitchen = ({
|
|
|
21794
21990
|
isEntryPoint,
|
|
21795
21991
|
isInline,
|
|
21796
21992
|
injected,
|
|
21797
|
-
|
|
21798
|
-
// for inline
|
|
21993
|
+
isResourceHint,
|
|
21994
|
+
// for inline resources the reference contains the content
|
|
21799
21995
|
content,
|
|
21800
21996
|
contentType,
|
|
21801
21997
|
timing: {},
|
|
@@ -21846,8 +22042,8 @@ const createKitchen = ({
|
|
|
21846
22042
|
// And this is because this hook inject query params used to:
|
|
21847
22043
|
// - bypass browser cache (?v)
|
|
21848
22044
|
// - convey information (?hmr)
|
|
21849
|
-
// But do not represent an other
|
|
21850
|
-
// the same
|
|
22045
|
+
// But do not represent an other resource, it is considered as
|
|
22046
|
+
// the same resource under the hood
|
|
21851
22047
|
|
|
21852
22048
|
pluginController.callHooks("transformUrlSearchParams", reference, kitchenContext, returnValue => {
|
|
21853
22049
|
Object.keys(returnValue).forEach(key => {
|
|
@@ -22656,11 +22852,11 @@ const loadUrlGraph = async ({
|
|
|
22656
22852
|
references
|
|
22657
22853
|
} = urlInfo;
|
|
22658
22854
|
references.forEach(reference => {
|
|
22659
|
-
// we don't cook
|
|
22660
|
-
// because they might refer to
|
|
22855
|
+
// we don't cook resource hints
|
|
22856
|
+
// because they might refer to resource that will be modified during build
|
|
22661
22857
|
// It also means something else have to reference that url in order to cook it
|
|
22662
|
-
// so that the preload is deleted by "
|
|
22663
|
-
if (reference.
|
|
22858
|
+
// so that the preload is deleted by "resync_resource_hints.js" otherwise
|
|
22859
|
+
if (reference.isResourceHint) {
|
|
22664
22860
|
return;
|
|
22665
22861
|
} // we use reference.generatedUrl to mimic what a browser would do:
|
|
22666
22862
|
// do a fetch to the specifier as found in the file
|
|
@@ -23325,23 +23521,23 @@ self.serviceWorkerUrls = ${JSON.stringify(serviceWorkerUrls, null, " ")};
|
|
|
23325
23521
|
/*
|
|
23326
23522
|
* Update <link rel="preload"> and friends after build (once we know everything)
|
|
23327
23523
|
*
|
|
23328
|
-
* - Used to remove
|
|
23524
|
+
* - Used to remove resource hint targeting an url that is no longer used:
|
|
23329
23525
|
* - Happens because of import assertions transpilation (file is inlined into JS)
|
|
23330
23526
|
*/
|
|
23331
|
-
const
|
|
23527
|
+
const resyncResourceHints = async ({
|
|
23332
23528
|
logger,
|
|
23333
23529
|
finalGraphKitchen,
|
|
23334
23530
|
finalGraph,
|
|
23335
23531
|
rawUrls,
|
|
23336
23532
|
postBuildRedirections
|
|
23337
23533
|
}) => {
|
|
23338
|
-
const
|
|
23534
|
+
const resourceHintActions = [];
|
|
23339
23535
|
GRAPH.forEach(finalGraph, urlInfo => {
|
|
23340
23536
|
if (urlInfo.type !== "html") {
|
|
23341
23537
|
return;
|
|
23342
23538
|
}
|
|
23343
23539
|
|
|
23344
|
-
|
|
23540
|
+
resourceHintActions.push(async () => {
|
|
23345
23541
|
const htmlAst = parseHtmlString(urlInfo.content, {
|
|
23346
23542
|
storeOriginalPositions: false
|
|
23347
23543
|
});
|
|
@@ -23353,9 +23549,9 @@ const resyncRessourceHints = async ({
|
|
|
23353
23549
|
}
|
|
23354
23550
|
|
|
23355
23551
|
const rel = getHtmlNodeAttribute(linkNode, "rel");
|
|
23356
|
-
const
|
|
23552
|
+
const isresourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
|
|
23357
23553
|
|
|
23358
|
-
if (!
|
|
23554
|
+
if (!isresourceHint) {
|
|
23359
23555
|
return;
|
|
23360
23556
|
}
|
|
23361
23557
|
|
|
@@ -23369,7 +23565,7 @@ const resyncRessourceHints = async ({
|
|
|
23369
23565
|
}
|
|
23370
23566
|
|
|
23371
23567
|
if (!buildUrl) {
|
|
23372
|
-
logger.warn(`remove
|
|
23568
|
+
logger.warn(`remove resource hint because cannot find "${href}"`);
|
|
23373
23569
|
actions.push(() => {
|
|
23374
23570
|
removeHtmlNode(linkNode);
|
|
23375
23571
|
});
|
|
@@ -23380,7 +23576,7 @@ const resyncRessourceHints = async ({
|
|
|
23380
23576
|
const urlInfo = finalGraph.getUrlInfo(buildUrl);
|
|
23381
23577
|
|
|
23382
23578
|
if (!urlInfo) {
|
|
23383
|
-
logger.warn(`remove
|
|
23579
|
+
logger.warn(`remove resource hint because cannot find "${buildUrl}" in the graph`);
|
|
23384
23580
|
actions.push(() => {
|
|
23385
23581
|
removeHtmlNode(linkNode);
|
|
23386
23582
|
});
|
|
@@ -23388,7 +23584,7 @@ const resyncRessourceHints = async ({
|
|
|
23388
23584
|
}
|
|
23389
23585
|
|
|
23390
23586
|
if (urlInfo.dependents.size === 0) {
|
|
23391
|
-
logger.info(`remove
|
|
23587
|
+
logger.info(`remove resource hint because "${href}" not used anymore`);
|
|
23392
23588
|
actions.push(() => {
|
|
23393
23589
|
removeHtmlNode(linkNode);
|
|
23394
23590
|
});
|
|
@@ -23420,7 +23616,7 @@ const resyncRessourceHints = async ({
|
|
|
23420
23616
|
}
|
|
23421
23617
|
});
|
|
23422
23618
|
});
|
|
23423
|
-
await Promise.all(
|
|
23619
|
+
await Promise.all(resourceHintActions.map(resourceHintAction => resourceHintAction()));
|
|
23424
23620
|
};
|
|
23425
23621
|
|
|
23426
23622
|
/*
|
|
@@ -23701,10 +23897,10 @@ build ${entryPointKeys.length} entry points`);
|
|
|
23701
23897
|
addToBundlerIfAny(dependencyUrlInfo);
|
|
23702
23898
|
});
|
|
23703
23899
|
rawUrlInfo.references.forEach(reference => {
|
|
23704
|
-
if (reference.
|
|
23900
|
+
if (reference.isResourceHint && reference.expectedType === "js_module") {
|
|
23705
23901
|
const referencedUrlInfo = rawGraph.getUrlInfo(reference.url);
|
|
23706
23902
|
|
|
23707
|
-
if (referencedUrlInfo && // something else than the
|
|
23903
|
+
if (referencedUrlInfo && // something else than the resource hint is using this url
|
|
23708
23904
|
referencedUrlInfo.dependents.size > 0) {
|
|
23709
23905
|
addToBundlerIfAny(referencedUrlInfo);
|
|
23710
23906
|
}
|
|
@@ -23997,7 +24193,7 @@ build ${entryPointKeys.length} entry points`);
|
|
|
23997
24193
|
throw new Error(`urls should be inside build directory at this stage, found "${reference.url}"`);
|
|
23998
24194
|
}
|
|
23999
24195
|
|
|
24000
|
-
if (reference.
|
|
24196
|
+
if (reference.isResourceHint) {
|
|
24001
24197
|
// return the raw url, we will resync at the end
|
|
24002
24198
|
return rawUrls[reference.url];
|
|
24003
24199
|
} // remove eventual search params and hash
|
|
@@ -24101,7 +24297,7 @@ build ${entryPointKeys.length} entry points`);
|
|
|
24101
24297
|
kitchen: finalGraphKitchen,
|
|
24102
24298
|
outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
|
|
24103
24299
|
writeGeneratedFiles,
|
|
24104
|
-
|
|
24300
|
+
skipResourceHint: true,
|
|
24105
24301
|
startLoading: cookEntryFile => {
|
|
24106
24302
|
entryUrls.forEach(entryUrl => {
|
|
24107
24303
|
const [, postBuildEntryUrlInfo] = cookEntryFile({
|
|
@@ -24173,7 +24369,7 @@ ${Array.from(finalGraph.urlInfoMap.keys()).join("\n")}`);
|
|
|
24173
24369
|
urlInfo.data.buildUrlIsVersioned = useVersionedUrl;
|
|
24174
24370
|
urlInfo.data.buildUrlSpecifier = buildUrlSpecifier;
|
|
24175
24371
|
});
|
|
24176
|
-
await
|
|
24372
|
+
await resyncResourceHints({
|
|
24177
24373
|
logger,
|
|
24178
24374
|
finalGraphKitchen,
|
|
24179
24375
|
finalGraph,
|
|
@@ -24517,7 +24713,7 @@ const applyUrlVersioning = async ({
|
|
|
24517
24713
|
return null;
|
|
24518
24714
|
}
|
|
24519
24715
|
|
|
24520
|
-
if (reference.
|
|
24716
|
+
if (reference.isResourceHint) {
|
|
24521
24717
|
return null;
|
|
24522
24718
|
} // specifier comes from "normalize" hook done a bit earlier in this file
|
|
24523
24719
|
// we want to get back their build url to access their infos
|
|
@@ -24578,7 +24774,7 @@ const applyUrlVersioning = async ({
|
|
|
24578
24774
|
operation: buildOperation,
|
|
24579
24775
|
urlGraph: finalGraph,
|
|
24580
24776
|
kitchen: versioningKitchen,
|
|
24581
|
-
|
|
24777
|
+
skipResourceHint: true,
|
|
24582
24778
|
writeGeneratedFiles,
|
|
24583
24779
|
startLoading: cookEntryFile => {
|
|
24584
24780
|
postBuildEntryUrls.forEach(postBuildEntryUrl => {
|
|
@@ -25060,7 +25256,7 @@ const createFileService = ({
|
|
|
25060
25256
|
|
|
25061
25257
|
return async request => {
|
|
25062
25258
|
// serve file inside ".jsenv" directory
|
|
25063
|
-
const requestFileUrl = new URL(request.
|
|
25259
|
+
const requestFileUrl = new URL(request.resource.slice(1), rootDirectoryUrl).href;
|
|
25064
25260
|
|
|
25065
25261
|
if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
|
|
25066
25262
|
return fetchFileSystem(requestFileUrl, {
|
|
@@ -25084,7 +25280,7 @@ const createFileService = ({
|
|
|
25084
25280
|
const parentUrl = inferParentFromRequest(request, rootDirectoryUrl);
|
|
25085
25281
|
|
|
25086
25282
|
if (parentUrl) {
|
|
25087
|
-
reference = urlGraph.inferReference(request.
|
|
25283
|
+
reference = urlGraph.inferReference(request.resource, parentUrl);
|
|
25088
25284
|
}
|
|
25089
25285
|
|
|
25090
25286
|
if (!reference) {
|
|
@@ -25094,7 +25290,7 @@ const createFileService = ({
|
|
|
25094
25290
|
},
|
|
25095
25291
|
parentUrl: parentUrl || rootDirectoryUrl,
|
|
25096
25292
|
type: "http_request",
|
|
25097
|
-
specifier: request.
|
|
25293
|
+
specifier: request.resource
|
|
25098
25294
|
});
|
|
25099
25295
|
reference = entryPoint[0];
|
|
25100
25296
|
}
|
|
@@ -25261,7 +25457,7 @@ const startOmegaServer = async ({
|
|
|
25261
25457
|
privateKey,
|
|
25262
25458
|
certificate,
|
|
25263
25459
|
acceptAnyIp,
|
|
25264
|
-
|
|
25460
|
+
hostname,
|
|
25265
25461
|
port = 0,
|
|
25266
25462
|
keepProcessAlive = false,
|
|
25267
25463
|
onStop = () => {},
|
|
@@ -25302,7 +25498,7 @@ const startOmegaServer = async ({
|
|
|
25302
25498
|
certificate,
|
|
25303
25499
|
privateKey,
|
|
25304
25500
|
acceptAnyIp,
|
|
25305
|
-
|
|
25501
|
+
hostname,
|
|
25306
25502
|
port,
|
|
25307
25503
|
requestWaitingMs: 60_1000,
|
|
25308
25504
|
services: [jsenvServiceCORS({
|
|
@@ -25408,7 +25604,7 @@ const startDevServer = async ({
|
|
|
25408
25604
|
http2 = false,
|
|
25409
25605
|
certificate,
|
|
25410
25606
|
privateKey,
|
|
25411
|
-
|
|
25607
|
+
hostname,
|
|
25412
25608
|
port = 3456,
|
|
25413
25609
|
acceptAnyIp,
|
|
25414
25610
|
keepProcessAlive = true,
|
|
@@ -25548,7 +25744,7 @@ const startDevServer = async ({
|
|
|
25548
25744
|
http2,
|
|
25549
25745
|
certificate,
|
|
25550
25746
|
privateKey,
|
|
25551
|
-
|
|
25747
|
+
hostname,
|
|
25552
25748
|
port,
|
|
25553
25749
|
services,
|
|
25554
25750
|
rootDirectoryUrl,
|
|
@@ -25651,87 +25847,6 @@ const generateCoverageTextLog = (coverage, {
|
|
|
25651
25847
|
report.execute(context);
|
|
25652
25848
|
};
|
|
25653
25849
|
|
|
25654
|
-
const babelPluginInstrument = (api, {
|
|
25655
|
-
rootDirectoryUrl,
|
|
25656
|
-
useInlineSourceMaps = false,
|
|
25657
|
-
coverageConfig = {
|
|
25658
|
-
"./**/*": true
|
|
25659
|
-
}
|
|
25660
|
-
}) => {
|
|
25661
|
-
const {
|
|
25662
|
-
programVisitor
|
|
25663
|
-
} = requireFromJsenv("istanbul-lib-instrument");
|
|
25664
|
-
const {
|
|
25665
|
-
types
|
|
25666
|
-
} = api;
|
|
25667
|
-
const associations = URL_META.resolveAssociations({
|
|
25668
|
-
cover: coverageConfig
|
|
25669
|
-
}, rootDirectoryUrl);
|
|
25670
|
-
|
|
25671
|
-
const shouldInstrument = url => {
|
|
25672
|
-
return URL_META.applyAssociations({
|
|
25673
|
-
url,
|
|
25674
|
-
associations
|
|
25675
|
-
}).cover;
|
|
25676
|
-
};
|
|
25677
|
-
|
|
25678
|
-
return {
|
|
25679
|
-
name: "transform-instrument",
|
|
25680
|
-
visitor: {
|
|
25681
|
-
Program: {
|
|
25682
|
-
enter(path) {
|
|
25683
|
-
const {
|
|
25684
|
-
file
|
|
25685
|
-
} = this;
|
|
25686
|
-
const {
|
|
25687
|
-
opts
|
|
25688
|
-
} = file;
|
|
25689
|
-
|
|
25690
|
-
if (!opts.sourceFileName) {
|
|
25691
|
-
console.warn(`cannot instrument file when "sourceFileName" option is not set`);
|
|
25692
|
-
return;
|
|
25693
|
-
}
|
|
25694
|
-
|
|
25695
|
-
const fileUrl = fileSystemPathToUrl$1(opts.sourceFileName);
|
|
25696
|
-
|
|
25697
|
-
if (!shouldInstrument(fileUrl)) {
|
|
25698
|
-
return;
|
|
25699
|
-
}
|
|
25700
|
-
|
|
25701
|
-
this.__dv__ = null;
|
|
25702
|
-
let inputSourceMap;
|
|
25703
|
-
|
|
25704
|
-
if (useInlineSourceMaps) {
|
|
25705
|
-
// https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
|
|
25706
|
-
inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
|
|
25707
|
-
} else {
|
|
25708
|
-
inputSourceMap = opts.inputSourceMap;
|
|
25709
|
-
}
|
|
25710
|
-
|
|
25711
|
-
this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
|
|
25712
|
-
coverageVariable: "__coverage__",
|
|
25713
|
-
inputSourceMap
|
|
25714
|
-
});
|
|
25715
|
-
|
|
25716
|
-
this.__dv__.enter(path);
|
|
25717
|
-
},
|
|
25718
|
-
|
|
25719
|
-
exit(path) {
|
|
25720
|
-
if (!this.__dv__) {
|
|
25721
|
-
return;
|
|
25722
|
-
}
|
|
25723
|
-
|
|
25724
|
-
const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
this.file.metadata.coverage = object.fileCoverage;
|
|
25728
|
-
}
|
|
25729
|
-
|
|
25730
|
-
}
|
|
25731
|
-
}
|
|
25732
|
-
};
|
|
25733
|
-
};
|
|
25734
|
-
|
|
25735
25850
|
const readNodeV8CoverageDirectory = async ({
|
|
25736
25851
|
logger,
|
|
25737
25852
|
signal,
|
|
@@ -26424,6 +26539,41 @@ const run = async ({
|
|
|
26424
26539
|
}
|
|
26425
26540
|
};
|
|
26426
26541
|
|
|
26542
|
+
const pingServer = async url => {
|
|
26543
|
+
const server = createServer();
|
|
26544
|
+
const {
|
|
26545
|
+
hostname,
|
|
26546
|
+
port
|
|
26547
|
+
} = new URL(url);
|
|
26548
|
+
|
|
26549
|
+
try {
|
|
26550
|
+
await new Promise((resolve, reject) => {
|
|
26551
|
+
server.on("error", reject);
|
|
26552
|
+
server.on("listening", () => {
|
|
26553
|
+
resolve();
|
|
26554
|
+
});
|
|
26555
|
+
server.listen(port, hostname);
|
|
26556
|
+
});
|
|
26557
|
+
} catch (error) {
|
|
26558
|
+
if (error && error.code === "EADDRINUSE") {
|
|
26559
|
+
return true;
|
|
26560
|
+
}
|
|
26561
|
+
|
|
26562
|
+
if (error && error.code === "EACCES") {
|
|
26563
|
+
return true;
|
|
26564
|
+
}
|
|
26565
|
+
|
|
26566
|
+
throw error;
|
|
26567
|
+
}
|
|
26568
|
+
|
|
26569
|
+
await new Promise((resolve, reject) => {
|
|
26570
|
+
server.on("error", reject);
|
|
26571
|
+
server.on("close", resolve);
|
|
26572
|
+
server.close();
|
|
26573
|
+
});
|
|
26574
|
+
return false;
|
|
26575
|
+
};
|
|
26576
|
+
|
|
26427
26577
|
const ensureGlobalGc = () => {
|
|
26428
26578
|
if (!global.gc) {
|
|
26429
26579
|
v8.setFlagsFromString("--expose_gc");
|
|
@@ -26859,8 +27009,8 @@ const executePlan = async (plan, {
|
|
|
26859
27009
|
completedExecutionLogMerging,
|
|
26860
27010
|
completedExecutionLogAbbreviation,
|
|
26861
27011
|
rootDirectoryUrl,
|
|
27012
|
+
devServerOrigin,
|
|
26862
27013
|
keepRunning,
|
|
26863
|
-
services,
|
|
26864
27014
|
defaultMsAllocatedPerExecution,
|
|
26865
27015
|
maxExecutionsInParallel,
|
|
26866
27016
|
failFast,
|
|
@@ -26873,18 +27023,6 @@ const executePlan = async (plan, {
|
|
|
26873
27023
|
coverageMethodForNodeJs,
|
|
26874
27024
|
coverageV8ConflictWarning,
|
|
26875
27025
|
coverageTempDirectoryRelativeUrl,
|
|
26876
|
-
scenarios,
|
|
26877
|
-
sourcemaps,
|
|
26878
|
-
plugins,
|
|
26879
|
-
nodeEsmResolution,
|
|
26880
|
-
fileSystemMagicResolution,
|
|
26881
|
-
transpilation,
|
|
26882
|
-
writeGeneratedFiles,
|
|
26883
|
-
protocol,
|
|
26884
|
-
privateKey,
|
|
26885
|
-
certificate,
|
|
26886
|
-
host,
|
|
26887
|
-
port,
|
|
26888
27026
|
beforeExecutionCallback = () => {},
|
|
26889
27027
|
afterExecutionCallback = () => {}
|
|
26890
27028
|
} = {}) => {
|
|
@@ -26908,7 +27046,7 @@ const executePlan = async (plan, {
|
|
|
26908
27046
|
if (runtime) {
|
|
26909
27047
|
runtimes[runtime.name] = runtime.version;
|
|
26910
27048
|
|
|
26911
|
-
if (runtime.
|
|
27049
|
+
if (runtime.type === "browser") {
|
|
26912
27050
|
someNeedsServer = true;
|
|
26913
27051
|
}
|
|
26914
27052
|
|
|
@@ -26999,6 +27137,7 @@ const executePlan = async (plan, {
|
|
|
26999
27137
|
|
|
27000
27138
|
let runtimeParams = {
|
|
27001
27139
|
rootDirectoryUrl,
|
|
27140
|
+
devServerOrigin,
|
|
27002
27141
|
coverageEnabled,
|
|
27003
27142
|
coverageConfig,
|
|
27004
27143
|
coverageMethodForBrowsers,
|
|
@@ -27007,48 +27146,15 @@ const executePlan = async (plan, {
|
|
|
27007
27146
|
};
|
|
27008
27147
|
|
|
27009
27148
|
if (someNeedsServer) {
|
|
27010
|
-
|
|
27011
|
-
|
|
27012
|
-
|
|
27013
|
-
keepProcessAlive: false,
|
|
27014
|
-
port,
|
|
27015
|
-
host,
|
|
27016
|
-
protocol,
|
|
27017
|
-
certificate,
|
|
27018
|
-
privateKey,
|
|
27019
|
-
services,
|
|
27020
|
-
rootDirectoryUrl,
|
|
27021
|
-
scenarios,
|
|
27022
|
-
runtimeCompat: runtimes,
|
|
27023
|
-
plugins,
|
|
27024
|
-
htmlSupervisor: true,
|
|
27025
|
-
nodeEsmResolution,
|
|
27026
|
-
fileSystemMagicResolution,
|
|
27027
|
-
transpilation: { ...transpilation,
|
|
27028
|
-
getCustomBabelPlugins: ({
|
|
27029
|
-
clientRuntimeCompat
|
|
27030
|
-
}) => {
|
|
27031
|
-
if (coverageEnabled && (coverageMethodForBrowsers !== "playwright_api" || Object.keys(clientRuntimeCompat)[0] !== "chrome")) {
|
|
27032
|
-
return {
|
|
27033
|
-
"transform-instrument": [babelPluginInstrument, {
|
|
27034
|
-
rootDirectoryUrl,
|
|
27035
|
-
coverageConfig
|
|
27036
|
-
}]
|
|
27037
|
-
};
|
|
27038
|
-
}
|
|
27149
|
+
if (!devServerOrigin) {
|
|
27150
|
+
throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
|
|
27151
|
+
}
|
|
27039
27152
|
|
|
27040
|
-
|
|
27041
|
-
|
|
27042
|
-
|
|
27043
|
-
|
|
27044
|
-
|
|
27045
|
-
});
|
|
27046
|
-
multipleExecutionsOperation.addEndCallback(async () => {
|
|
27047
|
-
await server.stop();
|
|
27048
|
-
});
|
|
27049
|
-
runtimeParams = { ...runtimeParams,
|
|
27050
|
-
server
|
|
27051
|
-
};
|
|
27153
|
+
const devServerStarted = await pingServer(devServerOrigin);
|
|
27154
|
+
|
|
27155
|
+
if (!devServerStarted) {
|
|
27156
|
+
throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
|
|
27157
|
+
}
|
|
27052
27158
|
}
|
|
27053
27159
|
|
|
27054
27160
|
logger.debug(`Generate executions`);
|
|
@@ -27391,9 +27497,10 @@ const executeInParallel = async ({
|
|
|
27391
27497
|
};
|
|
27392
27498
|
|
|
27393
27499
|
/**
|
|
27394
|
-
* Execute a list of files and log how it goes
|
|
27500
|
+
* Execute a list of files and log how it goes.
|
|
27395
27501
|
* @param {Object} testPlanParameters
|
|
27396
27502
|
* @param {string|url} testPlanParameters.rootDirectoryUrl Root directory of the project
|
|
27503
|
+
* @param {string|url} [testPlanParameters.serverOrigin=undefined] Jsenv dev server origin; required when executing test on browsers
|
|
27397
27504
|
* @param {Object} testPlanParameters.testPlan Object associating patterns leading to files to runtimes where they should be executed
|
|
27398
27505
|
* @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
|
|
27399
27506
|
* @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
|
|
@@ -27420,6 +27527,7 @@ const executeTestPlan = async ({
|
|
|
27420
27527
|
completedExecutionLogAbbreviation = false,
|
|
27421
27528
|
completedExecutionLogMerging = false,
|
|
27422
27529
|
rootDirectoryUrl,
|
|
27530
|
+
devServerOrigin,
|
|
27423
27531
|
testPlan,
|
|
27424
27532
|
updateProcessExitCode = true,
|
|
27425
27533
|
maxExecutionsInParallel = 1,
|
|
@@ -27450,17 +27558,7 @@ const executeTestPlan = async ({
|
|
|
27450
27558
|
coverageReportSkipFull = false,
|
|
27451
27559
|
coverageReportTextLog = true,
|
|
27452
27560
|
coverageReportJsonFile = process.env.CI ? null : "./.coverage/coverage.json",
|
|
27453
|
-
coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null
|
|
27454
|
-
sourcemaps = "inline",
|
|
27455
|
-
plugins = [],
|
|
27456
|
-
nodeEsmResolution,
|
|
27457
|
-
fileSystemMagicResolution,
|
|
27458
|
-
writeGeneratedFiles = false,
|
|
27459
|
-
protocol,
|
|
27460
|
-
privateKey,
|
|
27461
|
-
certificate,
|
|
27462
|
-
host,
|
|
27463
|
-
port
|
|
27561
|
+
coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null
|
|
27464
27562
|
}) => {
|
|
27465
27563
|
const logger = createLogger({
|
|
27466
27564
|
logLevel
|
|
@@ -27520,6 +27618,7 @@ const executeTestPlan = async ({
|
|
|
27520
27618
|
completedExecutionLogMerging,
|
|
27521
27619
|
completedExecutionLogAbbreviation,
|
|
27522
27620
|
rootDirectoryUrl,
|
|
27621
|
+
devServerOrigin,
|
|
27523
27622
|
maxExecutionsInParallel,
|
|
27524
27623
|
defaultMsAllocatedPerExecution,
|
|
27525
27624
|
failFast,
|
|
@@ -27532,21 +27631,7 @@ const executeTestPlan = async ({
|
|
|
27532
27631
|
coverageMethodForBrowsers,
|
|
27533
27632
|
coverageMethodForNodeJs,
|
|
27534
27633
|
coverageV8ConflictWarning,
|
|
27535
|
-
coverageTempDirectoryRelativeUrl
|
|
27536
|
-
scenarios: {
|
|
27537
|
-
dev: true,
|
|
27538
|
-
test: true
|
|
27539
|
-
},
|
|
27540
|
-
sourcemaps,
|
|
27541
|
-
plugins,
|
|
27542
|
-
nodeEsmResolution,
|
|
27543
|
-
fileSystemMagicResolution,
|
|
27544
|
-
writeGeneratedFiles,
|
|
27545
|
-
protocol,
|
|
27546
|
-
privateKey,
|
|
27547
|
-
certificate,
|
|
27548
|
-
host,
|
|
27549
|
-
port
|
|
27634
|
+
coverageTempDirectoryRelativeUrl
|
|
27550
27635
|
});
|
|
27551
27636
|
|
|
27552
27637
|
if (updateProcessExitCode && result.planSummary.counters.total !== result.planSummary.counters.completed) {
|
|
@@ -27664,8 +27749,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
27664
27749
|
const runtime = {
|
|
27665
27750
|
type: "browser",
|
|
27666
27751
|
name: browserName,
|
|
27667
|
-
version: browserVersion
|
|
27668
|
-
needsServer: true
|
|
27752
|
+
version: browserVersion
|
|
27669
27753
|
};
|
|
27670
27754
|
let browserAndContextPromise;
|
|
27671
27755
|
|
|
@@ -27674,7 +27758,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
27674
27758
|
logger,
|
|
27675
27759
|
rootDirectoryUrl,
|
|
27676
27760
|
fileRelativeUrl,
|
|
27677
|
-
|
|
27761
|
+
devServerOrigin,
|
|
27678
27762
|
// measurePerformance,
|
|
27679
27763
|
collectPerformance,
|
|
27680
27764
|
coverageEnabled = false,
|
|
@@ -27749,7 +27833,13 @@ const createRuntimeFromPlaywright = ({
|
|
|
27749
27833
|
await disconnected;
|
|
27750
27834
|
};
|
|
27751
27835
|
|
|
27752
|
-
const
|
|
27836
|
+
const coverageInHeaders = coverageEnabled && (!coveragePlaywrightAPIAvailable || coverageMethodForBrowsers !== "playwright_api");
|
|
27837
|
+
const page = await browserContext.newPage({
|
|
27838
|
+
extraHTTPHeaders: { ...(coverageInHeaders ? {
|
|
27839
|
+
"x-coverage-istanbul": JSON.stringify(coverageConfig)
|
|
27840
|
+
} : {})
|
|
27841
|
+
}
|
|
27842
|
+
});
|
|
27753
27843
|
|
|
27754
27844
|
const closePage = async () => {
|
|
27755
27845
|
try {
|
|
@@ -27777,7 +27867,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
27777
27867
|
const v8CoveragesWithFsUrls = v8CoveragesWithWebUrls.map(v8CoveragesWithWebUrl => {
|
|
27778
27868
|
const fsUrl = moveUrl({
|
|
27779
27869
|
url: v8CoveragesWithWebUrl.url,
|
|
27780
|
-
from: `${
|
|
27870
|
+
from: `${devServerOrigin}/`,
|
|
27781
27871
|
to: rootDirectoryUrl,
|
|
27782
27872
|
preferAbsolute: true
|
|
27783
27873
|
});
|
|
@@ -27848,7 +27938,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
27848
27938
|
});
|
|
27849
27939
|
}
|
|
27850
27940
|
|
|
27851
|
-
const fileClientUrl = new URL(fileRelativeUrl, `${
|
|
27941
|
+
const fileClientUrl = new URL(fileRelativeUrl, `${devServerOrigin}/`).href; // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
|
|
27852
27942
|
|
|
27853
27943
|
const removeConsoleListener = registerEvent({
|
|
27854
27944
|
object: page,
|
|
@@ -27962,7 +28052,7 @@ const createRuntimeFromPlaywright = ({
|
|
|
27962
28052
|
} = returnValue;
|
|
27963
28053
|
const error = evalException(exceptionSource, {
|
|
27964
28054
|
rootDirectoryUrl,
|
|
27965
|
-
|
|
28055
|
+
devServerOrigin,
|
|
27966
28056
|
transformErrorHook
|
|
27967
28057
|
});
|
|
27968
28058
|
cb({
|
|
@@ -28198,7 +28288,7 @@ const registerEvent = ({
|
|
|
28198
28288
|
|
|
28199
28289
|
const evalException = (exceptionSource, {
|
|
28200
28290
|
rootDirectoryUrl,
|
|
28201
|
-
|
|
28291
|
+
devServerOrigin,
|
|
28202
28292
|
transformErrorHook
|
|
28203
28293
|
}) => {
|
|
28204
28294
|
const script = new Script(exceptionSource, {
|
|
@@ -28207,7 +28297,7 @@ const evalException = (exceptionSource, {
|
|
|
28207
28297
|
const error = script.runInThisContext();
|
|
28208
28298
|
|
|
28209
28299
|
if (error && error instanceof Error) {
|
|
28210
|
-
const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${
|
|
28300
|
+
const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${devServerOrigin}/`), "g");
|
|
28211
28301
|
error.stack = error.stack.replace(remoteRootRegexp, rootDirectoryUrl);
|
|
28212
28302
|
error.message = error.message.replace(remoteRootRegexp, rootDirectoryUrl);
|
|
28213
28303
|
}
|
|
@@ -29205,7 +29295,7 @@ const startBuildServer = async ({
|
|
|
29205
29295
|
certificate,
|
|
29206
29296
|
privateKey,
|
|
29207
29297
|
acceptAnyIp,
|
|
29208
|
-
|
|
29298
|
+
hostname,
|
|
29209
29299
|
port = 9779,
|
|
29210
29300
|
services = [],
|
|
29211
29301
|
keepProcessAlive = true,
|
|
@@ -29342,7 +29432,7 @@ const startBuildServer = async ({
|
|
|
29342
29432
|
certificate,
|
|
29343
29433
|
privateKey,
|
|
29344
29434
|
acceptAnyIp,
|
|
29345
|
-
|
|
29435
|
+
hostname,
|
|
29346
29436
|
port,
|
|
29347
29437
|
serverTiming: true,
|
|
29348
29438
|
requestWaitingMs: 60_000,
|
|
@@ -29387,15 +29477,15 @@ const createBuildFilesService = ({
|
|
|
29387
29477
|
buildIndexPath
|
|
29388
29478
|
}) => {
|
|
29389
29479
|
return request => {
|
|
29390
|
-
const urlIsVersioned = new URL(request.
|
|
29480
|
+
const urlIsVersioned = new URL(request.url).searchParams.has("v");
|
|
29391
29481
|
|
|
29392
|
-
if (buildIndexPath && request.
|
|
29482
|
+
if (buildIndexPath && request.resource === "/") {
|
|
29393
29483
|
request = { ...request,
|
|
29394
|
-
|
|
29484
|
+
resource: `/${buildIndexPath}`
|
|
29395
29485
|
};
|
|
29396
29486
|
}
|
|
29397
29487
|
|
|
29398
|
-
return fetchFileSystem(new URL(request.
|
|
29488
|
+
return fetchFileSystem(new URL(request.resource.slice(1), buildDirectoryUrl), {
|
|
29399
29489
|
headers: request.headers,
|
|
29400
29490
|
cacheControl: urlIsVersioned ? `private,max-age=${SECONDS_IN_30_DAYS},immutable` : "private,max-age=0,must-revalidate",
|
|
29401
29491
|
etagEnabled: true,
|
|
@@ -29413,32 +29503,17 @@ const execute = async ({
|
|
|
29413
29503
|
handleSIGINT = true,
|
|
29414
29504
|
logLevel,
|
|
29415
29505
|
rootDirectoryUrl,
|
|
29506
|
+
devServerOrigin,
|
|
29416
29507
|
fileRelativeUrl,
|
|
29417
29508
|
allocatedMs,
|
|
29418
29509
|
mirrorConsole = true,
|
|
29419
29510
|
keepRunning = false,
|
|
29420
|
-
services,
|
|
29421
29511
|
collectConsole,
|
|
29422
29512
|
collectCoverage,
|
|
29423
29513
|
coverageTempDirectoryUrl,
|
|
29424
29514
|
collectPerformance = false,
|
|
29425
29515
|
runtime,
|
|
29426
29516
|
runtimeParams,
|
|
29427
|
-
scenarios = {
|
|
29428
|
-
dev: true
|
|
29429
|
-
},
|
|
29430
|
-
plugins = [],
|
|
29431
|
-
nodeEsmResolution,
|
|
29432
|
-
fileSystemMagicResolution,
|
|
29433
|
-
transpilation,
|
|
29434
|
-
htmlSupervisor = true,
|
|
29435
|
-
sourcemaps = "inline",
|
|
29436
|
-
writeGeneratedFiles = false,
|
|
29437
|
-
port,
|
|
29438
|
-
protocol,
|
|
29439
|
-
http2,
|
|
29440
|
-
certificate,
|
|
29441
|
-
privateKey,
|
|
29442
29517
|
ignoreError = false
|
|
29443
29518
|
}) => {
|
|
29444
29519
|
const logger = createLogger({
|
|
@@ -29460,45 +29535,21 @@ const execute = async ({
|
|
|
29460
29535
|
|
|
29461
29536
|
runtimeParams = {
|
|
29462
29537
|
rootDirectoryUrl,
|
|
29538
|
+
devServerOrigin,
|
|
29463
29539
|
fileRelativeUrl,
|
|
29464
29540
|
...runtimeParams
|
|
29465
29541
|
};
|
|
29466
29542
|
|
|
29467
|
-
if (runtime.
|
|
29468
|
-
|
|
29469
|
-
|
|
29470
|
-
|
|
29471
|
-
keepProcessAlive: false,
|
|
29472
|
-
services,
|
|
29473
|
-
port,
|
|
29474
|
-
protocol,
|
|
29475
|
-
http2,
|
|
29476
|
-
certificate,
|
|
29477
|
-
privateKey,
|
|
29478
|
-
rootDirectoryUrl,
|
|
29479
|
-
scenarios,
|
|
29480
|
-
runtimeCompat: {
|
|
29481
|
-
[runtime.name]: runtime.version
|
|
29482
|
-
},
|
|
29483
|
-
plugins,
|
|
29484
|
-
htmlSupervisor,
|
|
29485
|
-
nodeEsmResolution,
|
|
29486
|
-
fileSystemMagicResolution,
|
|
29487
|
-
transpilation,
|
|
29488
|
-
sourcemaps,
|
|
29489
|
-
writeGeneratedFiles
|
|
29490
|
-
});
|
|
29491
|
-
executeOperation.addEndCallback(async () => {
|
|
29492
|
-
await server.stop("execution done");
|
|
29493
|
-
});
|
|
29494
|
-
runtimeParams = { ...runtimeParams,
|
|
29495
|
-
server
|
|
29496
|
-
};
|
|
29543
|
+
if (runtime.type === "browser") {
|
|
29544
|
+
if (!devServerOrigin) {
|
|
29545
|
+
throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
|
|
29546
|
+
}
|
|
29497
29547
|
|
|
29498
|
-
|
|
29499
|
-
|
|
29500
|
-
|
|
29501
|
-
|
|
29548
|
+
const devServerStarted = await pingServer(devServerOrigin);
|
|
29549
|
+
|
|
29550
|
+
if (!devServerStarted) {
|
|
29551
|
+
throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
|
|
29552
|
+
}
|
|
29502
29553
|
}
|
|
29503
29554
|
|
|
29504
29555
|
let result = await run({
|
|
@@ -29620,4 +29671,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
|
|
|
29620
29671
|
};
|
|
29621
29672
|
};
|
|
29622
29673
|
|
|
29623
|
-
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|
|
29674
|
+
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|