@jsenv/core 34.2.1 → 34.3.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 (36) hide show
  1. package/dist/html/explorer.html +5 -4
  2. package/dist/importmap_node_loader.mjs +49 -0
  3. package/dist/js/resolveImport.js +504 -0
  4. package/dist/jsenv.js +392 -670
  5. package/dist/no_experimental_warnings.cjs +8 -0
  6. package/package.json +3 -2
  7. package/src/build/build.js +32 -14
  8. package/src/build/version_mappings_injection.js +20 -27
  9. package/src/dev/file_service.js +1 -1
  10. package/src/execute/execute.js +2 -0
  11. package/src/execute/runtimes/node/exec_options.js +15 -2
  12. package/src/execute/runtimes/node/importmap_node_loader.mjs +51 -0
  13. package/src/execute/runtimes/node/importmap_node_loader_file_url.js +4 -0
  14. package/src/execute/runtimes/node/no_experimental_warnings.cjs +12 -0
  15. package/src/execute/runtimes/node/no_experimental_warnings_file_url.js +4 -0
  16. package/src/execute/runtimes/node/node_child_process.js +15 -0
  17. package/src/execute/runtimes/node/node_worker_thread.js +13 -0
  18. package/src/kitchen/kitchen.js +5 -3
  19. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +2 -2
  20. package/src/plugins/importmap/jsenv_plugin_importmap.js +6 -2
  21. package/src/plugins/{inline/jsenv_plugin_html_inline_content.js → inline_content_analysis/jsenv_plugin_html_inline_content_analysis.js} +12 -6
  22. package/src/plugins/{inline/jsenv_plugin_inline.js → inline_content_analysis/jsenv_plugin_inline_content_analysis.js} +8 -10
  23. package/src/plugins/{inline/jsenv_plugin_js_inline_content.js → inline_content_analysis/jsenv_plugin_js_inline_content_analysis.js} +4 -2
  24. package/src/plugins/inlining/jsenv_plugin_inlining.js +22 -0
  25. package/src/plugins/{inline/jsenv_plugin_inline_query_param.js → inlining/jsenv_plugin_inlining_as_data_url.js} +16 -9
  26. package/src/plugins/inlining/jsenv_plugin_inlining_into_html.js +149 -0
  27. package/src/plugins/plugins.js +5 -2
  28. package/src/plugins/ribbon/jsenv_plugin_ribbon.js +11 -10
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +2 -2
  30. package/src/plugins/supervisor/html_supervisor_injection.js +23 -25
  31. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +20 -5
  32. package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +2 -2
  33. package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +3 -3
  34. package/src/plugins/url_analysis/html/html_urls.js +1 -1
  35. /package/src/plugins/{inline → inline_content_analysis}/client/inline_content.js +0 -0
  36. /package/src/plugins/{inline → inline_content_analysis}/jsenv_plugin_data_urls.js +0 -0
@@ -1,16 +1,10 @@
1
1
  import { DATA_URL } from "@jsenv/urls"
2
2
 
3
- export const jsenvPluginInlineQueryParam = () => {
3
+ export const jsenvPluginInliningAsDataUrl = () => {
4
4
  return {
5
- name: "jsenv:inline_query_param",
5
+ name: "jsenv:inlining_as_data_url",
6
6
  appliesDuring: "*",
7
7
  formatUrl: {
8
- // <link> and <script> can be inlined in the html
9
- // this should be done during dev and postbuild but not build
10
- // so that the bundled file gets inlined and not the entry point
11
- "link_href": () => null,
12
- "style": () => null,
13
- "script": () => null,
14
8
  // if the referenced url is a worker we could use
15
9
  // https://www.oreilly.com/library/view/web-workers/9781449322120/ch04.html
16
10
  // but maybe we should rather use ?object_url
@@ -21,7 +15,20 @@ export const jsenvPluginInlineQueryParam = () => {
21
15
  // in any case the recommended way is to use an url
22
16
  // to benefit from shared worker and reuse worker between tabs
23
17
  "*": (reference, context) => {
24
- if (!reference.searchParams.has("inline")) {
18
+ if (
19
+ !reference.original ||
20
+ !reference.original.searchParams.has("inline")
21
+ ) {
22
+ return null
23
+ }
24
+ // <link rel="stylesheet"> and <script> can be inlined in the html
25
+ if (
26
+ reference.type === "link_href" &&
27
+ reference.subtype === "stylesheet"
28
+ ) {
29
+ return null
30
+ }
31
+ if (reference.type === "script") {
25
32
  return null
26
33
  }
27
34
  return (async () => {
@@ -0,0 +1,149 @@
1
+ import {
2
+ parseHtmlString,
3
+ stringifyHtmlAst,
4
+ visitHtmlNodes,
5
+ getHtmlNodeText,
6
+ analyzeScriptNode,
7
+ getHtmlNodeAttribute,
8
+ setHtmlNodeAttributes,
9
+ setHtmlNodeText,
10
+ getHtmlNodePosition,
11
+ } from "@jsenv/ast"
12
+
13
+ export const jsenvPluginInliningIntoHtml = () => {
14
+ return {
15
+ name: "jsenv:inlining_into_html",
16
+ appliesDuring: "*",
17
+ transformUrlContent: {
18
+ html: async (urlInfo, context) => {
19
+ const htmlAst = parseHtmlString(urlInfo.content)
20
+ const mutations = []
21
+ const actions = []
22
+
23
+ const onStyleSheet = (linkNode, { href }) => {
24
+ const linkReference = context.referenceUtils.find(
25
+ (ref) =>
26
+ ref.generatedSpecifier === href &&
27
+ ref.type === "link_href" &&
28
+ ref.subtype === "stylesheet",
29
+ )
30
+ if (
31
+ !linkReference.original ||
32
+ !linkReference.original.searchParams.has("inline")
33
+ ) {
34
+ return
35
+ }
36
+ const linkUrlInfo = context.urlGraph.getUrlInfo(linkReference.url)
37
+ actions.push(async () => {
38
+ await context.cook(linkUrlInfo, {
39
+ reference: linkReference,
40
+ })
41
+ const { line, column, isOriginal } = getHtmlNodePosition(linkNode, {
42
+ preferOriginal: true,
43
+ })
44
+ context.referenceUtils.becomesInline(linkReference, {
45
+ line: line - 1,
46
+ column,
47
+ isOriginal,
48
+ specifier: linkReference.generatedSpecifier,
49
+ content: linkUrlInfo.content,
50
+ contentType: linkUrlInfo.contentType,
51
+ })
52
+ mutations.push(() => {
53
+ setHtmlNodeAttributes(linkNode, {
54
+ "inlined-from-href": href,
55
+ "href": undefined,
56
+ "rel": undefined,
57
+ "type": undefined,
58
+ "as": undefined,
59
+ "crossorigin": undefined,
60
+ "integrity": undefined,
61
+ "jsenv-inlined-by": "jsenv:inlining_into_html",
62
+ })
63
+ linkNode.nodeName = "style"
64
+ linkNode.tagName = "style"
65
+ setHtmlNodeText(linkNode, linkUrlInfo.content, {
66
+ indentation: "auto",
67
+ })
68
+ })
69
+ })
70
+ }
71
+ const onScriptWithSrc = (scriptNode, { src }) => {
72
+ const scriptReference = context.referenceUtils.find(
73
+ (ref) => ref.generatedSpecifier === src && ref.type === "script",
74
+ )
75
+ if (
76
+ !scriptReference.original ||
77
+ !scriptReference.original.searchParams.has("inline")
78
+ ) {
79
+ return
80
+ }
81
+ const scriptUrlInfo = context.urlGraph.getUrlInfo(scriptReference.url)
82
+ actions.push(async () => {
83
+ await context.cook(scriptUrlInfo, {
84
+ reference: scriptReference,
85
+ })
86
+ const { line, column, isOriginal } = getHtmlNodePosition(
87
+ scriptNode,
88
+ {
89
+ preferOriginal: true,
90
+ },
91
+ )
92
+ context.referenceUtils.becomesInline(scriptReference, {
93
+ line: line - 1,
94
+ column,
95
+ isOriginal,
96
+ specifier: scriptReference.generatedSpecifier,
97
+ content: scriptUrlInfo.content,
98
+ contentType: scriptUrlInfo.contentType,
99
+ })
100
+ mutations.push(() => {
101
+ setHtmlNodeAttributes(scriptNode, {
102
+ "inlined-from-src": src,
103
+ "src": undefined,
104
+ "crossorigin": undefined,
105
+ "integrity": undefined,
106
+ "jsenv-inlined-by": "jsenv:inlining_into_html",
107
+ })
108
+ setHtmlNodeText(scriptNode, scriptUrlInfo.content, {
109
+ indentation: "auto",
110
+ })
111
+ })
112
+ })
113
+ }
114
+
115
+ visitHtmlNodes(htmlAst, {
116
+ link: (linkNode) => {
117
+ const rel = getHtmlNodeAttribute(linkNode, "rel")
118
+ if (rel !== "stylesheet") {
119
+ return
120
+ }
121
+ const href = getHtmlNodeAttribute(linkNode, "href")
122
+ if (!href) {
123
+ return
124
+ }
125
+ onStyleSheet(linkNode, { href })
126
+ },
127
+ script: (scriptNode) => {
128
+ const { type } = analyzeScriptNode(scriptNode)
129
+ const scriptNodeText = getHtmlNodeText(scriptNode)
130
+ if (scriptNodeText) {
131
+ return
132
+ }
133
+ const src = getHtmlNodeAttribute(scriptNode, "src")
134
+ if (!src) {
135
+ return
136
+ }
137
+ onScriptWithSrc(scriptNode, { type, src })
138
+ },
139
+ })
140
+ if (actions.length > 0) {
141
+ await Promise.all(actions.map((action) => action()))
142
+ }
143
+ mutations.forEach((mutation) => mutation())
144
+ const htmlModified = stringifyHtmlAst(htmlAst)
145
+ return htmlModified
146
+ },
147
+ },
148
+ }
149
+ }
@@ -4,7 +4,8 @@ import { jsenvPluginUrlResolution } from "./url_resolution/jsenv_plugin_url_reso
4
4
  import { jsenvPluginUrlVersion } from "./url_version/jsenv_plugin_url_version.js"
5
5
  import { jsenvPluginFileUrls } from "./file_urls/jsenv_plugin_file_urls.js"
6
6
  import { jsenvPluginHttpUrls } from "./http_urls/jsenv_plugin_http_urls.js"
7
- import { jsenvPluginInline } from "./inline/jsenv_plugin_inline.js"
7
+ import { jsenvPluginInlineContentAnalysis } from "./inline_content_analysis/jsenv_plugin_inline_content_analysis.js"
8
+ import { jsenvPluginInlining } from "./inlining/jsenv_plugin_inlining.js"
8
9
  import { jsenvPluginSupervisor } from "./supervisor/jsenv_plugin_supervisor.js"
9
10
  import { jsenvPluginCommonJsGlobals } from "./commonjs_globals/jsenv_plugin_commonjs_globals.js"
10
11
  import { jsenvPluginImportMetaScenarios } from "./import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js"
@@ -31,6 +32,7 @@ export const getCorePlugins = ({
31
32
  directoryReferenceAllowed,
32
33
  supervisor,
33
34
  transpilation = true,
35
+ inlining = true,
34
36
 
35
37
  clientAutoreload = false,
36
38
  clientFileChangeCallbackList,
@@ -66,7 +68,8 @@ export const getCorePlugins = ({
66
68
  jsenvPluginImportmap(),
67
69
  // before node esm to handle bare specifiers
68
70
  // + before node esm to handle importmap before inline content
69
- jsenvPluginInline(), // before "file urls" to resolve and load inline urls
71
+ jsenvPluginInlineContentAnalysis(), // before "file urls" to resolve and load inline urls
72
+ ...(inlining ? [jsenvPluginInlining()] : []),
70
73
  ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []), // after inline as it needs inline script to be cooked
71
74
  jsenvPluginFileUrls({
72
75
  directoryReferenceAllowed,
@@ -47,16 +47,17 @@ export const jsenvPluginRibbon = ({
47
47
  null,
48
48
  " ",
49
49
  )
50
- const scriptNode = createHtmlNode({
51
- tagName: "script",
52
- type: "module",
53
- textContent: `
54
- import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}"
55
-
56
- injectRibbon(${paramsJson})
57
- `,
58
- })
59
- injectHtmlNode(htmlAst, scriptNode, "jsenv:ribbon")
50
+ injectHtmlNode(
51
+ htmlAst,
52
+ createHtmlNode({
53
+ tagName: "script",
54
+ type: "module",
55
+ textContent: `import { injectRibbon } from "${ribbonClientFileReference.generatedSpecifier}"
56
+
57
+ injectRibbon(${paramsJson});`,
58
+ }),
59
+ "jsenv:ribbon",
60
+ )
60
61
  return stringifyHtmlAst(htmlAst)
61
62
  },
62
63
  },
@@ -6,7 +6,7 @@
6
6
  import {
7
7
  parseHtmlString,
8
8
  stringifyHtmlAst,
9
- injectScriptNodeAsEarlyAsPossible,
9
+ injectHtmlNodeAsEarlyAsPossible,
10
10
  createHtmlNode,
11
11
  } from "@jsenv/ast"
12
12
 
@@ -30,7 +30,7 @@ export const jsenvPluginServerEventsClientInjection = () => {
30
30
  specifier: serverEventsClientFileUrl,
31
31
  },
32
32
  )
33
- injectScriptNodeAsEarlyAsPossible(
33
+ injectHtmlNodeAsEarlyAsPossible(
34
34
  htmlAst,
35
35
  createHtmlNode({
36
36
  tagName: "script",
@@ -52,7 +52,7 @@ import {
52
52
  getHtmlNodeAttribute,
53
53
  setHtmlNodeAttributes,
54
54
  analyzeScriptNode,
55
- injectScriptNodeAsEarlyAsPossible,
55
+ injectHtmlNodeAsEarlyAsPossible,
56
56
  createHtmlNode,
57
57
  getHtmlNodePosition,
58
58
  getHtmlNodeText,
@@ -125,7 +125,9 @@ export const injectSupervisorIntoHTML = async (
125
125
  src: inlineScriptSrc,
126
126
  })
127
127
  mutations.push(() => {
128
- setHtmlNodeText(scriptNode, remoteJsSupervised)
128
+ setHtmlNodeText(scriptNode, remoteJsSupervised, {
129
+ indentation: "auto",
130
+ })
129
131
  setHtmlNodeAttributes(scriptNode, {
130
132
  "jsenv-cooked-by": "jsenv:supervisor",
131
133
  "src": undefined,
@@ -144,7 +146,9 @@ export const injectSupervisorIntoHTML = async (
144
146
  inlineSrc: inlineScriptSrc,
145
147
  })
146
148
  mutations.push(() => {
147
- setHtmlNodeText(scriptNode, inlineJsSupervised)
149
+ setHtmlNodeText(scriptNode, inlineJsSupervised, {
150
+ indentation: "auto",
151
+ })
148
152
  setHtmlNodeAttributes(scriptNode, {
149
153
  "jsenv-cooked-by": "jsenv:supervisor",
150
154
  })
@@ -171,7 +175,7 @@ export const injectSupervisorIntoHTML = async (
171
175
  src,
172
176
  })
173
177
  mutations.push(() => {
174
- setHtmlNodeText(scriptNode, remoteJsSupervised)
178
+ setHtmlNodeText(scriptNode, remoteJsSupervised, { indentation: "auto" })
175
179
  setHtmlNodeAttributes(scriptNode, {
176
180
  "jsenv-cooked-by": "jsenv:supervisor",
177
181
  "src": undefined,
@@ -204,6 +208,10 @@ export const injectSupervisorIntoHTML = async (
204
208
  }
205
209
  const src = getHtmlNodeAttribute(scriptNode, "src")
206
210
  if (src) {
211
+ const urlObject = new URL(src, "http://example.com")
212
+ if (urlObject.searchParams.has("inline")) {
213
+ return
214
+ }
207
215
  handleScriptWithSrc(scriptNode, { type, src })
208
216
  return
209
217
  }
@@ -219,27 +227,22 @@ export const injectSupervisorIntoHTML = async (
219
227
  rootDirectoryUrl: webServer.rootDirectoryUrl,
220
228
  scriptInfos,
221
229
  },
222
- " ",
230
+ " ",
223
231
  )
224
- injectScriptNodeAsEarlyAsPossible(
232
+ injectHtmlNodeAsEarlyAsPossible(
225
233
  htmlAst,
226
234
  createHtmlNode({
227
235
  tagName: "script",
228
- textContent: `
229
- window.__supervisor__.setup({
230
- ${setupParamsSource}
231
- })
232
- `,
236
+ textContent: `window.__supervisor__.setup({${setupParamsSource}})`,
233
237
  }),
234
238
  "jsenv:supervisor",
235
239
  )
236
- const supervisorScript = createHtmlNode({
237
- tagName: "script",
238
- src: supervisorScriptSrc,
239
- })
240
- injectScriptNodeAsEarlyAsPossible(
240
+ injectHtmlNodeAsEarlyAsPossible(
241
241
  htmlAst,
242
- supervisorScript,
242
+ createHtmlNode({
243
+ tagName: "script",
244
+ src: supervisorScriptSrc,
245
+ }),
243
246
  "jsenv:supervisor",
244
247
  )
245
248
  }
@@ -268,14 +271,9 @@ const stringifyParams = (params, prefix = "") => {
268
271
  }
269
272
 
270
273
  const generateCodeToSuperviseScriptWithSrc = ({ type, src }) => {
274
+ const srcEncoded = JSON.stringify(src)
271
275
  if (type === "js_module") {
272
- return `
273
- window.__supervisor__.superviseScriptTypeModule(${JSON.stringify(
274
- src,
275
- )}, (url) => import(url));
276
- `
276
+ return `window.__supervisor__.superviseScriptTypeModule(${srcEncoded}, (url) => import(url));`
277
277
  }
278
- return `
279
- window.__supervisor__.superviseScript(${JSON.stringify(src)});
280
- `
278
+ return `window.__supervisor__.superviseScript(${srcEncoded});`
281
279
  }
@@ -36,10 +36,25 @@ export const jsenvPluginImportAssertions = ({
36
36
  }
37
37
  const turnIntoJsModuleProxy = (reference, type) => {
38
38
  reference.mutation = (magicSource) => {
39
- magicSource.remove({
40
- start: reference.assertNode.start,
41
- end: reference.assertNode.end,
42
- })
39
+ const { assertNode } = reference
40
+ if (reference.subtype === "import_dynamic") {
41
+ const assertPropertyNode = assertNode.properties.find(
42
+ (prop) => prop.key.name === "assert",
43
+ )
44
+ const assertPropertyValue = assertPropertyNode.value
45
+ const typePropertyNode = assertPropertyValue.properties.find(
46
+ (prop) => prop.key.name === "type",
47
+ )
48
+ magicSource.remove({
49
+ start: typePropertyNode.start,
50
+ end: typePropertyNode.end,
51
+ })
52
+ } else {
53
+ magicSource.remove({
54
+ start: assertNode.start,
55
+ end: assertNode.end,
56
+ })
57
+ }
43
58
  }
44
59
  const newUrl = injectQueryParams(reference.url, {
45
60
  [`as_${type}_module`]: "",
@@ -88,7 +103,7 @@ export const jsenvPluginImportAssertions = ({
88
103
 
89
104
  const jsenvPluginAsModules = () => {
90
105
  const inlineContentClientFileUrl = new URL(
91
- "../../inline/client/inline_content.js",
106
+ "../../inline_content_analysis/client/inline_content.js",
92
107
  import.meta.url,
93
108
  ).href
94
109
 
@@ -13,7 +13,7 @@ import {
13
13
  getHtmlNodeAttribute,
14
14
  setHtmlNodeAttributes,
15
15
  analyzeScriptNode,
16
- injectScriptNodeAsEarlyAsPossible,
16
+ injectHtmlNodeAsEarlyAsPossible,
17
17
  createHtmlNode,
18
18
  } from "@jsenv/ast"
19
19
  import { injectQueryParams, urlToRelativeUrl } from "@jsenv/urls"
@@ -202,7 +202,7 @@ export const jsenvPluginJsModuleFallbackInsideHtml = ({
202
202
  await context.cook(systemJsUrlInfo, {
203
203
  reference: systemJsReference,
204
204
  })
205
- injectScriptNodeAsEarlyAsPossible(
205
+ injectHtmlNodeAsEarlyAsPossible(
206
206
  htmlAst,
207
207
  createHtmlNode({
208
208
  tagName: "script",
@@ -2,13 +2,13 @@
2
2
  * when {type: "module"} cannot be used on web workers:
3
3
  * - new Worker("worker.js", { type: "module" })
4
4
  * transformed into
5
- * new Worker("worker.js?as_js_classic", { type: " lassic" })
5
+ * new Worker("worker.js?js_module_fallback", { type: " lassic" })
6
6
  * - navigator.serviceWorker.register("service_worker.js", { type: "module" })
7
7
  * transformed into
8
- * navigator.serviceWorker.register("service_worker.js?as_js_classic", { type: "classic" })
8
+ * navigator.serviceWorker.register("service_worker.js?js_module_fallback", { type: "classic" })
9
9
  * - new SharedWorker("shared_worker.js", { type: "module" })
10
10
  * transformed into
11
- * new SharedWorker("shared_worker.js?as_js_classic", { type: "classic" })
11
+ * new SharedWorker("shared_worker.js?js_module_fallback", { type: "classic" })
12
12
  */
13
13
 
14
14
  import { injectQueryParams } from "@jsenv/urls"
@@ -208,7 +208,7 @@ const visitHtmlUrls = ({ url, htmlAst }) => {
208
208
  if (type === "text") {
209
209
  // ignore <script type="whatever" src="./file.js">
210
210
  // per HTML spec https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
211
- // this will be handled by jsenv_plugin_html_inline_content
211
+ // this will be handled by jsenv_plugin_html_inline_content_analysis
212
212
  return
213
213
  }
214
214
  visitAttributeAsUrlSpecifier({