@jsenv/core 28.1.1 → 28.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 (51) hide show
  1. package/dist/js/script_type_module_supervisor.js +8 -13
  2. package/dist/js/supervisor.js +702 -534
  3. package/dist/main.js +13275 -13164
  4. package/package.json +5 -5
  5. package/readme.md +3 -3
  6. package/src/build/build.js +960 -712
  7. package/src/build/inject_global_version_mappings.js +5 -20
  8. package/src/build/start_build_server.js +2 -2
  9. package/src/dev/start_dev_server.js +3 -2
  10. package/src/execute/run.js +1 -1
  11. package/src/execute/runtimes/browsers/from_playwright.js +1 -1
  12. package/src/omega/compat/runtime_compat.js +9 -6
  13. package/src/omega/errors.js +3 -0
  14. package/src/omega/fetched_content_compliance.js +2 -2
  15. package/src/omega/kitchen.js +189 -145
  16. package/src/omega/server/file_service.js +104 -71
  17. package/src/omega/url_graph/url_graph_loader.js +77 -0
  18. package/src/omega/url_graph/url_info_transformations.js +12 -15
  19. package/src/omega/url_graph.js +115 -101
  20. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -0
  21. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +34 -36
  22. package/src/plugins/autoreload/jsenv_plugin_hmr.js +3 -2
  23. package/src/plugins/bundling/js_module/{bundle_js_module.js → bundle_js_modules.js} +51 -14
  24. package/src/plugins/bundling/jsenv_plugin_bundling.js +2 -2
  25. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +11 -0
  26. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +73 -62
  27. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +77 -89
  28. package/src/plugins/plugin_controller.js +26 -22
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +1 -0
  30. package/src/plugins/supervisor/client/script_type_module_supervisor.js +7 -9
  31. package/src/plugins/supervisor/client/supervisor.js +125 -96
  32. package/src/plugins/supervisor/jsenv_plugin_supervisor.js +2 -4
  33. package/src/plugins/toolbar/client/execution/toolbar_execution.js +1 -1
  34. package/src/plugins/transpilation/as_js_classic/async-to-promises.js +16 -0
  35. package/src/plugins/transpilation/as_js_classic/convert_js_module_to_js_classic.js +85 -0
  36. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +48 -190
  37. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_conversion.js +102 -0
  38. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +161 -240
  39. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_library.js +84 -0
  40. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_workers.js +19 -12
  41. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +1 -24
  42. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +82 -52
  43. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +12 -13
  44. package/src/plugins/url_analysis/html/html_urls.js +91 -34
  45. package/src/plugins/url_analysis/js/js_urls.js +5 -4
  46. package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +1 -0
  47. package/src/test/execute_plan.js +3 -8
  48. package/src/test/execute_test_plan.js +1 -1
  49. package/src/build/inject_service_worker_urls.js +0 -78
  50. package/src/build/resync_resource_hints.js +0 -112
  51. package/src/omega/url_graph/url_graph_load.js +0 -74
@@ -19,6 +19,7 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
19
19
  transformUrlContent: {
20
20
  html: async (urlInfo, context) => {
21
21
  const htmlAst = parseHtmlString(urlInfo.content)
22
+ const mutations = []
22
23
  const actions = []
23
24
  visitHtmlNodes(htmlAst, {
24
25
  style: (styleNode) => {
@@ -26,37 +27,42 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
26
27
  if (!styleNodeText) {
27
28
  return
28
29
  }
29
- actions.push(async () => {
30
- const { line, column, lineEnd, columnEnd, isOriginal } =
31
- getHtmlNodePosition(styleNode, {
32
- preferOriginal: true,
33
- })
34
- const inlineStyleUrl = generateInlineContentUrl({
35
- url: urlInfo.url,
36
- extension: ".css",
37
- line,
38
- column,
39
- lineEnd,
40
- columnEnd,
30
+ const { line, column, lineEnd, columnEnd, isOriginal } =
31
+ getHtmlNodePosition(styleNode, {
32
+ preferOriginal: true,
33
+ })
34
+ const inlineStyleUrl = generateInlineContentUrl({
35
+ url: urlInfo.url,
36
+ extension: ".css",
37
+ line,
38
+ column,
39
+ lineEnd,
40
+ columnEnd,
41
+ })
42
+ const debug =
43
+ getHtmlNodeAttribute(styleNode, "jsenv-debug") !== undefined
44
+ const [inlineStyleReference, inlineStyleUrlInfo] =
45
+ context.referenceUtils.foundInline({
46
+ node: styleNode,
47
+ type: "link_href",
48
+ expectedType: "css",
49
+ isOriginalPosition: isOriginal,
50
+ // we remove 1 to the line because imagine the following html:
51
+ // <style>body { color: red; }</style>
52
+ // -> content starts same line as <style>
53
+ specifierLine: line - 1,
54
+ specifierColumn: column,
55
+ specifier: inlineStyleUrl,
56
+ contentType: "text/css",
57
+ content: styleNodeText,
58
+ debug,
41
59
  })
42
- const [inlineStyleReference, inlineStyleUrlInfo] =
43
- context.referenceUtils.foundInline({
44
- node: styleNode,
45
- type: "link_href",
46
- expectedType: "css",
47
- isOriginalPosition: isOriginal,
48
- // we remove 1 to the line because imagine the following html:
49
- // <style>body { color: red; }</style>
50
- // -> content starts same line as <style>
51
- specifierLine: line - 1,
52
- specifierColumn: column,
53
- specifier: inlineStyleUrl,
54
- contentType: "text/css",
55
- content: styleNodeText,
56
- })
60
+ actions.push(async () => {
57
61
  await context.cook(inlineStyleUrlInfo, {
58
62
  reference: inlineStyleReference,
59
63
  })
64
+ })
65
+ mutations.push(() => {
60
66
  setHtmlNodeText(styleNode, inlineStyleUrlInfo.content)
61
67
  setHtmlNodeAttributes(styleNode, {
62
68
  "jsenv-plugin-owner": "jsenv:html_inline_content",
@@ -85,40 +91,44 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
85
91
  if (jsenvPluginOwner === "jsenv:supervisor") {
86
92
  return
87
93
  }
88
- actions.push(async () => {
89
- const { type, contentType, extension } =
90
- analyzeScriptNode(scriptNode)
91
- const { line, column, lineEnd, columnEnd, isOriginal } =
92
- getHtmlNodePosition(scriptNode, {
93
- preferOriginal: true,
94
- })
95
- let inlineScriptUrl = generateInlineContentUrl({
96
- url: urlInfo.url,
97
- extension:
98
- extension || CONTENT_TYPE.asFileExtension(contentType),
99
- line,
100
- column,
101
- lineEnd,
102
- columnEnd,
94
+ const { type, contentType, extension } =
95
+ analyzeScriptNode(scriptNode)
96
+ const { line, column, lineEnd, columnEnd, isOriginal } =
97
+ getHtmlNodePosition(scriptNode, {
98
+ preferOriginal: true,
103
99
  })
104
- const [inlineScriptReference, inlineScriptUrlInfo] =
105
- context.referenceUtils.foundInline({
106
- node: scriptNode,
107
- type: "script_src",
108
- expectedType: type,
109
- // we remove 1 to the line because imagine the following html:
110
- // <script>console.log('ok')</script>
111
- // -> content starts same line as <script>
112
- specifierLine: line - 1,
113
- specifierColumn: column,
114
- isOriginalPosition: isOriginal,
115
- specifier: inlineScriptUrl,
116
- contentType,
117
- content: scriptNodeText,
118
- })
100
+ let inlineScriptUrl = generateInlineContentUrl({
101
+ url: urlInfo.url,
102
+ extension: extension || CONTENT_TYPE.asFileExtension(contentType),
103
+ line,
104
+ column,
105
+ lineEnd,
106
+ columnEnd,
107
+ })
108
+ const debug =
109
+ getHtmlNodeAttribute(scriptNode, "jsenv-debug") !== undefined
110
+ const [inlineScriptReference, inlineScriptUrlInfo] =
111
+ context.referenceUtils.foundInline({
112
+ node: scriptNode,
113
+ type: "script_src",
114
+ expectedType: type,
115
+ // we remove 1 to the line because imagine the following html:
116
+ // <script>console.log('ok')</script>
117
+ // -> content starts same line as <script>
118
+ specifierLine: line - 1,
119
+ specifierColumn: column,
120
+ isOriginalPosition: isOriginal,
121
+ specifier: inlineScriptUrl,
122
+ contentType,
123
+ content: scriptNodeText,
124
+ debug,
125
+ })
126
+ actions.push(async () => {
119
127
  await context.cook(inlineScriptUrlInfo, {
120
128
  reference: inlineScriptReference,
121
129
  })
130
+ })
131
+ mutations.push(() => {
122
132
  setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content)
123
133
  setHtmlNodeAttributes(scriptNode, {
124
134
  "jsenv-plugin-owner": "jsenv:html_inline_content",
@@ -130,14 +140,15 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
130
140
  })
131
141
  },
132
142
  })
133
- if (actions.length === 0) {
143
+ if (actions.length > 0) {
144
+ await Promise.all(actions.map((action) => action()))
145
+ }
146
+ if (mutations.length === 0) {
134
147
  return null
135
148
  }
136
- await Promise.all(actions.map((action) => action()))
149
+ mutations.forEach((mutation) => mutation())
137
150
  const htmlModified = stringifyHtmlAst(htmlAst)
138
- return {
139
- content: htmlModified,
140
- }
151
+ return htmlModified
141
152
  },
142
153
  },
143
154
  }
@@ -7,8 +7,8 @@
7
7
  * it should likely be an other plugin happening after the others
8
8
  */
9
9
 
10
- import { registerFileLifecycle } from "@jsenv/filesystem"
11
-
10
+ import { readFileSync } from "node:fs"
11
+ import { bufferToEtag } from "@jsenv/filesystem"
12
12
  import {
13
13
  applyNodeEsmResolution,
14
14
  defaultLookupPackageScope,
@@ -16,13 +16,34 @@ import {
16
16
  readCustomConditionsFromProcessArgs,
17
17
  } from "@jsenv/node-esm-resolution"
18
18
 
19
- export const jsenvPluginNodeEsmResolution = ({
20
- packageConditions,
21
- filesInvalidatingCache = ["package.json", "package-lock.json"],
22
- }) => {
23
- const unregisters = []
24
- let lookupPackageScope // defined in "init"
25
- let readPackageJson // defined in "init"
19
+ export const jsenvPluginNodeEsmResolution = ({ packageConditions }) => {
20
+ const addRelationshipWithPackageJson = ({
21
+ context,
22
+ packageJsonUrl,
23
+ field,
24
+ hasVersioningEffect = false,
25
+ }) => {
26
+ const referenceFound = context.referenceUtils.find(
27
+ (ref) => ref.type === "package_json" && ref.subtype === field,
28
+ )
29
+ if (referenceFound) {
30
+ return
31
+ }
32
+ const [, packageJsonUrlInfo] = context.referenceUtils.inject({
33
+ type: "package_json",
34
+ subtype: field,
35
+ specifier: packageJsonUrl,
36
+ isImplicit: true,
37
+ hasVersioningEffect,
38
+ })
39
+ if (packageJsonUrlInfo.type === undefined) {
40
+ const packageJsonContentAsBuffer = readFileSync(new URL(packageJsonUrl))
41
+ packageJsonUrlInfo.type = "json"
42
+ packageJsonUrlInfo.content = String(packageJsonContentAsBuffer)
43
+ packageJsonUrlInfo.originalContentEtag = packageJsonUrlInfo.contentEtag =
44
+ bufferToEtag(packageJsonContentAsBuffer)
45
+ }
46
+ }
26
47
 
27
48
  return {
28
49
  name: "jsenv:node_esm_resolution",
@@ -37,91 +58,41 @@ export const jsenvPluginNodeEsmResolution = ({
37
58
  nodeRuntimeEnabled ? "node" : "browser",
38
59
  "import",
39
60
  ]
40
-
41
- const packageScopesCache = new Map()
42
- lookupPackageScope = (url) => {
43
- const fromCache = packageScopesCache.get(url)
44
- if (fromCache) {
45
- return fromCache
46
- }
47
- const packageScope = defaultLookupPackageScope(url)
48
- packageScopesCache.set(url, packageScope)
49
- return packageScope
50
- }
51
- const packageJsonsCache = new Map()
52
- readPackageJson = (url) => {
53
- const fromCache = packageJsonsCache.get(url)
54
- if (fromCache) {
55
- return fromCache
56
- }
57
- const packageJson = defaultReadPackageJson(url)
58
- packageJsonsCache.set(url, packageJson)
59
- return packageJson
60
- }
61
-
62
- if (context.scenarios.dev) {
63
- const onFileChange = () => {
64
- packageScopesCache.clear()
65
- packageJsonsCache.clear()
66
- context.urlGraph.urlInfoMap.forEach((urlInfo) => {
67
- if (urlInfo.dependsOnPackageJson) {
68
- context.urlGraph.considerModified(urlInfo)
69
- }
70
- })
71
- }
72
- filesInvalidatingCache.forEach((file) => {
73
- const unregister = registerFileLifecycle(
74
- new URL(file, context.rootDirectoryUrl),
75
- {
76
- added: () => {
77
- onFileChange()
78
- },
79
- updated: () => {
80
- onFileChange()
81
- },
82
- removed: () => {
83
- onFileChange()
84
- },
85
- keepProcessAlive: false,
86
- },
87
- )
88
- unregisters.push(unregister)
89
- })
90
- }
91
61
  },
92
62
  resolveUrl: {
93
- js_import_export: (reference) => {
63
+ js_import_export: (reference, context) => {
94
64
  const { parentUrl, specifier } = reference
95
- const { type, url } = applyNodeEsmResolution({
65
+ const { url, type, packageUrl } = applyNodeEsmResolution({
96
66
  conditions: packageConditions,
97
67
  parentUrl,
98
68
  specifier,
99
- lookupPackageScope,
100
- readPackageJson,
101
69
  })
102
- // this reference depend on package.json and node_modules
103
- // to be resolved. Each file using this specifier
104
- // must be invalidated when package.json or package_lock.json
105
- // changes
106
- const dependsOnPackageJson =
107
- type !== "relative_specifier" &&
108
- type !== "absolute_specifier" &&
109
- type !== "node_builtin_specifier"
110
- reference.dependsOnPackageJson = dependsOnPackageJson
70
+ if (context.scenarios.dev) {
71
+ const dependsOnPackageJson =
72
+ type !== "relative_specifier" &&
73
+ type !== "absolute_specifier" &&
74
+ type !== "node_builtin_specifier"
75
+ if (dependsOnPackageJson) {
76
+ // this reference depends on package.json and node_modules
77
+ // to be resolved. Each file using this specifier
78
+ // must be invalidated when corresponding package.json changes
79
+ addRelationshipWithPackageJson({
80
+ reference,
81
+ context,
82
+ packageJsonUrl: `${packageUrl}package.json`,
83
+ field: type.startsWith("field:")
84
+ ? `#${type.slice("field:".length)}`
85
+ : "",
86
+ })
87
+ }
88
+ }
111
89
  return url
112
90
  },
113
91
  },
114
- fetchUrlContent: (urlInfo) => {
115
- if (urlInfo.url.startsWith("file:///@ignore/")) {
116
- return {
117
- content: "export default {}",
118
- contentType: "text/javascript",
119
- type: "js_module",
120
- }
121
- }
122
- return null
123
- },
124
92
  transformUrlSearchParams: (reference, context) => {
93
+ if (reference.type === "package_json") {
94
+ return null
95
+ }
125
96
  if (context.scenarios.build) {
126
97
  return null
127
98
  }
@@ -137,24 +108,41 @@ export const jsenvPluginNodeEsmResolution = ({
137
108
  if (reference.searchParams.has("v")) {
138
109
  return null
139
110
  }
140
- const packageUrl = lookupPackageScope(reference.url)
141
- if (!packageUrl) {
111
+ const packageDirectoryUrl = defaultLookupPackageScope(reference.url)
112
+ if (!packageDirectoryUrl) {
142
113
  return null
143
114
  }
144
- if (packageUrl === context.rootDirectoryUrl) {
115
+ if (packageDirectoryUrl === context.rootDirectoryUrl) {
145
116
  return null
146
117
  }
147
- const packageVersion = readPackageJson(packageUrl).version
118
+ // there is a dependency between this file and the package.json version field
119
+ const packageVersion = defaultReadPackageJson(packageDirectoryUrl).version
148
120
  if (!packageVersion) {
149
121
  // example where it happens: https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
150
122
  return null
151
123
  }
124
+ if (reference.type === "js_import_export") {
125
+ addRelationshipWithPackageJson({
126
+ reference,
127
+ context,
128
+ packageJsonUrl: `${packageDirectoryUrl}package.json`,
129
+ field: "version",
130
+ hasVersioningEffect: true,
131
+ })
132
+ }
152
133
  return {
153
134
  v: packageVersion,
154
135
  }
155
136
  },
156
- destroy: () => {
157
- unregisters.forEach((unregister) => unregister())
137
+ fetchUrlContent: (urlInfo) => {
138
+ if (urlInfo.url.startsWith("file:///@ignore/")) {
139
+ return {
140
+ content: "export default {}",
141
+ contentType: "text/javascript",
142
+ type: "js_module",
143
+ }
144
+ }
145
+ return null
158
146
  },
159
147
  }
160
148
  }
@@ -1,4 +1,4 @@
1
- import { timeStart } from "@jsenv/server"
1
+ import { performance } from "node:perf_hooks"
2
2
 
3
3
  const HOOK_NAMES = [
4
4
  "init",
@@ -60,6 +60,7 @@ export const createPluginController = ({ plugins, scenarios }) => {
60
60
  pushPlugin(plugin)
61
61
  })
62
62
 
63
+ let lastPluginUsed = null
63
64
  let currentPlugin = null
64
65
  let currentHookName = null
65
66
  const callHook = (hook, info, context) => {
@@ -67,21 +68,21 @@ export const createPluginController = ({ plugins, scenarios }) => {
67
68
  if (!hookFn) {
68
69
  return null
69
70
  }
70
- currentPlugin = hook.plugin
71
- currentHookName = hook.name
72
- let timeEnd
71
+ let startTimestamp
73
72
  if (info.timing) {
74
- timeEnd = timeStart(
75
- `${currentHookName}-${currentPlugin.name.replace("jsenv:", "")}`,
76
- )
73
+ startTimestamp = performance.now()
77
74
  }
75
+ lastPluginUsed = hook.plugin
76
+ currentPlugin = hook.plugin
77
+ currentHookName = hook.name
78
78
  let valueReturned = hookFn(info, context)
79
+ currentPlugin = null
80
+ currentHookName = null
79
81
  if (info.timing) {
80
- Object.assign(info.timing, timeEnd())
82
+ info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
83
+ performance.now() - startTimestamp
81
84
  }
82
85
  valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned)
83
- currentPlugin = null
84
- currentHookName = null
85
86
  return valueReturned
86
87
  }
87
88
  const callAsyncHook = async (hook, info, context) => {
@@ -89,21 +90,22 @@ export const createPluginController = ({ plugins, scenarios }) => {
89
90
  if (!hookFn) {
90
91
  return null
91
92
  }
92
- currentPlugin = hook.plugin
93
- currentHookName = hook.name
94
- let timeEnd
93
+
94
+ let startTimestamp
95
95
  if (info.timing) {
96
- timeEnd = timeStart(
97
- `${currentHookName}-${currentPlugin.name.replace("jsenv:", "")}`,
98
- )
96
+ startTimestamp = performance.now()
99
97
  }
98
+ lastPluginUsed = hook.plugin
99
+ currentPlugin = hook.plugin
100
+ currentHookName = hook.name
100
101
  let valueReturned = await hookFn(info, context)
102
+ currentPlugin = null
103
+ currentHookName = null
101
104
  if (info.timing) {
102
- Object.assign(info.timing, timeEnd())
105
+ info.timing[`${hook.name}-${hook.plugin.name.replace("jsenv:", "")}`] =
106
+ performance.now() - startTimestamp
103
107
  }
104
108
  valueReturned = assertAndNormalizeReturnValue(hook.name, valueReturned)
105
- currentPlugin = null
106
- currentHookName = null
107
109
  return valueReturned
108
110
  }
109
111
 
@@ -113,7 +115,7 @@ export const createPluginController = ({ plugins, scenarios }) => {
113
115
  for (const hook of hooks) {
114
116
  const returnValue = callHook(hook, info, context)
115
117
  if (returnValue && callback) {
116
- callback(returnValue)
118
+ callback(returnValue, hook.plugin)
117
119
  }
118
120
  }
119
121
  }
@@ -125,7 +127,7 @@ export const createPluginController = ({ plugins, scenarios }) => {
125
127
  await previous
126
128
  const returnValue = await callAsyncHook(hook, info, context)
127
129
  if (returnValue && callback) {
128
- await callback(returnValue)
130
+ await callback(returnValue, hook.plugin)
129
131
  }
130
132
  }, Promise.resolve())
131
133
  }
@@ -182,6 +184,7 @@ export const createPluginController = ({ plugins, scenarios }) => {
182
184
  callAsyncHooks,
183
185
  callAsyncHooksUntil,
184
186
 
187
+ getLastPluginUsed: () => lastPluginUsed,
185
188
  getCurrentPlugin: () => currentPlugin,
186
189
  getCurrentHookName: () => currentHookName,
187
190
  }
@@ -200,7 +203,8 @@ const flattenAndFilterPlugins = (plugins, { scenarios }) => {
200
203
  }
201
204
  const { appliesDuring } = pluginEntry
202
205
  if (appliesDuring === undefined) {
203
- console.warn(`"appliesDuring" is undefined on ${pluginEntry.name}`)
206
+ // console.debug(`"appliesDuring" is undefined on ${pluginEntry.name}`)
207
+ flatPlugins.push(pluginEntry)
204
208
  return
205
209
  }
206
210
  if (appliesDuring === "*") {
@@ -25,6 +25,7 @@ export const jsenvPluginServerEventsClientInjection = () => {
25
25
  const [serverEventsClientFileReference] = context.referenceUtils.inject(
26
26
  {
27
27
  type: "script_src",
28
+ subtype: "js_module",
28
29
  expectedType: "js_module",
29
30
  specifier: serverEventsClientFileUrl,
30
31
  },
@@ -9,16 +9,12 @@ export const superviseScriptTypeModule = async ({ src, async }) => {
9
9
  const execute = isWebkitOrSafari
10
10
  ? createExecuteWithDynamicImport({ src })
11
11
  : createExecuteWithScript({ currentScript, src })
12
- if (!async) {
13
- await window.__supervisor__.getPreviousExecutionDonePromise()
14
- }
15
- const execution = window.__supervisor__.createExecution({
12
+ return window.__supervisor__.addExecution({
16
13
  src,
17
14
  async,
18
15
  type: "js_module",
19
16
  execute,
20
17
  })
21
- return execution.start()
22
18
  }
23
19
 
24
20
  const createExecuteWithScript = ({ currentScript, src }) => {
@@ -64,10 +60,10 @@ const createExecuteWithScript = ({ currentScript, src }) => {
64
60
  needsReport: true,
65
61
  }
66
62
  }
67
- // do not resolve right away, wait for top level execution
68
63
  try {
69
- const namespace = await import(urlObject.href)
70
- return namespace
64
+ return {
65
+ executionPromise: import(urlObject.href),
66
+ }
71
67
  } catch (e) {
72
68
  e.reportedBy = "dynamic_import"
73
69
  throw e
@@ -83,7 +79,9 @@ const createExecuteWithDynamicImport = ({ src }) => {
83
79
  }
84
80
  try {
85
81
  const namespace = await import(urlObject.href)
86
- return namespace
82
+ return {
83
+ executionPromise: Promise.resolve(namespace),
84
+ }
87
85
  } catch (e) {
88
86
  e.reportedBy = "dynamic_import"
89
87
  // dynamic import would hide the error to the browser