@jsenv/core 27.0.0-alpha.4 → 27.0.0-alpha.40

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 (141) hide show
  1. package/dist/event_source_client.js +549 -0
  2. package/dist/event_source_client.js.map +188 -0
  3. package/dist/html_supervisor_installer.js +1145 -0
  4. package/dist/html_supervisor_installer.js.map +322 -0
  5. package/dist/html_supervisor_setup.js +92 -0
  6. package/dist/html_supervisor_setup.js.map +57 -0
  7. package/main.js +8 -1
  8. package/package.json +22 -21
  9. package/readme.md +4 -12
  10. package/src/build/build.js +731 -433
  11. package/src/build/build_urls_generator.js +55 -21
  12. package/src/build/graph_utils.js +31 -0
  13. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +33 -15
  14. package/src/build/inject_service_worker_urls.js +79 -0
  15. package/src/build/resync_ressource_hints.js +68 -0
  16. package/src/build/start_build_server.js +205 -0
  17. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
  18. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  19. package/src/dev/start_dev_server.js +58 -26
  20. package/src/execute/execute.js +30 -4
  21. package/src/execute/run.js +19 -56
  22. package/src/execute/runtimes/browsers/from_playwright.js +201 -147
  23. package/src/execute/runtimes/node/controllable_file.mjs +26 -10
  24. package/src/execute/runtimes/node/node_execution_performance.js +67 -0
  25. package/src/execute/runtimes/node/node_process.js +280 -39
  26. package/src/jsenv_root_directory_url.js +1 -0
  27. package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
  28. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +66 -4
  29. package/src/omega/compat/runtime_compat.js +50 -0
  30. package/src/omega/errors.js +51 -58
  31. package/src/omega/fetched_content_compliance.js +24 -0
  32. package/src/omega/file_url_converter.js +8 -50
  33. package/src/omega/kitchen.js +414 -285
  34. package/src/omega/server/file_service.js +21 -22
  35. package/src/omega/url_graph/url_graph_load.js +14 -7
  36. package/src/omega/url_graph/url_graph_report.js +17 -15
  37. package/src/omega/url_graph/url_info_transformations.js +17 -5
  38. package/src/omega/url_graph.js +33 -10
  39. package/src/omega/web_workers.js +42 -0
  40. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
  41. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +2 -2
  42. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
  43. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
  44. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +46 -0
  45. package/src/{dev/plugins/autoreload/jsenv_plugin_autoreload.js → plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js} +31 -172
  46. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +27 -0
  47. package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
  48. package/src/plugins/bundling/css/bundle_css.js +21 -0
  49. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  50. package/src/{build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js → plugins/bundling/js_module/bundle_js_module.js} +120 -79
  51. package/src/plugins/bundling/jsenv_plugin_bundling.js +51 -0
  52. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +54 -41
  53. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
  54. package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +8 -5
  55. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  56. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  57. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_installer.js +3 -2
  58. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_setup.js +0 -0
  59. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  60. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  61. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +52 -55
  62. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  63. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +4 -5
  64. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +3 -1
  65. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +2 -2
  66. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +101 -0
  67. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +33 -8
  68. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  69. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  70. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +37 -31
  71. package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +67 -0
  72. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  73. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
  74. package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +61 -40
  75. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  76. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
  77. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +296 -0
  78. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  79. package/src/plugins/minification/css/minify_css.js +9 -0
  80. package/src/plugins/minification/html/minify_html.js +15 -0
  81. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  82. package/src/plugins/minification/jsenv_plugin_minification.js +78 -0
  83. package/src/plugins/minification/json/minify_json.js +8 -0
  84. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +146 -0
  85. package/src/{omega → plugins}/plugin_controller.js +39 -11
  86. package/src/plugins/plugins.js +89 -0
  87. package/src/plugins/transpilation/as_js_classic/client/s.js +808 -0
  88. package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
  89. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  90. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  91. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +183 -0
  92. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +256 -0
  93. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +93 -0
  94. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  95. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  96. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  97. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +4 -22
  98. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  99. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +37 -21
  100. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +30 -6
  101. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
  102. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  103. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  104. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  105. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  106. package/src/plugins/transpilation/fetch_original_url_info.js +30 -0
  107. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +200 -0
  108. package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +70 -0
  109. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +44 -0
  110. package/src/plugins/url_references/css/css_urls.js +49 -0
  111. package/src/plugins/url_references/html/html_urls.js +273 -0
  112. package/src/plugins/url_references/js/js_urls.js +43 -0
  113. package/src/plugins/url_references/jsenv_plugin_imports_analysis.js +46 -0
  114. package/src/plugins/url_references/jsenv_plugin_url_analysis.js +18 -0
  115. package/src/plugins/url_references/jsenv_plugin_url_references.js +6 -0
  116. package/src/plugins/url_references/webmanifest/webmanifest_urls.js +17 -0
  117. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
  118. package/src/{omega/core_plugins → plugins}/url_version/jsenv_plugin_url_version.js +12 -15
  119. package/src/test/execute_plan.js +28 -11
  120. package/src/test/execute_test_plan.js +23 -8
  121. package/src/test/logs_file_execution.js +8 -7
  122. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  123. package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
  124. package/src/dev/plugins/autoreload/sse_service.js +0 -149
  125. package/src/execute/runtimes/node/controlled_process.js +0 -316
  126. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  127. package/src/omega/core_plugins/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -98
  128. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  129. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  130. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  131. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  132. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -210
  133. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  134. package/src/omega/core_plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +0 -77
  135. package/src/omega/core_plugins.js +0 -39
  136. package/src/omega/runtime_support/runtime_support.js +0 -20
  137. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  138. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  139. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  140. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  141. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -0,0 +1 @@
1
+ s.js exists to ease jsenv ability to find the file.
@@ -0,0 +1,47 @@
1
+ import babelParser from "@babel/parser"
2
+
3
+ export const babelPluginTransformImportMetaUrl = (babel) => {
4
+ return {
5
+ name: "transform-import-meta-url",
6
+ visitor: {
7
+ Program: (programPath) => {
8
+ const currentUrlIdentifier =
9
+ programPath.scope.generateUidIdentifier("currentUrl")
10
+ let used = false
11
+
12
+ programPath.traverse({
13
+ MemberExpression: (path) => {
14
+ const node = path.node
15
+ if (
16
+ node.object.type === "MetaProperty" &&
17
+ node.object.property.name === "meta" &&
18
+ node.property.name === "url"
19
+ ) {
20
+ // const node = babel.types.valueToNode(10)
21
+ const identifier = babel.types.identifier(
22
+ currentUrlIdentifier.name,
23
+ )
24
+ const expressionStatement =
25
+ babel.types.expressionStatement(identifier)
26
+ path.replaceWith(expressionStatement)
27
+ used = true
28
+ }
29
+ },
30
+ })
31
+ if (used) {
32
+ const ast = generateExpressionAst(`document.currentScript.src`)
33
+ programPath.scope.push({
34
+ id: currentUrlIdentifier,
35
+ init: ast,
36
+ })
37
+ }
38
+ },
39
+ },
40
+ }
41
+ }
42
+
43
+ const generateExpressionAst = (expression, options) => {
44
+ const { parseExpression } = babelParser
45
+ const ast = parseExpression(expression, options)
46
+ return ast
47
+ }
@@ -0,0 +1,43 @@
1
+ // const { clientRuntimeCompat, isSupportedOnCurrentClient } = context
2
+ // const shouldBeCompatibleWithNode =
3
+ // Object.keys(clientRuntimeCompat).includes("node")
4
+ // const requiredFeatureNames = [
5
+ // "import_dynamic",
6
+ // "top_level_await",
7
+ // "global_this",
8
+ // // when using node we assume the code won't use browser specific feature
9
+ // ...(shouldBeCompatibleWithNode
10
+ // ? []
11
+ // : [
12
+ // "script_type_module",
13
+ // "worker_type_module",
14
+ // "import_type_json",
15
+ // "import_type_css",
16
+ // ]),
17
+ // // "importmap",
18
+ // ]
19
+ // const needsSystemJs = featuresRelatedToSystemJs.some((featureName) => {
20
+ // const isRequired = requiredFeatureNames.includes(featureName)
21
+ // return isRequired && !isSupportedOnCurrentClient(featureName)
22
+ // })
23
+ // if (!needsSystemJs) {
24
+ // return null
25
+ // }
26
+ // const { code, map } = await applyBabelPlugins({
27
+
28
+ // })
29
+ // return {
30
+ // content: code,
31
+ // soourcemap: map,
32
+ // }
33
+
34
+ // const featuresRelatedToSystemJs = [
35
+ // "script_type_module",
36
+ // "worker_type_module",
37
+ // "import_dynamic",
38
+ // "import_type_json",
39
+ // "import_type_css",
40
+ // "top_level_await",
41
+ // // "importmap",
42
+ // // "worker_importmap",
43
+ // ]
@@ -0,0 +1,183 @@
1
+ /*
2
+ * Something to keep in mind:
3
+ * When systemjs format is used by babel, it will generated UID based on
4
+ * the import specifier:
5
+ * https://github.com/babel/babel/blob/97d1967826077f15e766778c0d64711399e9a72a/packages/babel-plugin-transform-modules-systemjs/src/index.ts#L498
6
+ * But at this stage import specifier are absolute file urls
7
+ * So without minification these specifier are long and dependent
8
+ * on where the files are on the filesystem.
9
+ * This is mitigated by minification that will shorten them
10
+ * But ideally babel should not generate this in the first place
11
+ * and prefer to unique identifier based solely on the specifier basename for instance
12
+ */
13
+
14
+ import { createRequire } from "node:module"
15
+ import { readFileSync, urlToFilename } from "@jsenv/filesystem"
16
+
17
+ import { requireBabelPlugin } from "@jsenv/babel-plugins"
18
+ import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
19
+ import { injectQueryParams } from "@jsenv/utils/urls/url_utils.js"
20
+ import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
21
+ import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_composition_v3.js"
22
+
23
+ import { fetchOriginalUrlInfo } from "../fetch_original_url_info.js"
24
+ import { babelPluginTransformImportMetaUrl } from "./helpers/babel_plugin_transform_import_meta_url.js"
25
+ import { jsenvPluginScriptTypeModuleAsClassic } from "./jsenv_plugin_script_type_module_as_classic.js"
26
+ import { jsenvPluginWorkersTypeModuleAsClassic } from "./jsenv_plugin_workers_type_module_as_classic.js"
27
+
28
+ const require = createRequire(import.meta.url)
29
+
30
+ export const jsenvPluginAsJsClassic = ({ systemJsInjection }) => {
31
+ const systemJsClientFileUrl = new URL("./client/s.js", import.meta.url).href
32
+
33
+ return [
34
+ asJsClassic({ systemJsInjection, systemJsClientFileUrl }),
35
+ jsenvPluginScriptTypeModuleAsClassic({
36
+ systemJsInjection,
37
+ systemJsClientFileUrl,
38
+ generateJsClassicFilename,
39
+ }),
40
+ jsenvPluginWorkersTypeModuleAsClassic({
41
+ generateJsClassicFilename,
42
+ }),
43
+ ]
44
+ }
45
+
46
+ const asJsClassic = ({ systemJsInjection, systemJsClientFileUrl }) => {
47
+ return {
48
+ name: "jsenv:as_js_classic",
49
+ appliesDuring: "*",
50
+ // forward ?as_js_classic to referenced urls
51
+ normalizeUrl: (reference, context) => {
52
+ // We want to propagate transformation of js module to js classic
53
+ // but only for import specifier (static/dynamic import + re-export)
54
+ // All other references won't get the ?as_js_classic
55
+ // otherwise we could try to transform inline ressources, specifiers inside new URL(). ...
56
+ if (
57
+ reference.type !== "js_import_export" &&
58
+ reference.subtype !== "system_register_arg" &&
59
+ reference.subtype !== "system_import_arg"
60
+ ) {
61
+ return null
62
+ }
63
+ const parentUrlInfo = context.urlGraph.getUrlInfo(reference.parentUrl)
64
+ if (
65
+ !parentUrlInfo ||
66
+ !new URL(parentUrlInfo.url).searchParams.has("as_js_classic")
67
+ ) {
68
+ return null
69
+ }
70
+ const urlTransformed = injectQueryParams(reference.url, {
71
+ as_js_classic: "",
72
+ })
73
+ reference.filename = generateJsClassicFilename(reference.url)
74
+ return urlTransformed
75
+ },
76
+ fetchUrlContent: async (urlInfo, context) => {
77
+ const originalUrlInfo = await fetchOriginalUrlInfo({
78
+ urlInfo,
79
+ context,
80
+ searchParam: "as_js_classic",
81
+ // override the expectedType to "js_module"
82
+ // because when there is ?as_js_classic it means the underlying ressource
83
+ // is a js_module
84
+ expectedType: "js_module",
85
+ })
86
+ if (!originalUrlInfo) {
87
+ return null
88
+ }
89
+ const isJsEntryPoint =
90
+ // in general html files are entry points
91
+ // but during build js can be sepcified as an entry point
92
+ // (meaning there is no html file where we can inject systemjs)
93
+ // in that case we need to inject systemjs in the js file
94
+ originalUrlInfo.data.isEntryPoint ||
95
+ // In thoose case we need to inject systemjs the worker js file
96
+ originalUrlInfo.data.isWebWorkerEntryPoint
97
+ // if it's an entry point without dependency (it does not use import)
98
+ // then we can use UMD, otherwise we have to use systemjs
99
+ // because it is imported by systemjs
100
+ const jsClassicFormat =
101
+ isJsEntryPoint && !originalUrlInfo.data.usesImport ? "umd" : "system"
102
+ const { content, sourcemap } = await convertJsModuleToJsClassic({
103
+ systemJsInjection,
104
+ systemJsClientFileUrl,
105
+ urlInfo: originalUrlInfo,
106
+ isJsEntryPoint,
107
+ jsClassicFormat,
108
+ })
109
+ urlInfo.data.jsClassicFormat = jsClassicFormat
110
+ return {
111
+ type: "js_classic",
112
+ contentType: "text/javascript",
113
+ content,
114
+ sourcemap,
115
+ }
116
+ },
117
+ }
118
+ }
119
+
120
+ const generateJsClassicFilename = (url) => {
121
+ const filename = urlToFilename(url)
122
+ const [basename, extension] = splitFileExtension(filename)
123
+ return `${basename}.es5${extension}`
124
+ }
125
+
126
+ const splitFileExtension = (filename) => {
127
+ const dotLastIndex = filename.lastIndexOf(".")
128
+ if (dotLastIndex === -1) {
129
+ return [filename, ""]
130
+ }
131
+ return [filename.slice(0, dotLastIndex), filename.slice(dotLastIndex)]
132
+ }
133
+
134
+ const convertJsModuleToJsClassic = async ({
135
+ systemJsInjection,
136
+ systemJsClientFileUrl,
137
+ urlInfo,
138
+ isJsEntryPoint,
139
+ jsClassicFormat,
140
+ }) => {
141
+ const { code, map } = await applyBabelPlugins({
142
+ babelPlugins: [
143
+ ...(jsClassicFormat === "system"
144
+ ? [
145
+ // propposal-dynamic-import required with systemjs for babel8:
146
+ // https://github.com/babel/babel/issues/10746
147
+ require("@babel/plugin-proposal-dynamic-import"),
148
+ [
149
+ requireBabelPlugin("babel-plugin-transform-async-to-promises"),
150
+ {
151
+ topLevelAwait: "return",
152
+ },
153
+ ],
154
+ require("@babel/plugin-transform-modules-systemjs"),
155
+ ]
156
+ : [
157
+ [
158
+ requireBabelPlugin("babel-plugin-transform-async-to-promises"),
159
+ {
160
+ topLevelAwait: "simple",
161
+ },
162
+ ],
163
+ babelPluginTransformImportMetaUrl,
164
+ require("@babel/plugin-transform-modules-umd"),
165
+ ]),
166
+ ],
167
+ urlInfo,
168
+ })
169
+ if (systemJsInjection && jsClassicFormat === "system" && isJsEntryPoint) {
170
+ const magicSource = createMagicSource(code)
171
+ const systemjsCode = readFileSync(systemJsClientFileUrl, { as: "string" })
172
+ magicSource.prepend(`${systemjsCode}\n\n`)
173
+ const { content, sourcemap } = magicSource.toContentAndSourcemap()
174
+ return {
175
+ content,
176
+ sourcemap: await composeTwoSourcemaps(map, sourcemap),
177
+ }
178
+ }
179
+ return {
180
+ content: code,
181
+ sourcemap: map,
182
+ }
183
+ }
@@ -0,0 +1,256 @@
1
+ import {
2
+ getHtmlNodeAttributeByName,
3
+ getHtmlNodeTextNode,
4
+ parseHtmlString,
5
+ removeHtmlNodeAttributeByName,
6
+ assignHtmlNodeAttributes,
7
+ stringifyHtmlAst,
8
+ visitHtmlAst,
9
+ htmlNodePosition,
10
+ setHtmlNodeGeneratedText,
11
+ injectScriptAsEarlyAsPossible,
12
+ createHtmlNode,
13
+ } from "@jsenv/utils/html_ast/html_ast.js"
14
+ import { generateInlineContentUrl } from "@jsenv/utils/urls/inline_content_url_generator.js"
15
+ import { injectQueryParamsIntoSpecifier } from "@jsenv/utils/urls/url_utils.js"
16
+
17
+ export const jsenvPluginScriptTypeModuleAsClassic = ({
18
+ systemJsInjection,
19
+ systemJsClientFileUrl,
20
+ generateJsClassicFilename,
21
+ }) => {
22
+ return {
23
+ name: "jsenv:script_type_module_as_classic",
24
+ appliesDuring: "*",
25
+ transformUrlContent: {
26
+ html: async (urlInfo, context) => {
27
+ if (
28
+ context.isSupportedOnCurrentClients("script_type_module") &&
29
+ context.isSupportedOnCurrentClients("import_dynamic")
30
+ ) {
31
+ return null
32
+ }
33
+ const htmlAst = parseHtmlString(urlInfo.content)
34
+ const preloadAsScriptNodes = []
35
+ const modulePreloadNodes = []
36
+ const moduleScriptNodes = []
37
+ const classicScriptNodes = []
38
+ const visitLinkNodes = (node) => {
39
+ if (node.nodeName !== "link") {
40
+ return
41
+ }
42
+ const relAttribute = getHtmlNodeAttributeByName(node, "rel")
43
+ const rel = relAttribute ? relAttribute.value : undefined
44
+ if (rel === "modulepreload") {
45
+ modulePreloadNodes.push(node)
46
+ return
47
+ }
48
+ if (rel === "preload") {
49
+ const asAttribute = getHtmlNodeAttributeByName(node, "as")
50
+ const as = asAttribute ? asAttribute.value : undefined
51
+ if (as === "script") {
52
+ preloadAsScriptNodes.push(node)
53
+ }
54
+ return
55
+ }
56
+ }
57
+ const visitScriptNodes = (node) => {
58
+ if (node.nodeName !== "script") {
59
+ return
60
+ }
61
+ const typeAttribute = getHtmlNodeAttributeByName(node, "type")
62
+ const type = typeAttribute ? typeAttribute.value : undefined
63
+ if (type === "module") {
64
+ moduleScriptNodes.push(node)
65
+ return
66
+ }
67
+ if (type === undefined || type === "text/javascript") {
68
+ classicScriptNodes.push(node)
69
+ return
70
+ }
71
+ }
72
+ visitHtmlAst(htmlAst, (node) => {
73
+ visitLinkNodes(node)
74
+ visitScriptNodes(node)
75
+ })
76
+
77
+ const classicScriptUrls = []
78
+ const moduleScriptUrls = []
79
+ classicScriptNodes.forEach((classicScriptNode) => {
80
+ const srcAttribute = getHtmlNodeAttributeByName(
81
+ classicScriptNode,
82
+ "src",
83
+ )
84
+ if (srcAttribute) {
85
+ const url = new URL(srcAttribute.value, urlInfo.url).href
86
+ classicScriptUrls.push(url)
87
+ }
88
+ })
89
+ moduleScriptNodes.forEach((moduleScriptNode) => {
90
+ const srcAttribute = getHtmlNodeAttributeByName(
91
+ moduleScriptNode,
92
+ "src",
93
+ )
94
+ if (srcAttribute) {
95
+ const url = new URL(srcAttribute.value, urlInfo.url).href
96
+ moduleScriptUrls.push(url)
97
+ }
98
+ })
99
+
100
+ const jsModuleUrls = []
101
+ const getReferenceAsJsClassic = async (reference) => {
102
+ const [newReference, newUrlInfo] = context.referenceUtils.update(
103
+ reference,
104
+ {
105
+ expectedType: "js_classic",
106
+ specifier: injectQueryParamsIntoSpecifier(reference.specifier, {
107
+ as_js_classic: "",
108
+ }),
109
+ filename: generateJsClassicFilename(reference.url),
110
+ },
111
+ )
112
+ const jsModuleUrl = newUrlInfo.url
113
+ if (!jsModuleUrls.includes(jsModuleUrl)) {
114
+ jsModuleUrls.push(newUrlInfo.url)
115
+ // during dev it means js modules will be cooked before server sends the HTML
116
+ // it's ok because:
117
+ // - during dev script_type_module are supported (dev use a recent browser)
118
+ // - even if browser is not supported it still works it's jus a bit slower
119
+ // because it needs to decide if systemjs will be injected or not
120
+ await context.cook({
121
+ reference: newReference,
122
+ urlInfo: newUrlInfo,
123
+ })
124
+ }
125
+ return [newReference, newUrlInfo]
126
+ }
127
+ const actions = []
128
+ preloadAsScriptNodes.forEach((preloadAsScriptNode) => {
129
+ const hrefAttribute = getHtmlNodeAttributeByName(
130
+ preloadAsScriptNode,
131
+ "href",
132
+ )
133
+ const href = hrefAttribute.value
134
+ const url = new URL(href, urlInfo.url).href
135
+ const expectedScriptType = moduleScriptUrls.includes(url)
136
+ ? "module"
137
+ : "classic"
138
+ // keep in mind:
139
+ // when the url is not referenced by a <script type="module">
140
+ // we assume we want to preload "classic" but it might not be the case
141
+ // but it's unlikely to happen and people should use "modulepreload" in that case anyway
142
+ if (expectedScriptType === "module") {
143
+ actions.push(async () => {
144
+ const [newReference] = await getReferenceAsJsClassic(
145
+ context.referenceUtils.findByGeneratedSpecifier(href),
146
+ )
147
+ assignHtmlNodeAttributes(preloadAsScriptNode, {
148
+ href: newReference.generatedSpecifier,
149
+ })
150
+ removeHtmlNodeAttributeByName(preloadAsScriptNode, "crossorigin")
151
+ })
152
+ }
153
+ })
154
+ modulePreloadNodes.forEach((modulePreloadNode) => {
155
+ const hrefAttribute = getHtmlNodeAttributeByName(
156
+ modulePreloadNode,
157
+ "href",
158
+ )
159
+ const href = hrefAttribute.value
160
+ actions.push(async () => {
161
+ const [newReference] = await getReferenceAsJsClassic(
162
+ context.referenceUtils.findByGeneratedSpecifier(href),
163
+ )
164
+ assignHtmlNodeAttributes(modulePreloadNode, {
165
+ rel: "preload",
166
+ as: "script",
167
+ href: newReference.generatedSpecifier,
168
+ })
169
+ })
170
+ })
171
+ moduleScriptNodes.forEach((moduleScriptNode) => {
172
+ const srcAttribute = getHtmlNodeAttributeByName(
173
+ moduleScriptNode,
174
+ "src",
175
+ )
176
+ if (srcAttribute) {
177
+ actions.push(async () => {
178
+ const specifier = srcAttribute.value
179
+ const [newReference] = await getReferenceAsJsClassic(
180
+ context.referenceUtils.findByGeneratedSpecifier(specifier),
181
+ )
182
+ removeHtmlNodeAttributeByName(moduleScriptNode, "type")
183
+ srcAttribute.value = newReference.generatedSpecifier
184
+ })
185
+ return
186
+ }
187
+ const textNode = getHtmlNodeTextNode(moduleScriptNode)
188
+ actions.push(async () => {
189
+ const { line, column, lineEnd, columnEnd, isOriginal } =
190
+ htmlNodePosition.readNodePosition(moduleScriptNode, {
191
+ preferOriginal: true,
192
+ })
193
+ let inlineScriptUrl = generateInlineContentUrl({
194
+ url: urlInfo.url,
195
+ extension: ".js",
196
+ line,
197
+ column,
198
+ lineEnd,
199
+ columnEnd,
200
+ })
201
+ const [inlineReference] = context.referenceUtils.foundInline({
202
+ node: moduleScriptNode,
203
+ type: "script_src",
204
+ expectedType: "js_module",
205
+ // we remove 1 to the line because imagine the following html:
206
+ // <script>console.log('ok')</script>
207
+ // -> content starts same line as <script>
208
+ line: line - 1,
209
+ column,
210
+ isOriginalPosition: isOriginal,
211
+ specifier: inlineScriptUrl,
212
+ contentType: "application/javascript",
213
+ content: textNode.value,
214
+ })
215
+ const [, newUrlInfo] = await getReferenceAsJsClassic(
216
+ inlineReference,
217
+ )
218
+ removeHtmlNodeAttributeByName(moduleScriptNode, "type")
219
+ setHtmlNodeGeneratedText(moduleScriptNode, {
220
+ generatedText: newUrlInfo.content,
221
+ generatedBy: "jsenv:script_type_module_as_classic",
222
+ })
223
+ })
224
+ })
225
+
226
+ if (actions.length === 0) {
227
+ return null
228
+ }
229
+ await Promise.all(actions.map((action) => action()))
230
+ if (systemJsInjection) {
231
+ const needsSystemJs = jsModuleUrls.some(
232
+ (jsModuleUrl) =>
233
+ context.urlGraph.getUrlInfo(jsModuleUrl).data.jsClassicFormat ===
234
+ "system",
235
+ )
236
+ if (needsSystemJs) {
237
+ const [systemJsReference] = context.referenceUtils.inject({
238
+ type: "script_src",
239
+ expectedType: "js_classic",
240
+ specifier: systemJsClientFileUrl,
241
+ })
242
+ injectScriptAsEarlyAsPossible(
243
+ htmlAst,
244
+ createHtmlNode({
245
+ "tagName": "script",
246
+ "src": systemJsReference.generatedSpecifier,
247
+ "injected-by": "jsenv:script_type_module_as_classic",
248
+ }),
249
+ )
250
+ }
251
+ }
252
+ return stringifyHtmlAst(htmlAst)
253
+ },
254
+ },
255
+ }
256
+ }
@@ -0,0 +1,93 @@
1
+ import { injectQueryParamsIntoSpecifier } from "@jsenv/utils/urls/url_utils.js"
2
+ import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
3
+ import { parseJsUrls } from "@jsenv/core/packages/utils/js_ast/parse_js_urls.js"
4
+
5
+ export const jsenvPluginWorkersTypeModuleAsClassic = ({
6
+ generateJsClassicFilename,
7
+ }) => {
8
+ const transformJsWorkerTypes = async (urlInfo, context) => {
9
+ const toUpdate = []
10
+ let workerTypeModuleIsSupported
11
+ let serviceWorkerTypeModuleIsSupported
12
+ let sharedWorkerTypeModuleIsSupported
13
+ const jsUrls = parseJsUrls({
14
+ js: urlInfo.content,
15
+ url: (urlInfo.data && urlInfo.data.rawUrl) || urlInfo.url,
16
+ isJsModule: urlInfo.type === "js_module",
17
+ })
18
+ jsUrls.forEach((jsUrlMention) => {
19
+ if (jsUrlMention.expectedType !== "js_module") {
20
+ return
21
+ }
22
+ if (jsUrlMention.expectedSubtype === "worker") {
23
+ if (workerTypeModuleIsSupported === undefined) {
24
+ workerTypeModuleIsSupported =
25
+ context.isSupportedOnCurrentClients("worker_type_module")
26
+ }
27
+ if (workerTypeModuleIsSupported) {
28
+ return
29
+ }
30
+ toUpdate.push(jsUrlMention)
31
+ return
32
+ }
33
+ if (jsUrlMention.expectedSubtype === "service_worker") {
34
+ if (serviceWorkerTypeModuleIsSupported === undefined) {
35
+ serviceWorkerTypeModuleIsSupported =
36
+ context.isSupportedOnCurrentClients("service_worker_type_module")
37
+ }
38
+ if (serviceWorkerTypeModuleIsSupported) {
39
+ return
40
+ }
41
+ toUpdate.push(jsUrlMention)
42
+ return
43
+ }
44
+ if (jsUrlMention.expectedSubtype === "shared_worker") {
45
+ if (sharedWorkerTypeModuleIsSupported === undefined) {
46
+ sharedWorkerTypeModuleIsSupported =
47
+ context.isSupportedOnCurrentClients("shared_worker_type_module")
48
+ }
49
+ if (sharedWorkerTypeModuleIsSupported) {
50
+ return
51
+ }
52
+ toUpdate.push(jsUrlMention)
53
+ return
54
+ }
55
+ })
56
+ if (toUpdate.length === 0) {
57
+ return null
58
+ }
59
+ const magicSource = createMagicSource(urlInfo.content)
60
+ toUpdate.forEach((jsUrlMention) => {
61
+ const reference = context.referenceUtils.findByGeneratedSpecifier(
62
+ JSON.stringify(jsUrlMention.specifier),
63
+ )
64
+ const [newReference] = context.referenceUtils.update(reference, {
65
+ expectedType: "js_classic",
66
+ specifier: injectQueryParamsIntoSpecifier(reference.specifier, {
67
+ as_js_classic: "",
68
+ }),
69
+ filename: generateJsClassicFilename(reference.url),
70
+ })
71
+ magicSource.replace({
72
+ start: jsUrlMention.start,
73
+ end: jsUrlMention.end,
74
+ replacement: newReference.generatedSpecifier,
75
+ })
76
+ magicSource.replace({
77
+ start: jsUrlMention.typePropertyNode.value.start,
78
+ end: jsUrlMention.typePropertyNode.value.end,
79
+ replacement: JSON.stringify("classic"),
80
+ })
81
+ })
82
+ return magicSource.toContentAndSourcemap()
83
+ }
84
+
85
+ return {
86
+ name: "jsenv:workers_type_module_as_classic",
87
+ appliesDuring: "*",
88
+ transformUrlContent: {
89
+ js_module: transformJsWorkerTypes,
90
+ js_classic: transformJsWorkerTypes,
91
+ },
92
+ }
93
+ }
@@ -1,19 +1,9 @@
1
1
  import { getBabelHelperFileUrl, requireBabelPlugin } from "@jsenv/babel-plugins"
2
2
  import { babelPluginCompatMap } from "./babel_plugins_compatibility.js"
3
3
 
4
- export const getBaseBabelPluginStructure = ({
5
- url,
6
- isSupportedOnRuntime,
7
- usesTopLevelAwait,
8
- // // https://github.com/rpetrich/babel-plugin-transform-async-to-promises/blob/92755ff8c943c97596523e586b5fa515c2e99326/async-to-promises.ts#L55
9
- topLevelAwait = "simple",
10
- isJsModule,
11
- }) => {
4
+ export const getBaseBabelPluginStructure = ({ url, isSupported }) => {
12
5
  const isBabelPluginNeeded = (babelPluginName) => {
13
- return !isSupportedOnRuntime(
14
- babelPluginName,
15
- babelPluginCompatMap[babelPluginName],
16
- )
6
+ return !isSupported(babelPluginCompatMap[babelPluginName])
17
7
  }
18
8
 
19
9
  const babelPluginStructure = {}
@@ -40,21 +30,13 @@ export const getBaseBabelPluginStructure = ({
40
30
  babelPluginStructure["proposal-unicode-property-regex"] =
41
31
  requireBabelPlugin("@babel/plugin-proposal-unicode-property-regex")
42
32
  }
43
- if (
44
- isJsModule &&
45
- usesTopLevelAwait &&
46
- !isSupportedOnRuntime("top_level_await")
47
- ) {
33
+ if (isBabelPluginNeeded("transform-async-to-promises")) {
48
34
  babelPluginStructure["transform-async-to-promises"] = [
49
35
  requireBabelPlugin("babel-plugin-transform-async-to-promises"),
50
36
  {
51
- topLevelAwait,
37
+ topLevelAwait: "ignore", // will be handled by "jsenv:top_level_await" plugin
52
38
  },
53
39
  ]
54
- } else if (isBabelPluginNeeded("transform-async-to-promises")) {
55
- babelPluginStructure["transform-async-to-promises"] = requireBabelPlugin(
56
- "babel-plugin-transform-async-to-promises",
57
- )
58
40
  }
59
41
  if (isBabelPluginNeeded("transform-arrow-functions")) {
60
42
  babelPluginStructure["transform-arrow-functions"] = requireBabelPlugin(