@jsenv/core 27.0.0-alpha.10 → 27.0.0-alpha.13

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 (116) hide show
  1. package/main.js +4 -0
  2. package/package.json +13 -7
  3. package/readme.md +4 -12
  4. package/src/build/build.js +438 -387
  5. package/src/build/build_urls_generator.js +23 -20
  6. package/src/build/graph_utils.js +31 -0
  7. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +31 -14
  8. package/src/build/inject_service_worker_urls.js +66 -12
  9. package/src/build/resync_ressource_hints.js +83 -0
  10. package/src/dev/plugins/autoreload/babel_plugin_metadata_import_meta_hot.js +1 -1
  11. package/src/dev/plugins/autoreload/client/import_meta_hot.js +3 -1
  12. package/src/dev/plugins/autoreload/html_hot_dependencies.js +2 -2
  13. package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +61 -51
  14. package/src/dev/plugins/autoreload/sse_service.js +23 -3
  15. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
  16. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  17. package/src/dev/start_dev_server.js +10 -5
  18. package/src/execute/execute.js +10 -4
  19. package/src/execute/run.js +17 -54
  20. package/src/execute/runtimes/browsers/from_playwright.js +167 -146
  21. package/src/execute/runtimes/node/node_process.js +281 -37
  22. package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
  23. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +30 -7
  24. package/src/omega/{runtime_support/runtime_support.js → compat/runtime_compat.js} +14 -16
  25. package/src/omega/errors.js +51 -58
  26. package/src/omega/fetched_content_compliance.js +24 -0
  27. package/src/omega/kitchen.js +396 -280
  28. package/src/omega/server/file_service.js +9 -11
  29. package/src/omega/url_graph/url_graph_load.js +13 -7
  30. package/src/omega/url_graph/url_graph_report.js +7 -5
  31. package/src/omega/url_graph.js +22 -10
  32. package/src/omega/web_workers.js +42 -0
  33. package/src/plugins/bundling/css/bundle_css.js +17 -0
  34. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  35. package/src/{build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js → plugins/bundling/js_module/bundle_js_module.js} +100 -75
  36. package/src/plugins/bundling/jsenv_plugin_bundling.js +51 -0
  37. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +48 -41
  38. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
  39. package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +7 -4
  40. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  41. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  42. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_installer.js +3 -2
  43. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_setup.js +0 -0
  44. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  45. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  46. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +38 -46
  47. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  48. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +26 -8
  49. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  50. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  51. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +37 -31
  52. package/src/{omega/core_plugins → plugins}/inject_globals/jsenv_plugin_inject_globals.js +5 -7
  53. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  54. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
  55. package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +61 -40
  56. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  57. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
  58. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +263 -0
  59. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  60. package/src/plugins/minification/css/minify_css.js +9 -0
  61. package/src/plugins/minification/html/minify_html.js +15 -0
  62. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  63. package/src/plugins/minification/jsenv_plugin_minification.js +77 -0
  64. package/src/plugins/minification/json/minify_json.js +8 -0
  65. package/src/{omega/core_plugins → plugins}/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +15 -15
  66. package/src/{omega → plugins}/plugin_controller.js +18 -10
  67. package/src/plugins/plugins.js +50 -0
  68. package/src/plugins/transpilation/as_js_classic/client/s.js +808 -0
  69. package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
  70. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  71. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  72. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +178 -0
  73. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +156 -0
  74. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_top_level_await.js +37 -0
  75. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +133 -0
  76. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  77. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  78. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  79. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +3 -21
  80. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  81. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +29 -27
  82. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +0 -0
  83. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
  84. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  85. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  86. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  87. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  88. package/src/{omega/core_plugins → plugins/transpilation}/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -0
  89. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +243 -0
  90. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +40 -0
  91. package/src/plugins/url_references/css/css_urls.js +49 -0
  92. package/src/plugins/url_references/html/html_urls.js +273 -0
  93. package/src/plugins/url_references/js/js_urls.js +170 -0
  94. package/src/plugins/url_references/jsenv_plugin_url_references.js +18 -0
  95. package/src/plugins/url_references/webmanifest/webmanifest_urls.js +17 -0
  96. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
  97. package/src/{omega/core_plugins → plugins}/url_version/jsenv_plugin_url_version.js +8 -8
  98. package/src/preview/preview.js +3 -0
  99. package/src/test/execute_plan.js +18 -11
  100. package/src/test/execute_test_plan.js +5 -6
  101. package/src/test/logs_file_execution.js +8 -7
  102. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  103. package/src/execute/runtimes/node/controlled_process.js +0 -316
  104. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  105. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  106. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  107. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  108. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  109. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -207
  110. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  111. package/src/omega/core_plugins.js +0 -42
  112. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  113. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  114. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  115. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  116. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -21,6 +21,7 @@ import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
21
21
  import {
22
22
  injectQueryParams,
23
23
  setUrlFilename,
24
+ asUrlUntilPathname,
24
25
  } from "@jsenv/utils/urls/url_utils.js"
25
26
  import { createVersionGenerator } from "@jsenv/utils/versioning/version_generator.js"
26
27
  import { generateSourcemapUrl } from "@jsenv/utils/sourcemap/sourcemap_utils.js"
@@ -29,21 +30,21 @@ import {
29
30
  stringifyHtmlAst,
30
31
  } from "@jsenv/utils/html_ast/html_ast.js"
31
32
 
32
- import { defaultRuntimeSupport } from "../omega/runtime_support/default_runtime_support.js"
33
- import { jsenvPluginInline } from "../omega/core_plugins/inline/jsenv_plugin_inline.js"
33
+ import { jsenvPluginInline } from "../plugins/inline/jsenv_plugin_inline.js"
34
+ import { jsenvPluginAsJsClassic } from "../plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js"
34
35
  import { createUrlGraph } from "../omega/url_graph.js"
35
- import { getCorePlugins } from "../omega/core_plugins.js"
36
+ import { getCorePlugins } from "../plugins/plugins.js"
36
37
  import { createKitchen } from "../omega/kitchen.js"
37
38
  import { loadUrlGraph } from "../omega/url_graph/url_graph_load.js"
38
39
  import { createUrlGraphSummary } from "../omega/url_graph/url_graph_report.js"
39
40
  import { sortUrlGraphByDependencies } from "../omega/url_graph/url_graph_sort.js"
41
+ import { isWebWorkerEntryPointReference } from "../omega/web_workers.js"
40
42
 
41
- import { jsenvPluginBundleJsModule } from "./plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js"
42
- import { jsenvPluginMinifyJs } from "./plugins/minify_js/jsenv_plugin_minify_js.js"
43
- import { jsenvPluginMinifyHtml } from "./plugins/minify_html/jsenv_plugin_minify_html.js"
43
+ import { GRAPH } from "./graph_utils.js"
44
44
  import { createBuilUrlsGenerator } from "./build_urls_generator.js"
45
- import { injectVersionMappings } from "./inject_version_mappings.js"
45
+ import { injectGlobalVersionMapping } from "./inject_global_version_mappings.js"
46
46
  import { injectServiceWorkerUrls } from "./inject_service_worker_urls.js"
47
+ import { resyncRessourceHints } from "./resync_ressource_hints.js"
47
48
 
48
49
  export const build = async ({
49
50
  signal = new AbortController().signal,
@@ -55,18 +56,19 @@ export const build = async ({
55
56
  // that will just pass different options to build project
56
57
  // and this function will be agnostic about "preview" concept
57
58
  isPreview = false,
59
+
58
60
  plugins = [],
59
- htmlSupervisor,
61
+ sourcemaps = isPreview ? "file" : false,
60
62
  nodeEsmResolution,
61
63
  fileSystemMagicResolution,
62
- babel,
63
64
  injectedGlobals,
64
- runtimeSupport = defaultRuntimeSupport,
65
- sourcemaps = isPreview ? "file" : false,
66
-
65
+ runtimeCompat,
66
+ transpilation = {},
67
67
  bundling = true,
68
- minify = true,
69
- versioning = "filename", // "filename", "search_param", "none"
68
+ minification = true,
69
+
70
+ versioning = true,
71
+ versioningMethod = "search_param", // "filename", "search_param"
70
72
  lineBreakNormalization = process.platform === "win32",
71
73
 
72
74
  writeOnFileSystem = true,
@@ -79,9 +81,9 @@ export const build = async ({
79
81
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
80
82
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
81
83
  assertEntryPoints({ entryPoints })
82
- if (!["filename", "search_param", "none"].includes(versioning)) {
84
+ if (!["filename", "search_param"].includes(versioningMethod)) {
83
85
  throw new Error(
84
- `Unexpected "versioning": must be "filename", "search_param" or "none"; got ${versioning}`,
86
+ `Unexpected "versioningMethod": must be "filename", "search_param"; got ${versioning}`,
85
87
  )
86
88
  }
87
89
 
@@ -101,6 +103,9 @@ build ${entryPointKeys.length} entry points`)
101
103
  logger,
102
104
  rootDirectoryUrl,
103
105
  urlGraph: rawGraph,
106
+ scenario: "build",
107
+ sourcemaps,
108
+ runtimeCompat,
104
109
  plugins: [
105
110
  ...plugins,
106
111
  {
@@ -112,17 +117,17 @@ build ${entryPointKeys.length} entry points`)
112
117
  },
113
118
  },
114
119
  ...getCorePlugins({
115
- htmlSupervisor,
116
120
  nodeEsmResolution,
117
121
  fileSystemMagicResolution,
118
- babel,
119
122
  injectedGlobals,
123
+ transpilation: {
124
+ ...transpilation,
125
+ jsModuleAsJsClassic: false,
126
+ },
127
+ minification,
128
+ bundling,
120
129
  }),
121
- jsenvPluginBundleJsModule(),
122
- ...(minify ? [jsenvPluginMinifyJs(), jsenvPluginMinifyHtml()] : []),
123
130
  ],
124
- scenario: "build",
125
- sourcemaps,
126
131
  })
127
132
  const entryUrls = []
128
133
  try {
@@ -130,7 +135,6 @@ build ${entryPointKeys.length} entry points`)
130
135
  urlGraph: rawGraph,
131
136
  kitchen: rawGraphKitchen,
132
137
  outDirectoryUrl: new URL(`.jsenv/build/`, rootDirectoryUrl),
133
- runtimeSupport,
134
138
  startLoading: (cookEntryFile) => {
135
139
  Object.keys(entryPoints).forEach((key) => {
136
140
  const [, entryUrlInfo] = cookEntryFile({
@@ -153,209 +157,207 @@ build ${entryPointKeys.length} entry points`)
153
157
  ${Object.keys(rawGraph.urlInfos).join("\n")}`,
154
158
  )
155
159
 
160
+ const buildUrlsGenerator = createBuilUrlsGenerator({
161
+ buildDirectoryUrl,
162
+ })
163
+ const rawUrls = {}
164
+ const buildUrls = {}
165
+ const rawUrlRedirections = {}
156
166
  const bundleUrlInfos = {}
157
- if (bundling) {
158
- const bundlers = {}
159
- rawGraphKitchen.pluginController.plugins.forEach((plugin) => {
160
- const bundle = plugin.bundle
161
- if (!bundle) {
167
+ const bundlers = {}
168
+ rawGraphKitchen.pluginController.plugins.forEach((plugin) => {
169
+ const bundle = plugin.bundle
170
+ if (!bundle) {
171
+ return
172
+ }
173
+ if (typeof bundle !== "object") {
174
+ throw new Error(
175
+ `bundle must be an object, found "${bundle}" on plugin named "${plugin.name}"`,
176
+ )
177
+ }
178
+ Object.keys(bundle).forEach((type) => {
179
+ const bundleFunction = bundle[type]
180
+ if (!bundleFunction) {
162
181
  return
163
182
  }
164
- if (typeof bundle !== "object") {
165
- throw new Error(
166
- `bundle must be an object, found "${bundle}" on plugin named "${plugin.name}"`,
167
- )
168
- }
169
- Object.keys(bundle).forEach((type) => {
170
- const bundlerForThatType = bundlers[type]
171
- if (bundlerForThatType) {
172
- // first plugin to define a bundle hook wins
173
- return
174
- }
175
- bundlers[type] = {
176
- plugin,
177
- bundleFunction: bundle[type],
178
- urlInfos: [],
179
- }
180
- })
181
- })
182
- const addToBundlerIfAny = (rawUrlInfo) => {
183
- const bundler = bundlers[rawUrlInfo.type]
184
- if (bundler) {
185
- bundler.urlInfos.push(rawUrlInfo)
183
+ const bundlerForThatType = bundlers[type]
184
+ if (bundlerForThatType) {
185
+ // first plugin to define a bundle hook wins
186
186
  return
187
187
  }
188
+ bundlers[type] = {
189
+ plugin,
190
+ bundleFunction: bundle[type],
191
+ urlInfos: [],
192
+ }
193
+ })
194
+ })
195
+ const addToBundlerIfAny = (rawUrlInfo) => {
196
+ const bundler = bundlers[rawUrlInfo.type]
197
+ if (bundler) {
198
+ bundler.urlInfos.push(rawUrlInfo)
199
+ return
188
200
  }
189
- GRAPH.forEach(rawGraph, (rawUrlInfo) => {
190
- if (rawUrlInfo.data.isEntryPoint) {
191
- addToBundlerIfAny(rawUrlInfo)
192
- if (rawUrlInfo.type === "html") {
193
- rawUrlInfo.dependencies.forEach((dependencyUrl) => {
194
- const dependencyUrlInfo = rawGraph.getUrlInfo(dependencyUrl)
195
- if (dependencyUrlInfo.isInline) {
196
- if (dependencyUrlInfo.type === "js_module") {
197
- // bundle inline script type module deps
198
- dependencyUrlInfo.references.forEach((inlineScriptRef) => {
199
- if (inlineScriptRef.type === "js_import_export") {
200
- addToBundlerIfAny(rawGraph.getUrlInfo(inlineScriptRef.url))
201
- }
202
- })
203
- }
204
- // inline content cannot be bundled
205
- return
201
+ }
202
+ GRAPH.forEach(rawGraph, (rawUrlInfo) => {
203
+ if (rawUrlInfo.data.isEntryPoint) {
204
+ addToBundlerIfAny(rawUrlInfo)
205
+ if (rawUrlInfo.type === "html") {
206
+ rawUrlInfo.dependencies.forEach((dependencyUrl) => {
207
+ const dependencyUrlInfo = rawGraph.getUrlInfo(dependencyUrl)
208
+ if (dependencyUrlInfo.isInline) {
209
+ if (dependencyUrlInfo.type === "js_module") {
210
+ // bundle inline script type module deps
211
+ dependencyUrlInfo.references.forEach((inlineScriptRef) => {
212
+ if (inlineScriptRef.type === "js_import_export") {
213
+ const inlineUrlInfo = rawGraph.getUrlInfo(inlineScriptRef.url)
214
+ addToBundlerIfAny(inlineUrlInfo)
215
+ }
216
+ })
206
217
  }
207
- addToBundlerIfAny(dependencyUrlInfo)
208
- })
209
- return
210
- }
211
- }
212
- // File referenced with new URL('./file.js', import.meta.url)
213
- // are entry points that can be bundled
214
- // For instance we will bundle service worker/workers detected like this
215
- if (rawUrlInfo.type === "js_module") {
216
- rawUrlInfo.references.forEach((reference) => {
217
- if (reference.type === "js_import_meta_url_pattern") {
218
- const urlInfo = rawGraph.getUrlInfo(reference.url)
219
- addToBundlerIfAny(urlInfo)
218
+ // inline content cannot be bundled
219
+ return
220
220
  }
221
+ addToBundlerIfAny(dependencyUrlInfo)
221
222
  })
222
- }
223
- })
224
- await Object.keys(bundlers).reduce(async (previous, type) => {
225
- await previous
226
- const bundler = bundlers[type]
227
- const urlInfosToBundle = bundler.urlInfos
228
- if (urlInfosToBundle.length === 0) {
229
223
  return
230
224
  }
231
- const bundleTask = createTaskLog(logger, `bundle "${type}"`)
232
- try {
233
- const bundlerGeneratedUrlInfos =
234
- await rawGraphKitchen.pluginController.callAsyncHook(
235
- {
236
- plugin: bundler.plugin,
237
- hookName: "bundle",
238
- value: bundler.bundleFunction,
239
- },
240
- urlInfosToBundle,
241
- {
242
- signal,
243
- logger,
244
- rootDirectoryUrl,
245
- buildDirectoryUrl,
246
- urlGraph: rawGraph,
247
- runtimeSupport,
248
- sourcemaps,
249
- },
250
- )
251
- Object.keys(bundlerGeneratedUrlInfos).forEach((url) => {
252
- const bundleUrlInfo = bundlerGeneratedUrlInfos[url]
253
- const rawUrlInfo = rawGraph.getUrlInfo(url)
254
- bundleUrlInfos[url] = {
255
- type,
256
- subtype: rawUrlInfo ? rawUrlInfo.subtype : undefined,
257
- ...bundleUrlInfo,
258
- data: {
259
- ...(rawUrlInfo ? rawUrlInfo.data : {}),
260
- ...bundleUrlInfo.data,
261
- fromBundle: true,
262
- },
263
- }
225
+ }
226
+ // File referenced with new URL('./file.js', import.meta.url)
227
+ // are entry points that can be bundled
228
+ // For instance we will bundle service worker/workers detected like this
229
+ if (rawUrlInfo.type === "js_module") {
230
+ rawUrlInfo.references.forEach((reference) => {
231
+ if (reference.type === "js_url_specifier") {
232
+ const urlInfo = rawGraph.getUrlInfo(reference.url)
233
+ addToBundlerIfAny(urlInfo)
234
+ }
235
+ })
236
+ }
237
+ })
238
+ await Object.keys(bundlers).reduce(async (previous, type) => {
239
+ await previous
240
+ const bundler = bundlers[type]
241
+ const urlInfosToBundle = bundler.urlInfos
242
+ if (urlInfosToBundle.length === 0) {
243
+ return
244
+ }
245
+ const bundleTask = createTaskLog(logger, `bundle "${type}"`)
246
+ try {
247
+ const bundlerGeneratedUrlInfos =
248
+ await rawGraphKitchen.pluginController.callAsyncHook(
249
+ {
250
+ plugin: bundler.plugin,
251
+ hookName: "bundle",
252
+ value: bundler.bundleFunction,
253
+ },
254
+ urlInfosToBundle,
255
+ {
256
+ ...rawGraphKitchen.baseContext,
257
+ buildDirectoryUrl,
258
+ },
259
+ )
260
+ Object.keys(bundlerGeneratedUrlInfos).forEach((url) => {
261
+ const rawUrlInfo = rawGraph.getUrlInfo(url)
262
+ const bundlerGeneratedUrlInfo = bundlerGeneratedUrlInfos[url]
263
+ const bundleUrlInfo = {
264
+ type,
265
+ subtype: rawUrlInfo ? rawUrlInfo.subtype : undefined,
266
+ filename: rawUrlInfo ? rawUrlInfo.filename : undefined,
267
+ ...bundlerGeneratedUrlInfo,
268
+ data: {
269
+ ...(rawUrlInfo ? rawUrlInfo.data : {}),
270
+ ...bundlerGeneratedUrlInfo.data,
271
+ fromBundle: true,
272
+ },
273
+ }
274
+ const buildUrl = buildUrlsGenerator.generate(url, {
275
+ urlInfo: bundleUrlInfo,
264
276
  })
265
- } catch (e) {
266
- bundleTask.fail()
267
- throw e
268
- }
269
- bundleTask.done()
270
- }, Promise.resolve())
271
- }
277
+ rawUrlRedirections[url] = buildUrl
278
+ rawUrls[buildUrl] = url
279
+ bundleUrlInfos[buildUrl] = bundleUrlInfo
280
+ })
281
+ } catch (e) {
282
+ bundleTask.fail()
283
+ throw e
284
+ }
285
+ bundleTask.done()
286
+ }, Promise.resolve())
272
287
 
273
- const buildUrlsGenerator = createBuilUrlsGenerator({
274
- buildDirectoryUrl,
275
- })
276
- const rawUrls = {}
277
- const buildUrls = {}
288
+ const buildUrlRedirections = {}
278
289
  const finalGraph = createUrlGraph()
279
- const optimizeHooks = rawGraphKitchen.pluginController.addHook("optimize")
290
+ const optimizeUrlContentHooks =
291
+ rawGraphKitchen.pluginController.addHook("optimizeUrlContent")
280
292
  const finalGraphKitchen = createKitchen({
281
293
  logger,
282
294
  rootDirectoryUrl,
283
295
  urlGraph: finalGraph,
284
- // Inline content, such as <script> inside html, is transformed during the previous phase.
285
- // If we read the inline content it would be considered as the original content.
286
- // - It could be "fixed" by taking into account sourcemap and consider sourcemap sources
287
- // as the original content.
288
- // - But it would not work when sourcemap are not generated
289
- // - would be a bit slower
290
- // - So instead of reading the inline content directly, we search into raw graph
291
- // to get "originalContent" and "sourcemap"
292
- loadInlineUrlInfos: (finalUrlInfo) => {
293
- const rawUrl = finalUrlInfo.data.rawUrl
294
- const bundleUrlInfo = bundleUrlInfos[rawUrl]
295
- const urlInfo = bundleUrlInfo || finalUrlInfo
296
- const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
297
- return {
298
- originalContent: rawUrlInfo ? rawUrlInfo.originalContent : undefined,
299
- sourcemap: bundleUrlInfo
300
- ? bundleUrlInfo.sourcemap
301
- : rawUrlInfo
302
- ? rawUrlInfo.sourcemap
303
- : undefined,
304
- contentType: urlInfo.contentType,
305
- content: urlInfo.content,
306
- }
307
- },
296
+ scenario: "build",
297
+ sourcemaps,
298
+ runtimeCompat,
308
299
  plugins: [
309
- jsenvPluginInline(),
300
+ jsenvPluginAsJsClassic({
301
+ systemJsInjection: true,
302
+ }),
303
+ jsenvPluginInline({
304
+ fetchInlineUrls: false,
305
+ }),
310
306
  {
311
307
  name: "jsenv:postbuild",
312
308
  appliesDuring: { build: true },
313
- resolve: (reference) => {
314
- if (reference.specifier[0] === "/") {
315
- const url = new URL(reference.specifier.slice(1), rootDirectoryUrl)
316
- .href
317
- return url
309
+ resolveUrl: (reference) => {
310
+ if (reference.specifier[0] === "#") {
311
+ reference.external = true
318
312
  }
319
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
320
- if (parentUrlInfo && parentUrlInfo.data.fromBundle) {
321
- // code generated by rollup contains specifier relative
322
- // to the generated file.
323
- // This file does not exists yet we must resolve against the raw url, not the build url
324
- const parentRawUrl = parentUrlInfo.data.rawUrl
325
- const rawUrl = new URL(reference.specifier, parentRawUrl).href
326
- return rawUrl
327
- }
328
- return new URL(reference.specifier, reference.parentUrl).href
313
+ const url =
314
+ reference.specifier[0] === "/"
315
+ ? new URL(reference.specifier.slice(1), buildDirectoryUrl).href
316
+ : new URL(reference.specifier, reference.parentUrl).href
317
+ const urlRedirected = rawUrlRedirections[url]
318
+ return urlRedirected || url
329
319
  },
330
- normalize: (reference) => {
320
+ normalizeUrl: (reference) => {
331
321
  if (!reference.url.startsWith("file:")) {
332
322
  return null
333
323
  }
334
324
  // already a build url
335
325
  const rawUrl = rawUrls[reference.url]
336
326
  if (rawUrl) {
337
- reference.data.rawUrl = rawUrl
338
327
  return reference.url
339
328
  }
340
- const bundleUrlInfo = bundleUrlInfos[reference.url]
341
329
  // from rollup or postcss
330
+ const bundleUrlInfo = bundleUrlInfos[reference.url]
342
331
  if (bundleUrlInfo) {
343
- const buildUrl = buildUrlsGenerator.generate(
344
- reference.url,
345
- bundleUrlInfo,
346
- )
347
- reference.data.rawUrl = reference.url
348
- rawUrls[buildUrl] = reference.url
349
- return buildUrl
332
+ return reference.url
350
333
  }
351
- const rawUrlInfo = rawGraph.getUrlInfo(reference.url)
352
- // files from root directory but not given to rollup nor postcss
353
- if (rawUrlInfo) {
354
- const buildUrl = buildUrlsGenerator.generate(
334
+ // from "js_module_as_js_classic":
335
+ // - injecting "?as_js_classic" for the first time
336
+ // - injecting "?as_js_classic" because the parentUrl has it
337
+ if (reference.original) {
338
+ // the url info do not exists yet (it will be created after this "normalize" hook)
339
+ // And the content will be generated when url is cooked by url graph loader.
340
+ // Here we just want to reserve an url for that file
341
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
342
+ urlInfo: {
343
+ data: {
344
+ ...reference.data,
345
+ isWebWorkerEntryPoint:
346
+ isWebWorkerEntryPointReference(reference),
347
+ },
348
+ type: reference.expectedType,
349
+ subtype: reference.expectedSubtype,
350
+ filename: reference.filename,
351
+ },
352
+ })
353
+ const originalUrl = reference.original.url
354
+ const originalBuildUrl = urlIsInsideOf(
355
355
  reference.url,
356
- rawUrlInfo,
356
+ buildDirectoryUrl,
357
357
  )
358
- reference.data.rawUrl = reference.url
358
+ ? originalUrl
359
+ : Object.keys(rawUrls).find((key) => rawUrls[key] === originalUrl)
360
+ buildUrlRedirections[originalBuildUrl] = buildUrl
359
361
  rawUrls[buildUrl] = reference.url
360
362
  return buildUrl
361
363
  }
@@ -367,84 +369,146 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
367
369
  if (rawUrlInfo.content === reference.content) {
368
370
  return true
369
371
  }
372
+ if (rawUrlInfo.originalContent === reference.content) {
373
+ return true
374
+ }
370
375
  return false
371
376
  })
377
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
372
378
  if (!rawUrlInfo) {
373
- throw new Error(`cannot find raw url`)
379
+ // generated during final graph
380
+ // (happens for JSON.parse injected for import assertions for instance)
381
+ // throw new Error(`cannot find raw url for "${reference.url}"`)
382
+ return reference.url
374
383
  }
375
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
376
- const buildUrl = buildUrlsGenerator.generate(
377
- reference.url,
378
- rawUrlInfo,
384
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
385
+ urlInfo: rawUrlInfo,
379
386
  parentUrlInfo,
380
- )
387
+ })
388
+ rawUrls[buildUrl] = rawUrlInfo.url
389
+ return buildUrl
390
+ }
391
+ // from "js_module_as_js_classic":
392
+ // - to inject "s.js"
393
+ if (reference.injected) {
394
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
395
+ urlInfo: {
396
+ data: {},
397
+ type: "js_classic",
398
+ },
399
+ })
381
400
  rawUrls[buildUrl] = reference.url
382
- reference.data.rawUrl = rawUrlInfo.url
401
+ return buildUrl
402
+ }
403
+ const rawUrlInfo = rawGraph.getUrlInfo(reference.url)
404
+ // files from root directory but not given to rollup nor postcss
405
+ if (rawUrlInfo) {
406
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
407
+ urlInfo: rawUrlInfo,
408
+ })
409
+ rawUrls[buildUrl] = rawUrlInfo.url
383
410
  return buildUrl
384
411
  }
385
412
  if (reference.type === "sourcemap_comment") {
386
413
  // inherit parent build url
387
414
  return generateSourcemapUrl(reference.parentUrl)
388
415
  }
389
- // files generated during the final graph (sourcemaps)
416
+ // files generated during the final graph:
417
+ // - sourcemaps
390
418
  // const finalUrlInfo = finalGraph.getUrlInfo(url)
391
419
  const buildUrl = buildUrlsGenerator.generate(reference.url, {
392
- data: {},
393
- type: "asset",
420
+ urlInfo: {
421
+ data: {},
422
+ type: "asset",
423
+ },
394
424
  })
395
425
  return buildUrl
396
426
  },
397
- formatReferencedUrl: (reference) => {
398
- if (!reference.url.startsWith("file:")) {
427
+ formatUrl: (reference) => {
428
+ if (!reference.generatedUrl.startsWith("file:")) {
399
429
  return null
400
430
  }
401
- if (!urlIsInsideOf(reference.url, buildDirectoryUrl)) {
431
+ if (!urlIsInsideOf(reference.generatedUrl, buildDirectoryUrl)) {
402
432
  throw new Error(
403
433
  `urls should be inside build directory at this stage, found "${reference.url}"`,
404
434
  )
405
435
  }
436
+ // remove eventual search params and hash
437
+ const urlUntilPathname = asUrlUntilPathname(reference.generatedUrl)
406
438
  // if a file is in the same directory we could prefer the relative notation
407
- // but to keep things simple let's keep the notation relative to baseUrl for now
439
+ // but to keep things simple let's keep the "absolutely relative" to baseUrl for now
408
440
  const specifier = `${baseUrl}${urlToRelativeUrl(
409
- reference.url,
441
+ urlUntilPathname,
410
442
  buildDirectoryUrl,
411
443
  )}`
412
- buildUrls[specifier] = reference.url
444
+ buildUrls[specifier] = reference.generatedUrl
413
445
  return specifier
414
446
  },
415
- load: (finalUrlInfo) => {
416
- const rawUrl = finalUrlInfo.data.rawUrl
417
- const bundleUrlInfo = bundleUrlInfos[rawUrl]
418
- const urlInfo = bundleUrlInfo || rawGraph.getUrlInfo(rawUrl)
419
- finalUrlInfo.subtype = urlInfo.subtype
420
- return {
421
- data: bundleUrlInfo ? bundleUrlInfo.data : undefined,
422
- originalContent: urlInfo.originalContent,
423
- contentType: urlInfo.contentType,
424
- content: urlInfo.content,
425
- sourcemap: urlInfo.sourcemap,
447
+ fetchUrlContent: async (finalUrlInfo, context) => {
448
+ if (!finalUrlInfo.url.startsWith("file:")) {
449
+ return { external: true }
426
450
  }
427
- },
428
- transform: {
429
- html: (urlInfo) => {
430
- const htmlAst = parseHtmlString(urlInfo.content, {
431
- storeOriginalPositions: false,
432
- })
433
- return {
434
- content: stringifyHtmlAst(htmlAst, {
435
- removeOriginalPositionAttributes: true,
436
- }),
451
+ const fromBundleOrRawGraph = (url) => {
452
+ const bundleUrlInfo = bundleUrlInfos[url]
453
+ if (bundleUrlInfo) {
454
+ return bundleUrlInfo
437
455
  }
438
- },
456
+ const rawUrl = rawUrls[url] || url
457
+ const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
458
+ if (!rawUrlInfo) {
459
+ const originalBuildUrl = buildUrlRedirections[url]
460
+ if (originalBuildUrl) {
461
+ return fromBundleOrRawGraph(originalBuildUrl)
462
+ }
463
+ throw new Error(`Cannot find url`)
464
+ }
465
+ if (rawUrlInfo.isInline) {
466
+ // Inline content, such as <script> inside html, is transformed during the previous phase.
467
+ // If we read the inline content it would be considered as the original content.
468
+ // - It could be "fixed" by taking into account sourcemap and consider sourcemap sources
469
+ // as the original content.
470
+ // - But it would not work when sourcemap are not generated
471
+ // - would be a bit slower
472
+ // - So instead of reading the inline content directly, we search into raw graph
473
+ // to get "originalContent" and "sourcemap"
474
+ finalUrlInfo.type = rawUrlInfo.type
475
+ finalUrlInfo.subtype = rawUrlInfo.subtype
476
+ return rawUrlInfo
477
+ }
478
+ return rawUrlInfo
479
+ }
480
+ // reference injected during "postbuild":
481
+ // - happens for "as_js_classic" injecting "s.js"
482
+ if (context.reference.injected) {
483
+ const [ref, rawUrlInfo] = rawGraphKitchen.injectReference({
484
+ type: context.reference.type,
485
+ expectedType: context.reference.expectedType,
486
+ expectedSubtype: context.reference.expectedSubtype,
487
+ parentUrl: rawUrls[context.reference.parentUrl],
488
+ specifier: context.reference.specifier,
489
+ injected: true,
490
+ })
491
+ await rawGraphKitchen.cook({
492
+ reference: ref,
493
+ urlInfo: rawUrlInfo,
494
+ })
495
+ return rawUrlInfo
496
+ }
497
+ // reference updated during "postbuild":
498
+ // - happens for "as_js_classic"
499
+ if (context.reference.original) {
500
+ return fromBundleOrRawGraph(context.reference.original.url)
501
+ }
502
+ return fromBundleOrRawGraph(finalUrlInfo.url)
439
503
  },
440
504
  },
441
505
  {
442
506
  name: "jsenv:optimize",
443
507
  appliesDuring: { build: true },
444
- transform: async (urlInfo, context) => {
445
- if (optimizeHooks.length) {
508
+ finalizeUrlContent: async (urlInfo, context) => {
509
+ if (optimizeUrlContentHooks.length) {
446
510
  await rawGraphKitchen.pluginController.callAsyncHooks(
447
- "optimize",
511
+ "optimizeUrlContent",
448
512
  urlInfo,
449
513
  context,
450
514
  async (optimizeReturnValue) => {
@@ -458,8 +522,6 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
458
522
  },
459
523
  },
460
524
  ],
461
- scenario: "build",
462
- sourcemaps,
463
525
  })
464
526
  const buildTask = createTaskLog(logger, "build")
465
527
  const postBuildEntryUrls = []
@@ -468,7 +530,6 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
468
530
  urlGraph: finalGraph,
469
531
  kitchen: finalGraphKitchen,
470
532
  outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
471
- runtimeSupport,
472
533
  startLoading: (cookEntryFile) => {
473
534
  entryUrls.forEach((entryUrl) => {
474
535
  const [, postBuildEntryUrlInfo] = cookEntryFile({
@@ -490,7 +551,7 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
490
551
  `graph urls pre-versioning:
491
552
  ${Object.keys(finalGraph.urlInfos).join("\n")}`,
492
553
  )
493
- if (versioning !== "none") {
554
+ if (versioning) {
494
555
  const versioningTask = createTaskLog(logger, "inject version in urls")
495
556
  try {
496
557
  const urlsSorted = sortUrlGraphByDependencies(finalGraph)
@@ -502,9 +563,25 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
502
563
  if (urlInfo.type === "sourcemap") {
503
564
  return
504
565
  }
566
+ // ignore:
567
+ // - inline files:
568
+ // they are already taken into account in the file where they appear
569
+ // - external files
570
+ // we don't know their content
571
+ // - unused files without reference
572
+ // File updated such as style.css -> style.css.js or file.js->file.es5.js
573
+ // Are used at some point just to be discarded later because they need to be converted
574
+ // There is no need to version them and we could not because the file have been ignored
575
+ // so their content is unknown
505
576
  if (urlInfo.isInline) {
506
577
  return
507
578
  }
579
+ if (urlInfo.external) {
580
+ return
581
+ }
582
+ if (!urlInfo.data.isEntryPoint && urlInfo.dependents.size === 0) {
583
+ return
584
+ }
508
585
  const versionGenerator = createVersionGenerator()
509
586
  versionGenerator.augmentWithContent({
510
587
  content: urlInfo.content,
@@ -513,8 +590,12 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
513
590
  })
514
591
  urlInfo.dependencies.forEach((dependencyUrl) => {
515
592
  const dependencyUrlInfo = finalGraph.getUrlInfo(dependencyUrl)
516
- if (dependencyUrlInfo.isInline) {
593
+ if (
517
594
  // this content is part of the file, no need to take into account twice
595
+ dependencyUrlInfo.isInline ||
596
+ // this dependency content is not known
597
+ dependencyUrlInfo.external
598
+ ) {
518
599
  return
519
600
  }
520
601
  if (dependencyUrlInfo.data.version) {
@@ -537,7 +618,7 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
537
618
  urlInfo.data.versionedUrl = injectVersionIntoBuildUrl({
538
619
  buildUrl: urlInfo.url,
539
620
  version: urlInfo.data.version,
540
- versioning,
621
+ versioningMethod,
541
622
  })
542
623
  })
543
624
  const versionMappings = {}
@@ -546,26 +627,22 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
546
627
  logger,
547
628
  rootDirectoryUrl: buildDirectoryUrl,
548
629
  urlGraph: finalGraph,
549
- loadInlineUrlInfos: (versionedUrlInfo) => {
550
- const rawUrlInfo = rawGraph.getUrlInfo(versionedUrlInfo.data.rawUrl)
551
- const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
552
- return {
553
- originalContent: rawUrlInfo
554
- ? rawUrlInfo.originalContent
555
- : undefined,
556
- sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
557
- contentType: versionedUrlInfo.contentType,
558
- content: versionedUrlInfo.content,
559
- }
560
- },
630
+ scenario: "build",
631
+ sourcemaps,
632
+ runtimeCompat,
561
633
  plugins: [
562
634
  jsenvPluginInline({
635
+ fetchInlineUrls: false,
636
+ analyzeConvertedScripts: true, // to be able to version their urls
563
637
  allowEscapeForVersioning: true,
564
638
  }),
565
639
  {
566
640
  name: "jsenv:versioning",
567
641
  appliesDuring: { build: true },
568
- resolve: (reference) => {
642
+ resolveUrl: (reference) => {
643
+ if (reference.specifier[0] === "#") {
644
+ reference.external = true
645
+ }
569
646
  const buildUrl = buildUrls[reference.specifier]
570
647
  if (buildUrl) {
571
648
  return buildUrl
@@ -573,18 +650,14 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
573
650
  const url = new URL(reference.specifier, reference.parentUrl).href
574
651
  return url
575
652
  },
576
- formatReferencedUrl: (reference) => {
653
+ formatUrl: (reference) => {
577
654
  if (reference.isInline) {
578
655
  return null
579
656
  }
580
657
  // specifier comes from "normalize" hook done a bit earlier in this file
581
658
  // we want to get back their build url to access their infos
582
659
  const referencedUrlInfo = finalGraph.getUrlInfo(reference.url)
583
- if (
584
- referencedUrlInfo.data.isEntryPoint ||
585
- referencedUrlInfo.subtype === "service_worker" ||
586
- referencedUrlInfo.type === "webmanifest"
587
- ) {
660
+ if (!canUseVersionedUrl(referencedUrlInfo)) {
588
661
  return reference.specifier
589
662
  }
590
663
  // data:* urls and so on
@@ -604,6 +677,8 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
604
677
  buildDirectoryUrl,
605
678
  )}`
606
679
  versionMappings[reference.specifier] = versionedSpecifier
680
+ buildUrls[versionedSpecifier] = versionedUrl
681
+
607
682
  const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
608
683
  if (parentUrlInfo.jsQuote) {
609
684
  // the url is inline inside js quotes
@@ -614,7 +689,7 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
614
689
  )})+${parentUrlInfo.jsQuote}`
615
690
  }
616
691
  if (
617
- reference.type === "js_import_meta_url_pattern" ||
692
+ reference.type === "js_url_specifier" ||
618
693
  reference.subtype === "import_dynamic"
619
694
  ) {
620
695
  usedVersionMappings.push(reference.specifier)
@@ -622,27 +697,44 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
622
697
  }
623
698
  return versionedSpecifier
624
699
  },
625
- load: (finalUrlInfo) => {
626
- return {
627
- originalContent: finalUrlInfo.originalContent,
628
- contentType: finalUrlInfo.contentType,
629
- content: finalUrlInfo.content,
630
- sourcemap: finalUrlInfo.sourcemap,
700
+ fetchUrlContent: (versionedUrlInfo) => {
701
+ if (!versionedUrlInfo.url.startsWith("file:")) {
702
+ return { external: true }
631
703
  }
704
+ if (versionedUrlInfo.isInline) {
705
+ const rawUrlInfo = rawGraph.getUrlInfo(
706
+ rawUrls[versionedUrlInfo.url],
707
+ )
708
+ const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
709
+ return {
710
+ originalContent: rawUrlInfo
711
+ ? rawUrlInfo.originalContent
712
+ : undefined,
713
+ sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
714
+ contentType: versionedUrlInfo.contentType,
715
+ content: versionedUrlInfo.content,
716
+ }
717
+ }
718
+ return versionedUrlInfo
719
+ },
720
+ transformUrlContent: {
721
+ html: (urlInfo) => {
722
+ const htmlAst = parseHtmlString(urlInfo.content, {
723
+ storeOriginalPositions: false,
724
+ })
725
+ return {
726
+ content: stringifyHtmlAst(htmlAst, {
727
+ removeOriginalPositionAttributes: true,
728
+ }),
729
+ }
730
+ },
632
731
  },
633
732
  },
634
733
  ],
635
- scenario: "build",
636
- sourcemaps,
637
- })
638
- // arrange state before reloading all files
639
- GRAPH.forEach(finalGraph, (finalUrlInfo) => {
640
- finalUrlInfo.data.promise = null
641
734
  })
642
735
  await loadUrlGraph({
643
736
  urlGraph: finalGraph,
644
737
  kitchen: versioningKitchen,
645
- runtimeSupport,
646
738
  startLoading: (cookEntryFile) => {
647
739
  postBuildEntryUrls.forEach((postBuildEntryUrl) => {
648
740
  cookEntryFile({
@@ -658,123 +750,94 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
658
750
  usedVersionMappings.forEach((specifier) => {
659
751
  versionMappingsNeeded[specifier] = versionMappings[specifier]
660
752
  })
661
- await Promise.all(
662
- GRAPH.map(finalGraph, async (urlInfo) => {
663
- if (!urlInfo.data.isEntryPoint) {
664
- return
665
- }
666
- await injectVersionMappings({
667
- urlInfo,
668
- kitchen: finalGraphKitchen,
669
- versionMappings: versionMappingsNeeded,
670
- })
671
- }),
672
- )
753
+ await injectGlobalVersionMapping({
754
+ finalGraphKitchen,
755
+ finalGraph,
756
+ versionMappings: versionMappingsNeeded,
757
+ })
673
758
  }
674
759
  } catch (e) {
675
760
  versioningTask.fail()
676
761
  throw e
677
762
  }
678
763
  versioningTask.done()
764
+ } else {
765
+ // TODO: remove html attributes such as original-src-position
679
766
  }
680
767
 
681
768
  GRAPH.forEach(finalGraph, (urlInfo) => {
682
769
  if (!urlInfo.url.startsWith("file:")) {
683
770
  return
684
771
  }
772
+ if (urlInfo.external) {
773
+ return
774
+ }
685
775
  const version = urlInfo.data.version
686
- const useVersionedUrl =
687
- !urlInfo.data.isEntryPoint &&
688
- urlInfo.subtype !== "service_worker" &&
689
- urlInfo.type !== "webmanifest" &&
690
- version
776
+ const useVersionedUrl = version && canUseVersionedUrl(urlInfo, finalGraph)
691
777
  const buildUrl = useVersionedUrl ? urlInfo.data.versionedUrl : urlInfo.url
692
- if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
693
- throw new Error(`build url outside build directory`)
694
- }
695
- const buildRelativeUrl = urlToRelativeUrl(buildUrl, buildDirectoryUrl)
778
+ const buildUrlSpecifier = Object.keys(buildUrls).find(
779
+ (key) => buildUrls[key] === buildUrl,
780
+ )
696
781
  urlInfo.data.buildUrl = buildUrl
697
782
  urlInfo.data.buildUrlIsVersioned = useVersionedUrl
698
- urlInfo.data.buildRelativeUrl = buildRelativeUrl
783
+ urlInfo.data.buildUrlSpecifier = buildUrlSpecifier
784
+ })
785
+
786
+ await resyncRessourceHints({
787
+ finalGraphKitchen,
788
+ finalGraph,
789
+ rawUrls,
790
+ buildUrls,
791
+ buildUrlRedirections,
792
+ })
793
+ const cleanupActions = []
794
+ GRAPH.forEach(finalGraph, (urlInfo) => {
795
+ // nothing uses this url anymore
796
+ // - versioning update inline content
797
+ // - file converted for import assertion of js_classic conversion
798
+ if (!urlInfo.data.isEntryPoint && urlInfo.dependents.size === 0) {
799
+ cleanupActions.push(() => {
800
+ delete finalGraph.urlInfos[urlInfo.url]
801
+ })
802
+ }
803
+ })
804
+ cleanupActions.forEach((cleanupAction) => cleanupAction())
805
+ await injectServiceWorkerUrls({
806
+ finalGraphKitchen,
807
+ finalGraph,
808
+ lineBreakNormalization,
699
809
  })
700
810
 
701
- const hasServiceWorker = Boolean(
702
- GRAPH.find(
703
- finalGraph,
704
- (finalUrlInfo) => finalUrlInfo.subtype === "service_worker",
705
- ),
811
+ logger.debug(
812
+ `graph urls post-versioning:
813
+ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
706
814
  )
707
- if (hasServiceWorker) {
708
- const serviceWorkerUrls = {}
709
- GRAPH.forEach(finalGraph, (urlInfo) => {
710
- if (!urlInfo.url.startsWith("file:")) {
711
- return
712
- }
713
- if (urlInfo.isInline) {
714
- return
715
- }
716
- if (urlInfo.data.buildUrlIsVersioned) {
717
- serviceWorkerUrls[urlInfo.data.buildRelativeUrl] = {
718
- versioned: true,
719
- }
720
- return
721
- }
722
- if (!urlInfo.data.version) {
723
- // when url is not versioned we compute a "version" for that url anyway
724
- // so that service worker source still changes and navigator
725
- // detect there is a change
726
- const versionGenerator = createVersionGenerator()
727
- versionGenerator.augmentWithContent({
728
- content: urlInfo.content,
729
- contentType: urlInfo.contentType,
730
- lineBreakNormalization,
731
- })
732
- const version = versionGenerator.generate()
733
- urlInfo.data.version = version
734
- }
735
- serviceWorkerUrls[urlInfo.data.buildRelativeUrl] = {
736
- versioned: false,
737
- version: urlInfo.data.version,
738
- }
739
- })
740
- await Promise.all(
741
- GRAPH.map(finalGraph, async (urlInfo) => {
742
- if (urlInfo.subtype !== "service_worker") {
743
- return
744
- }
745
- await injectServiceWorkerUrls({
746
- urlInfo,
747
- kitchen: finalGraphKitchen,
748
- serviceWorkerUrls,
749
- })
750
- }),
751
- )
752
- }
753
815
 
754
816
  const buildManifest = {}
755
817
  const buildFileContents = {}
756
- const buildInlineFileContents = {}
818
+ const buildInlineContents = {}
757
819
  GRAPH.forEach(finalGraph, (urlInfo) => {
758
- const { buildUrlIsVersioned, buildRelativeUrl } = urlInfo.data
820
+ if (urlInfo.external) {
821
+ return
822
+ }
823
+ if (urlInfo.url.startsWith("data:")) {
824
+ return
825
+ }
826
+ const buildRelativeUrl = urlToRelativeUrl(
827
+ urlInfo.data.buildUrl,
828
+ buildDirectoryUrl,
829
+ )
759
830
  if (urlInfo.isInline) {
760
- buildInlineFileContents[buildRelativeUrl] = urlInfo.content
831
+ buildInlineContents[buildRelativeUrl] = urlInfo.content
761
832
  } else {
762
833
  buildFileContents[buildRelativeUrl] = urlInfo.content
763
834
  }
764
- if (buildUrlIsVersioned) {
765
- const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
766
- urlInfo.url,
767
- buildDirectoryUrl,
768
- )
769
- buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
770
- }
835
+ const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
836
+ urlInfo.url,
837
+ buildDirectoryUrl,
838
+ )
839
+ buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
771
840
  })
772
-
773
- logger.debug(
774
- `graph urls post-versioning:
775
- ${Object.keys(finalGraph.urlInfos).join("\n")}`,
776
- )
777
-
778
841
  if (writeOnFileSystem) {
779
842
  if (buildDirectoryClean) {
780
843
  await ensureEmptyDirectory(buildDirectoryUrl)
@@ -788,11 +851,7 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
788
851
  )
789
852
  }),
790
853
  )
791
- if (
792
- versioning !== "none" &&
793
- assetManifest &&
794
- Object.keys(buildManifest).length
795
- ) {
854
+ if (versioning && assetManifest && Object.keys(buildManifest).length) {
796
855
  await writeFile(
797
856
  new URL(assetManifestFileRelativeUrl, buildDirectoryUrl),
798
857
  JSON.stringify(buildManifest, null, " "),
@@ -802,34 +861,13 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
802
861
  logger.info(createUrlGraphSummary(finalGraph, { title: "build files" }))
803
862
  return {
804
863
  buildFileContents,
805
- buildInlineFileContents,
864
+ buildInlineContents,
806
865
  buildManifest,
807
866
  }
808
867
  }
809
868
 
810
- const GRAPH = {
811
- map: (graph, callback) => {
812
- return Object.keys(graph.urlInfos).map((url) => {
813
- return callback(graph.urlInfos[url])
814
- })
815
- },
816
-
817
- forEach: (graph, callback) => {
818
- Object.keys(graph.urlInfos).forEach((url) => {
819
- callback(graph.urlInfos[url], url)
820
- })
821
- },
822
-
823
- find: (graph, callback) => {
824
- const urlFound = Object.keys(graph.urlInfos).find((url) => {
825
- return callback(graph.urlInfos[url])
826
- })
827
- return graph.urlInfos[urlFound]
828
- },
829
- }
830
-
831
- const injectVersionIntoBuildUrl = ({ buildUrl, version, versioning }) => {
832
- if (versioning === "search_param") {
869
+ const injectVersionIntoBuildUrl = ({ buildUrl, version, versioningMethod }) => {
870
+ if (versioningMethod === "search_param") {
833
871
  return injectQueryParams(buildUrl, {
834
872
  v: version,
835
873
  })
@@ -865,3 +903,16 @@ const assertEntryPoints = ({ entryPoints }) => {
865
903
  }
866
904
  })
867
905
  }
906
+
907
+ const canUseVersionedUrl = (urlInfo) => {
908
+ if (urlInfo.data.isEntryPoint) {
909
+ return false
910
+ }
911
+ if (urlInfo.type === "webmanifest") {
912
+ return false
913
+ }
914
+ if (urlInfo.subtype === "service_worker") {
915
+ return !urlInfo.data.isWebWorkerEntryPoint
916
+ }
917
+ return true
918
+ }