@jsenv/core 27.0.0-alpha.12 → 27.0.0-alpha.15

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