@jsenv/core 27.0.0-alpha.7 → 27.0.0-alpha.72

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 (248) hide show
  1. package/dist/babel_helpers/AsyncGenerator/AsyncGenerator.js +95 -0
  2. package/dist/babel_helpers/AwaitValue/AwaitValue.js +3 -0
  3. package/dist/babel_helpers/applyDecoratorDescriptor/applyDecoratorDescriptor.js +29 -0
  4. package/dist/babel_helpers/arrayLikeToArray/arrayLikeToArray.js +9 -0
  5. package/dist/babel_helpers/arrayWithHoles/arrayWithHoles.js +4 -0
  6. package/dist/babel_helpers/arrayWithoutHoles/arrayWithoutHoles.js +5 -0
  7. package/dist/babel_helpers/assertThisInitialized/assertThisInitialized.js +8 -0
  8. package/dist/babel_helpers/asyncGeneratorDelegate/asyncGeneratorDelegate.js +52 -0
  9. package/dist/babel_helpers/asyncIterator/asyncIterator.js +78 -0
  10. package/dist/babel_helpers/asyncToGenerator/asyncToGenerator.js +39 -0
  11. package/dist/babel_helpers/awaitAsyncGenerator/awaitAsyncGenerator.js +4 -0
  12. package/dist/babel_helpers/classApplyDescriptorDestructureSet/classApplyDescriptorDestructureSet.js +24 -0
  13. package/dist/babel_helpers/classApplyDescriptorGet/classApplyDescriptorGet.js +7 -0
  14. package/dist/babel_helpers/classApplyDescriptorSet/classApplyDescriptorSet.js +14 -0
  15. package/dist/babel_helpers/classCallCheck/classCallCheck.js +5 -0
  16. package/dist/babel_helpers/classCheckPrivateStaticAccess/classCheckPrivateStaticAccess.js +5 -0
  17. package/dist/babel_helpers/classCheckPrivateStaticFieldDescriptor/classCheckPrivateStaticFieldDescriptor.js +6 -0
  18. package/dist/babel_helpers/classExtractFieldDescriptor/classExtractFieldDescriptor.js +8 -0
  19. package/dist/babel_helpers/classNameTDZError/classNameTDZError.js +4 -0
  20. package/dist/babel_helpers/classPrivateFieldDestructureSet/classPrivateFieldDestructureSet.js +6 -0
  21. package/dist/babel_helpers/classPrivateFieldGet/classPrivateFieldGet.js +6 -0
  22. package/dist/babel_helpers/classPrivateFieldLooseBase/classPrivateFieldLooseBase.js +7 -0
  23. package/dist/babel_helpers/classPrivateFieldLooseKey/classPrivateFieldLooseKey.js +5 -0
  24. package/dist/babel_helpers/classPrivateFieldSet/classPrivateFieldSet.js +7 -0
  25. package/dist/babel_helpers/classPrivateMethodGet/classPrivateMethodGet.js +7 -0
  26. package/dist/babel_helpers/classPrivateMethodSet/classPrivateMethodSet.js +3 -0
  27. package/dist/babel_helpers/classStaticPrivateFieldSpecGet/classStaticPrivateFieldSpecGet.js +8 -0
  28. package/dist/babel_helpers/classStaticPrivateFieldSpecSet/classStaticPrivateFieldSpecSet.js +9 -0
  29. package/dist/babel_helpers/classStaticPrivateMethodGet/classStaticPrivateMethodGet.js +5 -0
  30. package/dist/babel_helpers/classStaticPrivateMethodSet/classStaticPrivateMethodSet.js +3 -0
  31. package/dist/babel_helpers/construct/construct.js +15 -0
  32. package/dist/babel_helpers/createClass/createClass.js +18 -0
  33. package/dist/babel_helpers/createForOfIteratorHelper/createForOfIteratorHelper.js +63 -0
  34. package/dist/babel_helpers/createForOfIteratorHelperLoose/createForOfIteratorHelperLoose.js +22 -0
  35. package/dist/babel_helpers/createRawReactElement/createRawReactElement.js +50 -0
  36. package/dist/babel_helpers/createSuper/createSuper.js +22 -0
  37. package/dist/babel_helpers/decorate/decorate.js +622 -0
  38. package/dist/babel_helpers/defaults/defaults.js +14 -0
  39. package/dist/babel_helpers/defineEnumerableProperties/defineEnumerableProperties.js +26 -0
  40. package/dist/babel_helpers/defineProperty/defineProperty.js +19 -0
  41. package/dist/babel_helpers/extends/extends.js +16 -0
  42. package/dist/babel_helpers/get/get.js +21 -0
  43. package/dist/babel_helpers/getPrototypeOf/getPrototypeOf.js +2 -0
  44. package/dist/babel_helpers/inherits/inherits.js +21 -0
  45. package/dist/babel_helpers/inheritsLoose/inheritsLoose.js +6 -0
  46. package/dist/babel_helpers/initializerDefineProperty/initializerDefineProperty.js +10 -0
  47. package/dist/babel_helpers/initializerWarningHelper/initializerWarningHelper.js +3 -0
  48. package/dist/babel_helpers/instanceof/instanceof.js +7 -0
  49. package/dist/babel_helpers/interopRequireDefault/interopRequireDefault.js +5 -0
  50. package/dist/babel_helpers/interopRequireWildcard/interopRequireWildcard.js +49 -0
  51. package/dist/babel_helpers/isNativeFunction/isNativeFunction.js +4 -0
  52. package/dist/babel_helpers/isNativeReflectConstruct/isNativeReflectConstruct.js +21 -0
  53. package/dist/babel_helpers/iterableToArray/iterableToArray.js +3 -0
  54. package/dist/babel_helpers/iterableToArrayLimit/iterableToArrayLimit.js +38 -0
  55. package/dist/babel_helpers/iterableToArrayLimitLoose/iterableToArrayLimitLoose.js +13 -0
  56. package/dist/babel_helpers/jsx/jsx.js +49 -0
  57. package/dist/babel_helpers/maybeArrayLike/maybeArrayLike.js +10 -0
  58. package/dist/babel_helpers/newArrowCheck/newArrowCheck.js +5 -0
  59. package/dist/babel_helpers/nonIterableRest/nonIterableRest.js +3 -0
  60. package/dist/babel_helpers/nonIterableSpread/nonIterableSpread.js +3 -0
  61. package/dist/babel_helpers/objectDestructuringEmpty/objectDestructuringEmpty.js +3 -0
  62. package/dist/babel_helpers/objectSpread/objectSpread.js +22 -0
  63. package/dist/babel_helpers/objectSpread2/objectSpread2.js +41 -0
  64. package/dist/babel_helpers/objectWithoutProperties/objectWithoutProperties.js +20 -0
  65. package/dist/babel_helpers/objectWithoutPropertiesLoose/objectWithoutPropertiesLoose.js +15 -0
  66. package/dist/babel_helpers/possibleConstructorReturn/possibleConstructorReturn.js +10 -0
  67. package/dist/babel_helpers/readOnlyError/readOnlyError.js +4 -0
  68. package/dist/babel_helpers/readme.md +8 -0
  69. package/dist/babel_helpers/set/set.js +51 -0
  70. package/dist/babel_helpers/setPrototypeOf/setPrototypeOf.js +5 -0
  71. package/dist/babel_helpers/skipFirstGeneratorNext/skipFirstGeneratorNext.js +8 -0
  72. package/dist/babel_helpers/slicedToArray/slicedToArray.js +5 -0
  73. package/dist/babel_helpers/slicedToArrayLoose/slicedToArrayLoose.js +7 -0
  74. package/dist/babel_helpers/superPropBase/superPropBase.js +10 -0
  75. package/dist/babel_helpers/taggedTemplateLiteral/taggedTemplateLiteral.js +11 -0
  76. package/dist/babel_helpers/taggedTemplateLiteralLoose/taggedTemplateLiteralLoose.js +8 -0
  77. package/dist/babel_helpers/tdz/tdz.js +4 -0
  78. package/dist/babel_helpers/temporalRef/temporalRef.js +5 -0
  79. package/dist/babel_helpers/temporalUndefined/temporalUndefined.js +3 -0
  80. package/dist/babel_helpers/toArray/toArray.js +5 -0
  81. package/dist/babel_helpers/toConsumableArray/toConsumableArray.js +5 -0
  82. package/dist/babel_helpers/toPrimitive/toPrimitive.js +14 -0
  83. package/dist/babel_helpers/toPropertyKey/toPropertyKey.js +5 -0
  84. package/dist/babel_helpers/typeof/typeof.js +7 -0
  85. package/dist/babel_helpers/unsupportedIterableToArray/unsupportedIterableToArray.js +10 -0
  86. package/dist/babel_helpers/wrapAsyncGenerator/wrapAsyncGenerator.js +7 -0
  87. package/dist/babel_helpers/wrapNativeSuper/wrapNativeSuper.js +35 -0
  88. package/dist/babel_helpers/wrapRegExp/wrapRegExp.js +67 -0
  89. package/dist/babel_helpers/writeOnlyError/writeOnlyError.js +4 -0
  90. package/dist/html/explorer.html +557 -0
  91. package/dist/js/controllable_file.mjs +227 -0
  92. package/dist/js/event_source_client.js +324 -0
  93. package/dist/js/global_this.js +32 -0
  94. package/dist/js/html_supervisor_installer.js +522 -0
  95. package/dist/js/html_supervisor_setup.js +79 -0
  96. package/dist/js/import_meta_hot.js +84 -0
  97. package/dist/js/inline_content.js +8 -0
  98. package/dist/js/new_stylesheet.js +409 -0
  99. package/dist/js/regenerator_runtime.js +721 -0
  100. package/dist/js/s.js +429 -0
  101. package/dist/main.js +13455 -0
  102. package/dist/other/jsenv.png +0 -0
  103. package/dist/s.js +626 -0
  104. package/dist/s.js.map +204 -0
  105. package/main.js +9 -1
  106. package/package.json +46 -33
  107. package/readme.md +6 -14
  108. package/src/build/build.js +1080 -562
  109. package/src/build/build_urls_generator.js +65 -24
  110. package/src/build/graph_utils.js +31 -0
  111. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +49 -18
  112. package/src/build/inject_service_worker_urls.js +79 -0
  113. package/src/build/resync_ressource_hints.js +115 -0
  114. package/src/build/start_build_server.js +211 -0
  115. package/src/dev/plugins/explorer/client/explorer.html +1 -1
  116. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +9 -13
  117. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  118. package/src/dev/start_dev_server.js +170 -38
  119. package/src/execute/execute.js +36 -6
  120. package/src/execute/run.js +21 -57
  121. package/src/execute/runtimes/browsers/from_playwright.js +218 -148
  122. package/src/execute/runtimes/node/controllable_file.mjs +26 -10
  123. package/src/execute/runtimes/node/node_execution_performance.js +67 -0
  124. package/src/execute/runtimes/node/node_process.js +288 -39
  125. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +30 -7
  126. package/src/omega/{runtime_support/runtime_support.js → compat/runtime_compat.js} +14 -16
  127. package/src/omega/errors.js +62 -66
  128. package/src/omega/fetched_content_compliance.js +24 -0
  129. package/src/omega/file_url_converter.js +9 -51
  130. package/src/omega/kitchen.js +593 -463
  131. package/src/omega/omega_server.js +2 -3
  132. package/src/omega/server/file_service.js +86 -38
  133. package/src/omega/server/user_agent.js +4 -2
  134. package/src/omega/url_graph/url_graph_load.js +31 -23
  135. package/src/omega/url_graph/url_graph_report.js +94 -51
  136. package/src/omega/url_graph/url_info_transformations.js +37 -17
  137. package/src/omega/url_graph.js +88 -19
  138. package/src/omega/url_specifier_encoding.js +59 -0
  139. package/src/omega/web_workers.js +42 -0
  140. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
  141. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +19 -12
  142. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
  143. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
  144. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +41 -0
  145. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +204 -0
  146. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +25 -0
  147. package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
  148. package/src/plugins/bundling/css/bundle_css.js +140 -0
  149. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  150. package/src/plugins/bundling/js_module/bundle_js_module.js +343 -0
  151. package/src/plugins/bundling/jsenv_plugin_bundling.js +54 -0
  152. package/src/plugins/cache_control/jsenv_plugin_cache_control.js +34 -0
  153. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +54 -41
  154. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +198 -0
  155. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  156. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  157. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +254 -0
  158. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +79 -0
  159. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  160. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  161. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +73 -55
  162. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  163. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +4 -5
  164. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +3 -1
  165. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +7 -4
  166. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +100 -0
  167. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +33 -8
  168. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  169. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  170. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +40 -36
  171. package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +76 -0
  172. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  173. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +20 -19
  174. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +161 -0
  175. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  176. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +8 -11
  177. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +294 -0
  178. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  179. package/src/plugins/minification/css/minify_css.js +9 -0
  180. package/src/plugins/minification/html/minify_html.js +15 -0
  181. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  182. package/src/plugins/minification/jsenv_plugin_minification.js +78 -0
  183. package/src/plugins/minification/json/minify_json.js +8 -0
  184. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +160 -0
  185. package/src/plugins/node_runtime/jsenv_plugin_node_runtime.js +12 -0
  186. package/src/{omega → plugins}/plugin_controller.js +56 -11
  187. package/src/plugins/plugins.js +92 -0
  188. package/src/plugins/transpilation/as_js_classic/client/s.js +429 -0
  189. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  190. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  191. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +213 -0
  192. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +304 -0
  193. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_workers.js +55 -0
  194. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  195. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  196. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  197. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +14 -17
  198. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  199. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +39 -32
  200. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +30 -6
  201. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  202. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  203. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  204. package/src/plugins/transpilation/babel/require_babel_plugin.js +8 -0
  205. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  206. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +184 -0
  207. package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +79 -0
  208. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +46 -0
  209. package/src/plugins/url_analysis/css/css_urls.js +49 -0
  210. package/src/plugins/url_analysis/html/html_urls.js +272 -0
  211. package/src/plugins/url_analysis/js/js_urls.js +68 -0
  212. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +103 -0
  213. package/src/plugins/url_analysis/webmanifest/webmanifest_urls.js +20 -0
  214. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +9 -5
  215. package/src/plugins/url_version/jsenv_plugin_url_version.js +28 -0
  216. package/src/test/execute_plan.js +82 -44
  217. package/src/test/execute_test_plan.js +38 -24
  218. package/src/test/execution_steps.js +1 -4
  219. package/src/test/logs_file_execution.js +56 -49
  220. package/src/build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js +0 -225
  221. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  222. package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
  223. package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +0 -374
  224. package/src/dev/plugins/autoreload/sse_service.js +0 -149
  225. package/src/execute/runtimes/node/controlled_process.js +0 -316
  226. package/src/omega/core_plugins/babel/new_stylesheet/client/.eslintrc.cjs +0 -24
  227. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  228. package/src/omega/core_plugins/filesystem_magic/jsenv_plugin_filesystem_magic.js +0 -58
  229. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_installer.js +0 -168
  230. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_setup.js +0 -77
  231. package/src/omega/core_plugins/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -98
  232. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  233. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  234. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  235. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  236. package/src/omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js +0 -142
  237. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -207
  238. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  239. package/src/omega/core_plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +0 -77
  240. package/src/omega/core_plugins/url_version/jsenv_plugin_url_version.js +0 -50
  241. package/src/omega/core_plugins.js +0 -39
  242. package/src/omega/runtime_support/default_runtime_support.js +0 -13
  243. package/src/omega/url_graph/url_graph_sort.js +0 -29
  244. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  245. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  246. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  247. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  248. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -7,151 +7,268 @@
7
7
  */
8
8
 
9
9
  import {
10
- assertAndNormalizeDirectoryUrl,
11
- ensureEmptyDirectory,
10
+ injectQueryParams,
11
+ setUrlFilename,
12
+ asUrlUntilPathname,
13
+ normalizeUrl,
14
+ asUrlWithoutSearch,
15
+ ensurePathnameTrailingSlash,
12
16
  urlIsInsideOf,
13
17
  urlToBasename,
14
18
  urlToExtension,
15
19
  urlToRelativeUrl,
20
+ } from "@jsenv/urls"
21
+ import {
22
+ assertAndNormalizeDirectoryUrl,
23
+ ensureEmptyDirectory,
16
24
  writeFile,
25
+ registerDirectoryLifecycle,
17
26
  } from "@jsenv/filesystem"
18
- import { createLogger } from "@jsenv/logger"
27
+ import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
28
+ import { createLogger, loggerToLevels } from "@jsenv/logger"
19
29
 
20
- import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
21
- import {
22
- injectQueryParams,
23
- setUrlFilename,
24
- } from "@jsenv/utils/urls/url_utils.js"
25
- import { createUrlVersionGenerator } from "@jsenv/utils/urls/url_version_generator.js"
30
+ import { createTaskLog } from "@jsenv/log"
31
+ import { createVersionGenerator } from "@jsenv/utils/versioning/version_generator.js"
26
32
  import { generateSourcemapUrl } from "@jsenv/utils/sourcemap/sourcemap_utils.js"
27
33
  import {
28
34
  parseHtmlString,
29
35
  stringifyHtmlAst,
30
36
  } from "@jsenv/utils/html_ast/html_ast.js"
37
+ import { sortByDependencies } from "@jsenv/utils/graph/sort_by_dependencies.js"
31
38
 
32
- import { defaultRuntimeSupport } from "../omega/runtime_support/default_runtime_support.js"
33
- import { jsenvPluginInline } from "../omega/core_plugins/inline/jsenv_plugin_inline.js"
34
39
  import { createUrlGraph } from "../omega/url_graph.js"
35
- import { getCorePlugins } from "../omega/core_plugins.js"
40
+ import { jsenvPluginUrlAnalysis } from "../plugins/url_analysis/jsenv_plugin_url_analysis.js"
41
+ import { jsenvPluginInline } from "../plugins/inline/jsenv_plugin_inline.js"
42
+ import { jsenvPluginAsJsClassic } from "../plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js"
43
+ import { getCorePlugins } from "../plugins/plugins.js"
36
44
  import { createKitchen } from "../omega/kitchen.js"
37
45
  import { loadUrlGraph } from "../omega/url_graph/url_graph_load.js"
38
46
  import { createUrlGraphSummary } from "../omega/url_graph/url_graph_report.js"
39
- import { sortUrlGraphByDependencies } from "../omega/url_graph/url_graph_sort.js"
47
+ import { isWebWorkerEntryPointReference } from "../omega/web_workers.js"
40
48
 
49
+ import { GRAPH } from "./graph_utils.js"
41
50
  import { createBuilUrlsGenerator } from "./build_urls_generator.js"
42
- import { injectVersionMappings } from "./inject_version_mappings.js"
43
- import { jsenvPluginBundleJsModule } from "./plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js"
44
- import { jsenvPluginMinifyJs } from "./plugins/minify_js/jsenv_plugin_minify_js.js"
45
- import { jsenvPluginMinifyHtml } from "./plugins/minify_html/jsenv_plugin_minify_html.js"
51
+ import { injectGlobalVersionMapping } from "./inject_global_version_mappings.js"
52
+ import { injectServiceWorkerUrls } from "./inject_service_worker_urls.js"
53
+ import { resyncRessourceHints } from "./resync_ressource_hints.js"
46
54
 
55
+ /**
56
+ * Generate an optimized version of source files into a directory
57
+ * @param {Object} buildParameters
58
+ * @param {string|url} buildParameters.rootDirectoryUrl
59
+ * Directory containing source files
60
+ * @param {string|url} buildParameters.buildDirectoryUrl
61
+ * Directory where optimized files will be written
62
+ * @param {object} buildParameters.entryPoints
63
+ * Describe entry point paths and control their names in the build directory
64
+ * @param {object} buildParameters.runtimeCompat
65
+ * Code generated will be compatible with these runtimes
66
+ * @param {string="/"} buildParameters.baseUrl
67
+ * All urls in build file contents are prefixed with this url
68
+ * @param {boolean|object} [buildParameters.minification=true]
69
+ * Minify build file contents
70
+ * @param {boolean} [buildParameters.versioning=true]
71
+ * Controls if url in build file contents are versioned
72
+ * @param {('search_param'|'filename')} [buildParameters.versioningMethod="search_param"]
73
+ * Controls how url are versioned
74
+ * @param {boolean|string} [buildParameters.sourcemaps=false]
75
+ * Generate sourcemaps in the build directory
76
+ * @return {Object} buildReturnValue
77
+ * @return {Object} buildReturnValue.buildFileContents
78
+ * Contains all build file paths relative to the build directory and their content
79
+ * @return {Object} buildReturnValue.buildInlineContents
80
+ * Contains content that is inline into build files
81
+ * @return {Object} buildReturnValue.buildManifest
82
+ * Map build file paths without versioning to versioned file paths
83
+ */
47
84
  export const build = async ({
48
85
  signal = new AbortController().signal,
86
+ handleSIGINT = true,
49
87
  logLevel = "info",
50
88
  rootDirectoryUrl,
51
89
  buildDirectoryUrl,
52
90
  entryPoints = {},
53
- // for now it's here but I think preview will become an other script
54
- // that will just pass different options to build project
55
- // and this function will be agnostic about "preview" concept
56
- isPreview = false,
91
+ baseUrl = "/",
92
+
93
+ // default runtimeCompat corresponds to dynamic import
94
+ // (meaning we can keep <script type="module">)
95
+ runtimeCompat = {
96
+ // android: "8",
97
+ chrome: "63",
98
+ edge: "79",
99
+ firefox: "67",
100
+ ios: "11.3",
101
+ opera: "50",
102
+ safari: "11.3",
103
+ samsung: "8.2",
104
+ },
57
105
  plugins = [],
58
- htmlSupervisor,
106
+ sourcemaps = false,
107
+ sourcemapsSourcesContent,
108
+ urlAnalysis = {},
59
109
  nodeEsmResolution,
60
110
  fileSystemMagicResolution,
61
- babel,
62
- runtimeSupport = defaultRuntimeSupport,
63
- sourcemaps = isPreview ? "file" : false,
64
-
111
+ directoryReferenceAllowed,
112
+ injectedGlobals,
113
+ transpilation = {},
65
114
  bundling = true,
66
- minify = true,
67
- versioning = "filename", // "filename", "search_param", "none"
115
+ minification = true,
116
+ versioning = true,
117
+ versioningMethod = "search_param", // "filename", "search_param"
68
118
  lineBreakNormalization = process.platform === "win32",
69
119
 
70
- writeOnFileSystem = true,
120
+ clientFiles = {
121
+ "./**": true,
122
+ "./**/.*/": false, // any folder starting with a dot is ignored (includes .git,.jsenv for instance)
123
+ "./dist/": false,
124
+ "./**/node_modules/": false,
125
+ },
126
+ cooldownBetweenFileEvents,
127
+ watch = false,
128
+
71
129
  buildDirectoryClean = true,
72
- baseUrl = "/",
130
+ writeOnFileSystem = true,
131
+ writeGeneratedFiles = false,
73
132
  assetManifest = true,
74
133
  assetManifestFileRelativeUrl = "asset-manifest.json",
75
134
  }) => {
76
- const logger = createLogger({ logLevel })
135
+ const operation = Abort.startOperation()
136
+ operation.addAbortSignal(signal)
137
+ if (handleSIGINT) {
138
+ operation.addAbortSource((abort) => {
139
+ return raceProcessTeardownEvents(
140
+ {
141
+ SIGINT: true,
142
+ },
143
+ abort,
144
+ )
145
+ })
146
+ }
147
+
77
148
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
78
149
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
79
150
  assertEntryPoints({ entryPoints })
80
- if (!["filename", "search_param", "none"].includes(versioning)) {
151
+ if (!["filename", "search_param"].includes(versioningMethod)) {
81
152
  throw new Error(
82
- `Unexpected "versioning": must be "filename", "search_param" or "none"; got ${versioning}`,
153
+ `Unexpected "versioningMethod": must be "filename", "search_param"; got ${versioning}`,
83
154
  )
84
155
  }
85
156
 
86
- const entryPointKeys = Object.keys(entryPoints)
87
- if (entryPointKeys.length === 1) {
88
- logger.info(`
157
+ const runBuild = async ({ signal, logLevel }) => {
158
+ const logger = createLogger({ logLevel })
159
+ const buildOperation = Abort.startOperation()
160
+ const infoLogsAreDisabled = !loggerToLevels(logger).info
161
+ buildOperation.addAbortSignal(signal)
162
+ const entryPointKeys = Object.keys(entryPoints)
163
+ if (entryPointKeys.length === 1) {
164
+ logger.info(`
89
165
  build "${entryPointKeys[0]}"`)
90
- } else {
91
- logger.info(`
166
+ } else {
167
+ logger.info(`
92
168
  build ${entryPointKeys.length} entry points`)
93
- }
94
- const rawGraph = createUrlGraph()
95
- const prebuildTask = createTaskLog(logger, "prebuild")
96
- let urlCount = 0
97
- const rawGraphKitchen = createKitchen({
98
- signal,
99
- logger,
100
- rootDirectoryUrl,
101
- urlGraph: rawGraph,
102
- plugins: [
103
- ...plugins,
104
- {
105
- name: "jsenv:build_log",
106
- appliesDuring: { build: true },
107
- cooked: () => {
108
- urlCount++
109
- prebuildTask.setRightText(urlCount)
110
- },
111
- },
112
- ...getCorePlugins({
113
- htmlSupervisor,
114
- nodeEsmResolution,
115
- fileSystemMagicResolution,
116
- babel,
117
- }),
118
- jsenvPluginBundleJsModule(),
119
- ...(minify ? [jsenvPluginMinifyJs(), jsenvPluginMinifyHtml()] : []),
120
- ],
121
- scenario: "build",
122
- sourcemaps,
123
- })
124
- const entryUrls = []
125
- try {
126
- await loadUrlGraph({
169
+ }
170
+ const useExplicitJsClassicConversion = entryPointKeys.some((key) =>
171
+ entryPoints[key].includes("?as_js_classic"),
172
+ )
173
+
174
+ const rawGraph = createUrlGraph()
175
+ const prebuildTask = createTaskLog("prebuild", {
176
+ disabled: infoLogsAreDisabled,
177
+ })
178
+ let urlCount = 0
179
+ const prebuildRedirections = new Map()
180
+ const rawGraphKitchen = createKitchen({
181
+ signal,
182
+ logger,
183
+ rootDirectoryUrl,
127
184
  urlGraph: rawGraph,
128
- kitchen: rawGraphKitchen,
129
- outDirectoryUrl: new URL(`.jsenv/build/`, rootDirectoryUrl),
130
- runtimeSupport,
131
- startLoading: (cookEntryFile) => {
132
- Object.keys(entryPoints).forEach((key) => {
133
- const [, entryUrlInfo] = cookEntryFile({
134
- trace: `"${key}" in entryPoints parameter`,
135
- type: "entry_point",
136
- specifier: key,
137
- })
138
- entryUrls.push(entryUrlInfo.url)
139
- })
140
- },
185
+ scenario: "build",
186
+ sourcemaps,
187
+ sourcemapsSourcesContent,
188
+ runtimeCompat,
189
+ writeGeneratedFiles,
190
+ plugins: [
191
+ ...plugins,
192
+ {
193
+ name: "jsenv:build_log",
194
+ appliesDuring: { build: true },
195
+ cooked: () => {
196
+ urlCount++
197
+ prebuildTask.setRightText(urlCount)
198
+ },
199
+ },
200
+ {
201
+ appliesDuring: "build",
202
+ fetchUrlContent: (urlInfo, context) => {
203
+ if (context.reference.original) {
204
+ prebuildRedirections.set(
205
+ context.reference.original.url,
206
+ context.reference.url,
207
+ )
208
+ }
209
+ },
210
+ formatUrl: (reference) => {
211
+ if (!reference.shouldHandle) {
212
+ return `ignore:${reference.specifier}`
213
+ }
214
+ return null
215
+ },
216
+ },
217
+ ...getCorePlugins({
218
+ rootDirectoryUrl,
219
+ urlGraph: rawGraph,
220
+ scenario: "build",
221
+ runtimeCompat,
222
+
223
+ urlAnalysis,
224
+ nodeEsmResolution,
225
+ fileSystemMagicResolution,
226
+ directoryReferenceAllowed,
227
+ injectedGlobals,
228
+ transpilation: {
229
+ ...transpilation,
230
+ babelHelpersAsImport: !useExplicitJsClassicConversion,
231
+ jsModuleAsJsClassic: false,
232
+ },
233
+ minification,
234
+ bundling,
235
+ }),
236
+ ],
141
237
  })
142
- } catch (e) {
143
- prebuildTask.fail()
144
- throw e
145
- }
146
- // here we can perform many checks such as ensuring ressource hints are used
147
- prebuildTask.done()
148
- logger.debug(
149
- `raw graph urls:
150
- ${Object.keys(rawGraph.urlInfos).join("\n")}`,
151
- )
238
+ const entryUrls = []
239
+ try {
240
+ await loadUrlGraph({
241
+ operation: buildOperation,
242
+ urlGraph: rawGraph,
243
+ kitchen: rawGraphKitchen,
244
+ writeGeneratedFiles,
245
+ outDirectoryUrl: new URL(`.jsenv/build/`, rootDirectoryUrl),
246
+ startLoading: (cookEntryFile) => {
247
+ Object.keys(entryPoints).forEach((key) => {
248
+ const [, entryUrlInfo] = cookEntryFile({
249
+ trace: `"${key}" in entryPoints parameter`,
250
+ type: "entry_point",
251
+ specifier: key,
252
+ })
253
+ entryUrls.push(entryUrlInfo.url)
254
+ entryUrlInfo.filename = entryPoints[key]
255
+ // entryUrlInfo.data.entryPointKey = key
256
+ })
257
+ },
258
+ })
259
+ } catch (e) {
260
+ prebuildTask.fail()
261
+ throw e
262
+ }
263
+ prebuildTask.done()
152
264
 
153
- const bundleUrlInfos = {}
154
- if (bundling) {
265
+ const buildUrlsGenerator = createBuilUrlsGenerator({
266
+ buildDirectoryUrl,
267
+ })
268
+ const rawUrls = {}
269
+ const bundleRedirections = {}
270
+ const buildUrls = {}
271
+ const bundleUrlInfos = {}
155
272
  const bundlers = {}
156
273
  rawGraphKitchen.pluginController.plugins.forEach((plugin) => {
157
274
  const bundle = plugin.bundle
@@ -164,6 +281,10 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
164
281
  )
165
282
  }
166
283
  Object.keys(bundle).forEach((type) => {
284
+ const bundleFunction = bundle[type]
285
+ if (!bundleFunction) {
286
+ return
287
+ }
167
288
  const bundlerForThatType = bundlers[type]
168
289
  if (bundlerForThatType) {
169
290
  // first plugin to define a bundle hook wins
@@ -183,32 +304,60 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
183
304
  return
184
305
  }
185
306
  }
186
- Object.keys(rawGraph.urlInfos).forEach((rawUrl) => {
187
- const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
188
- if (!rawUrlInfo.data.isEntryPoint) {
189
- return
190
- }
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
- })
307
+ GRAPH.forEach(rawGraph, (rawUrlInfo) => {
308
+ if (rawUrlInfo.data.isEntryPoint) {
309
+ addToBundlerIfAny(rawUrlInfo)
310
+ if (rawUrlInfo.type === "html") {
311
+ rawUrlInfo.dependencies.forEach((dependencyUrl) => {
312
+ const dependencyUrlInfo = rawGraph.getUrlInfo(dependencyUrl)
313
+ if (dependencyUrlInfo.isInline) {
314
+ if (dependencyUrlInfo.type === "js_module") {
315
+ // bundle inline script type module deps
316
+ dependencyUrlInfo.references.forEach((inlineScriptRef) => {
317
+ if (inlineScriptRef.type === "js_import_export") {
318
+ const inlineUrlInfo = rawGraph.getUrlInfo(
319
+ inlineScriptRef.url,
320
+ )
321
+ addToBundlerIfAny(inlineUrlInfo)
322
+ }
323
+ })
324
+ }
325
+ // inline content cannot be bundled
326
+ return
203
327
  }
204
- // inline content cannot be bundled
205
- return
328
+ addToBundlerIfAny(dependencyUrlInfo)
329
+ })
330
+ rawUrlInfo.references.forEach((reference) => {
331
+ if (
332
+ reference.isRessourceHint &&
333
+ reference.expectedType === "js_module"
334
+ ) {
335
+ const referencedUrlInfo = rawGraph.getUrlInfo(reference.url)
336
+ if (
337
+ referencedUrlInfo &&
338
+ // something else than the ressource hint is using this url
339
+ referencedUrlInfo.dependents.size > 0
340
+ ) {
341
+ addToBundlerIfAny(referencedUrlInfo)
342
+ }
343
+ }
344
+ })
345
+ return
346
+ }
347
+ }
348
+ // File referenced with new URL('./file.js', import.meta.url)
349
+ // are entry points that can be bundled
350
+ // For instance we will bundle service worker/workers detected like this
351
+ if (rawUrlInfo.type === "js_module") {
352
+ rawUrlInfo.references.forEach((reference) => {
353
+ if (reference.type === "js_url_specifier") {
354
+ const urlInfo = rawGraph.getUrlInfo(reference.url)
355
+ addToBundlerIfAny(urlInfo)
206
356
  }
207
- addToBundlerIfAny(dependencyUrlInfo)
208
357
  })
209
- return
210
358
  }
211
359
  })
360
+ const bundleInternalRedirections = {}
212
361
  await Object.keys(bundlers).reduce(async (previous, type) => {
213
362
  await previous
214
363
  const bundler = bundlers[type]
@@ -216,7 +365,9 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
216
365
  if (urlInfosToBundle.length === 0) {
217
366
  return
218
367
  }
219
- const bundleTask = createTaskLog(logger, `bundle "${type}"`)
368
+ const bundleTask = createTaskLog(`bundle "${type}"`, {
369
+ disabled: infoLogsAreDisabled,
370
+ })
220
371
  try {
221
372
  const bundlerGeneratedUrlInfos =
222
373
  await rawGraphKitchen.pluginController.callAsyncHook(
@@ -227,27 +378,46 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
227
378
  },
228
379
  urlInfosToBundle,
229
380
  {
230
- signal,
231
- logger,
232
- rootDirectoryUrl,
381
+ ...rawGraphKitchen.kitchenContext,
233
382
  buildDirectoryUrl,
234
- urlGraph: rawGraph,
235
- runtimeSupport,
236
- sourcemaps,
237
383
  },
238
384
  )
239
385
  Object.keys(bundlerGeneratedUrlInfos).forEach((url) => {
240
- const bundleUrlInfo = bundlerGeneratedUrlInfos[url]
241
386
  const rawUrlInfo = rawGraph.getUrlInfo(url)
242
- bundleUrlInfos[url] = {
387
+ const bundlerGeneratedUrlInfo = bundlerGeneratedUrlInfos[url]
388
+ const bundleUrlInfo = {
243
389
  type,
244
- ...bundleUrlInfo,
390
+ subtype: rawUrlInfo ? rawUrlInfo.subtype : undefined,
391
+ filename: rawUrlInfo ? rawUrlInfo.filename : undefined,
392
+ originalUrl: rawUrlInfo ? rawUrlInfo.originalUrl : undefined,
393
+ originalContent: rawUrlInfo
394
+ ? rawUrlInfo.originalContent
395
+ : undefined,
396
+ ...bundlerGeneratedUrlInfo,
245
397
  data: {
246
398
  ...(rawUrlInfo ? rawUrlInfo.data : {}),
247
- ...bundleUrlInfo.data,
399
+ ...bundlerGeneratedUrlInfo.data,
248
400
  fromBundle: true,
249
401
  },
250
402
  }
403
+ const buildUrl = buildUrlsGenerator.generate(url, {
404
+ urlInfo: bundleUrlInfo,
405
+ })
406
+ bundleRedirections[url] = buildUrl
407
+ rawUrls[buildUrl] = url
408
+ bundleUrlInfos[buildUrl] = bundleUrlInfo
409
+ if (buildUrl.includes("?")) {
410
+ bundleUrlInfos[asUrlWithoutSearch(buildUrl)] = bundleUrlInfo
411
+ }
412
+ if (bundlerGeneratedUrlInfo.data.bundleRelativeUrl) {
413
+ const urlForBundler = new URL(
414
+ bundlerGeneratedUrlInfo.data.bundleRelativeUrl,
415
+ buildDirectoryUrl,
416
+ ).href
417
+ if (urlForBundler !== buildUrl) {
418
+ bundleInternalRedirections[urlForBundler] = buildUrl
419
+ }
420
+ }
251
421
  })
252
422
  } catch (e) {
253
423
  bundleTask.fail()
@@ -255,482 +425,817 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
255
425
  }
256
426
  bundleTask.done()
257
427
  }, Promise.resolve())
258
- }
259
428
 
260
- const buildUrlsGenerator = createBuilUrlsGenerator({
261
- buildDirectoryUrl,
262
- })
263
- const rawUrls = {}
264
- const buildUrls = {}
265
- const finalGraph = createUrlGraph()
266
- const optimizeHooks = rawGraphKitchen.pluginController.addHook("optimize")
267
- const finalGraphKitchen = createKitchen({
268
- logger,
269
- rootDirectoryUrl,
270
- urlGraph: finalGraph,
271
- // Inline content, such as <script> inside html, is transformed during the previous phase.
272
- // If we read the inline content it would be considered as the original content.
273
- // - It could be "fixed" by taking into account sourcemap and consider sourcemap sources
274
- // as the original content.
275
- // - But it would not work when sourcemap are not generated
276
- // - would be a bit slower
277
- // - So instead of reading the inline content directly, we search into raw graph
278
- // to get "originalContent" and "sourcemap"
279
- loadInlineUrlInfos: (finalUrlInfo) => {
280
- const rawUrl = finalUrlInfo.data.rawUrl
281
- const bundleUrlInfo = bundleUrlInfos[rawUrl]
282
- const urlInfo = bundleUrlInfo || finalUrlInfo
283
- const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
284
- return {
285
- originalContent: rawUrlInfo ? rawUrlInfo.originalContent : undefined,
286
- sourcemap: bundleUrlInfo
287
- ? bundleUrlInfo.sourcemap
288
- : rawUrlInfo
289
- ? rawUrlInfo.sourcemap
290
- : undefined,
291
- contentType: urlInfo.contentType,
292
- content: urlInfo.content,
293
- }
294
- },
295
- plugins: [
296
- jsenvPluginInline(),
297
- {
298
- name: "jsenv:postbuild",
299
- appliesDuring: { build: true },
300
- resolve: (reference) => {
301
- if (reference.specifier[0] === "/") {
302
- const url = new URL(reference.specifier.slice(1), rootDirectoryUrl)
303
- .href
304
- return url
305
- }
306
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
307
- if (parentUrlInfo && parentUrlInfo.data.fromBundle) {
308
- // code generated by rollup contains specifier relative
309
- // to the generated file.
310
- // This file does not exists yet we must resolve against the raw url, not the build url
311
- const parentRawUrl = parentUrlInfo.data.rawUrl
312
- const rawUrl = new URL(reference.specifier, parentRawUrl).href
313
- return rawUrl
314
- }
315
- return new URL(reference.specifier, reference.parentUrl).href
316
- },
317
- normalize: (reference) => {
318
- if (!reference.url.startsWith("file:")) {
319
- return null
320
- }
321
- // already a build url
322
- const rawUrl = rawUrls[reference.url]
323
- if (rawUrl) {
324
- reference.data.rawUrl = rawUrl
325
- return reference.url
326
- }
327
- const bundleUrlInfo = bundleUrlInfos[reference.url]
328
- // from rollup or postcss
329
- if (bundleUrlInfo) {
330
- const buildUrl = buildUrlsGenerator.generate(
331
- reference.url,
332
- bundleUrlInfo,
333
- )
334
- reference.data.rawUrl = reference.url
335
- rawUrls[buildUrl] = reference.url
336
- return buildUrl
337
- }
338
- const rawUrlInfo = rawGraph.getUrlInfo(reference.url)
339
- // files from root directory but not given to rollup nor postcss
340
- if (rawUrlInfo) {
341
- const buildUrl = buildUrlsGenerator.generate(
342
- reference.url,
343
- rawUrlInfo,
344
- )
345
- reference.data.rawUrl = reference.url
346
- rawUrls[buildUrl] = reference.url
347
- return buildUrl
348
- }
349
- if (reference.isInline) {
350
- const rawUrl = Object.keys(rawGraph.urlInfos).find((url) => {
351
- const rawUrlInfo = rawGraph.urlInfos[url]
352
- if (!rawUrlInfo.isInline) {
353
- return false
429
+ const urlAnalysisPlugin = jsenvPluginUrlAnalysis({
430
+ rootDirectoryUrl,
431
+ ...urlAnalysis,
432
+ })
433
+ const postBuildRedirections = {}
434
+ const finalGraph = createUrlGraph()
435
+ const optimizeUrlContentHooks =
436
+ rawGraphKitchen.pluginController.addHook("optimizeUrlContent")
437
+ const finalGraphKitchen = createKitchen({
438
+ logger,
439
+ rootDirectoryUrl,
440
+ urlGraph: finalGraph,
441
+ scenario: "build",
442
+ sourcemaps,
443
+ sourcemapsSourcesContent,
444
+ sourcemapsRelativeSources: !versioning,
445
+ runtimeCompat,
446
+ writeGeneratedFiles,
447
+ plugins: [
448
+ urlAnalysisPlugin,
449
+ jsenvPluginAsJsClassic({ systemJsInjection: true }),
450
+ jsenvPluginInline({ fetchInlineUrls: false }),
451
+ {
452
+ name: "jsenv:postbuild",
453
+ appliesDuring: "build",
454
+ resolveUrl: (reference) => {
455
+ const performInternalRedirections = (url) => {
456
+ const prebuildRedirection = prebuildRedirections.get(url)
457
+ if (prebuildRedirection) {
458
+ logger.debug(
459
+ `\nprebuild redirection\n${url} ->\n${prebuildRedirection}\n`,
460
+ )
461
+ url = prebuildRedirection
354
462
  }
355
- if (rawUrlInfo.content === reference.content) {
356
- return true
463
+ const bundleRedirection = bundleRedirections[url]
464
+ if (bundleRedirection) {
465
+ logger.debug(
466
+ `\nbundler redirection\n${url} ->\n${bundleRedirection}\n`,
467
+ )
468
+ url = bundleRedirection
357
469
  }
358
- return false
359
- })
360
- if (!rawUrl) {
361
- throw new Error(`cannot find raw url`)
470
+ const bundleInternalRedirection = bundleInternalRedirections[url]
471
+ if (bundleInternalRedirection) {
472
+ logger.debug(
473
+ `\nbundler internal redirection\n${url} ->\n${bundleInternalRedirection}\n`,
474
+ )
475
+ url = bundleInternalRedirection
476
+ }
477
+ return url
362
478
  }
363
- const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
364
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
365
- const buildUrl = buildUrlsGenerator.generate(
366
- reference.url,
367
- rawUrlInfo,
368
- parentUrlInfo,
369
- )
370
- rawUrls[buildUrl] = reference.url
371
- reference.data.rawUrl = rawUrl
372
- return buildUrl
373
- }
374
- if (reference.type === "sourcemap_comment") {
375
- // inherit parent build url
376
- return generateSourcemapUrl(reference.parentUrl)
377
- }
378
- // files generated during the final graph (sourcemaps)
379
- // const finalUrlInfo = finalGraph.getUrlInfo(url)
380
- const buildUrl = buildUrlsGenerator.generate(reference.url, {
381
- data: {},
382
- type: "asset",
383
- })
384
- return buildUrl
385
- },
386
- formatReferencedUrl: (reference) => {
387
- if (!reference.url.startsWith("file:")) {
388
- return null
389
- }
390
- if (!urlIsInsideOf(reference.url, buildDirectoryUrl)) {
391
- throw new Error(
392
- `urls should be inside build directory at this stage, found "${reference.url}"`,
393
- )
394
- }
395
- // if a file is in the same directory we could prefer the relative notation
396
- // but to keep things simple let's keep the notation relative to baseUrl for now
397
- const specifier = `${baseUrl}${urlToRelativeUrl(
398
- reference.url,
399
- buildDirectoryUrl,
400
- )}`
401
- buildUrls[specifier] = reference.url
402
- return specifier
403
- },
404
- load: (finalUrlInfo) => {
405
- const rawUrl = finalUrlInfo.data.rawUrl
406
- const bundleUrlInfo = bundleUrlInfos[rawUrl]
407
- const urlInfo = bundleUrlInfo || rawGraph.getUrlInfo(rawUrl)
408
- return {
409
- data: bundleUrlInfo ? bundleUrlInfo.data : undefined,
410
- originalContent: urlInfo.originalContent,
411
- contentType: urlInfo.contentType,
412
- content: urlInfo.content,
413
- sourcemap: urlInfo.sourcemap,
414
- }
415
- },
416
- transform: {
417
- html: (urlInfo) => {
418
- const htmlAst = parseHtmlString(urlInfo.content, {
419
- storeOriginalPositions: false,
420
- })
421
- return {
422
- content: stringifyHtmlAst(htmlAst, {
423
- removeOriginalPositionAttributes: true,
424
- }),
479
+
480
+ if (reference.type === "filesystem") {
481
+ const parentRawUrl = rawUrls[reference.parentUrl]
482
+ const baseUrl = ensurePathnameTrailingSlash(parentRawUrl)
483
+ return performInternalRedirections(
484
+ new URL(reference.specifier, baseUrl).href,
485
+ )
486
+ }
487
+ if (reference.specifier[0] === "/") {
488
+ return performInternalRedirections(
489
+ new URL(reference.specifier.slice(1), buildDirectoryUrl).href,
490
+ )
425
491
  }
492
+ return performInternalRedirections(
493
+ new URL(
494
+ reference.specifier,
495
+ reference.baseUrl || reference.parentUrl,
496
+ ).href,
497
+ )
426
498
  },
427
- },
428
- },
429
- {
430
- name: "jsenv:optimize",
431
- appliesDuring: { build: true },
432
- transform: async (urlInfo, context) => {
433
- if (optimizeHooks.length) {
434
- await rawGraphKitchen.pluginController.callAsyncHooks(
435
- "optimize",
436
- urlInfo,
437
- context,
438
- async (optimizeReturnValue) => {
439
- await finalGraphKitchen.urlInfoTransformer.applyFinalTransformations(
440
- urlInfo,
441
- optimizeReturnValue,
499
+ // redirecting urls into the build directory
500
+ redirectUrl: (reference) => {
501
+ if (!reference.url.startsWith("file:")) {
502
+ return null
503
+ }
504
+ // already a build url
505
+ const rawUrl = rawUrls[reference.url]
506
+ if (rawUrl) {
507
+ return reference.url
508
+ }
509
+ // from "js_module_as_js_classic":
510
+ // - injecting "?as_js_classic" for the first time
511
+ // - injecting "?as_js_classic" because the parentUrl has it
512
+ if (reference.original) {
513
+ const referenceOriginalUrl = reference.original.url
514
+ let originalBuildUrl
515
+ if (urlIsInsideOf(referenceOriginalUrl, buildDirectoryUrl)) {
516
+ originalBuildUrl = referenceOriginalUrl
517
+ } else {
518
+ originalBuildUrl = Object.keys(rawUrls).find(
519
+ (key) => rawUrls[key] === referenceOriginalUrl,
442
520
  )
443
- },
444
- )
445
- }
446
- },
447
- },
448
- ],
449
- scenario: "build",
450
- sourcemaps,
451
- })
452
- const buildTask = createTaskLog(logger, "build")
453
- const postBuildEntryUrls = []
454
- try {
455
- await loadUrlGraph({
456
- urlGraph: finalGraph,
457
- kitchen: finalGraphKitchen,
458
- outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
459
- runtimeSupport,
460
- startLoading: (cookEntryFile) => {
461
- entryUrls.forEach((entryUrl) => {
462
- const [, postBuildEntryUrlInfo] = cookEntryFile({
463
- trace: `entryPoint`,
464
- type: "entry_point",
465
- specifier: entryUrl,
466
- })
467
- postBuildEntryUrls.push(postBuildEntryUrlInfo.url)
468
- })
469
- },
470
- })
471
- } catch (e) {
472
- buildTask.fail()
473
- throw e
474
- }
475
- buildTask.done()
476
-
477
- logger.debug(
478
- `graph urls pre-versioning:
479
- ${Object.keys(finalGraph.urlInfos).join("\n")}`,
480
- )
481
- if (versioning !== "none") {
482
- const versioningTask = createTaskLog(logger, "inject version in urls")
483
- try {
484
- const urlsSorted = sortUrlGraphByDependencies(finalGraph)
485
- urlsSorted.forEach((url) => {
486
- if (url.startsWith("data:")) {
487
- return
488
- }
489
- const urlInfo = finalGraph.getUrlInfo(url)
490
- if (urlInfo.type === "sourcemap") {
491
- return
492
- }
493
- if (urlInfo.isInline) {
494
- return
495
- }
496
- const urlVersionGenerator = createUrlVersionGenerator()
497
- urlVersionGenerator.augmentWithContent({
498
- content: urlInfo.content,
499
- contentType: urlInfo.contentType,
500
- lineBreakNormalization,
501
- })
502
- urlInfo.dependencies.forEach((dependencyUrl) => {
503
- const dependencyUrlInfo = finalGraph.getUrlInfo(dependencyUrl)
504
- if (dependencyUrlInfo.isInline) {
505
- // this content is part of the file, no need to take into account twice
506
- return
507
- }
508
- if (dependencyUrlInfo.data.version) {
509
- urlVersionGenerator.augmentWithDependencyVersion(
510
- dependencyUrlInfo.data.version,
511
- )
512
- } else {
513
- // because all dependencies are know, if the dependency has no version
514
- // it means there is a circular dependency between this file
515
- // and it's dependency
516
- // in that case we'll use the dependency content
517
- urlVersionGenerator.augmentWithContent({
518
- content: dependencyUrlInfo.content,
519
- contentType: dependencyUrlInfo.contentType,
520
- lineBreakNormalization,
521
- })
522
- }
523
- })
524
- urlInfo.data.version = urlVersionGenerator.generate()
525
- urlInfo.data.versionedUrl = injectVersionIntoBuildUrl({
526
- buildUrl: urlInfo.url,
527
- version: urlInfo.data.version,
528
- versioning,
529
- })
530
- })
531
- const versionMappings = {}
532
- const usedVersionMappings = []
533
- const versioningKitchen = createKitchen({
534
- logger,
535
- rootDirectoryUrl: buildDirectoryUrl,
536
- urlGraph: finalGraph,
537
- loadInlineUrlInfos: (versionedUrlInfo) => {
538
- const rawUrlInfo = rawGraph.getUrlInfo(versionedUrlInfo.data.rawUrl)
539
- const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
540
- return {
541
- originalContent: rawUrlInfo
542
- ? rawUrlInfo.originalContent
543
- : undefined,
544
- sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
545
- contentType: versionedUrlInfo.contentType,
546
- content: versionedUrlInfo.content,
547
- }
548
- },
549
- plugins: [
550
- jsenvPluginInline({
551
- allowEscapeForVersioning: true,
552
- }),
553
- {
554
- name: "jsenv:versioning",
555
- appliesDuring: { build: true },
556
- resolve: (reference) => {
557
- const buildUrl = buildUrls[reference.specifier]
558
- if (buildUrl) {
559
- return buildUrl
560
521
  }
561
- const url = new URL(reference.specifier, reference.parentUrl).href
562
- return url
563
- },
564
- formatReferencedUrl: (reference) => {
565
- if (reference.isInline) {
566
- return null
522
+ let rawUrl
523
+ if (urlIsInsideOf(reference.url, buildDirectoryUrl)) {
524
+ const originalBuildUrl =
525
+ postBuildRedirections[referenceOriginalUrl]
526
+ rawUrl = originalBuildUrl
527
+ ? rawUrls[originalBuildUrl]
528
+ : reference.url
529
+ } else {
530
+ rawUrl = reference.url
567
531
  }
568
- // specifier comes from "normalize" hook done a bit earlier in this file
569
- // we want to get back their build url to access their infos
570
- const referencedUrlInfo = finalGraph.getUrlInfo(reference.url)
571
- if (referencedUrlInfo.data.isEntryPoint) {
572
- return reference.specifier
532
+ // the url info do not exists yet (it will be created after this "normalize" hook)
533
+ // And the content will be generated when url is cooked by url graph loader.
534
+ // Here we just want to reserve an url for that file
535
+ const buildUrl = buildUrlsGenerator.generate(rawUrl, {
536
+ urlInfo: {
537
+ data: {
538
+ ...reference.data,
539
+ isWebWorkerEntryPoint:
540
+ isWebWorkerEntryPointReference(reference),
541
+ },
542
+ type: reference.expectedType,
543
+ subtype: reference.expectedSubtype,
544
+ filename: reference.filename,
545
+ },
546
+ })
547
+ postBuildRedirections[originalBuildUrl] = buildUrl
548
+ rawUrls[buildUrl] = rawUrl
549
+ return buildUrl
550
+ }
551
+ if (reference.isInline) {
552
+ const rawUrlInfo = GRAPH.find(rawGraph, (rawUrlInfo) => {
553
+ if (!rawUrlInfo.isInline) {
554
+ return false
555
+ }
556
+ if (rawUrlInfo.content === reference.content) {
557
+ return true
558
+ }
559
+ if (rawUrlInfo.originalContent === reference.content) {
560
+ return true
561
+ }
562
+ return false
563
+ })
564
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
565
+ if (!rawUrlInfo) {
566
+ // generated during final graph
567
+ // (happens for JSON.parse injected for import assertions for instance)
568
+ // throw new Error(`cannot find raw url for "${reference.url}"`)
569
+ return reference.url
573
570
  }
574
- // data:* urls and so on
575
- if (!referencedUrlInfo.url.startsWith("file:")) {
576
- return null
571
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
572
+ urlInfo: rawUrlInfo,
573
+ parentUrlInfo,
574
+ })
575
+ rawUrls[buildUrl] = rawUrlInfo.url
576
+ return buildUrl
577
+ }
578
+ // from "js_module_as_js_classic":
579
+ // - to inject "s.js"
580
+ if (reference.injected) {
581
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
582
+ urlInfo: {
583
+ data: {},
584
+ type: "js_classic",
585
+ },
586
+ })
587
+ rawUrls[buildUrl] = reference.url
588
+ return buildUrl
589
+ }
590
+ const rawUrlInfo = rawGraph.getUrlInfo(reference.url)
591
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
592
+ // files from root directory but not given to rollup nor postcss
593
+ if (rawUrlInfo) {
594
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
595
+ urlInfo: rawUrlInfo,
596
+ parentUrlInfo,
597
+ })
598
+ rawUrls[buildUrl] = rawUrlInfo.url
599
+ if (buildUrl.includes("?")) {
600
+ rawUrls[asUrlWithoutSearch(buildUrl)] = rawUrlInfo.url
577
601
  }
578
- const versionedUrl = referencedUrlInfo.data.versionedUrl
579
- if (!versionedUrl) {
580
- // happens for sourcemap
581
- return `${baseUrl}${urlToRelativeUrl(
582
- referencedUrlInfo.url,
583
- buildDirectoryUrl,
584
- )}`
602
+ return buildUrl
603
+ }
604
+ if (reference.type === "sourcemap_comment") {
605
+ // inherit parent build url
606
+ return generateSourcemapUrl(reference.parentUrl)
607
+ }
608
+ // files generated during the final graph:
609
+ // - sourcemaps
610
+ // const finalUrlInfo = finalGraph.getUrlInfo(url)
611
+ const buildUrl = buildUrlsGenerator.generate(reference.url, {
612
+ urlInfo: {
613
+ data: {},
614
+ type: "asset",
615
+ },
616
+ })
617
+ return buildUrl
618
+ },
619
+ formatUrl: (reference) => {
620
+ if (!reference.generatedUrl.startsWith("file:")) {
621
+ if (!versioning && reference.generatedUrl.startsWith("ignore:")) {
622
+ return reference.generatedUrl.slice("ignore:".length)
585
623
  }
586
- const versionedSpecifier = `${baseUrl}${urlToRelativeUrl(
587
- versionedUrl,
624
+ return null
625
+ }
626
+ if (!urlIsInsideOf(reference.generatedUrl, buildDirectoryUrl)) {
627
+ throw new Error(
628
+ `urls should be inside build directory at this stage, found "${reference.url}"`,
629
+ )
630
+ }
631
+ if (reference.isRessourceHint) {
632
+ // return the raw url, we will resync at the end
633
+ return rawUrls[reference.url]
634
+ }
635
+ // remove eventual search params and hash
636
+ const urlUntilPathname = asUrlUntilPathname(reference.generatedUrl)
637
+ let specifier
638
+ if (baseUrl === "./") {
639
+ const relativeUrl = urlToRelativeUrl(
640
+ urlUntilPathname,
641
+ reference.parentUrl === rootDirectoryUrl
642
+ ? buildDirectoryUrl
643
+ : reference.parentUrl,
644
+ )
645
+ // ensure "./" on relative url (otherwise it could be a "bare specifier")
646
+ specifier =
647
+ relativeUrl[0] === "." ? relativeUrl : `./${relativeUrl}`
648
+ } else {
649
+ // if a file is in the same directory we could prefer the relative notation
650
+ // but to keep things simple let's keep the "absolutely relative" to baseUrl for now
651
+ specifier = `${baseUrl}${urlToRelativeUrl(
652
+ urlUntilPathname,
588
653
  buildDirectoryUrl,
589
654
  )}`
590
- versionMappings[reference.specifier] = versionedSpecifier
591
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
592
- if (parentUrlInfo.jsQuote) {
593
- // the url is inline inside js quotes
594
- usedVersionMappings.push(reference.specifier)
595
- return () =>
596
- `${parentUrlInfo.jsQuote}+__v__(${JSON.stringify(
597
- reference.specifier,
598
- )})+${parentUrlInfo.jsQuote}`
655
+ }
656
+ buildUrls[specifier] = reference.generatedUrl
657
+ return specifier
658
+ },
659
+ fetchUrlContent: async (finalUrlInfo, context) => {
660
+ const fromBundleOrRawGraph = (url) => {
661
+ const bundleUrlInfo = bundleUrlInfos[url]
662
+ if (bundleUrlInfo) {
663
+ logger.debug(`fetching from bundle ${url}`)
664
+ return bundleUrlInfo
599
665
  }
600
- if (
601
- reference.type === "js_import_meta_url_pattern" ||
602
- reference.subtype === "import_dynamic"
603
- ) {
604
- usedVersionMappings.push(reference.specifier)
605
- return () => `__v__(${JSON.stringify(reference.specifier)})`
666
+ const rawUrl = rawUrls[url] || url
667
+ const rawUrlInfo = rawGraph.getUrlInfo(rawUrl)
668
+ if (!rawUrlInfo) {
669
+ throw new Error(`Cannot find url`)
606
670
  }
607
- return versionedSpecifier
608
- },
609
- load: ({ url }) => {
610
- const urlInfo = finalGraph.getUrlInfo(url)
611
- return {
612
- originalContent: urlInfo.originalContent,
613
- contentType: urlInfo.contentType,
614
- content: urlInfo.content,
615
- sourcemap: urlInfo.sourcemap,
671
+ logger.debug(`fetching from raw graph ${url}`)
672
+ if (rawUrlInfo.isInline) {
673
+ // Inline content, such as <script> inside html, is transformed during the previous phase.
674
+ // If we read the inline content it would be considered as the original content.
675
+ // - It could be "fixed" by taking into account sourcemap and consider sourcemap sources
676
+ // as the original content.
677
+ // - But it would not work when sourcemap are not generated
678
+ // - would be a bit slower
679
+ // - So instead of reading the inline content directly, we search into raw graph
680
+ // to get "originalContent" and "sourcemap"
681
+ finalUrlInfo.type = rawUrlInfo.type
682
+ finalUrlInfo.subtype = rawUrlInfo.subtype
683
+ return rawUrlInfo
616
684
  }
617
- },
685
+ return rawUrlInfo
686
+ }
687
+ // reference injected during "postbuild":
688
+ // - happens for "as_js_classic" injecting "s.js"
689
+ if (context.reference.injected) {
690
+ const [ref, rawUrlInfo] = rawGraphKitchen.injectReference({
691
+ type: context.reference.type,
692
+ expectedType: context.reference.expectedType,
693
+ expectedSubtype: context.reference.expectedSubtype,
694
+ parentUrl: rawUrls[context.reference.parentUrl],
695
+ specifier: context.reference.specifier,
696
+ injected: true,
697
+ })
698
+ await rawGraphKitchen.cook(rawUrlInfo, { reference: ref })
699
+ return rawUrlInfo
700
+ }
701
+ // reference updated during "postbuild":
702
+ // - happens for "as_js_classic"
703
+ if (context.reference.original) {
704
+ return fromBundleOrRawGraph(context.reference.original.url)
705
+ }
706
+ return fromBundleOrRawGraph(finalUrlInfo.url)
618
707
  },
619
- ],
620
- scenario: "build",
621
- sourcemaps,
622
- })
623
- // arrange state before reloading all files
624
- Object.keys(finalGraph.urlInfos).forEach((url) => {
625
- const urlInfo = finalGraph.urlInfos[url]
626
- urlInfo.data.promise = null
627
- })
708
+ },
709
+ {
710
+ name: "jsenv:optimize",
711
+ appliesDuring: "build",
712
+ finalizeUrlContent: async (urlInfo, context) => {
713
+ if (optimizeUrlContentHooks.length) {
714
+ await rawGraphKitchen.pluginController.callAsyncHooks(
715
+ "optimizeUrlContent",
716
+ urlInfo,
717
+ context,
718
+ async (optimizeReturnValue) => {
719
+ await finalGraphKitchen.urlInfoTransformer.applyFinalTransformations(
720
+ urlInfo,
721
+ optimizeReturnValue,
722
+ )
723
+ },
724
+ )
725
+ }
726
+ },
727
+ },
728
+ ],
729
+ })
730
+ const buildTask = createTaskLog("build", { disabled: infoLogsAreDisabled })
731
+ const postBuildEntryUrls = []
732
+ try {
628
733
  await loadUrlGraph({
734
+ operation: buildOperation,
629
735
  urlGraph: finalGraph,
630
- kitchen: versioningKitchen,
631
- runtimeSupport,
736
+ kitchen: finalGraphKitchen,
737
+ outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
738
+ writeGeneratedFiles,
739
+ skipRessourceHint: true,
632
740
  startLoading: (cookEntryFile) => {
633
- postBuildEntryUrls.forEach((postBuildEntryUrl) => {
634
- cookEntryFile({
741
+ entryUrls.forEach((entryUrl) => {
742
+ const [, postBuildEntryUrlInfo] = cookEntryFile({
635
743
  trace: `entryPoint`,
636
744
  type: "entry_point",
637
- specifier: postBuildEntryUrl,
745
+ specifier: entryUrl,
638
746
  })
747
+ postBuildEntryUrls.push(postBuildEntryUrlInfo.url)
639
748
  })
640
749
  },
641
750
  })
642
- if (usedVersionMappings.length) {
643
- const versionMappingsNeeded = {}
644
- usedVersionMappings.forEach((specifier) => {
645
- versionMappingsNeeded[specifier] = versionMappings[specifier]
646
- })
647
- await Promise.all(
648
- Object.keys(finalGraph.urlInfos).map(async (buildUrl) => {
649
- const buildUrlInfo = finalGraph.getUrlInfo(buildUrl)
650
- if (!buildUrlInfo.data.isEntryPoint) {
651
- return
652
- }
653
- await injectVersionMappings(buildUrlInfo, {
654
- kitchen: finalGraphKitchen,
655
- versionMappings: versionMappingsNeeded,
656
- })
657
- }),
658
- )
659
- }
660
751
  } catch (e) {
661
- versioningTask.fail()
752
+ buildTask.fail()
662
753
  throw e
663
754
  }
664
- versioningTask.done()
665
- }
755
+ buildTask.done()
666
756
 
667
- const buildFileContents = {}
668
- const buildInlineFileContents = {}
669
- const buildManifest = {}
670
- Object.keys(finalGraph.urlInfos).forEach((url) => {
671
- if (!url.startsWith("file:")) {
672
- return
673
- }
674
- const buildUrlInfo = finalGraph.getUrlInfo(url)
675
- const versionedUrl = buildUrlInfo.data.versionedUrl
676
- const useVersionedUrl = versionedUrl && !buildUrlInfo.data.isEntryPoint
677
- const buildUrl = useVersionedUrl ? versionedUrl : buildUrlInfo.url
678
- if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
679
- throw new Error(`build url outside build directory`)
680
- }
681
- const buildRelativeUrl = urlToRelativeUrl(buildUrl, buildDirectoryUrl)
682
- if (buildUrlInfo.isInline) {
683
- buildInlineFileContents[buildRelativeUrl] = buildUrlInfo.content
684
- } else {
685
- buildFileContents[buildRelativeUrl] = buildUrlInfo.content
757
+ logger.debug(
758
+ `graph urls pre-versioning:
759
+ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
760
+ )
761
+ if (versioning) {
762
+ await applyUrlVersioning({
763
+ buildOperation,
764
+ logger,
765
+ infoLogsAreDisabled,
766
+ buildDirectoryUrl,
767
+ rawUrls,
768
+ buildUrls,
769
+ baseUrl,
770
+ postBuildEntryUrls,
771
+ sourcemaps,
772
+ sourcemapsSourcesContent,
773
+ runtimeCompat,
774
+ writeGeneratedFiles,
775
+ rawGraph,
776
+ urlAnalysisPlugin,
777
+ finalGraph,
778
+ finalGraphKitchen,
779
+ lineBreakNormalization,
780
+ versioningMethod,
781
+ })
686
782
  }
687
- if (useVersionedUrl) {
688
- const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
689
- buildUrlInfo.url,
783
+ GRAPH.forEach(finalGraph, (urlInfo) => {
784
+ if (!urlInfo.shouldHandle) {
785
+ return
786
+ }
787
+ if (!urlInfo.url.startsWith("file:")) {
788
+ return
789
+ }
790
+ if (urlInfo.type === "html") {
791
+ const htmlAst = parseHtmlString(urlInfo.content, {
792
+ storeOriginalPositions: false,
793
+ })
794
+ urlInfo.content = stringifyHtmlAst(htmlAst, {
795
+ removeOriginalPositionAttributes: true,
796
+ })
797
+ }
798
+ const version = urlInfo.data.version
799
+ const useVersionedUrl = version && canUseVersionedUrl(urlInfo, finalGraph)
800
+ const buildUrl = useVersionedUrl ? urlInfo.data.versionedUrl : urlInfo.url
801
+ const buildUrlSpecifier = Object.keys(buildUrls).find(
802
+ (key) => buildUrls[key] === buildUrl,
803
+ )
804
+ urlInfo.data.buildUrl = buildUrl
805
+ urlInfo.data.buildUrlIsVersioned = useVersionedUrl
806
+ urlInfo.data.buildUrlSpecifier = buildUrlSpecifier
807
+ })
808
+ await resyncRessourceHints({
809
+ logger,
810
+ finalGraphKitchen,
811
+ finalGraph,
812
+ rawUrls,
813
+ postBuildRedirections,
814
+ })
815
+ buildOperation.throwIfAborted()
816
+ const cleanupActions = []
817
+ GRAPH.forEach(finalGraph, (urlInfo) => {
818
+ // nothing uses this url anymore
819
+ // - versioning update inline content
820
+ // - file converted for import assertion of js_classic conversion
821
+ if (
822
+ !urlInfo.data.isEntryPoint &&
823
+ urlInfo.type !== "sourcemap" &&
824
+ urlInfo.dependents.size === 0
825
+ ) {
826
+ cleanupActions.push(() => {
827
+ finalGraph.deleteUrlInfo(urlInfo.url)
828
+ })
829
+ }
830
+ })
831
+ cleanupActions.forEach((cleanupAction) => cleanupAction())
832
+ await injectServiceWorkerUrls({
833
+ finalGraphKitchen,
834
+ finalGraph,
835
+ lineBreakNormalization,
836
+ })
837
+ buildOperation.throwIfAborted()
838
+
839
+ const buildManifest = {}
840
+ const buildFileContents = {}
841
+ const buildInlineContents = {}
842
+ GRAPH.forEach(finalGraph, (urlInfo) => {
843
+ if (!urlInfo.shouldHandle) {
844
+ return
845
+ }
846
+ if (!urlInfo.url.startsWith("file:")) {
847
+ return
848
+ }
849
+ if (urlInfo.type === "directory") {
850
+ return
851
+ }
852
+ const buildRelativeUrl = urlToRelativeUrl(
853
+ urlInfo.data.buildUrl,
690
854
  buildDirectoryUrl,
691
855
  )
692
- buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
856
+ if (urlInfo.isInline) {
857
+ buildInlineContents[buildRelativeUrl] = urlInfo.content
858
+ } else {
859
+ buildFileContents[buildRelativeUrl] = urlInfo.content
860
+ const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
861
+ urlInfo.url,
862
+ buildDirectoryUrl,
863
+ )
864
+ buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
865
+ }
866
+ })
867
+ if (writeOnFileSystem) {
868
+ if (buildDirectoryClean) {
869
+ await ensureEmptyDirectory(buildDirectoryUrl)
870
+ }
871
+ const buildRelativeUrls = Object.keys(buildFileContents)
872
+ await Promise.all(
873
+ buildRelativeUrls.map(async (buildRelativeUrl) => {
874
+ await writeFile(
875
+ new URL(buildRelativeUrl, buildDirectoryUrl),
876
+ buildFileContents[buildRelativeUrl],
877
+ )
878
+ }),
879
+ )
880
+ if (versioning && assetManifest && Object.keys(buildManifest).length) {
881
+ await writeFile(
882
+ new URL(assetManifestFileRelativeUrl, buildDirectoryUrl),
883
+ JSON.stringify(buildManifest, null, " "),
884
+ )
885
+ }
886
+ }
887
+ logger.info(createUrlGraphSummary(finalGraph, { title: "build files" }))
888
+ return {
889
+ buildFileContents,
890
+ buildInlineContents,
891
+ buildManifest,
693
892
  }
893
+ }
894
+
895
+ if (!watch) {
896
+ return runBuild({ signal: operation.signal, logLevel })
897
+ }
898
+
899
+ let resolveFirstBuild
900
+ let rejectFirstBuild
901
+ const firstBuildPromise = new Promise((resolve, reject) => {
902
+ resolveFirstBuild = resolve
903
+ rejectFirstBuild = reject
694
904
  })
695
- logger.debug(
696
- `graph urls post-versioning:
697
- ${Object.keys(finalGraph.urlInfos).join("\n")}`,
698
- )
905
+ let buildAbortController
906
+ let watchFilesTask
907
+ const startBuild = async () => {
908
+ const buildTask = createTaskLog("build")
909
+ buildAbortController = new AbortController()
910
+ try {
911
+ const result = await runBuild({
912
+ signal: buildAbortController.signal,
913
+ logLevel: "warn",
914
+ })
915
+ buildTask.done()
916
+ resolveFirstBuild(result)
917
+ watchFilesTask = createTaskLog("watch files")
918
+ } catch (e) {
919
+ if (Abort.isAbortError(e)) {
920
+ buildTask.fail(`build aborted`)
921
+ } else if (e.code === "PARSE_ERROR") {
922
+ buildTask.fail()
923
+ console.error(e.stack)
924
+ watchFilesTask = createTaskLog("watch files")
925
+ } else {
926
+ buildTask.fail()
927
+ rejectFirstBuild(e)
928
+ throw e
929
+ }
930
+ }
931
+ }
699
932
 
700
- if (writeOnFileSystem) {
701
- if (buildDirectoryClean) {
702
- await ensureEmptyDirectory(buildDirectoryUrl)
933
+ startBuild()
934
+ let startTimeout
935
+ const clientFileChangeCallback = ({ relativeUrl, event }) => {
936
+ const url = new URL(relativeUrl, rootDirectoryUrl).href
937
+ if (watchFilesTask) {
938
+ watchFilesTask.happen(`${url.slice(rootDirectoryUrl.length)} ${event}`)
939
+ watchFilesTask = null
703
940
  }
704
- const buildRelativeUrls = Object.keys(buildFileContents)
705
- await Promise.all(
706
- buildRelativeUrls.map(async (buildRelativeUrl) => {
707
- await writeFile(
708
- new URL(buildRelativeUrl, buildDirectoryUrl),
709
- buildFileContents[buildRelativeUrl],
710
- )
711
- }),
712
- )
713
- if (
714
- versioning !== "none" &&
715
- assetManifest &&
716
- Object.keys(buildManifest).length
717
- ) {
718
- await writeFile(
719
- new URL(assetManifestFileRelativeUrl, buildDirectoryUrl),
720
- JSON.stringify(buildManifest, null, " "),
941
+ buildAbortController.abort()
942
+ // setTimeout is to ensure the abortController.abort() above
943
+ // is properly taken into account so that logs about abort comes first
944
+ // then logs about re-running the build happens
945
+ clearTimeout(startTimeout)
946
+ startTimeout = setTimeout(startBuild, 20)
947
+ }
948
+ const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
949
+ watchPatterns: clientFiles,
950
+ cooldownBetweenFileEvents,
951
+ keepProcessAlive: true,
952
+ recursive: true,
953
+ added: ({ relativeUrl }) => {
954
+ clientFileChangeCallback({ relativeUrl, event: "added" })
955
+ },
956
+ updated: ({ relativeUrl }) => {
957
+ clientFileChangeCallback({ relativeUrl, event: "modified" })
958
+ },
959
+ removed: ({ relativeUrl }) => {
960
+ clientFileChangeCallback({ relativeUrl, event: "removed" })
961
+ },
962
+ })
963
+ operation.addAbortCallback(() => {
964
+ stopWatchingClientFiles()
965
+ })
966
+ await firstBuildPromise
967
+ return stopWatchingClientFiles
968
+ }
969
+
970
+ const applyUrlVersioning = async ({
971
+ buildOperation,
972
+ logger,
973
+ infoLogsAreDisabled,
974
+ buildDirectoryUrl,
975
+ rawUrls,
976
+ buildUrls,
977
+ baseUrl,
978
+ postBuildEntryUrls,
979
+ sourcemaps,
980
+ sourcemapsSourcesContent,
981
+ runtimeCompat,
982
+ writeGeneratedFiles,
983
+ rawGraph,
984
+ urlAnalysisPlugin,
985
+ finalGraph,
986
+ finalGraphKitchen,
987
+ lineBreakNormalization,
988
+ versioningMethod,
989
+ }) => {
990
+ const versioningTask = createTaskLog("inject version in urls", {
991
+ disabled: infoLogsAreDisabled,
992
+ })
993
+ try {
994
+ const urlsSorted = sortByDependencies(finalGraph.urlInfos)
995
+ urlsSorted.forEach((url) => {
996
+ if (url.startsWith("data:")) {
997
+ return
998
+ }
999
+ const urlInfo = finalGraph.getUrlInfo(url)
1000
+ if (urlInfo.type === "sourcemap") {
1001
+ return
1002
+ }
1003
+ // ignore:
1004
+ // - inline files:
1005
+ // they are already taken into account in the file where they appear
1006
+ // - ignored files:
1007
+ // we don't know their content
1008
+ // - unused files without reference
1009
+ // File updated such as style.css -> style.css.js or file.js->file.es5.js
1010
+ // Are used at some point just to be discarded later because they need to be converted
1011
+ // There is no need to version them and we could not because the file have been ignored
1012
+ // so their content is unknown
1013
+ if (urlInfo.isInline) {
1014
+ return
1015
+ }
1016
+ if (!urlInfo.shouldHandle) {
1017
+ return
1018
+ }
1019
+ if (!urlInfo.data.isEntryPoint && urlInfo.dependents.size === 0) {
1020
+ return
1021
+ }
1022
+
1023
+ const urlContent =
1024
+ urlInfo.type === "html"
1025
+ ? stringifyHtmlAst(
1026
+ parseHtmlString(urlInfo.content, {
1027
+ storeOriginalPositions: false,
1028
+ }),
1029
+ { removeOriginalPositionAttributes: true },
1030
+ )
1031
+ : urlInfo.content
1032
+ const versionGenerator = createVersionGenerator()
1033
+ versionGenerator.augmentWithContent({
1034
+ content: urlContent,
1035
+ contentType: urlInfo.contentType,
1036
+ lineBreakNormalization,
1037
+ })
1038
+ urlInfo.dependencies.forEach((dependencyUrl) => {
1039
+ // this dependency is inline
1040
+ if (dependencyUrl.startsWith("data:")) {
1041
+ return
1042
+ }
1043
+ const dependencyUrlInfo = finalGraph.getUrlInfo(dependencyUrl)
1044
+ if (
1045
+ // this content is part of the file, no need to take into account twice
1046
+ dependencyUrlInfo.isInline ||
1047
+ // this dependency content is not known
1048
+ !dependencyUrlInfo.shouldHandle
1049
+ ) {
1050
+ return
1051
+ }
1052
+ if (dependencyUrlInfo.data.version) {
1053
+ versionGenerator.augmentWithDependencyVersion(
1054
+ dependencyUrlInfo.data.version,
1055
+ )
1056
+ } else {
1057
+ // because all dependencies are know, if the dependency has no version
1058
+ // it means there is a circular dependency between this file
1059
+ // and it's dependency
1060
+ // in that case we'll use the dependency content
1061
+ versionGenerator.augmentWithContent({
1062
+ content: dependencyUrlInfo.content,
1063
+ contentType: dependencyUrlInfo.contentType,
1064
+ lineBreakNormalization,
1065
+ })
1066
+ }
1067
+ })
1068
+ urlInfo.data.version = versionGenerator.generate()
1069
+
1070
+ urlInfo.data.versionedUrl = normalizeUrl(
1071
+ injectVersionIntoBuildUrl({
1072
+ buildUrl: urlInfo.url,
1073
+ version: urlInfo.data.version,
1074
+ versioningMethod,
1075
+ }),
721
1076
  )
1077
+ })
1078
+ const versionMappings = {}
1079
+ const usedVersionMappings = []
1080
+ const versioningKitchen = createKitchen({
1081
+ logger,
1082
+ rootDirectoryUrl: buildDirectoryUrl,
1083
+ urlGraph: finalGraph,
1084
+ scenario: "build",
1085
+ sourcemaps,
1086
+ sourcemapsSourcesContent,
1087
+ sourcemapsRelativeSources: true,
1088
+ runtimeCompat,
1089
+ writeGeneratedFiles,
1090
+ plugins: [
1091
+ urlAnalysisPlugin,
1092
+ jsenvPluginInline({
1093
+ fetchInlineUrls: false,
1094
+ analyzeConvertedScripts: true, // to be able to version their urls
1095
+ allowEscapeForVersioning: true,
1096
+ }),
1097
+ {
1098
+ name: "jsenv:versioning",
1099
+ appliesDuring: { build: true },
1100
+ resolveUrl: (reference) => {
1101
+ const buildUrl = buildUrls[reference.specifier]
1102
+ if (buildUrl) {
1103
+ return buildUrl
1104
+ }
1105
+ const urlObject = new URL(
1106
+ reference.specifier,
1107
+ reference.baseUrl || reference.parentUrl,
1108
+ )
1109
+ const url = urlObject.href
1110
+ // during versioning we revisit the deps
1111
+ // but the code used to enforce trailing slash on directories
1112
+ // is not applied because "jsenv:file_url_resolution" is not used
1113
+ // so here we search if the url with a trailing slash exists
1114
+ if (
1115
+ reference.type === "filesystem" &&
1116
+ !urlObject.pathname.endsWith("/")
1117
+ ) {
1118
+ const urlWithTrailingSlash = `${url}/`
1119
+ const specifier = Object.keys(buildUrls).find(
1120
+ (key) => buildUrls[key] === urlWithTrailingSlash,
1121
+ )
1122
+ if (specifier) {
1123
+ return urlWithTrailingSlash
1124
+ }
1125
+ }
1126
+ return url
1127
+ },
1128
+ formatUrl: (reference) => {
1129
+ if (!reference.shouldHandle) {
1130
+ if (reference.generatedUrl.startsWith("ignore:")) {
1131
+ return reference.generatedUrl.slice("ignore:".length)
1132
+ }
1133
+ return null
1134
+ }
1135
+ if (reference.isInline || reference.url.startsWith("data:")) {
1136
+ return null
1137
+ }
1138
+ if (reference.isRessourceHint) {
1139
+ return null
1140
+ }
1141
+ // specifier comes from "normalize" hook done a bit earlier in this file
1142
+ // we want to get back their build url to access their infos
1143
+ const referencedUrlInfo = finalGraph.getUrlInfo(reference.url)
1144
+ if (!canUseVersionedUrl(referencedUrlInfo)) {
1145
+ return reference.specifier
1146
+ }
1147
+ if (!referencedUrlInfo.shouldHandle) {
1148
+ return null
1149
+ }
1150
+ const versionedUrl = referencedUrlInfo.data.versionedUrl
1151
+ if (!versionedUrl) {
1152
+ // happens for sourcemap
1153
+ return `${baseUrl}${urlToRelativeUrl(
1154
+ referencedUrlInfo.url,
1155
+ buildDirectoryUrl,
1156
+ )}`
1157
+ }
1158
+ const versionedSpecifier = `${baseUrl}${urlToRelativeUrl(
1159
+ versionedUrl,
1160
+ buildDirectoryUrl,
1161
+ )}`
1162
+ versionMappings[reference.specifier] = versionedSpecifier
1163
+ buildUrls[versionedSpecifier] = versionedUrl
1164
+
1165
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
1166
+ if (parentUrlInfo.jsQuote) {
1167
+ // the url is inline inside js quotes
1168
+ usedVersionMappings.push(reference.specifier)
1169
+ return () =>
1170
+ `${parentUrlInfo.jsQuote}+__v__(${JSON.stringify(
1171
+ reference.specifier,
1172
+ )})+${parentUrlInfo.jsQuote}`
1173
+ }
1174
+ if (
1175
+ reference.type === "js_url_specifier" ||
1176
+ reference.subtype === "import_dynamic"
1177
+ ) {
1178
+ usedVersionMappings.push(reference.specifier)
1179
+ return () => `__v__(${JSON.stringify(reference.specifier)})`
1180
+ }
1181
+ return versionedSpecifier
1182
+ },
1183
+ fetchUrlContent: (versionedUrlInfo) => {
1184
+ if (versionedUrlInfo.isInline) {
1185
+ const rawUrlInfo = rawGraph.getUrlInfo(
1186
+ rawUrls[versionedUrlInfo.url],
1187
+ )
1188
+ const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
1189
+ return {
1190
+ originalContent: rawUrlInfo
1191
+ ? rawUrlInfo.originalContent
1192
+ : undefined,
1193
+ sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
1194
+ contentType: versionedUrlInfo.contentType,
1195
+ content: versionedUrlInfo.content,
1196
+ }
1197
+ }
1198
+ return versionedUrlInfo
1199
+ },
1200
+ },
1201
+ ],
1202
+ })
1203
+ await loadUrlGraph({
1204
+ operation: buildOperation,
1205
+ urlGraph: finalGraph,
1206
+ kitchen: versioningKitchen,
1207
+ skipRessourceHint: true,
1208
+ writeGeneratedFiles,
1209
+ startLoading: (cookEntryFile) => {
1210
+ postBuildEntryUrls.forEach((postBuildEntryUrl) => {
1211
+ cookEntryFile({
1212
+ trace: `entryPoint`,
1213
+ type: "entry_point",
1214
+ specifier: postBuildEntryUrl,
1215
+ })
1216
+ })
1217
+ },
1218
+ })
1219
+ if (usedVersionMappings.length) {
1220
+ const versionMappingsNeeded = {}
1221
+ usedVersionMappings.forEach((specifier) => {
1222
+ versionMappingsNeeded[specifier] = versionMappings[specifier]
1223
+ })
1224
+ await injectGlobalVersionMapping({
1225
+ finalGraphKitchen,
1226
+ finalGraph,
1227
+ versionMappings: versionMappingsNeeded,
1228
+ })
722
1229
  }
1230
+ } catch (e) {
1231
+ versioningTask.fail()
1232
+ throw e
723
1233
  }
724
- logger.info(createUrlGraphSummary(finalGraph, { title: "build files" }))
725
- return {
726
- buildFileContents,
727
- buildInlineFileContents,
728
- buildManifest,
729
- }
1234
+ versioningTask.done()
730
1235
  }
731
1236
 
732
- const injectVersionIntoBuildUrl = ({ buildUrl, version, versioning }) => {
733
- if (versioning === "search_param") {
1237
+ const injectVersionIntoBuildUrl = ({ buildUrl, version, versioningMethod }) => {
1238
+ if (versioningMethod === "search_param") {
734
1239
  return injectQueryParams(buildUrl, {
735
1240
  v: version,
736
1241
  })
@@ -766,3 +1271,16 @@ const assertEntryPoints = ({ entryPoints }) => {
766
1271
  }
767
1272
  })
768
1273
  }
1274
+
1275
+ const canUseVersionedUrl = (urlInfo) => {
1276
+ if (urlInfo.data.isEntryPoint) {
1277
+ return false
1278
+ }
1279
+ if (urlInfo.type === "webmanifest") {
1280
+ return false
1281
+ }
1282
+ if (urlInfo.subtype === "service_worker") {
1283
+ return !urlInfo.data.isWebWorkerEntryPoint
1284
+ }
1285
+ return true
1286
+ }