@jsenv/core 24.6.5 → 25.0.0-alpha.3

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.
Files changed (83) hide show
  1. package/dist/browser_runtime/asset-manifest.json +2 -1
  2. package/dist/browser_runtime/{browser_runtime-bb0e3aa4.js → browser_runtime_91c5a3b8.js} +137 -26
  3. package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +1089 -0
  4. package/dist/build_manifest.js +6 -6
  5. package/dist/compile_proxy/asset-manifest.json +2 -1
  6. package/dist/compile_proxy/{compile_proxy-6eb67db4.html → compile_proxy_7ad5faa6.html} +119 -26
  7. package/dist/compile_proxy/{compile_proxy.html__inline__20-9e168143.js.map → compile_proxy_e3b0c442_809f35f7.js.map} +6 -6
  8. package/dist/event_source_client/asset-manifest.json +2 -1
  9. package/dist/event_source_client/{event_source_client-9f14c8b9.js → event_source_client_80644aee.js} +2 -2
  10. package/dist/event_source_client/{event_source_client-9f14c8b9.js.map → event_source_client_80644aee.js.map} +4 -3
  11. package/dist/redirector/asset-manifest.json +2 -1
  12. package/dist/redirector/{redirector.html__inline__15-3a34a156.js.map → redirector_e3b0c442_e391410e.js.map} +6 -6
  13. package/dist/redirector/{redirector-b6ad84bf.html → redirector_eb92e8a7.html} +119 -26
  14. package/dist/toolbar/asset-manifest.json +11 -10
  15. package/dist/toolbar/assets/{compilation.css-209d68b4.map → compilation.css_e37c747b.map} +1 -1
  16. package/dist/toolbar/assets/{eventsource.css-38cd0a36.map → eventsource.css_c0c71e7b.map} +1 -1
  17. package/dist/toolbar/assets/{execution.css-0ebe522f.map → execution.css_f3377c10.map} +1 -1
  18. package/dist/toolbar/assets/{focus.css-3f9c156d.map → focus.css_896f3e45.map} +1 -1
  19. package/dist/toolbar/assets/{light-theme.css-78b19a80.map → light-theme.css_72a60fa3.map} +1 -1
  20. package/dist/toolbar/assets/{overflow-menu.css-d9688a1c.map → overflow-menu.css_2859d519.map} +1 -1
  21. package/dist/toolbar/assets/{settings.css-2b81b245.map → settings.css_61548139.map} +1 -1
  22. package/dist/toolbar/assets/{toolbar.main.css-846920e9.map → toolbar.main.css_269d7ce2.map} +9 -9
  23. package/dist/toolbar/assets/{tooltip.css-03395ee6.map → tooltip.css_a94a8bdd.map} +1 -1
  24. package/dist/toolbar/{toolbar.main-a5ef2c60.js.map → toolbar.main2_6c1b3d82.js.map} +8 -8
  25. package/dist/toolbar/{toolbar-1fbf8dcb.html → toolbar_04ba410c.html} +129 -36
  26. package/dist/toolbar_injector/asset-manifest.json +3 -2
  27. package/dist/toolbar_injector/assets/{jsenv-logo-188b9ca6.svg → jsenv-logo_188b9ca6.svg} +0 -0
  28. package/dist/toolbar_injector/{toolbar_injector-997dbaa0.js → toolbar_injector_4a48bc53.js} +3 -3
  29. package/dist/toolbar_injector/{toolbar_injector-997dbaa0.js.map → toolbar_injector_4a48bc53.js.map} +2 -2
  30. package/package.json +5 -4
  31. package/readme.md +24 -91
  32. package/src/buildProject.js +51 -27
  33. package/src/dev_server.js +8 -2
  34. package/src/execute.js +7 -1
  35. package/src/executeTestPlan.js +17 -0
  36. package/src/internal/browser_feature_detection/browser_feature_detection.js +18 -25
  37. package/src/internal/browser_runtime/browser_runtime.js +2 -2
  38. package/src/internal/browser_runtime/createBrowserRuntime.js +1 -1
  39. package/src/internal/browser_runtime/displayErrorInDocument.js +2 -0
  40. package/src/internal/browser_runtime/displayErrorNotification.js +1 -1
  41. package/src/internal/building/buildUsingRollup.js +12 -15
  42. package/src/internal/building/build_logs.js +2 -2
  43. package/src/internal/building/build_stats.js +11 -1
  44. package/src/internal/building/html/parseHtmlRessource.js +2 -26
  45. package/src/internal/building/js/parseJsRessource.js +3 -2
  46. package/src/internal/building/json_module.js +11 -0
  47. package/src/internal/building/parseRessource.js +1 -1
  48. package/src/internal/building/ressource_builder.js +210 -216
  49. package/src/internal/building/rollup_plugin_jsenv.js +554 -378
  50. package/src/internal/building/url_loader.js +8 -145
  51. package/src/internal/building/url_versioning.js +220 -0
  52. package/src/internal/compiling/compileHtml.js +8 -1
  53. package/src/internal/compiling/createCompiledFileService.js +28 -40
  54. package/src/internal/compiling/html_source_file_service.js +66 -51
  55. package/src/internal/compiling/js-compilation-service/babel_plugin_systemjs_prepend.js +23 -0
  56. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +16 -12
  57. package/src/internal/compiling/js-compilation-service/transformJs.js +2 -0
  58. package/src/internal/compiling/jsenvCompilerForHtml.js +43 -44
  59. package/src/internal/compiling/jsenvCompilerForImportmap.js +15 -76
  60. package/src/internal/compiling/jsenvCompilerForJavaScript.js +9 -0
  61. package/src/internal/compiling/startCompileServer.js +29 -5
  62. package/src/internal/dev_server/event_source_client/livereload_preference.js +1 -1
  63. package/src/internal/dev_server/toolbar/compilation/toolbar.compilation.js +9 -9
  64. package/src/internal/executing/executePlan.js +6 -0
  65. package/src/internal/generateGroupMap/{jsenvBabelPluginCompatMap.js → babel_plugins_compatibility.js} +0 -0
  66. package/src/internal/generateGroupMap/{featuresCompatMap.js → features_compatibility.js} +9 -1
  67. package/src/internal/generateGroupMap/generateGroupMap.js +6 -35
  68. package/src/internal/generateGroupMap/one_runtime_compat.js +9 -12
  69. package/src/internal/generateGroupMap/runtime_compat.js +10 -15
  70. package/src/internal/generateGroupMap/runtime_compat_composition.js +2 -2
  71. package/src/internal/generateGroupMap/shake_babel_plugin_map.js +21 -0
  72. package/src/internal/import-resolution/importmap_default.js +52 -0
  73. package/src/internal/node_feature_detection/node_feature_detection.js +25 -19
  74. package/src/internal/runtime/s.js +101 -6
  75. package/src/internal/unevalException.js +1 -1
  76. package/src/jsenvServiceWorkerFinalizer.js +12 -17
  77. package/dist/browser_runtime/browser_runtime-bb0e3aa4.js.map +0 -1067
  78. package/src/internal/building/asset_url_versioning.js +0 -50
  79. package/src/internal/building/rollup_build_sourcemap.js +0 -54
  80. package/src/internal/building/url-versioning.js +0 -96
  81. package/src/internal/generateGroupMap/jsenvPluginCompatMap.js +0 -1
  82. package/src/internal/import-resolution/importmap-default.js +0 -34
  83. package/src/internal/renderNamePattern.js +0 -6
@@ -1,17 +1,12 @@
1
- import { resolveUrl, urlToFilename } from "@jsenv/filesystem"
2
-
3
- import { transformJs } from "@jsenv/core/src/internal/compiling/js-compilation-service/transformJs.js"
4
- import { convertCssTextToJavascriptModule } from "@jsenv/core/src/internal/building/css_module.js"
1
+ import { convertJsonTextToJavascriptModule } from "@jsenv/core/src/internal/building/json_module.js"
5
2
  import { getJavaScriptSourceMappingUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
3
+
6
4
  import { loadSourcemap } from "./sourcemap_loader.js"
7
5
 
8
6
  export const createUrlLoader = ({
9
- projectDirectoryUrl,
10
- buildDirectoryUrl,
11
- babelPluginMap,
7
+ urlCustomLoaders,
12
8
  allowJson,
13
9
  urlImporterMap,
14
- inlineModuleScripts,
15
10
 
16
11
  asServerUrl,
17
12
  asProjectUrl,
@@ -21,115 +16,13 @@ export const createUrlLoader = ({
21
16
  }) => {
22
17
  const urlResponseBodyMap = {}
23
18
 
24
- const loadUrl = async (rollupUrl, { signal, logger, ressourceBuilder }) => {
19
+ const loadUrl = async (rollupUrl, { signal, logger }) => {
25
20
  let url = asServerUrl(rollupUrl)
26
- const { importType, urlWithoutImportType } = extractImportTypeFromUrl(url)
27
- // importing CSS from JS with import assertions
28
- if (importType === "css") {
29
- const importer = urlImporterMap[url]
30
- const cssReference =
31
- await ressourceBuilder.createReferenceFoundInJsModule({
32
- referenceLabel: "css import assertion",
33
- // If all references to a ressource are only import assertions
34
- // the file referenced do not need to be written on filesystem
35
- // as it was converted to a js file
36
- // We pass "isImportAssertion: true" for this purpose
37
- isImportAssertion: true,
38
- jsUrl: importer.url,
39
- jsLine: importer.line,
40
- jsColumn: importer.column,
41
- ressourceSpecifier: urlWithoutImportType,
42
- contentTypeExpected: "text/css",
43
- })
44
- await cssReference.ressource.getReadyPromise()
45
- const cssBuildUrl = resolveUrl(
46
- cssReference.ressource.buildRelativeUrl,
47
- buildDirectoryUrl,
48
- )
49
- const jsBuildUrl = resolveUrl(
50
- urlToFilename(importer.url),
51
- buildDirectoryUrl,
52
- )
53
- let code = String(cssReference.ressource.bufferAfterBuild)
54
- let map
55
- const sourcemapReference = cssReference.ressource.dependencies.find(
56
- (dependency) => {
57
- return dependency.ressource.isSourcemap
58
- },
59
- )
60
- if (sourcemapReference) {
61
- // because css is ready, it's sourcemap is also ready
62
- // we can read directly sourcemapReference.ressource.bufferAfterBuild
63
- map = JSON.parse(sourcemapReference.ressource.bufferAfterBuild)
64
- }
65
-
66
- const jsModuleConversionResult = await convertCssTextToJavascriptModule({
67
- cssUrl: cssBuildUrl,
68
- jsUrl: jsBuildUrl,
69
- code,
70
- map,
71
- })
72
- code = jsModuleConversionResult.code
73
- map = jsModuleConversionResult.map
74
-
75
- return {
76
- url,
77
- code,
78
- map,
79
- }
80
- }
81
- // importing json from JS with import assertion
82
- if (importType === "json") {
83
- const importer = urlImporterMap[url]
84
- const jsonReference =
85
- await ressourceBuilder.createReferenceFoundInJsModule({
86
- referenceLabel: "json import assertion",
87
- // If all references to a ressource are only import assertions
88
- // the file referenced do not need to be written on filesystem
89
- // as it was converted to a js file
90
- // We pass "isImportAssertion: true" for this purpose
91
- isImportAssertion: true,
92
- jsUrl: importer.url,
93
- jsLine: importer.line,
94
- jsColumn: importer.column,
95
- ressourceSpecifier: asServerUrl(urlWithoutImportType),
96
- contentTypeExpected: "application/json",
97
- })
98
- await jsonReference.ressource.getReadyPromise()
99
- let code = String(jsonReference.ressource.bufferAfterBuild)
100
- let map
101
-
102
- const jsModuleConversionResult = await convertJsonTextToJavascriptModule({
103
- code,
104
- map,
105
- })
106
- code = jsModuleConversionResult.code
107
- map = jsModuleConversionResult.map
108
21
 
109
- return {
110
- url,
111
- code,
112
- }
113
- }
114
-
115
- if (url in inlineModuleScripts) {
116
- const transformResult = await transformJs({
117
- code: String(inlineModuleScripts[url].bufferBeforeBuild),
118
- url: asOriginalUrl(url), // transformJs expect a file:// url
119
- projectDirectoryUrl,
120
- babelPluginMap,
121
- // moduleOutFormat: format // we are compiling for rollup output must be "esmodule"
122
- // we compile for rollup, let top level await untouched
123
- // it will be converted, if needed, during "renderChunk" hook
124
- topLevelAwait: "ignore",
125
- })
126
- let code = transformResult.code
127
- let map = transformResult.map
128
- return {
129
- url,
130
- code,
131
- map,
132
- }
22
+ const customLoader = urlCustomLoaders[url]
23
+ if (customLoader) {
24
+ const result = await customLoader()
25
+ return result
133
26
  }
134
27
 
135
28
  const response = await urlFetcher.fetchUrl(url, {
@@ -236,33 +129,3 @@ export const createUrlLoader = ({
236
129
  getUrlResponseBodyMap: () => urlResponseBodyMap,
237
130
  }
238
131
  }
239
-
240
- const extractImportTypeFromUrl = (url) => {
241
- const urlObject = new URL(url)
242
- const { search } = urlObject
243
- const searchParams = new URLSearchParams(search)
244
-
245
- const importType = searchParams.get("import_type")
246
- if (!importType) {
247
- return {}
248
- }
249
-
250
- searchParams.delete("import_type")
251
- urlObject.search = String(searchParams)
252
- return {
253
- importType,
254
- urlWithoutImportType: urlObject.href,
255
- }
256
- }
257
-
258
- const convertJsonTextToJavascriptModule = ({ code }) => {
259
- // here we could do the following
260
- // return export default jsonText
261
- // This would return valid js, that would be minified later
262
- // however we will prefer using JSON.parse because it's faster
263
- // for js engine to parse JSON than JS
264
-
265
- return {
266
- code: `export default JSON.parse(${JSON.stringify(code.trim())})`,
267
- }
268
- }
@@ -0,0 +1,220 @@
1
+ import { createHash } from "crypto"
2
+ import {
3
+ urlToParentUrl,
4
+ urlToBasename,
5
+ urlToExtension,
6
+ } from "@jsenv/filesystem"
7
+
8
+ export const createUrlVersioner = ({
9
+ entryPointUrls,
10
+ asOriginalUrl,
11
+ lineBreakNormalization,
12
+ }) => {
13
+ const names = []
14
+ const getFreeName = (name) => {
15
+ let nameCandidate = name
16
+ let integer = 1
17
+ // eslint-disable-next-line no-constant-condition
18
+ while (true) {
19
+ if (!names.includes(nameCandidate)) {
20
+ names.push(nameCandidate)
21
+ return nameCandidate
22
+ }
23
+ integer++
24
+ nameCandidate = `${name}${integer}`
25
+ }
26
+ }
27
+
28
+ const computeBuildRelativeUrl = (ressource, precomputation) => {
29
+ const pattern = getFilenamePattern({
30
+ ressource,
31
+ entryPointUrls,
32
+ asOriginalUrl,
33
+ precomputeBuildRelativeUrl,
34
+ })
35
+
36
+ const buildRelativeUrl = generateBuildRelativeUrl(
37
+ ressource.url,
38
+ ressource.bufferAfterBuild,
39
+ {
40
+ pattern,
41
+ getName: precomputation
42
+ ? () => urlToBasename(ressource.url)
43
+ : () => getFreeName(urlToBasename(ressource.url)),
44
+ contentType: ressource.contentType,
45
+ lineBreakNormalization,
46
+ },
47
+ )
48
+ return buildRelativeUrl
49
+ }
50
+
51
+ const precomputeBuildRelativeUrl = (ressource, bufferAfterBuild = "") => {
52
+ if (ressource.buildRelativeUrl) {
53
+ return ressource.buildRelativeUrl
54
+ }
55
+ if (ressource.precomputedBuildRelativeUrl) {
56
+ return ressource.precomputedBuildRelativeUrl
57
+ }
58
+
59
+ ressource.bufferAfterBuild = bufferAfterBuild
60
+ const precomputedBuildRelativeUrl = computeBuildRelativeUrl(ressource, true)
61
+ ressource.bufferAfterBuild = undefined
62
+ ressource.precomputedBuildRelativeUrl = precomputedBuildRelativeUrl
63
+ return precomputedBuildRelativeUrl
64
+ }
65
+
66
+ return {
67
+ computeBuildRelativeUrl,
68
+ precomputeBuildRelativeUrl,
69
+ }
70
+ }
71
+
72
+ const getFilenamePattern = ({
73
+ ressource,
74
+ entryPointUrls,
75
+ asOriginalUrl,
76
+ precomputeBuildRelativeUrl,
77
+ }) => {
78
+ if (ressource.isEntryPoint) {
79
+ const originalUrl = asOriginalUrl(ressource.url)
80
+ const entryPointBuildRelativeUrl = entryPointUrls[originalUrl]
81
+ return entryPointBuildRelativeUrl
82
+ }
83
+
84
+ // inline ressource inherits location
85
+ if (ressource.isInline) {
86
+ // inherit parent directory location because it's an inline file
87
+ const importerBuildRelativeUrl = precomputeBuildRelativeUrl(
88
+ ressource.importer,
89
+ )
90
+ const name = urlToBasename(`file://${importerBuildRelativeUrl}`)
91
+ return `${name}_[hash][extname]`
92
+ }
93
+
94
+ // importmap.
95
+ // we want to force the fileName for the importmap
96
+ // so that we don't have to rewrite its content
97
+ // the goal is to put the importmap at the same relative path
98
+ // than in the project
99
+ if (ressource.contentType === "application/importmap+json") {
100
+ const importmapRessourceUrl = ressource.url
101
+ const name = urlToBasename(importmapRessourceUrl)
102
+ return `${name}_[hash][extname]`
103
+ }
104
+
105
+ // service worker:
106
+ // - MUST be at the root (same level than the HTML file)
107
+ // otherwise it might be registered for the scope "/assets/" instead of "/"
108
+ // - MUST not be versioned
109
+ if (ressource.isServiceWorker) {
110
+ return "[name][extname]"
111
+ }
112
+
113
+ if (ressource.isWorker) {
114
+ return "[name]_[hash][extname]"
115
+ }
116
+
117
+ if (ressource.isJsModule) {
118
+ return "[name]_[hash][extname]"
119
+ }
120
+
121
+ return ressource.urlVersioningDisabled
122
+ ? "assets/[name][extname]"
123
+ : "assets/[name]_[hash][extname]"
124
+ }
125
+
126
+ const generateBuildRelativeUrl = (
127
+ fileUrl,
128
+ fileContent,
129
+ {
130
+ getName,
131
+ pattern,
132
+ contentType = "application/octet-stream",
133
+ lineBreakNormalization = false,
134
+ } = {},
135
+ ) => {
136
+ pattern = typeof pattern === "function" ? pattern() : pattern
137
+ if (pattern.startsWith("./")) pattern = pattern.slice(2)
138
+ const buildRelativeUrl = renderFileNamePattern(pattern, {
139
+ dirname: () => urlToParentUrl(fileUrl),
140
+ name: getName,
141
+ hash: () =>
142
+ generateContentHash(fileContent, {
143
+ contentType,
144
+ lineBreakNormalization,
145
+ }),
146
+ extname: () => urlToExtension(fileUrl),
147
+ })
148
+ return buildRelativeUrl
149
+ }
150
+
151
+ const renderFileNamePattern = (pattern, replacements) => {
152
+ return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
153
+ const replacement = replacements[type]()
154
+ return replacement
155
+ })
156
+ }
157
+
158
+ // https://github.com/rollup/rollup/blob/19e50af3099c2f627451a45a84e2fa90d20246d5/src/utils/FileEmitter.ts#L47
159
+ export const generateContentHash = (
160
+ stringOrBuffer,
161
+ {
162
+ contentType = "application/octet-stream",
163
+ lineBreakNormalization = false,
164
+ } = {},
165
+ ) => {
166
+ const hash = createHash("sha256")
167
+ hash.update(
168
+ lineBreakNormalization && contentTypeIsTextual(contentType)
169
+ ? normalizeLineBreaks(stringOrBuffer)
170
+ : stringOrBuffer,
171
+ )
172
+ return hash.digest("hex").slice(0, 8)
173
+ }
174
+
175
+ const contentTypeIsTextual = (contentType) => {
176
+ if (contentType.startsWith("text/")) {
177
+ return true
178
+ }
179
+ // catch things like application/manifest+json, application/importmap+json
180
+ if (/^application\/\w+\+json$/.test(contentType)) {
181
+ return true
182
+ }
183
+ if (CONTENT_TYPE_AS_TEXT.includes(contentType)) {
184
+ return true
185
+ }
186
+ return false
187
+ }
188
+
189
+ const CONTENT_TYPE_AS_TEXT = [
190
+ "application/javascript",
191
+ "application/json",
192
+ "image/svg+xml",
193
+ ]
194
+
195
+ const normalizeLineBreaks = (stringOrBuffer) => {
196
+ if (typeof stringOrBuffer === "string") {
197
+ const stringWithLinuxBreaks = stringOrBuffer.replace(/\r\n/g, "\n")
198
+ return stringWithLinuxBreaks
199
+ }
200
+ return normalizeLineBreaksForBuffer(stringOrBuffer)
201
+ }
202
+
203
+ // https://github.com/nodejs/help/issues/1738#issuecomment-458460503
204
+ const normalizeLineBreaksForBuffer = (buffer) => {
205
+ const int32Array = new Int32Array(buffer, 0, buffer.length)
206
+ const int32ArrayWithLineBreaksNormalized = int32Array.filter(
207
+ (element, index, typedArray) => {
208
+ if (element === 0x0d) {
209
+ if (typedArray[index + 1] === 0x0a) {
210
+ // Windows -> Unix
211
+ return false
212
+ }
213
+ // Mac OS -> Unix
214
+ typedArray[index] = 0x0a
215
+ }
216
+ return true
217
+ },
218
+ )
219
+ return Buffer.from(int32ArrayWithLineBreaksNormalized)
220
+ }
@@ -9,8 +9,8 @@ which one is being done first
9
9
  */
10
10
 
11
11
  import { createHash } from "crypto"
12
+
12
13
  import { require } from "../require.js"
13
- import { renderNamePattern } from "../renderNamePattern.js"
14
14
 
15
15
  // https://github.com/inikulin/parse5/blob/master/packages/parse5/lib/tree-adapters/default.js
16
16
  // eslint-disable-next-line import/no-unresolved
@@ -519,6 +519,13 @@ export const getUniqueNameForInlineHtmlNode = (node, nodes, pattern) => {
519
519
  })
520
520
  }
521
521
 
522
+ const renderNamePattern = (pattern, replacements) => {
523
+ return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
524
+ const replacement = replacements[type]()
525
+ return replacement
526
+ })
527
+ }
528
+
522
529
  const parseHtmlAsSingleElement = (html) => {
523
530
  const parse5 = require("parse5")
524
531
  const fragment = parse5.parseFragment(html)
@@ -6,10 +6,10 @@ import {
6
6
  urlToMeta,
7
7
  } from "@jsenv/filesystem"
8
8
 
9
- import { featuresCompatMap } from "@jsenv/core/src/internal/generateGroupMap/featuresCompatMap.js"
10
9
  import { createRuntimeCompat } from "@jsenv/core/src/internal/generateGroupMap/runtime_compat.js"
11
-
10
+ import { shakeBabelPluginMap } from "@jsenv/core/src/internal/generateGroupMap/shake_babel_plugin_map.js"
12
11
  import { serverUrlToCompileInfo } from "@jsenv/core/src/internal/url_conversion.js"
12
+
13
13
  import { setUrlExtension } from "../url_utils.js"
14
14
  import {
15
15
  COMPILE_ID_BUILD_GLOBAL,
@@ -45,8 +45,12 @@ export const createCompiledFileService = ({
45
45
  moduleOutFormat,
46
46
  importMetaFormat,
47
47
  topLevelAwait,
48
+ prependSystemJs,
48
49
  groupMap,
49
50
  customCompilers,
51
+ workerUrls,
52
+ serviceWorkerUrls,
53
+ importMapInWebWorkers,
50
54
 
51
55
  jsenvEventSourceClientInjection,
52
56
  jsenvToolbarInjection,
@@ -60,6 +64,8 @@ export const createCompiledFileService = ({
60
64
  Object.keys(groupMap).forEach((groupName) => {
61
65
  compileIdModuleFormats[groupName] = canAvoidSystemJs({
62
66
  runtimeSupport: groupMap[groupName].minRuntimeVersions,
67
+ workerUrls,
68
+ importMapInWebWorkers,
63
69
  })
64
70
  ? "esmodule"
65
71
  : "systemjs"
@@ -183,18 +189,20 @@ export const createCompiledFileService = ({
183
189
  outDirectoryRelativeUrl,
184
190
  compileId,
185
191
  request,
186
-
187
- runtimeSupport,
188
- babelPluginMap: babelPluginMapFromCompileId(compileId, {
192
+ babelPluginMap: shakeBabelPluginMap({
189
193
  babelPluginMap,
190
- groupMap,
194
+ missingFeatureNames: groupMap[compileId].missingFeatureNames,
191
195
  }),
196
+ runtimeSupport,
197
+ workerUrls,
198
+ serviceWorkerUrls,
192
199
  moduleOutFormat:
193
200
  moduleOutFormat === undefined
194
201
  ? compileIdModuleFormats[compileId]
195
202
  : moduleOutFormat,
196
203
  importMetaFormat,
197
204
  topLevelAwait,
205
+ prependSystemJs,
198
206
 
199
207
  sourcemapMethod,
200
208
  sourcemapExcludeSources,
@@ -210,18 +218,23 @@ export const createCompiledFileService = ({
210
218
  }
211
219
  }
212
220
 
213
- const canAvoidSystemJs = ({ runtimeSupport }) => {
221
+ const canAvoidSystemJs = ({
222
+ runtimeSupport,
223
+ workerUrls,
224
+ importMapInWebWorkers,
225
+ }) => {
214
226
  const runtimeCompatMap = createRuntimeCompat({
227
+ featureNames: [
228
+ "module",
229
+ "importmap",
230
+ "import_assertion_type_json",
231
+ "import_assertion_type_css",
232
+ ...(workerUrls.length > 0 ? ["worker_type_module"] : []),
233
+ ...(importMapInWebWorkers ? ["worker_importmap"] : []),
234
+ ],
215
235
  runtimeSupport,
216
- pluginMap: {
217
- module: true,
218
- importmap: true,
219
- import_assertion_type_json: true,
220
- import_assertion_type_css: true,
221
- },
222
- pluginCompatMap: featuresCompatMap,
223
236
  })
224
- return runtimeCompatMap.pluginRequiredNameArray.length === 0
237
+ return runtimeCompatMap.missingFeatureNames.length === 0
225
238
  }
226
239
 
227
240
  const getCompiler = ({ originalFileUrl, compileMeta }) => {
@@ -295,31 +308,6 @@ const contentTypeExtensions = {
295
308
  // "text/css": ".css",
296
309
  }
297
310
 
298
- const babelPluginMapFromCompileId = (
299
- compileId,
300
- { babelPluginMap, groupMap },
301
- ) => {
302
- const babelPluginMapForGroup = {}
303
-
304
- groupMap[compileId].pluginRequiredNameArray.forEach((requiredPluginName) => {
305
- const babelPlugin = babelPluginMap[requiredPluginName]
306
- if (babelPlugin) {
307
- babelPluginMapForGroup[requiredPluginName] = babelPlugin
308
- }
309
- })
310
-
311
- Object.keys(babelPluginMap).forEach((key) => {
312
- if (key.startsWith("syntax-")) {
313
- babelPluginMapForGroup[key] = babelPluginMap[key]
314
- }
315
- if (key === "transform-replace-expressions") {
316
- babelPluginMapForGroup[key] = babelPluginMap[key]
317
- }
318
- })
319
-
320
- return babelPluginMapForGroup
321
- }
322
-
323
311
  const ressourceToPathname = (ressource) => {
324
312
  const searchSeparatorIndex = ressource.indexOf("?")
325
313
  const pathname =
@@ -18,7 +18,7 @@ import {
18
18
  urlToFilename,
19
19
  urlIsInsideOf,
20
20
  } from "@jsenv/filesystem"
21
- import { moveImportMap } from "@jsenv/importmap"
21
+ import { composeTwoImportMaps, moveImportMap } from "@jsenv/importmap"
22
22
  import { createDetailedMessage } from "@jsenv/logger"
23
23
 
24
24
  import {
@@ -28,6 +28,8 @@ import {
28
28
  } from "@jsenv/core/dist/build_manifest.js"
29
29
  import { fetchUrl } from "@jsenv/core/src/internal/fetchUrl.js"
30
30
  import { stringifyDataUrl } from "@jsenv/core/src/internal/dataUrl.utils.js"
31
+ import { getDefaultImportmap } from "@jsenv/core/src/internal/import-resolution/importmap_default.js"
32
+
31
33
  import {
32
34
  parseHtmlString,
33
35
  parseHtmlAstRessources,
@@ -155,14 +157,13 @@ const transformHTMLSourceFile = async ({
155
157
  fileUrl = urlWithoutSearch(fileUrl)
156
158
 
157
159
  const htmlAst = parseHtmlString(fileContent)
158
- if (inlineImportMapIntoHTML) {
159
- await inlineImportmapScripts({
160
- logger,
161
- htmlAst,
162
- htmlFileUrl: fileUrl,
163
- projectDirectoryUrl,
164
- })
165
- }
160
+ await visitImportmapScripts({
161
+ logger,
162
+ htmlAst,
163
+ inlineImportMapIntoHTML,
164
+ htmlFileUrl: fileUrl,
165
+ projectDirectoryUrl,
166
+ })
166
167
 
167
168
  const browserRuntimeBuildUrlRelativeToProject = urlToRelativeUrl(
168
169
  BROWSER_RUNTIME_BUILD_URL,
@@ -277,59 +278,73 @@ const transformHTMLSourceFile = async ({
277
278
  return stringifyHtmlAst(htmlAst)
278
279
  }
279
280
 
280
- const inlineImportmapScripts = async ({ logger, htmlAst, htmlFileUrl }) => {
281
+ const visitImportmapScripts = async ({
282
+ logger,
283
+ inlineImportMapIntoHTML,
284
+ htmlAst,
285
+ htmlFileUrl,
286
+ projectDirectoryUrl,
287
+ }) => {
281
288
  const { scripts } = parseHtmlAstRessources(htmlAst)
282
- const remoteImportmapScripts = scripts.filter((script) => {
289
+ const importmapScripts = scripts.filter((script) => {
283
290
  const typeAttribute = getHtmlNodeAttributeByName(script, "type")
284
- const srcAttribute = getHtmlNodeAttributeByName(script, "src")
285
- if (typeAttribute && typeAttribute.value === "importmap" && srcAttribute) {
291
+ if (typeAttribute && typeAttribute.value === "importmap") {
286
292
  return true
287
293
  }
288
294
  return false
289
295
  })
290
296
 
291
297
  await Promise.all(
292
- remoteImportmapScripts.map(async (remoteImportmapScript) => {
293
- const srcAttribute = getHtmlNodeAttributeByName(
294
- remoteImportmapScript,
295
- "src",
296
- )
297
- const importMapUrl = resolveUrl(srcAttribute.value, htmlFileUrl)
298
- const importMapResponse = await fetchUrl(importMapUrl)
299
- if (importMapResponse.status !== 200) {
300
- logger.warn(
301
- createDetailedMessage(
302
- importMapResponse.status === 404
303
- ? `Cannot inline importmap script because file cannot be found.`
304
- : `Cannot inline importmap script due to unexpected response status (${importMapResponse.status}).`,
305
- {
306
- "importmap script src": srcAttribute.value,
307
- "importmap url": importMapUrl,
308
- "html url": htmlFileUrl,
309
- },
310
- ),
298
+ importmapScripts.map(async (importmapScript) => {
299
+ const srcAttribute = getHtmlNodeAttributeByName(importmapScript, "src")
300
+ if (srcAttribute && inlineImportMapIntoHTML) {
301
+ const importMapUrl = resolveUrl(srcAttribute.value, htmlFileUrl)
302
+ const importMapResponse = await fetchUrl(importMapUrl)
303
+ if (importMapResponse.status !== 200) {
304
+ logger.warn(
305
+ createDetailedMessage(
306
+ importMapResponse.status === 404
307
+ ? `Cannot inline importmap script because file cannot be found.`
308
+ : `Cannot inline importmap script due to unexpected response status (${importMapResponse.status}).`,
309
+ {
310
+ "importmap script src": srcAttribute.value,
311
+ "importmap url": importMapUrl,
312
+ "html url": htmlFileUrl,
313
+ },
314
+ ),
315
+ )
316
+ return
317
+ }
318
+
319
+ const importMapContent = await importMapResponse.json()
320
+ const importMapInlined = moveImportMap(
321
+ importMapContent,
322
+ importMapUrl,
323
+ htmlFileUrl,
311
324
  )
312
- return
313
- }
314
325
 
315
- const importMapContent = await importMapResponse.json()
316
- const importMapInlined = moveImportMap(
317
- importMapContent,
318
- importMapUrl,
319
- htmlFileUrl,
320
- )
326
+ replaceHtmlNode(
327
+ importmapScript,
328
+ `<script type="importmap">${JSON.stringify(
329
+ importMapInlined,
330
+ null,
331
+ " ",
332
+ )}</script>`,
333
+ {
334
+ attributesToIgnore: ["src"],
335
+ },
336
+ )
337
+ }
321
338
 
322
- replaceHtmlNode(
323
- remoteImportmapScript,
324
- `<script type="importmap">${JSON.stringify(
325
- importMapInlined,
326
- null,
327
- " ",
328
- )}</script>`,
329
- {
330
- attributesToIgnore: ["src"],
331
- },
332
- )
339
+ const textNode = getHtmlNodeTextNode(importmapScript)
340
+ if (!srcAttribute && textNode) {
341
+ const jsenvImportmap = getDefaultImportmap(htmlFileUrl, {
342
+ projectDirectoryUrl,
343
+ })
344
+ const htmlImportmap = JSON.parse(textNode.value)
345
+ const importmap = composeTwoImportMaps(jsenvImportmap, htmlImportmap)
346
+ textNode.value = JSON.stringify(importmap, null, " ")
347
+ }
333
348
  }),
334
349
  )
335
350
  }