@jsenv/core 28.0.2 → 28.1.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 (55) hide show
  1. package/dist/controllable_child_process.mjs +1 -2
  2. package/dist/controllable_worker_thread.mjs +1 -2
  3. package/dist/js/autoreload.js +25 -9
  4. package/dist/js/execute_using_dynamic_import.js +804 -1
  5. package/dist/js/script_type_module_supervisor.js +129 -0
  6. package/dist/js/supervisor.js +921 -0
  7. package/dist/main.js +432 -492
  8. package/package.json +13 -13
  9. package/readme.md +1 -1
  10. package/src/build/inject_global_version_mappings.js +3 -3
  11. package/src/dev/start_dev_server.js +2 -2
  12. package/src/execute/execute.js +1 -1
  13. package/src/execute/run.js +26 -38
  14. package/src/execute/runtimes/browsers/from_playwright.js +51 -77
  15. package/src/execute/runtimes/node/node_child_process.js +36 -36
  16. package/src/execute/runtimes/node/node_worker_thread.js +36 -36
  17. package/src/omega/kitchen.js +12 -9
  18. package/src/omega/omega_server.js +2 -2
  19. package/src/omega/server/file_service.js +2 -2
  20. package/src/omega/url_graph/url_info_transformations.js +8 -1
  21. package/src/plugins/autoreload/client/reload.js +20 -7
  22. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +4 -4
  23. package/src/plugins/import_meta_hot/html_hot_dependencies.js +2 -2
  24. package/src/plugins/importmap/jsenv_plugin_importmap.js +5 -3
  25. package/src/plugins/inject_globals/inject_globals.js +3 -3
  26. package/src/plugins/inline/jsenv_plugin_data_urls.js +1 -1
  27. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +10 -5
  28. package/src/plugins/plugins.js +5 -5
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +4 -4
  30. package/src/plugins/supervisor/client/script_type_module_supervisor.js +108 -0
  31. package/src/plugins/supervisor/client/supervisor.js +921 -0
  32. package/src/plugins/{html_supervisor/jsenv_plugin_html_supervisor.js → supervisor/jsenv_plugin_supervisor.js} +128 -102
  33. package/src/plugins/toolbar/client/execution/toolbar_execution.js +1 -1
  34. package/src/plugins/toolbar/jsenv_plugin_toolbar.js +4 -4
  35. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +7 -5
  36. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +5 -4
  37. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -7
  38. package/src/plugins/transpilation/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +6 -4
  39. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +4 -2
  40. package/src/plugins/url_analysis/html/html_urls.js +11 -10
  41. package/src/test/coverage/babel_plugin_instrument.js +1 -35
  42. package/src/test/coverage/empty_coverage_factory.js +1 -1
  43. package/src/test/execute_plan.js +7 -3
  44. package/src/test/execute_test_plan.js +2 -1
  45. package/src/test/logs_file_execution.js +49 -8
  46. package/dist/js/html_supervisor_installer.js +0 -1091
  47. package/dist/js/html_supervisor_setup.js +0 -89
  48. package/dist/js/uneval.js +0 -804
  49. package/src/plugins/html_supervisor/client/error_formatter.js +0 -426
  50. package/src/plugins/html_supervisor/client/error_in_notification.js +0 -21
  51. package/src/plugins/html_supervisor/client/error_overlay.js +0 -191
  52. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +0 -315
  53. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +0 -89
  54. package/src/plugins/html_supervisor/client/perf_browser.js +0 -17
  55. package/src/plugins/html_supervisor/client/uneval_exception.js +0 -8
@@ -143,12 +143,12 @@ export const createKitchen = ({
143
143
  newReference.original = reference.original || reference
144
144
  // newReference.isEntryPoint = reference.isEntryPoint
145
145
  }
146
- const resolveReference = (reference) => {
146
+ const resolveReference = (reference, context = kitchenContext) => {
147
147
  try {
148
148
  let resolvedUrl = pluginController.callHooksUntil(
149
149
  "resolveUrl",
150
150
  reference,
151
- kitchenContext,
151
+ context,
152
152
  )
153
153
  if (!resolvedUrl) {
154
154
  throw new Error(`NO_RESOLVE`)
@@ -158,7 +158,7 @@ export const createKitchen = ({
158
158
  pluginController.callHooks(
159
159
  "redirectUrl",
160
160
  reference,
161
- kitchenContext,
161
+ context,
162
162
  (returnValue) => {
163
163
  const normalizedReturnValue = normalizeUrl(returnValue)
164
164
  if (normalizedReturnValue === reference.url) {
@@ -178,7 +178,7 @@ export const createKitchen = ({
178
178
  }
179
179
 
180
180
  const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url)
181
- applyReferenceEffectsOnUrlInfo(reference, urlInfo, kitchenContext)
181
+ applyReferenceEffectsOnUrlInfo(reference, urlInfo, context)
182
182
 
183
183
  // This hook must touch reference.generatedUrl, NOT reference.url
184
184
  // And this is because this hook inject query params used to:
@@ -189,7 +189,7 @@ export const createKitchen = ({
189
189
  pluginController.callHooks(
190
190
  "transformUrlSearchParams",
191
191
  reference,
192
- kitchenContext,
192
+ context,
193
193
  (returnValue) => {
194
194
  Object.keys(returnValue).forEach((key) => {
195
195
  referenceUrlObject.searchParams.set(key, returnValue[key])
@@ -200,7 +200,7 @@ export const createKitchen = ({
200
200
  const returnValue = pluginController.callHooksUntil(
201
201
  "formatUrl",
202
202
  reference,
203
- kitchenContext,
203
+ context,
204
204
  )
205
205
  reference.generatedSpecifier = returnValue || reference.generatedUrl
206
206
  reference.generatedSpecifier = urlSpecifierEncoding.encode(reference)
@@ -386,7 +386,7 @@ export const createKitchen = ({
386
386
  ...props,
387
387
  })
388
388
  references.push(reference)
389
- const referencedUrlInfo = resolveReference(reference)
389
+ const referencedUrlInfo = resolveReference(reference, context)
390
390
  return [reference, referencedUrlInfo]
391
391
  }
392
392
  const referenceUtils = {
@@ -460,7 +460,7 @@ export const createKitchen = ({
460
460
  })
461
461
  references[index] = nextReference
462
462
  mutateReference(previousReference, nextReference)
463
- const newUrlInfo = resolveReference(nextReference)
463
+ const newUrlInfo = resolveReference(nextReference, context)
464
464
  const currentUrlInfo = context.urlGraph.getUrlInfo(
465
465
  currentReference.url,
466
466
  )
@@ -677,7 +677,10 @@ export const createKitchen = ({
677
677
  await context.fetchUrlContent(originalUrlInfo, {
678
678
  reference: originalReference,
679
679
  })
680
- if (originalUrlInfo.dependents.size === 0) {
680
+ if (
681
+ originalUrlInfo.dependents.size === 0
682
+ // && context.scenarios.build
683
+ ) {
681
684
  context.urlGraph.deleteUrlInfo(originalUrlInfo.url)
682
685
  }
683
686
  return originalUrlInfo
@@ -30,7 +30,7 @@ export const startOmegaServer = async ({
30
30
 
31
31
  plugins,
32
32
  urlAnalysis,
33
- htmlSupervisor,
33
+ supervisor,
34
34
  nodeEsmResolution,
35
35
  fileSystemMagicResolution,
36
36
  transpilation,
@@ -92,7 +92,7 @@ export const startOmegaServer = async ({
92
92
 
93
93
  plugins,
94
94
  urlAnalysis,
95
- htmlSupervisor,
95
+ supervisor,
96
96
  nodeEsmResolution,
97
97
  fileSystemMagicResolution,
98
98
  transpilation,
@@ -25,7 +25,7 @@ export const createFileService = ({
25
25
 
26
26
  plugins,
27
27
  urlAnalysis,
28
- htmlSupervisor,
28
+ supervisor,
29
29
  nodeEsmResolution,
30
30
  fileSystemMagicResolution,
31
31
  transpilation,
@@ -118,7 +118,7 @@ export const createFileService = ({
118
118
  runtimeCompat,
119
119
 
120
120
  urlAnalysis,
121
- htmlSupervisor,
121
+ supervisor,
122
122
  nodeEsmResolution,
123
123
  fileSystemMagicResolution,
124
124
  transpilation,
@@ -81,6 +81,9 @@ export const createUrlInfoTransformer = ({
81
81
  if (!SOURCEMAP.enabledOnContentType(urlInfo.contentType)) {
82
82
  return
83
83
  }
84
+ if (urlInfo.generatedUrl.startsWith("data:")) {
85
+ return
86
+ }
84
87
  // sourcemap is a special kind of reference:
85
88
  // It's a reference to a content generated dynamically the content itself.
86
89
  // For this reason sourcemap are not added to urlInfo.references
@@ -173,7 +176,11 @@ export const createUrlInfoTransformer = ({
173
176
  if (transformations) {
174
177
  await applyIntermediateTransformations(urlInfo, transformations)
175
178
  }
176
- if (sourcemapsEnabled && urlInfo.sourcemap) {
179
+ if (
180
+ sourcemapsEnabled &&
181
+ urlInfo.sourcemap &&
182
+ !urlInfo.generatedUrl.startsWith("data:")
183
+ ) {
177
184
  // during build this function can be called after the file is cooked
178
185
  // - to update content and sourcemap after "optimize" hook
179
186
  // - to inject versioning into the entry point content
@@ -32,7 +32,20 @@ export const getDOMNodesUsingUrl = (urlToReload) => {
32
32
  nodes.push({
33
33
  node,
34
34
  reload: () => {
35
- node[attributeName] = injectQuery(attribute, { hmr: Date.now() })
35
+ if (node.nodeName === "SCRIPT") {
36
+ const copy = document.createElement("script")
37
+ Array.from(node.attributes).forEach((attribute) => {
38
+ copy.setAttribute(attribute.nodeName, attribute.nodeValue)
39
+ })
40
+ copy.src = injectQuery(node.src, { hmr: Date.now() })
41
+ if (node.parentNode) {
42
+ node.parentNode.replaceChild(copy, node)
43
+ } else {
44
+ document.body.appendChild(copy)
45
+ }
46
+ } else {
47
+ node[attributeName] = injectQuery(attribute, { hmr: Date.now() })
48
+ }
36
49
  },
37
50
  })
38
51
  }
@@ -46,17 +59,17 @@ export const getDOMNodesUsingUrl = (urlToReload) => {
46
59
  })
47
60
  Array.from(document.querySelectorAll("script")).forEach((script) => {
48
61
  visitNodeAttributeAsUrl(script, "src")
49
- const generatedFromSrc = script.getAttribute("generated-from-src")
50
- if (generatedFromSrc) {
51
- const generatedFromUrl = new URL(generatedFromSrc, window.location.origin)
62
+ const inlinedFromSrc = script.getAttribute("inlined-from-src")
63
+ if (inlinedFromSrc) {
64
+ const inlinedFromUrl = new URL(inlinedFromSrc, window.location.origin)
52
65
  .href
53
- if (shouldReloadUrl(generatedFromUrl)) {
66
+ if (shouldReloadUrl(inlinedFromUrl)) {
54
67
  nodes.push({
55
68
  node: script,
56
69
  reload: () =>
57
- window.__html_supervisor__.reloadSupervisedScript({
70
+ window.__supervisor__.reloadSupervisedScript({
58
71
  type: script.type,
59
- src: generatedFromSrc,
72
+ src: inlinedFromSrc,
60
73
  }),
61
74
  })
62
75
  }
@@ -25,11 +25,11 @@ export const jsenvPluginAutoreloadClient = () => {
25
25
  injectScriptNodeAsEarlyAsPossible(
26
26
  htmlAst,
27
27
  createHtmlNode({
28
- "tagName": "script",
29
- "type": "module",
30
- "src": autoreloadClientReference.generatedSpecifier,
31
- "injected-by": "jsenv:autoreload_client",
28
+ tagName: "script",
29
+ type: "module",
30
+ src: autoreloadClientReference.generatedSpecifier,
32
31
  }),
32
+ "jsenv:autoreload_client",
33
33
  )
34
34
  const htmlModified = stringifyHtmlAst(htmlAst)
35
35
  return {
@@ -48,7 +48,7 @@ export const collectHotDataFromHtmlAst = (htmlAst) => {
48
48
  })
49
49
  visitUrlSpecifierAttribute({
50
50
  node,
51
- attributeName: "generated-from-href",
51
+ attributeName: "inlined-from-href",
52
52
  hotAccepted,
53
53
  })
54
54
  }
@@ -60,7 +60,7 @@ export const collectHotDataFromHtmlAst = (htmlAst) => {
60
60
  })
61
61
  visitUrlSpecifierAttribute({
62
62
  node,
63
- attributeName: "generated-from-src",
63
+ attributeName: "inlined-from-src",
64
64
  hotAccepted,
65
65
  })
66
66
  }
@@ -134,7 +134,8 @@ export const jsenvPluginImportmap = () => {
134
134
  })
135
135
  setHtmlNodeText(importmap, inlineImportmapUrlInfo.content)
136
136
  setHtmlNodeAttributes(importmap, {
137
- "generated-by": "jsenv:importmap",
137
+ "jsenv-plugin-owner": "jsenv:importmap",
138
+ "jsenv-plugin-action": "content_cooked",
138
139
  })
139
140
  onHtmlImportmapParsed(
140
141
  JSON.parse(inlineImportmapUrlInfo.content),
@@ -162,8 +163,9 @@ export const jsenvPluginImportmap = () => {
162
163
  setHtmlNodeText(importmap, importmapUrlInfo.content)
163
164
  setHtmlNodeAttributes(importmap, {
164
165
  "src": undefined,
165
- "generated-by": "jsenv:importmap",
166
- "generated-from-src": src,
166
+ "jsenv-plugin-owner": "jsenv:importmap",
167
+ "jsenv-plugin-action": "inlined",
168
+ "inlined-from-src": src,
167
169
  })
168
170
 
169
171
  const { line, column, lineEnd, columnEnd, isOriginal } =
@@ -30,10 +30,10 @@ const globalInjectorOnHtml = async (urlInfo, globals) => {
30
30
  injectScriptNodeAsEarlyAsPossible(
31
31
  htmlAst,
32
32
  createHtmlNode({
33
- "tagName": "script",
34
- "textContent": clientCode,
35
- "injected-by": "jsenv:inject_globals",
33
+ tagName: "script",
34
+ textContent: clientCode,
36
35
  }),
36
+ "jsenv:inject_globals",
37
37
  )
38
38
  return stringifyHtmlAst(htmlAst)
39
39
  }
@@ -40,7 +40,7 @@ export const jsenvPluginDataUrls = () => {
40
40
  return reference.generatedUrl
41
41
  }
42
42
  const specifier = DATA_URL.stringify({
43
- contentType: urlInfo.headers["content-type"],
43
+ contentType: urlInfo.contentType,
44
44
  base64Flag: urlInfo.data.base64Flag,
45
45
  data: urlInfo.data.base64Flag
46
46
  ? dataToBase64(urlInfo.content)
@@ -59,7 +59,8 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
59
59
  })
60
60
  setHtmlNodeText(styleNode, inlineStyleUrlInfo.content)
61
61
  setHtmlNodeAttributes(styleNode, {
62
- "generated-by": "jsenv:html_inline_content",
62
+ "jsenv-plugin-owner": "jsenv:html_inline_content",
63
+ "jsenv-plugin-action": "content_cooked",
63
64
  })
64
65
  })
65
66
  },
@@ -71,14 +72,17 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
71
72
  // If the inline script was already handled by an other plugin, ignore it
72
73
  // - we want to preserve inline scripts generated by html supervisor during dev
73
74
  // - we want to avoid cooking twice a script during build
74
- const generatedBy = getHtmlNodeAttribute(scriptNode, "generated-by")
75
+ const jsenvPluginOwner = getHtmlNodeAttribute(
76
+ scriptNode,
77
+ "jsenv-plugin-owner",
78
+ )
75
79
  if (
76
- generatedBy === "jsenv:as_js_classic_html" &&
80
+ jsenvPluginOwner === "jsenv:as_js_classic_html" &&
77
81
  !analyzeConvertedScripts
78
82
  ) {
79
83
  return
80
84
  }
81
- if (generatedBy === "jsenv:html_supervisor") {
85
+ if (jsenvPluginOwner === "jsenv:supervisor") {
82
86
  return
83
87
  }
84
88
  actions.push(async () => {
@@ -117,7 +121,8 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
117
121
  })
118
122
  setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content)
119
123
  setHtmlNodeAttributes(scriptNode, {
120
- "generated-by": "jsenv:html_inline_content",
124
+ "jsenv-plugin-owner": "jsenv:html_inline_content",
125
+ "jsenv-plugin-action": "content_cooked",
121
126
  ...(extension
122
127
  ? { type: type === "js_module" ? "module" : undefined }
123
128
  : {}),
@@ -7,7 +7,7 @@ import { jsenvPluginUrlVersion } from "./url_version/jsenv_plugin_url_version.js
7
7
  import { jsenvPluginFileUrls } from "./file_urls/jsenv_plugin_file_urls.js"
8
8
  import { jsenvPluginHttpUrls } from "./http_urls/jsenv_plugin_http_urls.js"
9
9
  import { jsenvPluginInline } from "./inline/jsenv_plugin_inline.js"
10
- import { jsenvPluginHtmlSupervisor } from "./html_supervisor/jsenv_plugin_html_supervisor.js"
10
+ import { jsenvPluginSupervisor } from "./supervisor/jsenv_plugin_supervisor.js"
11
11
  import { jsenvPluginCommonJsGlobals } from "./commonjs_globals/jsenv_plugin_commonjs_globals.js"
12
12
  import { jsenvPluginImportMetaScenarios } from "./import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js"
13
13
  import { jsenvPluginTranspilation } from "./transpilation/jsenv_plugin_transpilation.js"
@@ -27,7 +27,7 @@ export const getCorePlugins = ({
27
27
  runtimeCompat,
28
28
 
29
29
  urlAnalysis = {},
30
- htmlSupervisor,
30
+ supervisor,
31
31
  nodeEsmResolution = true,
32
32
  fileSystemMagicResolution,
33
33
  directoryReferenceAllowed,
@@ -40,8 +40,8 @@ export const getCorePlugins = ({
40
40
  clientFilesPruneCallbackList,
41
41
  explorer,
42
42
  } = {}) => {
43
- if (htmlSupervisor === true) {
44
- htmlSupervisor = {}
43
+ if (supervisor === true) {
44
+ supervisor = {}
45
45
  }
46
46
  if (nodeEsmResolution === true) {
47
47
  nodeEsmResolution = {}
@@ -56,7 +56,7 @@ export const getCorePlugins = ({
56
56
  return [
57
57
  jsenvPluginUrlAnalysis({ rootDirectoryUrl, ...urlAnalysis }),
58
58
  jsenvPluginTranspilation(transpilation),
59
- ...(htmlSupervisor ? [jsenvPluginHtmlSupervisor(htmlSupervisor)] : []), // before inline as it turns inline <script> into <script src>
59
+ ...(supervisor ? [jsenvPluginSupervisor(supervisor)] : []), // before inline as it turns inline <script> into <script src>
60
60
  jsenvPluginImportmap(),
61
61
  // before node esm to handle bare specifiers
62
62
  // + before node esm to handle importmap before inline content
@@ -32,11 +32,11 @@ export const jsenvPluginServerEventsClientInjection = () => {
32
32
  injectScriptNodeAsEarlyAsPossible(
33
33
  htmlAst,
34
34
  createHtmlNode({
35
- "tagName": "script",
36
- "type": "module",
37
- "src": serverEventsClientFileReference.generatedSpecifier,
38
- "injected-by": "jsenv:server_events",
35
+ tagName: "script",
36
+ type: "module",
37
+ src: serverEventsClientFileReference.generatedSpecifier,
39
38
  }),
39
+ "jsenv:server_events",
40
40
  )
41
41
  const htmlModified = stringifyHtmlAst(htmlAst)
42
42
  return {
@@ -0,0 +1,108 @@
1
+ let previousExecutionPromise
2
+
3
+ // https://twitter.com/damienmaillard/status/1554752482273787906
4
+ const isWebkitOrSafari =
5
+ typeof window.webkitConvertPointFromNodeToPage === "function"
6
+
7
+ export const superviseScriptTypeModule = async ({ src, async }) => {
8
+ const execute = isWebkitOrSafari
9
+ ? createExecuteWithDynamicImport({ src })
10
+ : createExecuteWithScript({ src })
11
+ const startExecution = () => {
12
+ const execution = window.__supervisor__.createExecution({
13
+ src,
14
+ type: "js_module",
15
+ execute,
16
+ })
17
+ return execution.start()
18
+ }
19
+ if (async) {
20
+ startExecution()
21
+ return
22
+ }
23
+ // there is guaranteed execution order for non async script type="module"
24
+ // see https://gist.github.com/jakub-g/385ee6b41085303a53ad92c7c8afd7a6#typemodule-vs-non-module-typetextjavascript-vs-script-nomodule
25
+ if (previousExecutionPromise) {
26
+ await previousExecutionPromise
27
+ previousExecutionPromise = null
28
+ }
29
+ previousExecutionPromise = startExecution()
30
+ }
31
+
32
+ const createExecuteWithScript = ({ src }) => {
33
+ const currentScript = document.querySelector(
34
+ `script[type="module"][inlined-from-src="${src}"]`,
35
+ )
36
+ const parentNode = currentScript.parentNode
37
+ let nodeToReplace
38
+ let currentScriptClone
39
+
40
+ return async ({ isReload }) => {
41
+ const urlObject = new URL(src, window.location)
42
+ const loadPromise = new Promise((resolve, reject) => {
43
+ currentScriptClone = document.createElement("script")
44
+ Array.from(currentScript.attributes).forEach((attribute) => {
45
+ currentScriptClone.setAttribute(attribute.nodeName, attribute.nodeValue)
46
+ })
47
+ if (isReload) {
48
+ urlObject.searchParams.set("hmr", Date.now())
49
+ nodeToReplace = currentScriptClone
50
+ currentScriptClone.src = urlObject.href
51
+ } else {
52
+ currentScriptClone.removeAttribute("jsenv-plugin-owner")
53
+ currentScriptClone.removeAttribute("jsenv-plugin-action")
54
+ currentScriptClone.removeAttribute("inlined-from-src")
55
+ currentScriptClone.removeAttribute("original-position")
56
+ currentScriptClone.removeAttribute("original-src-position")
57
+ nodeToReplace = currentScript
58
+ currentScriptClone.src = src
59
+ }
60
+ currentScriptClone.addEventListener("error", reject)
61
+ currentScriptClone.addEventListener("load", resolve)
62
+ parentNode.replaceChild(currentScriptClone, nodeToReplace)
63
+ })
64
+ try {
65
+ await loadPromise
66
+ } catch (e) {
67
+ // eslint-disable-next-line no-throw-literal
68
+ throw {
69
+ message: `Failed to fetch module: ${urlObject.href}`,
70
+ reportedBy: "script_error_event",
71
+ url: urlObject.href,
72
+ // window.error won't be dispatched for this error
73
+ needsReport: true,
74
+ }
75
+ }
76
+ // do not resolve right away, wait for top level execution
77
+ try {
78
+ const namespace = await import(urlObject.href)
79
+ return namespace
80
+ } catch (e) {
81
+ e.reportedBy = "dynamic_import"
82
+ throw e
83
+ }
84
+ }
85
+ }
86
+
87
+ const createExecuteWithDynamicImport = ({ src }) => {
88
+ return async ({ isReload }) => {
89
+ const urlObject = new URL(src, window.location)
90
+ if (isReload) {
91
+ urlObject.searchParams.set("hmr", Date.now())
92
+ }
93
+ try {
94
+ const namespace = await import(urlObject.href)
95
+ return namespace
96
+ } catch (e) {
97
+ e.reportedBy = "dynamic_import"
98
+ // dynamic import would hide the error to the browser
99
+ // so it must be re-reported using window.reportError
100
+ if (typeof window.reportError === "function") {
101
+ window.reportError(e)
102
+ } else {
103
+ console.error(e)
104
+ }
105
+ throw e
106
+ }
107
+ }
108
+ }