@jsenv/plugin-transpilation 1.0.0 → 1.2.0

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 (25) hide show
  1. package/package.json +26 -26
  2. package/src/as_js_module/jsenv_plugin_as_js_module.js +14 -28
  3. package/src/babel/babel_helper_directory/README.md +1 -1
  4. package/src/babel/babel_helper_directory/babel_helpers/applyDecs2301/applyDecs2301.js +547 -528
  5. package/src/babel/babel_helper_directory/babel_helpers/applyDecs2305/applyDecs2305.js +681 -0
  6. package/src/babel/babel_plugin_structure.js +1 -1
  7. package/src/babel/jsenv_plugin_babel.js +91 -19
  8. package/src/babel/new_stylesheet/babel_plugin_new_stylesheet_injector.js +11 -135
  9. package/src/babel/new_stylesheet/constructable_stylesheet_usage.js +114 -0
  10. package/src/babel/new_stylesheet/new_stylesheet_client_file_url.js +4 -0
  11. package/src/babel/regenerator_runtime/babel_plugin_regenerator_runtime_injector.js +11 -35
  12. package/src/babel/regenerator_runtime/regenerator_runtime_client_file_url.js +4 -0
  13. package/src/babel/regenerator_runtime/regenerator_runtime_usage.js +23 -0
  14. package/src/babel/{polyfill_injection_in_babel_ast.js → side_effect_injection_in_babel_ast.js} +8 -8
  15. package/src/css/jsenv_plugin_css_transpilation.js +2 -2
  16. package/src/import_assertions/jsenv_plugin_import_assertions.js +39 -78
  17. package/src/import_meta_resolve/jsenv_plugin_import_meta_resolve.js +17 -13
  18. package/src/js_module_fallback/jsenv_plugin_js_module_conversion.js +56 -48
  19. package/src/js_module_fallback/jsenv_plugin_js_module_fallback.js +3 -38
  20. package/src/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +63 -122
  21. package/src/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +15 -6
  22. package/src/babel/apply_js_transpilation.js +0 -74
  23. package/src/babel/global_this/babel_plugin_global_this_injector.js +0 -56
  24. package/src/babel/global_this/client/global_this_js_classic.js +0 -25
  25. package/src/babel/global_this/client/global_this_js_module.js +0 -21
@@ -5,7 +5,7 @@
5
5
  * - <link rel="modulepreload"> are converted to <link rel="preload">
6
6
  */
7
7
 
8
- import { readFileSync } from "node:fs";
8
+ import { injectQueryParams } from "@jsenv/urls";
9
9
  import {
10
10
  parseHtmlString,
11
11
  visitHtmlNodes,
@@ -13,17 +13,18 @@ import {
13
13
  getHtmlNodeAttribute,
14
14
  setHtmlNodeAttributes,
15
15
  analyzeScriptNode,
16
- injectHtmlNodeAsEarlyAsPossible,
17
- createHtmlNode,
18
16
  } from "@jsenv/ast";
19
- import { injectQueryParams, urlToRelativeUrl } from "@jsenv/urls";
20
- import { SOURCEMAP } from "@jsenv/sourcemap";
21
17
 
22
- export const jsenvPluginJsModuleFallbackInsideHtml = ({
23
- systemJsInjection,
24
- systemJsClientFileUrl,
25
- }) => {
18
+ export const jsenvPluginJsModuleFallbackInsideHtml = () => {
26
19
  const turnIntoJsClassicProxy = (reference) => {
20
+ // not needed for now: redirections are disabled
21
+ // for getWithoutSearchParam
22
+ // if (
23
+ // reference.prev &&
24
+ // reference.prev.searchParams.has("js_module_fallback")
25
+ // ) {
26
+ // return null;
27
+ // }
27
28
  return injectQueryParams(reference.url, { js_module_fallback: "" });
28
29
  };
29
30
 
@@ -31,15 +32,15 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
31
32
  name: "jsenv:js_module_fallback_inside_html",
32
33
  appliesDuring: "*",
33
34
  redirectReference: {
34
- link_href: (reference, context) => {
35
+ link_href: (reference) => {
35
36
  if (
36
- context.systemJsTranspilation &&
37
+ reference.ownerUrlInfo.context.systemJsTranspilation &&
37
38
  reference.subtype === "modulepreload"
38
39
  ) {
39
40
  return turnIntoJsClassicProxy(reference);
40
41
  }
41
42
  if (
42
- context.systemJsTranspilation &&
43
+ reference.ownerUrlInfo.context.systemJsTranspilation &&
43
44
  reference.subtype === "preload" &&
44
45
  reference.expectedType === "js_module"
45
46
  ) {
@@ -47,18 +48,18 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
47
48
  }
48
49
  return null;
49
50
  },
50
- script: (reference, context) => {
51
+ script: (reference) => {
51
52
  if (
52
- context.systemJsTranspilation &&
53
+ reference.ownerUrlInfo.context.systemJsTranspilation &&
53
54
  reference.expectedType === "js_module"
54
55
  ) {
55
56
  return turnIntoJsClassicProxy(reference);
56
57
  }
57
58
  return null;
58
59
  },
59
- js_url: (reference, context) => {
60
+ js_url: (reference) => {
60
61
  if (
61
- context.systemJsTranspilation &&
62
+ reference.ownerUrlInfo.context.systemJsTranspilation &&
62
63
  reference.expectedType === "js_module"
63
64
  ) {
64
65
  return turnIntoJsClassicProxy(reference);
@@ -67,7 +68,7 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
67
68
  },
68
69
  },
69
70
  finalizeUrlContent: {
70
- html: async (urlInfo, context) => {
71
+ html: async (urlInfo) => {
71
72
  const htmlAst = parseHtmlString(urlInfo.content);
72
73
  const mutations = [];
73
74
  visitHtmlNodes(htmlAst, {
@@ -80,19 +81,21 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
80
81
  if (!href) {
81
82
  return;
82
83
  }
83
- const reference = context.referenceUtils.find(
84
- (ref) =>
85
- ref.generatedSpecifier === href &&
86
- ref.type === "link_href" &&
87
- ref.subtype === rel,
88
- );
89
- if (!isOrWasExpectingJsModule(reference)) {
84
+ let linkHintReference = null;
85
+ for (const referenceToOther of urlInfo.referenceToOthersSet) {
86
+ if (
87
+ referenceToOther.generatedSpecifier === href &&
88
+ referenceToOther.type === "link_href" &&
89
+ referenceToOther.subtype === rel
90
+ ) {
91
+ linkHintReference = referenceToOther;
92
+ break;
93
+ }
94
+ }
95
+ if (!wasOrWillBeConvertedToJsClassic(linkHintReference)) {
90
96
  return;
91
97
  }
92
- if (
93
- rel === "modulepreload" &&
94
- reference.expectedType === "js_classic"
95
- ) {
98
+ if (rel === "modulepreload") {
96
99
  mutations.push(() => {
97
100
  setHtmlNodeAttributes(node, {
98
101
  rel: "preload",
@@ -101,7 +104,7 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
101
104
  });
102
105
  });
103
106
  }
104
- if (rel === "preload" && reference.expectedType === "js_classic") {
107
+ if (rel === "preload") {
105
108
  mutations.push(() => {
106
109
  setHtmlNodeAttributes(node, { crossorigin: undefined });
107
110
  });
@@ -114,126 +117,64 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
114
117
  }
115
118
  const src = getHtmlNodeAttribute(node, "src");
116
119
  if (src) {
117
- const reference = context.referenceUtils.find(
118
- (ref) =>
119
- ref.generatedSpecifier === src &&
120
- ref.type === "script" &&
121
- ref.subtype === "js_module",
122
- );
123
- if (!reference) {
120
+ let scriptTypeModuleReference = null;
121
+ for (const referenceToOther of urlInfo.referenceToOthersSet) {
122
+ if (
123
+ referenceToOther.generatedSpecifier === src &&
124
+ referenceToOther.type === "script" &&
125
+ referenceToOther.subtype === "js_module"
126
+ ) {
127
+ scriptTypeModuleReference = referenceToOther;
128
+ break;
129
+ }
130
+ }
131
+ if (!scriptTypeModuleReference) {
124
132
  return;
125
133
  }
126
- if (reference.expectedType === "js_classic") {
134
+ if (scriptTypeModuleReference.expectedType === "js_classic") {
127
135
  mutations.push(() => {
128
136
  setHtmlNodeAttributes(node, { type: undefined });
129
137
  });
130
138
  }
131
- } else if (context.systemJsTranspilation) {
139
+ } else if (urlInfo.context.systemJsTranspilation) {
132
140
  mutations.push(() => {
133
141
  setHtmlNodeAttributes(node, { type: undefined });
134
142
  });
135
143
  }
136
144
  },
137
145
  });
138
- if (systemJsInjection) {
139
- let needsSystemJs = false;
140
- for (const reference of urlInfo.references) {
141
- if (reference.isResourceHint) {
142
- // we don't cook resource hints
143
- // because they might refer to resource that will be modified during build
144
- // It also means something else HAVE to reference that url in order to cook it
145
- // so that the preload is deleted by "resync_resource_hints.js" otherwise
146
- continue;
147
- }
148
- if (isOrWasExpectingJsModule(reference)) {
149
- const dependencyUrlInfo = context.urlGraph.getUrlInfo(
150
- reference.url,
151
- );
152
- try {
153
- await context.cook(dependencyUrlInfo, { reference });
154
- if (dependencyUrlInfo.data.jsClassicFormat === "system") {
155
- needsSystemJs = true;
156
- break;
157
- }
158
- } catch (e) {
159
- if (context.dev && e.code !== "PARSE_ERROR") {
160
- needsSystemJs = true;
161
- // ignore cooking error, the browser will trigger it again on fetch
162
- // + disable cache for this html file because when browser will reload
163
- // the error might be gone and we might need to inject systemjs
164
- urlInfo.headers["cache-control"] = "no-store";
165
- } else {
166
- throw e;
167
- }
168
- }
169
- }
170
- }
171
- if (needsSystemJs) {
172
- mutations.push(async () => {
173
- let systemJsFileContent = readFileSync(
174
- new URL(systemJsClientFileUrl),
175
- { encoding: "utf8" },
176
- );
177
- const sourcemapFound = SOURCEMAP.readComment({
178
- contentType: "text/javascript",
179
- content: systemJsFileContent,
180
- });
181
- if (sourcemapFound) {
182
- const sourcemapFileUrl = new URL(
183
- sourcemapFound.specifier,
184
- systemJsClientFileUrl,
185
- );
186
- systemJsFileContent = SOURCEMAP.writeComment({
187
- contentType: "text/javascript",
188
- content: systemJsFileContent,
189
- specifier: urlToRelativeUrl(sourcemapFileUrl, urlInfo.url),
190
- });
191
- }
192
- const [systemJsReference, systemJsUrlInfo] =
193
- context.referenceUtils.inject({
194
- type: "script",
195
- expectedType: "js_classic",
196
- isInline: true,
197
- contentType: "text/javascript",
198
- content: systemJsFileContent,
199
- specifier: "s.js",
200
- });
201
- await context.cook(systemJsUrlInfo, {
202
- reference: systemJsReference,
203
- });
204
- injectHtmlNodeAsEarlyAsPossible(
205
- htmlAst,
206
- createHtmlNode({
207
- tagName: "script",
208
- textContent: systemJsUrlInfo.content,
209
- }),
210
- "jsenv:js_module_fallback",
211
- );
212
- });
213
- }
214
- }
215
146
  await Promise.all(mutations.map((mutation) => mutation()));
216
147
  return stringifyHtmlAst(htmlAst, {
217
- cleanupPositionAttributes: context.dev,
148
+ cleanupPositionAttributes: urlInfo.context.dev,
218
149
  });
219
150
  },
220
151
  },
221
152
  };
222
153
  };
223
154
 
224
- const isOrWasExpectingJsModule = (reference) => {
225
- if (isExpectingJsModule(reference)) {
226
- return true;
155
+ const wasOrWillBeConvertedToJsClassic = (reference) => {
156
+ if (reference.expectedType !== "js_module") {
157
+ return false;
227
158
  }
228
- if (reference.original && isExpectingJsModule(reference.original)) {
159
+ if (willBeConvertedToJsClassic(reference)) {
229
160
  return true;
230
161
  }
162
+ let prev = reference.prev;
163
+ while (prev) {
164
+ if (prev.expectedType === "js_classic") {
165
+ return true;
166
+ }
167
+ if (willBeConvertedToJsClassic(prev)) {
168
+ return true;
169
+ }
170
+ prev = prev.prev;
171
+ }
172
+
231
173
  return false;
232
174
  };
233
175
 
234
- const isExpectingJsModule = (reference) => {
176
+ const willBeConvertedToJsClassic = (reference) => {
235
177
  return (
236
- reference.expectedType === "js_module" ||
237
178
  reference.searchParams.has("js_module_fallback") ||
238
179
  reference.searchParams.has("as_js_classic")
239
180
  );
@@ -16,9 +16,10 @@ import { injectQueryParams } from "@jsenv/urls";
16
16
  export const jsenvPluginJsModuleFallbackOnWorkers = () => {
17
17
  const turnIntoJsClassicProxy = (reference) => {
18
18
  reference.mutation = (magicSource) => {
19
+ const { typePropertyNode } = reference.astInfo;
19
20
  magicSource.replace({
20
- start: reference.typePropertyNode.value.start,
21
- end: reference.typePropertyNode.value.end,
21
+ start: typePropertyNode.value.start,
22
+ end: typePropertyNode.value.end,
22
23
  replacement: JSON.stringify("classic"),
23
24
  });
24
25
  };
@@ -29,19 +30,25 @@ export const jsenvPluginJsModuleFallbackOnWorkers = () => {
29
30
  name: "jsenv:js_module_fallback_on_workers",
30
31
  appliesDuring: "*",
31
32
  redirectReference: {
32
- js_url: (reference, context) => {
33
+ js_url: (reference) => {
33
34
  if (reference.expectedType !== "js_module") {
34
35
  return null;
35
36
  }
36
37
  if (reference.expectedSubtype === "worker") {
37
- if (context.isSupportedOnCurrentClients("worker_type_module")) {
38
+ if (
39
+ reference.ownerUrlInfo.context.isSupportedOnCurrentClients(
40
+ "worker_type_module",
41
+ )
42
+ ) {
38
43
  return null;
39
44
  }
40
45
  return turnIntoJsClassicProxy(reference);
41
46
  }
42
47
  if (reference.expectedSubtype === "service_worker") {
43
48
  if (
44
- context.isSupportedOnCurrentClients("service_worker_type_module")
49
+ reference.ownerUrlInfo.context.isSupportedOnCurrentClients(
50
+ "service_worker_type_module",
51
+ )
45
52
  ) {
46
53
  return null;
47
54
  }
@@ -49,7 +56,9 @@ export const jsenvPluginJsModuleFallbackOnWorkers = () => {
49
56
  }
50
57
  if (reference.expectedSubtype === "shared_worker") {
51
58
  if (
52
- context.isSupportedOnCurrentClients("shared_worker_type_module")
59
+ reference.ownerUrlInfo.context.isSupportedOnCurrentClients(
60
+ "shared_worker_type_module",
61
+ )
53
62
  ) {
54
63
  return null;
55
64
  }
@@ -1,74 +0,0 @@
1
- import { applyBabelPlugins } from "@jsenv/ast";
2
- import { RUNTIME_COMPAT } from "@jsenv/runtime-compat";
3
-
4
- import { getBaseBabelPluginStructure } from "./babel_plugin_structure.js";
5
- import { babelPluginBabelHelpersAsJsenvImports } from "./babel_plugin_babel_helpers_as_jsenv_imports.js";
6
- import { babelPluginNewStylesheetInjector } from "./new_stylesheet/babel_plugin_new_stylesheet_injector.js";
7
- import { babelPluginGlobalThisInjector } from "./global_this/babel_plugin_global_this_injector.js";
8
- import { babelPluginRegeneratorRuntimeInjector } from "./regenerator_runtime/babel_plugin_regenerator_runtime_injector.js";
9
-
10
- export const applyJsTranspilation = async ({
11
- input,
12
- inputIsJsModule = false,
13
- inputUrl,
14
- outputUrl,
15
- runtimeCompat,
16
- babelHelpersAsImport = true,
17
- babelOptions,
18
- getImportSpecifier,
19
- }) => {
20
- const isSupported = (feature) => {
21
- return RUNTIME_COMPAT.isSupported(runtimeCompat, feature);
22
- };
23
- const babelPluginStructure = getBaseBabelPluginStructure({
24
- url: inputUrl,
25
- isSupported,
26
- isJsModule: inputIsJsModule,
27
- getImportSpecifier,
28
- });
29
-
30
- if (!isSupported("global_this")) {
31
- babelPluginStructure["global-this-injector"] = [
32
- babelPluginGlobalThisInjector,
33
- { babelHelpersAsImport, getImportSpecifier },
34
- ];
35
- }
36
- if (!isSupported("async_generator_function")) {
37
- babelPluginStructure["regenerator-runtime-injector"] = [
38
- babelPluginRegeneratorRuntimeInjector,
39
- { babelHelpersAsImport, getImportSpecifier },
40
- ];
41
- }
42
- if (!isSupported("new_stylesheet")) {
43
- babelPluginStructure["new-stylesheet-injector"] = [
44
- babelPluginNewStylesheetInjector,
45
- { babelHelpersAsImport, getImportSpecifier },
46
- ];
47
- }
48
- if (
49
- inputIsJsModule &&
50
- babelHelpersAsImport &&
51
- Object.keys(babelPluginStructure).length > 0
52
- ) {
53
- babelPluginStructure["babel-helper-as-jsenv-import"] = [
54
- babelPluginBabelHelpersAsJsenvImports,
55
- { getImportSpecifier },
56
- ];
57
- }
58
-
59
- const babelPlugins = Object.keys(babelPluginStructure).map(
60
- (babelPluginName) => babelPluginStructure[babelPluginName],
61
- );
62
- const { code, map } = await applyBabelPlugins({
63
- babelPlugins,
64
- options: babelOptions,
65
- input,
66
- inputIsJsModule,
67
- inputUrl,
68
- outputUrl,
69
- });
70
- return {
71
- content: code,
72
- sourcemap: map,
73
- };
74
- };
@@ -1,56 +0,0 @@
1
- import { pathToFileURL } from "node:url";
2
- import { injectPolyfillIntoBabelAst } from "../polyfill_injection_in_babel_ast.js";
3
-
4
- const globalThisJsModuleClientFileUrl = new URL(
5
- "./client/global_this_js_module.js",
6
- import.meta.url,
7
- ).href;
8
- const globalThisJsClassicClientFileUrl = new URL(
9
- "./client/global_this_js_classic.js?js_classic",
10
- import.meta.url,
11
- ).href;
12
-
13
- export const babelPluginGlobalThisInjector = (
14
- babel,
15
- { babelHelpersAsImport, getImportSpecifier },
16
- ) => {
17
- return {
18
- name: "global-this-injector",
19
- visitor: {
20
- Program: {
21
- enter: (path, state) => {
22
- let globalThisDetected = false;
23
- const { filename } = state;
24
- const fileUrl = pathToFileURL(filename).href;
25
- if (fileUrl === globalThisJsModuleClientFileUrl) {
26
- return;
27
- }
28
- path.traverse({
29
- Identifier(path) {
30
- const { node } = path;
31
- if (node.name === "globalThis") {
32
- globalThisDetected = true;
33
- path.stop();
34
- }
35
- },
36
- });
37
- state.file.metadata.globalThisDetected = globalThisDetected;
38
- if (globalThisDetected) {
39
- const { sourceType } = state.file.opts.parserOpts;
40
- const isJsModule = sourceType === "module";
41
- injectPolyfillIntoBabelAst({
42
- programPath: path,
43
- isJsModule,
44
- asImport: babelHelpersAsImport,
45
- polyfillFileUrl: isJsModule
46
- ? globalThisJsModuleClientFileUrl
47
- : globalThisJsClassicClientFileUrl,
48
- getPolyfillImportSpecifier: getImportSpecifier,
49
- babel,
50
- });
51
- }
52
- },
53
- },
54
- },
55
- };
56
- };
@@ -1,25 +0,0 @@
1
- // https://mathiasbynens.be/notes/globalthis
2
-
3
- /* eslint-disable no-redeclare */
4
- /* global globalThis */
5
- let globalObject;
6
- if (typeof globalThis === "object") {
7
- globalObject = globalThis;
8
- } else {
9
- if (typeof this === "object") {
10
- globalObject = this;
11
- } else {
12
- // eslint-disable-next-line no-extend-native
13
- Object.defineProperty(Object.prototype, "__global__", {
14
- get() {
15
- return this;
16
- },
17
- configurable: true,
18
- });
19
- // eslint-disable-next-line no-undef
20
- globalObject = __global__;
21
- delete Object.prototype.__global__;
22
- }
23
-
24
- globalObject.globalThis = globalObject;
25
- }
@@ -1,21 +0,0 @@
1
- // https://mathiasbynens.be/notes/globalthis
2
-
3
- /* eslint-disable no-redeclare */
4
- /* global globalThis */
5
- let globalObject;
6
- if (typeof globalThis === "object") {
7
- globalObject = globalThis;
8
- } else {
9
- // eslint-disable-next-line no-extend-native
10
- Object.defineProperty(Object.prototype, "__global__", {
11
- get() {
12
- return this;
13
- },
14
- configurable: true,
15
- });
16
- // eslint-disable-next-line no-undef
17
- globalObject = __global__;
18
- delete Object.prototype.__global__;
19
- }
20
-
21
- globalObject.globalThis = globalObject;