@jsenv/core 25.1.1 → 25.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +2 -2
- package/dist/build_manifest.js +4 -4
- package/dist/compile_proxy/asset-manifest.json +2 -2
- package/dist/compile_proxy/{compile_proxy_e3b0c442_809f35f7.js.map → compile_proxy.html__inline__20_809f35f7.js.map} +0 -0
- package/dist/compile_proxy/{compile_proxy_7ad5faa6.html → compile_proxy_8dfaee51.html} +3 -4
- package/dist/redirector/asset-manifest.json +2 -2
- package/dist/redirector/{redirector_e3b0c442_e391410e.js.map → redirector.html__inline__15_e391410e.js.map} +0 -0
- package/dist/redirector/{redirector_eb92e8a7.html → redirector_3e9a97b9.html} +3 -4
- package/dist/toolbar/asset-manifest.json +1 -1
- package/dist/toolbar/{toolbar_f7b8a263.html → toolbar_361afb84.html} +2 -3
- package/dist/toolbar_injector/asset-manifest.json +2 -2
- package/dist/toolbar_injector/{toolbar_injector_49e4756e.js → toolbar_injector_fac1e995.js} +2 -2
- package/dist/toolbar_injector/{toolbar_injector_49e4756e.js.map → toolbar_injector_fac1e995.js.map} +2 -2
- package/package.json +13 -9
- package/readme.md +73 -79
- package/src/buildProject.js +21 -13
- package/src/commonJsToJavaScriptModule.js +8 -7
- package/src/dev_server.js +2 -0
- package/src/execute.js +2 -0
- package/src/executeTestPlan.js +4 -1
- package/src/internal/building/buildUsingRollup.js +4 -2
- package/src/internal/building/build_stats.js +3 -0
- package/src/internal/building/build_url_generator.js +153 -0
- package/src/internal/building/css/parseCssRessource.js +32 -26
- package/src/internal/building/html/parseHtmlRessource.js +93 -68
- package/src/internal/building/js/parseJsRessource.js +4 -7
- package/src/internal/building/parseRessource.js +3 -0
- package/src/internal/building/ressource_builder.js +64 -62
- package/src/internal/building/ressource_builder_util.js +17 -5
- package/src/internal/building/rollup_plugin_jsenv.js +259 -189
- package/src/internal/building/url_fetcher.js +16 -7
- package/src/internal/building/url_loader.js +1 -5
- package/src/internal/building/url_versioning.js +0 -173
- package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
- package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
- package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
- package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
- package/src/internal/compiling/compile-directory/updateMeta.js +4 -8
- package/src/internal/compiling/compile-directory/validateCache.js +1 -2
- package/src/internal/compiling/compileFile.js +22 -10
- package/src/internal/compiling/createCompiledFileService.js +22 -24
- package/src/internal/compiling/html_source_file_service.js +9 -9
- package/src/internal/compiling/js-compilation-service/babelHelper.js +10 -13
- package/src/internal/compiling/js-compilation-service/babel_plugin_babel_helpers_as_jsenv_imports.js +4 -2
- package/src/internal/compiling/js-compilation-service/jsenvTransform.js +16 -7
- package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
- package/src/internal/compiling/jsenvCompilerForHtml.js +226 -184
- package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
- package/src/internal/compiling/startCompileServer.js +79 -19
- package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
- package/src/internal/executing/executePlan.js +2 -0
- package/src/internal/fetchUrl.js +3 -2
- package/src/internal/jsenv_remote_directory.js +156 -0
- package/src/internal/origin_directory_converter.js +62 -0
- package/src/internal/response_validation.js +11 -24
- package/src/internal/sourceMappingURLUtils.js +10 -0
- package/src/internal/url_conversion.js +1 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { generateSourcemapUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
|
|
2
|
+
|
|
1
3
|
import { transformJs } from "./js-compilation-service/transformJs.js"
|
|
2
4
|
import { transformResultToCompilationResult } from "./transformResultToCompilationResult.js"
|
|
3
5
|
|
|
4
6
|
export const compileJavascript = async ({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
projectDirectoryUrl,
|
|
8
|
+
jsenvRemoteDirectory,
|
|
7
9
|
url,
|
|
8
10
|
compiledUrl,
|
|
9
|
-
projectDirectoryUrl,
|
|
10
11
|
|
|
11
12
|
babelPluginMap,
|
|
12
13
|
workerUrls,
|
|
@@ -16,6 +17,8 @@ export const compileJavascript = async ({
|
|
|
16
17
|
topLevelAwait,
|
|
17
18
|
prependSystemJs,
|
|
18
19
|
|
|
20
|
+
code,
|
|
21
|
+
map,
|
|
19
22
|
sourcemapExcludeSources,
|
|
20
23
|
sourcemapMethod,
|
|
21
24
|
}) => {
|
|
@@ -23,38 +26,39 @@ export const compileJavascript = async ({
|
|
|
23
26
|
prependSystemJs =
|
|
24
27
|
workerUrls.includes(url) || serviceWorkerUrls.includes(url)
|
|
25
28
|
}
|
|
26
|
-
|
|
27
29
|
const transformResult = await transformJs({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
projectDirectoryUrl,
|
|
31
|
+
jsenvRemoteDirectory,
|
|
30
32
|
url,
|
|
31
33
|
compiledUrl,
|
|
32
|
-
projectDirectoryUrl,
|
|
33
34
|
|
|
34
35
|
babelPluginMap,
|
|
35
36
|
moduleOutFormat,
|
|
36
37
|
importMetaFormat,
|
|
37
38
|
topLevelAwait,
|
|
38
39
|
prependSystemJs,
|
|
39
|
-
})
|
|
40
40
|
|
|
41
|
+
code,
|
|
42
|
+
map,
|
|
43
|
+
})
|
|
41
44
|
return transformResultToCompilationResult(
|
|
42
45
|
{
|
|
43
46
|
contentType: "application/javascript",
|
|
47
|
+
metadata: transformResult.metadata,
|
|
44
48
|
code: transformResult.code,
|
|
45
49
|
map: transformResult.map,
|
|
46
|
-
metadata: transformResult.metadata,
|
|
47
50
|
},
|
|
48
51
|
{
|
|
49
52
|
projectDirectoryUrl,
|
|
50
|
-
|
|
53
|
+
jsenvRemoteDirectory,
|
|
51
54
|
originalFileUrl: url,
|
|
52
55
|
compiledFileUrl: compiledUrl,
|
|
53
56
|
// sourcemap are not inside the asset folder because
|
|
54
57
|
// of https://github.com/microsoft/vscode-chrome-debug-core/issues/544
|
|
55
|
-
sourcemapFileUrl:
|
|
58
|
+
sourcemapFileUrl: generateSourcemapUrl(compiledUrl),
|
|
56
59
|
sourcemapExcludeSources,
|
|
57
60
|
sourcemapMethod,
|
|
61
|
+
originalFileContent: code,
|
|
58
62
|
},
|
|
59
63
|
)
|
|
60
64
|
}
|
|
@@ -36,17 +36,19 @@ import {
|
|
|
36
36
|
} from "@jsenv/core/dist/build_manifest.js"
|
|
37
37
|
import { generateGroupMap } from "@jsenv/core/src/internal/generateGroupMap/generateGroupMap.js"
|
|
38
38
|
import { isBrowserPartOfSupportedRuntimes } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
|
|
39
|
-
|
|
40
|
-
import {
|
|
39
|
+
|
|
40
|
+
import { createJsenvRemoteDirectory } from "../jsenv_remote_directory.js"
|
|
41
41
|
import {
|
|
42
42
|
sourcemapMainFileInfo,
|
|
43
43
|
sourcemapMappingFileInfo,
|
|
44
44
|
} from "../jsenvInternalFiles.js"
|
|
45
|
+
import { babelPluginReplaceExpressions } from "../babel_plugin_replace_expressions.js"
|
|
45
46
|
import {
|
|
46
47
|
jsenvCoreDirectoryUrl,
|
|
47
48
|
jsenvDistDirectoryUrl,
|
|
48
49
|
} from "../jsenvCoreDirectoryUrl.js"
|
|
49
|
-
import {
|
|
50
|
+
import { loadBabelPluginMapFromFile } from "./load_babel_plugin_map_from_file.js"
|
|
51
|
+
import { extractSyntaxBabelPluginMap } from "./babel_plugins.js"
|
|
50
52
|
import { babelPluginGlobalThisAsJsenvImport } from "./babel_plugin_global_this_as_jsenv_import.js"
|
|
51
53
|
import { babelPluginNewStylesheetAsJsenvImport } from "./babel_plugin_new_stylesheet_as_jsenv_import.js"
|
|
52
54
|
import { babelPluginImportAssertions } from "./babel_plugin_import_assertions.js"
|
|
@@ -98,6 +100,7 @@ export const startCompileServer = async ({
|
|
|
98
100
|
babelPluginMap,
|
|
99
101
|
babelConfigFileUrl,
|
|
100
102
|
customCompilers = {},
|
|
103
|
+
preservedUrls,
|
|
101
104
|
workers = [],
|
|
102
105
|
serviceWorkers = [],
|
|
103
106
|
importMapInWebWorkers = false,
|
|
@@ -146,6 +149,30 @@ export const startCompileServer = async ({
|
|
|
146
149
|
)
|
|
147
150
|
const logger = createLogger({ logLevel })
|
|
148
151
|
|
|
152
|
+
preservedUrls = {
|
|
153
|
+
// Authorize jsenv to modify any file url
|
|
154
|
+
// because the goal is to build the files into chunks
|
|
155
|
+
"file://": false,
|
|
156
|
+
// Preserves http and https urls
|
|
157
|
+
// because if code specifiy a CDN url it's usually because code wants
|
|
158
|
+
// to keep the url intact and keep HTTP request to CDN (both in dev and prod)
|
|
159
|
+
"http://": true,
|
|
160
|
+
"https://": true,
|
|
161
|
+
/*
|
|
162
|
+
* It's possible to selectively overrides the behaviour above:
|
|
163
|
+
* 1. The CDN file needs to be transformed to be executable in dev, build or both
|
|
164
|
+
* preservedUrls: {"https://cdn.skypack.dev/preact@10.6.4": false}
|
|
165
|
+
* 2. No strong need to preserve the CDN dependency
|
|
166
|
+
* 3. Prevent concatenation of a file during build
|
|
167
|
+
* preservedUrls: {"./file.js": false}
|
|
168
|
+
*/
|
|
169
|
+
...preservedUrls,
|
|
170
|
+
}
|
|
171
|
+
const jsenvRemoteDirectory = createJsenvRemoteDirectory({
|
|
172
|
+
projectDirectoryUrl,
|
|
173
|
+
jsenvDirectoryRelativeUrl,
|
|
174
|
+
preservedUrls,
|
|
175
|
+
})
|
|
149
176
|
const workerUrls = workers.map((worker) =>
|
|
150
177
|
resolveUrl(worker, projectDirectoryUrl),
|
|
151
178
|
)
|
|
@@ -290,11 +317,18 @@ export const startCompileServer = async ({
|
|
|
290
317
|
projectDirectoryUrl,
|
|
291
318
|
jsenvDirectoryRelativeUrl,
|
|
292
319
|
outDirectoryRelativeUrl,
|
|
320
|
+
jsenvRemoteDirectory,
|
|
293
321
|
importDefaultExtension,
|
|
322
|
+
|
|
323
|
+
preservedUrls,
|
|
324
|
+
workers,
|
|
325
|
+
serviceWorkers,
|
|
294
326
|
compileServerGroupMap,
|
|
327
|
+
babelPluginMap,
|
|
328
|
+
replaceProcessEnvNodeEnv,
|
|
329
|
+
processEnvNodeEnv,
|
|
295
330
|
env,
|
|
296
331
|
inlineImportMapIntoHTML,
|
|
297
|
-
babelPluginMap,
|
|
298
332
|
customCompilers,
|
|
299
333
|
jsenvToolbarInjection,
|
|
300
334
|
sourcemapMethod,
|
|
@@ -328,7 +362,9 @@ export const startCompileServer = async ({
|
|
|
328
362
|
logger,
|
|
329
363
|
|
|
330
364
|
projectDirectoryUrl,
|
|
365
|
+
jsenvDirectoryRelativeUrl,
|
|
331
366
|
outDirectoryRelativeUrl,
|
|
367
|
+
jsenvRemoteDirectory,
|
|
332
368
|
|
|
333
369
|
importDefaultExtension,
|
|
334
370
|
|
|
@@ -369,6 +405,7 @@ export const startCompileServer = async ({
|
|
|
369
405
|
: {}),
|
|
370
406
|
"service:source file": createSourceFileService({
|
|
371
407
|
projectDirectoryUrl,
|
|
408
|
+
jsenvRemoteDirectory,
|
|
372
409
|
projectFileRequestedCallback,
|
|
373
410
|
projectFileCacheStrategy,
|
|
374
411
|
}),
|
|
@@ -424,6 +461,7 @@ export const startCompileServer = async ({
|
|
|
424
461
|
...compileServer,
|
|
425
462
|
compileServerGroupMap,
|
|
426
463
|
babelPluginMap,
|
|
464
|
+
preservedUrls,
|
|
427
465
|
projectFileRequestedCallback,
|
|
428
466
|
}
|
|
429
467
|
}
|
|
@@ -939,30 +977,45 @@ const createSourceFileService = ({
|
|
|
939
977
|
projectDirectoryUrl,
|
|
940
978
|
projectFileRequestedCallback,
|
|
941
979
|
projectFileCacheStrategy,
|
|
980
|
+
jsenvRemoteDirectory,
|
|
942
981
|
}) => {
|
|
943
982
|
return async (request) => {
|
|
944
983
|
const relativeUrl = request.pathname.slice(1)
|
|
945
984
|
projectFileRequestedCallback(relativeUrl, request)
|
|
946
|
-
|
|
947
985
|
const fileUrl = new URL(request.ressource.slice(1), projectDirectoryUrl)
|
|
948
986
|
.href
|
|
949
987
|
const fileIsInsideJsenvDistDirectory = urlIsInsideOf(
|
|
950
988
|
fileUrl,
|
|
951
989
|
jsenvDistDirectoryUrl,
|
|
952
990
|
)
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
991
|
+
const fromFileSystem = () =>
|
|
992
|
+
fetchFileSystem(fileUrl, {
|
|
993
|
+
headers: request.headers,
|
|
994
|
+
etagEnabled: projectFileCacheStrategy === "etag",
|
|
995
|
+
mtimeEnabled: projectFileCacheStrategy === "mtime",
|
|
996
|
+
...(fileIsInsideJsenvDistDirectory
|
|
997
|
+
? {
|
|
998
|
+
cacheControl: `private,max-age=${60 * 60 * 24 * 30},immutable`,
|
|
999
|
+
}
|
|
1000
|
+
: {}),
|
|
1001
|
+
})
|
|
1002
|
+
const filesystemResponse = await fromFileSystem()
|
|
1003
|
+
if (
|
|
1004
|
+
filesystemResponse.status === 404 &&
|
|
1005
|
+
jsenvRemoteDirectory.isFileUrlForRemoteUrl(fileUrl)
|
|
1006
|
+
) {
|
|
1007
|
+
try {
|
|
1008
|
+
await jsenvRemoteDirectory.loadFileUrlFromRemote(fileUrl, request)
|
|
1009
|
+
// re-fetch filesystem instead to ensure response headers are correct
|
|
1010
|
+
return fromFileSystem()
|
|
1011
|
+
} catch (e) {
|
|
1012
|
+
if (e && e.asResponse) {
|
|
1013
|
+
return e.asResponse()
|
|
1014
|
+
}
|
|
1015
|
+
throw e
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return filesystemResponse
|
|
966
1019
|
}
|
|
967
1020
|
}
|
|
968
1021
|
|
|
@@ -971,6 +1024,10 @@ const createCompileServerMetaFileInfo = ({
|
|
|
971
1024
|
jsenvDirectoryRelativeUrl,
|
|
972
1025
|
outDirectoryRelativeUrl,
|
|
973
1026
|
importDefaultExtension,
|
|
1027
|
+
|
|
1028
|
+
preservedUrls,
|
|
1029
|
+
workers,
|
|
1030
|
+
serviceWorkers,
|
|
974
1031
|
compileServerGroupMap,
|
|
975
1032
|
babelPluginMap,
|
|
976
1033
|
replaceProcessEnvNodeEnv,
|
|
@@ -1016,6 +1073,9 @@ const createCompileServerMetaFileInfo = ({
|
|
|
1016
1073
|
outDirectoryRelativeUrl,
|
|
1017
1074
|
importDefaultExtension,
|
|
1018
1075
|
|
|
1076
|
+
preservedUrls,
|
|
1077
|
+
workers,
|
|
1078
|
+
serviceWorkers,
|
|
1019
1079
|
babelPluginMap: babelPluginMapAsData(babelPluginMap),
|
|
1020
1080
|
compileServerGroupMap,
|
|
1021
1081
|
customCompilerPatterns,
|
|
@@ -1029,7 +1089,7 @@ const createCompileServerMetaFileInfo = ({
|
|
|
1029
1089
|
sourcemapMappingFileRelativeUrl,
|
|
1030
1090
|
errorStackRemapping: true,
|
|
1031
1091
|
|
|
1032
|
-
// used to consider
|
|
1092
|
+
// used to consider logic generating files may have changed
|
|
1033
1093
|
jsenvCorePackageVersion,
|
|
1034
1094
|
|
|
1035
1095
|
// impact only HTML files
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
urlToRelativeUrl,
|
|
4
4
|
readFile,
|
|
5
5
|
ensureWindowsDriveLetter,
|
|
6
|
+
urlIsInsideOf,
|
|
6
7
|
} from "@jsenv/filesystem"
|
|
7
8
|
|
|
8
9
|
import {
|
|
@@ -15,16 +16,16 @@ import {
|
|
|
15
16
|
setCssSourceMappingUrl,
|
|
16
17
|
sourcemapToBase64Url,
|
|
17
18
|
} from "../sourceMappingURLUtils.js"
|
|
18
|
-
import {
|
|
19
|
+
import { generateCompilationAssetUrl } from "./compile-directory/compile-asset.js"
|
|
19
20
|
import { testFilePresence } from "./compile-directory/fs-optimized-for-cache.js"
|
|
20
21
|
|
|
21
22
|
const isWindows = process.platform === "win32"
|
|
22
23
|
|
|
23
24
|
export const transformResultToCompilationResult = async (
|
|
24
|
-
{ contentType,
|
|
25
|
+
{ contentType, metadata = {}, code, map },
|
|
25
26
|
{
|
|
26
27
|
projectDirectoryUrl,
|
|
27
|
-
|
|
28
|
+
jsenvRemoteDirectory,
|
|
28
29
|
originalFileUrl,
|
|
29
30
|
compiledFileUrl,
|
|
30
31
|
sourcemapFileUrl,
|
|
@@ -33,9 +34,13 @@ export const transformResultToCompilationResult = async (
|
|
|
33
34
|
// it also means client have to fetch source from server (additional http request)
|
|
34
35
|
// some client ignore sourcesContent property such as vscode-chrome-debugger
|
|
35
36
|
// Because it's the most complex scenario and we want to ensure client is always able
|
|
36
|
-
// to find source from the sourcemap,
|
|
37
|
-
|
|
37
|
+
// to find source from the sourcemap, it's a good idea
|
|
38
|
+
// to exclude sourcesContent from sourcemap.
|
|
39
|
+
// However some ressource are abstract and it means additional http request for the browser.
|
|
40
|
+
// For these reasons it's simpler to keep source content in sourcemap.
|
|
41
|
+
sourcemapExcludeSources = false,
|
|
38
42
|
sourcemapMethod = "comment", // "comment", "inline"
|
|
43
|
+
originalFileContent,
|
|
39
44
|
},
|
|
40
45
|
) => {
|
|
41
46
|
if (typeof contentType !== "string") {
|
|
@@ -71,6 +76,14 @@ export const transformResultToCompilationResult = async (
|
|
|
71
76
|
const sourcesContent = []
|
|
72
77
|
const assets = []
|
|
73
78
|
const assetsContent = []
|
|
79
|
+
const addSource = ({ url, content }) => {
|
|
80
|
+
sources.push(url)
|
|
81
|
+
sourcesContent.push(content)
|
|
82
|
+
}
|
|
83
|
+
const addAsset = ({ url, content }) => {
|
|
84
|
+
assets.push(url)
|
|
85
|
+
assetsContent.push(content)
|
|
86
|
+
}
|
|
74
87
|
|
|
75
88
|
let output = code
|
|
76
89
|
if (sourcemapEnabled && map) {
|
|
@@ -78,8 +91,10 @@ export const transformResultToCompilationResult = async (
|
|
|
78
91
|
// may happen in some cases where babel returns a wrong sourcemap
|
|
79
92
|
// there is at least one case where it happens
|
|
80
93
|
// a file with only import './whatever.js' inside
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
addSource({
|
|
95
|
+
url: originalFileUrl,
|
|
96
|
+
content: originalFileContent,
|
|
97
|
+
})
|
|
83
98
|
} else {
|
|
84
99
|
map.sources.forEach((source, index) => {
|
|
85
100
|
const sourceFileUrl = resolveSourceFile({
|
|
@@ -90,19 +105,25 @@ export const transformResultToCompilationResult = async (
|
|
|
90
105
|
projectDirectoryUrl,
|
|
91
106
|
})
|
|
92
107
|
if (sourceFileUrl) {
|
|
93
|
-
|
|
108
|
+
// In case the file comes from a remote url
|
|
109
|
+
// we prefer to consider remote url as the real source for this code
|
|
110
|
+
map.sources[index] =
|
|
111
|
+
jsenvRemoteDirectory &&
|
|
112
|
+
jsenvRemoteDirectory.isFileUrlForRemoteUrl(sourceFileUrl)
|
|
113
|
+
? jsenvRemoteDirectory.remoteUrlFromFileUrl(sourceFileUrl)
|
|
114
|
+
: urlToRelativeUrl(sourceFileUrl, sourcemapFileUrl)
|
|
94
115
|
sources[index] = sourceFileUrl
|
|
95
116
|
}
|
|
96
117
|
})
|
|
97
|
-
|
|
98
118
|
if (sources.length === 0) {
|
|
99
119
|
// happens when sourcemap is generated by webpack and looks like
|
|
100
120
|
// webpack://Package./src/file.js
|
|
101
121
|
// in that case we'll don't know how to find the source file
|
|
102
|
-
|
|
103
|
-
|
|
122
|
+
addSource({
|
|
123
|
+
url: originalFileUrl,
|
|
124
|
+
content: originalFileContent,
|
|
125
|
+
})
|
|
104
126
|
}
|
|
105
|
-
|
|
106
127
|
await Promise.all(
|
|
107
128
|
sources.map(async (sourceUrl, index) => {
|
|
108
129
|
const contentFromSourcemap = map.sourcesContent
|
|
@@ -121,7 +142,6 @@ export const transformResultToCompilationResult = async (
|
|
|
121
142
|
if (sourcemapExcludeSources) {
|
|
122
143
|
delete map.sourcesContent
|
|
123
144
|
}
|
|
124
|
-
|
|
125
145
|
// we don't need sourceRoot because our path are relative or absolute to the current location
|
|
126
146
|
// we could comment this line because it is not set by babel because not passed during transform
|
|
127
147
|
delete map.sourceRoot
|
|
@@ -139,22 +159,28 @@ export const transformResultToCompilationResult = async (
|
|
|
139
159
|
compiledFileUrl,
|
|
140
160
|
)
|
|
141
161
|
output = setSourceMappingUrl(output, sourcemapFileRelativePathForModule)
|
|
142
|
-
|
|
143
|
-
|
|
162
|
+
addAsset({
|
|
163
|
+
url: sourcemapFileUrl,
|
|
164
|
+
content: stringifyMap(map),
|
|
165
|
+
})
|
|
144
166
|
}
|
|
145
167
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
addSource({
|
|
169
|
+
url: originalFileUrl,
|
|
170
|
+
content: originalFileContent,
|
|
171
|
+
})
|
|
148
172
|
}
|
|
149
173
|
|
|
150
174
|
const { coverage } = metadata
|
|
151
175
|
if (coverage) {
|
|
152
|
-
const coverageAssetFileUrl =
|
|
176
|
+
const coverageAssetFileUrl = generateCompilationAssetUrl(
|
|
153
177
|
compiledFileUrl,
|
|
154
178
|
"coverage.json",
|
|
155
179
|
)
|
|
156
|
-
|
|
157
|
-
|
|
180
|
+
addAsset({
|
|
181
|
+
url: coverageAssetFileUrl,
|
|
182
|
+
content: stringifyCoverage(coverage),
|
|
183
|
+
})
|
|
158
184
|
}
|
|
159
185
|
|
|
160
186
|
const { dependencies = [] } = metadata
|
|
@@ -179,18 +205,15 @@ const resolveSourceFile = ({
|
|
|
179
205
|
projectDirectoryUrl,
|
|
180
206
|
}) => {
|
|
181
207
|
const sourceFileUrl = resolveSourceUrl({ source, sourcemapFileUrl })
|
|
182
|
-
|
|
183
|
-
if (!sourceFileUrl.startsWith(projectDirectoryUrl)) {
|
|
208
|
+
if (!urlIsInsideOf(sourceFileUrl, projectDirectoryUrl)) {
|
|
184
209
|
// do not track dependency outside project
|
|
185
210
|
// it means cache stays valid for those external sources
|
|
186
211
|
return null
|
|
187
212
|
}
|
|
188
|
-
|
|
189
213
|
const fileFound = testFilePresence(sourceFileUrl)
|
|
190
214
|
if (fileFound) {
|
|
191
215
|
return sourceFileUrl
|
|
192
216
|
}
|
|
193
|
-
|
|
194
217
|
// prefer original source file
|
|
195
218
|
const relativeUrl = urlToRelativeUrl(sourceFileUrl, compiledFileUrl)
|
|
196
219
|
const originalSourceUrl = resolveUrl(relativeUrl, originalFileUrl)
|
|
@@ -211,7 +234,6 @@ const resolveSourceUrl = ({ source, sourcemapFileUrl }) => {
|
|
|
211
234
|
)
|
|
212
235
|
return ensureWindowsDriveLetter(url, sourcemapFileUrl)
|
|
213
236
|
}
|
|
214
|
-
|
|
215
237
|
return resolveUrl(source, sourcemapFileUrl)
|
|
216
238
|
}
|
|
217
239
|
|
|
@@ -51,6 +51,7 @@ export const executePlan = async (
|
|
|
51
51
|
compileServerCanWriteOnFilesystem,
|
|
52
52
|
babelPluginMap,
|
|
53
53
|
babelConfigFileUrl,
|
|
54
|
+
preservedUrls,
|
|
54
55
|
workers,
|
|
55
56
|
serviceWorkers,
|
|
56
57
|
importMapInWebWorkers,
|
|
@@ -126,6 +127,7 @@ export const executePlan = async (
|
|
|
126
127
|
keepProcessAlive: true, // to be sure it stays alive
|
|
127
128
|
babelPluginMap,
|
|
128
129
|
babelConfigFileUrl,
|
|
130
|
+
preservedUrls,
|
|
129
131
|
workers,
|
|
130
132
|
serviceWorkers,
|
|
131
133
|
importMapInWebWorkers,
|
package/src/internal/fetchUrl.js
CHANGED
|
@@ -13,9 +13,9 @@ export const fetchUrl = async (
|
|
|
13
13
|
ignoreHttpsError,
|
|
14
14
|
...rest,
|
|
15
15
|
})
|
|
16
|
-
|
|
17
|
-
return {
|
|
16
|
+
const responseObject = {
|
|
18
17
|
url: response.url,
|
|
18
|
+
type: "default",
|
|
19
19
|
status: response.status,
|
|
20
20
|
statusText: response.statusText,
|
|
21
21
|
headers: headersToObject(response.headers),
|
|
@@ -24,4 +24,5 @@ export const fetchUrl = async (
|
|
|
24
24
|
blob: response.blob.bind(response),
|
|
25
25
|
arrayBuffer: response.arrayBuffer.bind(response),
|
|
26
26
|
}
|
|
27
|
+
return responseObject
|
|
27
28
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
urlIsInsideOf,
|
|
3
|
+
urlToRelativeUrl,
|
|
4
|
+
urlToRessource,
|
|
5
|
+
normalizeStructuredMetaMap,
|
|
6
|
+
urlToMeta,
|
|
7
|
+
writeFile,
|
|
8
|
+
} from "@jsenv/filesystem"
|
|
9
|
+
import { validateResponseIntegrity } from "@jsenv/integrity"
|
|
10
|
+
|
|
11
|
+
import { fetchUrl } from "@jsenv/core/src/internal/fetchUrl.js"
|
|
12
|
+
|
|
13
|
+
import { originDirectoryConverter } from "./origin_directory_converter.js"
|
|
14
|
+
|
|
15
|
+
export const createJsenvRemoteDirectory = ({
|
|
16
|
+
projectDirectoryUrl,
|
|
17
|
+
jsenvDirectoryRelativeUrl,
|
|
18
|
+
preservedUrls,
|
|
19
|
+
}) => {
|
|
20
|
+
const jsenvRemoteDirectoryUrl = `${projectDirectoryUrl}${jsenvDirectoryRelativeUrl}.remote/`
|
|
21
|
+
const structuredMetaMap = normalizeStructuredMetaMap(
|
|
22
|
+
{ preserved: preservedUrls },
|
|
23
|
+
projectDirectoryUrl,
|
|
24
|
+
)
|
|
25
|
+
const isPreservedUrl = (url) => {
|
|
26
|
+
const meta = urlToMeta({ url, structuredMetaMap })
|
|
27
|
+
return Boolean(meta.preserved)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const jsenvRemoteDirectory = {
|
|
31
|
+
isPreservedUrl,
|
|
32
|
+
|
|
33
|
+
isRemoteUrl: (url) => {
|
|
34
|
+
return url.startsWith("http://") || url.startsWith("https://")
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
isFileUrlForRemoteUrl: (url) => {
|
|
38
|
+
return urlIsInsideOf(url, jsenvRemoteDirectoryUrl)
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
fileUrlFromRemoteUrl: (remoteUrl) => {
|
|
42
|
+
const origin = originFromUrlOrUrlPattern(remoteUrl)
|
|
43
|
+
const ressource = urlToRessource(remoteUrl)
|
|
44
|
+
const [pathname, search = ""] = ressource.split("?")
|
|
45
|
+
const directoryName = originDirectoryConverter.toDirectoryName(origin)
|
|
46
|
+
const fileRelativeUrl = `${directoryName}${
|
|
47
|
+
pathname === "" ? "/" : pathname
|
|
48
|
+
}`
|
|
49
|
+
const fileUrl = `${jsenvRemoteDirectoryUrl}${fileRelativeUrl}${search}`
|
|
50
|
+
return fileUrl
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
remoteUrlFromFileUrl: (fileUrl) => {
|
|
54
|
+
const fileRelativeUrl = urlToRelativeUrl(fileUrl, jsenvRemoteDirectoryUrl)
|
|
55
|
+
const firstSlashIndex = fileRelativeUrl.indexOf("/")
|
|
56
|
+
const directoryName = fileRelativeUrl.slice(0, firstSlashIndex)
|
|
57
|
+
const origin = originDirectoryConverter.fromDirectoryName(directoryName)
|
|
58
|
+
const ressource = fileRelativeUrl.slice(firstSlashIndex)
|
|
59
|
+
const remoteUrlObject = new URL(ressource, origin)
|
|
60
|
+
remoteUrlObject.searchParams.delete("integrity")
|
|
61
|
+
const remoteUrl = remoteUrlObject.href
|
|
62
|
+
return remoteUrl
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
loadFileUrlFromRemote: async (url, request) => {
|
|
66
|
+
const urlObject = new URL(url)
|
|
67
|
+
const integrity = urlObject.searchParams.get("integrity")
|
|
68
|
+
if (integrity) {
|
|
69
|
+
urlObject.searchParams.delete("integrity")
|
|
70
|
+
}
|
|
71
|
+
const remoteUrl = jsenvRemoteDirectory.remoteUrlFromFileUrl(
|
|
72
|
+
urlObject.href,
|
|
73
|
+
)
|
|
74
|
+
const requestHeadersToForward = { ...request.headers }
|
|
75
|
+
delete requestHeadersToForward.host
|
|
76
|
+
const response = await fetchUrl(remoteUrl, {
|
|
77
|
+
mode: "cors",
|
|
78
|
+
headers: requestHeadersToForward,
|
|
79
|
+
})
|
|
80
|
+
if (response.status !== 200) {
|
|
81
|
+
throw createRemoteFetchError({
|
|
82
|
+
code: "UNEXPECTED_STATUS",
|
|
83
|
+
message: `unexpected status for ressource "${remoteUrl}", received ${response.status}`,
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
const responseBodyAsBuffer = Buffer.from(await response.arrayBuffer())
|
|
87
|
+
if (integrity) {
|
|
88
|
+
try {
|
|
89
|
+
validateResponseIntegrity(
|
|
90
|
+
{
|
|
91
|
+
url: response.url,
|
|
92
|
+
type: response.type,
|
|
93
|
+
dataRepresentation: responseBodyAsBuffer,
|
|
94
|
+
},
|
|
95
|
+
integrity,
|
|
96
|
+
)
|
|
97
|
+
} catch (e) {
|
|
98
|
+
throw createRemoteFetchError({
|
|
99
|
+
code: e.code,
|
|
100
|
+
message: e.message,
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
await writeFile(url, responseBodyAsBuffer)
|
|
105
|
+
return responseBodyAsBuffer
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return jsenvRemoteDirectory
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const createRemoteFetchError = ({ message, code }) => {
|
|
113
|
+
const error = new Error(message)
|
|
114
|
+
error.code = "UNEXPECTED_REMOTE_URL_RESPONSE"
|
|
115
|
+
error.asResponse = () => {
|
|
116
|
+
const data = {
|
|
117
|
+
code,
|
|
118
|
+
message,
|
|
119
|
+
}
|
|
120
|
+
const json = JSON.stringify(data)
|
|
121
|
+
return {
|
|
122
|
+
status: 502,
|
|
123
|
+
statusText: "Bad Gateway",
|
|
124
|
+
headers: {
|
|
125
|
+
"cache-control": "no-store",
|
|
126
|
+
"content-length": Buffer.byteLength(json),
|
|
127
|
+
"content-type": "application/json",
|
|
128
|
+
},
|
|
129
|
+
body: json,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return error
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const originFromUrlOrUrlPattern = (url) => {
|
|
136
|
+
if (url.startsWith("http://")) {
|
|
137
|
+
const slashAfterProtocol = url.indexOf("/", "http://".length + 1)
|
|
138
|
+
if (slashAfterProtocol === -1) {
|
|
139
|
+
return url
|
|
140
|
+
}
|
|
141
|
+
const origin = url.slice(0, slashAfterProtocol)
|
|
142
|
+
return origin
|
|
143
|
+
}
|
|
144
|
+
if (url.startsWith("https://")) {
|
|
145
|
+
const slashAfterProtocol = url.indexOf("/", "https://".length + 1)
|
|
146
|
+
if (slashAfterProtocol === -1) {
|
|
147
|
+
return url
|
|
148
|
+
}
|
|
149
|
+
const origin = url.slice(0, slashAfterProtocol)
|
|
150
|
+
return origin
|
|
151
|
+
}
|
|
152
|
+
if (url.startsWith("file://")) {
|
|
153
|
+
return "file://"
|
|
154
|
+
}
|
|
155
|
+
return new URL(url).origin
|
|
156
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// https://stackoverflow.com/a/1184263
|
|
2
|
+
// using the list of bad characters from:
|
|
3
|
+
// https://github.com/parshap/node-sanitize-filename/blob/master/index.js
|
|
4
|
+
// so that the directory name can be decoded
|
|
5
|
+
// so that we can find back the http origin
|
|
6
|
+
// we should also ignore the query string params part
|
|
7
|
+
// it does not matter, it can be removed from the url and added back
|
|
8
|
+
// when performing the http request
|
|
9
|
+
|
|
10
|
+
const escapeChar = "$"
|
|
11
|
+
const reservedChars = ["/", "?", "<", ">", "\\", ":", "*", "|", '"']
|
|
12
|
+
|
|
13
|
+
export const originDirectoryConverter = {
|
|
14
|
+
toDirectoryName: (origin) => {
|
|
15
|
+
let directoryName = ""
|
|
16
|
+
let i = 0
|
|
17
|
+
while (i < origin.length) {
|
|
18
|
+
const char = origin[i]
|
|
19
|
+
i++
|
|
20
|
+
if (reservedChars.includes(char)) {
|
|
21
|
+
const charAsHex = charToHexString(char)
|
|
22
|
+
directoryName += `${escapeChar}${charAsHex}`
|
|
23
|
+
} else {
|
|
24
|
+
directoryName += char
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return directoryName
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
fromDirectoryName: (filename) => {
|
|
31
|
+
let origin = ""
|
|
32
|
+
let i = 0
|
|
33
|
+
while (i < filename.length) {
|
|
34
|
+
const char = filename[i]
|
|
35
|
+
i++
|
|
36
|
+
if (char === escapeChar) {
|
|
37
|
+
const encodedChar = `${filename[i]}${filename[i + 1]}`
|
|
38
|
+
i += 2
|
|
39
|
+
const decodedChar = charFromHexString(encodedChar)
|
|
40
|
+
origin += decodedChar
|
|
41
|
+
} else {
|
|
42
|
+
origin += char
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return origin
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const charToHexString = (char) => {
|
|
50
|
+
const charCode = char.charCodeAt(0)
|
|
51
|
+
const hexString = charCode.toString(16)
|
|
52
|
+
if (charCode < 16) {
|
|
53
|
+
return `0${hexString}`
|
|
54
|
+
}
|
|
55
|
+
return hexString
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const charFromHexString = (hexString) => {
|
|
59
|
+
const charCode = parseInt(hexString, 16)
|
|
60
|
+
const char = String.fromCharCode(charCode)
|
|
61
|
+
return char
|
|
62
|
+
}
|