@jsenv/core 27.4.0 → 27.5.2

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 (86) hide show
  1. package/dist/js/autoreload.js +359 -0
  2. package/dist/js/execute_using_dynamic_import.js +1 -1
  3. package/dist/js/html_supervisor_installer.js +469 -254
  4. package/dist/js/html_supervisor_setup.js +3 -4
  5. package/dist/js/new_stylesheet.js +26 -58
  6. package/dist/js/server_events_client.js +307 -0
  7. package/dist/main.js +7558 -7311
  8. package/package.json +12 -10
  9. package/{README.md → readme.md} +8 -9
  10. package/src/build/build.js +12 -16
  11. package/src/build/start_build_server.js +24 -28
  12. package/src/dev/start_dev_server.js +34 -96
  13. package/src/execute/execute.js +17 -35
  14. package/src/omega/errors.js +20 -18
  15. package/src/omega/kitchen.js +7 -6
  16. package/src/omega/omega_server.js +96 -127
  17. package/src/omega/server/file_service.js +247 -46
  18. package/src/omega/url_graph.js +33 -20
  19. package/src/plugins/autoreload/client/autoreload.js +201 -0
  20. package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
  21. package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
  22. package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
  23. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -4
  24. package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
  26. package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
  27. package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
  28. package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
  29. package/src/plugins/html_supervisor/client/error_formatter.js +300 -0
  30. package/src/plugins/html_supervisor/client/error_overlay.js +172 -0
  31. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +124 -54
  32. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  33. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +72 -27
  34. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
  35. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
  36. package/src/plugins/plugin_controller.js +102 -67
  37. package/src/plugins/plugins.js +10 -8
  38. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +102 -31
  39. package/src/plugins/server_events/client/server_events_client.js +17 -0
  40. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
  41. package/src/plugins/server_events/server_events_dispatcher.js +69 -0
  42. package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
  43. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
  44. package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
  45. package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
  46. package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
  47. package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
  48. package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
  49. package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
  50. package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
  51. package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
  52. package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
  53. package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
  54. package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
  55. package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
  56. package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
  57. package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
  58. package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
  59. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
  60. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
  61. package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
  62. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
  63. package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
  64. package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
  65. package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
  66. package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
  67. package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
  68. package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
  69. package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
  70. package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
  71. package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
  72. package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
  73. package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
  74. package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
  75. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
  76. package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
  77. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
  78. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
  79. package/src/plugins/url_analysis/html/html_urls.js +8 -8
  80. package/src/test/execute_plan.js +36 -54
  81. package/src/test/execute_test_plan.js +2 -2
  82. package/dist/js/event_source_client.js +0 -549
  83. package/src/helpers/event_source/sse_service.js +0 -53
  84. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  85. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -192
  86. package/src/plugins/html_supervisor/client/error_in_document.js +0 -345
@@ -14,7 +14,7 @@ window.__html_supervisor__ = {
14
14
  type: "js_classic",
15
15
  isInline,
16
16
  currentScript: document.currentScript,
17
- execute: () => {
17
+ execute: (url) => {
18
18
  return new Promise((resolve, reject) => {
19
19
  const script = document.createElement("script")
20
20
  if (crossorigin) {
@@ -23,8 +23,7 @@ window.__html_supervisor__ = {
23
23
  if (integrity) {
24
24
  script.integrity = integrity
25
25
  }
26
- script.src = src
27
- const scriptUrl = new URL(src, window.location).href
26
+ script.src = url
28
27
  let lastWindowErrorUrl
29
28
  let lastWindowError
30
29
  const windowErrorCallback = (e) => {
@@ -45,7 +44,7 @@ window.__html_supervisor__ = {
45
44
  })
46
45
  script.addEventListener("load", () => {
47
46
  cleanup()
48
- if (lastWindowErrorUrl === scriptUrl) {
47
+ if (lastWindowErrorUrl === url) {
49
48
  reject(lastWindowError)
50
49
  } else {
51
50
  resolve()
@@ -19,13 +19,16 @@ import {
19
19
  removeHtmlNodeText,
20
20
  setHtmlNodeText,
21
21
  } from "@jsenv/ast"
22
- import { generateInlineContentUrl } from "@jsenv/urls"
22
+ import { generateInlineContentUrl, stringifyUrlSite } from "@jsenv/urls"
23
23
 
24
24
  import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
25
25
 
26
26
  export const jsenvPluginHtmlSupervisor = ({
27
27
  logs = false,
28
28
  measurePerf = false,
29
+ errorOverlay = true,
30
+ openInEditor = true,
31
+ errorBaseUrl,
29
32
  }) => {
30
33
  const htmlSupervisorSetupFileUrl = new URL(
31
34
  "./client/html_supervisor_setup.js?js_classic",
@@ -43,24 +46,60 @@ export const jsenvPluginHtmlSupervisor = ({
43
46
  dev: true,
44
47
  test: true,
45
48
  },
46
- serve: (request) => {
47
- if (!request.ressource.startsWith("/__open_in_editor__/")) {
48
- return null
49
- }
50
- const file = request.ressource.slice("/__open_in_editor__/".length)
51
- if (!file) {
49
+ serve: (request, context) => {
50
+ if (request.ressource.startsWith("/__open_in_editor__/")) {
51
+ const file = request.ressource.slice("/__open_in_editor__/".length)
52
+ if (!file) {
53
+ return {
54
+ status: 400,
55
+ body: "Missing file in url",
56
+ }
57
+ }
58
+ const launch = requireFromJsenv("launch-editor")
59
+ launch(fileURLToPath(file), () => {
60
+ // ignore error for now
61
+ })
52
62
  return {
53
- status: 400,
54
- body: 'Missing "file" in url search params',
63
+ status: 200,
64
+ headers: {
65
+ "cache-control": "no-store",
66
+ },
55
67
  }
56
68
  }
57
- const launch = requireFromJsenv("launch-editor")
58
- launch(fileURLToPath(file), () => {
59
- // ignore error for now
60
- })
61
- return {
62
- status: 200,
69
+ if (request.ressource.startsWith("/__get_code_frame__/")) {
70
+ const url = request.ressource.slice("/__get_code_frame__/".length)
71
+ const match = url.match(/:([0-9]+):([0-9]+)$/)
72
+ if (!match) {
73
+ return {
74
+ status: 400,
75
+ body: "Missing line and column in url",
76
+ }
77
+ }
78
+ const file = url.slice(0, match.index)
79
+ const line = parseInt(match[1])
80
+ const column = parseInt(match[2])
81
+ const urlInfo = context.urlGraph.getUrlInfo(file)
82
+ if (!urlInfo) {
83
+ return {
84
+ status: 404,
85
+ }
86
+ }
87
+ const codeFrame = stringifyUrlSite({
88
+ url: file,
89
+ line,
90
+ column,
91
+ content: urlInfo.originalContent,
92
+ })
93
+ return {
94
+ status: 200,
95
+ headers: {
96
+ "content-type": "text/plain",
97
+ "content-length": Buffer.byteLength(codeFrame),
98
+ },
99
+ body: codeFrame,
100
+ }
63
101
  }
102
+ return null
64
103
  },
65
104
  transformUrlContent: {
66
105
  html: ({ url, content }, context) => {
@@ -68,14 +107,14 @@ export const jsenvPluginHtmlSupervisor = ({
68
107
  const scriptsToSupervise = []
69
108
 
70
109
  const handleInlineScript = (node, htmlNodeText) => {
71
- const scriptCategory = analyzeScriptNode(node)
110
+ const { type, extension } = analyzeScriptNode(node)
72
111
  const { line, column, lineEnd, columnEnd, isOriginal } =
73
112
  getHtmlNodePosition(node, {
74
113
  preferOriginal: true,
75
114
  })
76
115
  let inlineScriptUrl = generateInlineContentUrl({
77
116
  url,
78
- extension: ".js",
117
+ extension: extension || ".js",
79
118
  line,
80
119
  column,
81
120
  lineEnd,
@@ -83,9 +122,7 @@ export const jsenvPluginHtmlSupervisor = ({
83
122
  })
84
123
  const [inlineScriptReference] = context.referenceUtils.foundInline({
85
124
  type: "script_src",
86
- expectedType: { classic: "js_classic", module: "js_module" }[
87
- scriptCategory
88
- ],
125
+ expectedType: type,
89
126
  isOriginalPosition: isOriginal,
90
127
  specifierLine: line - 1,
91
128
  specifierColumn: column,
@@ -94,15 +131,20 @@ export const jsenvPluginHtmlSupervisor = ({
94
131
  content: htmlNodeText,
95
132
  })
96
133
  removeHtmlNodeText(node)
134
+ if (extension) {
135
+ setHtmlNodeAttributes(node, {
136
+ type: type === "js_module" ? "module" : undefined,
137
+ })
138
+ }
97
139
  scriptsToSupervise.push({
98
140
  node,
99
141
  isInline: true,
100
- type: scriptCategory,
142
+ type,
101
143
  src: inlineScriptReference.generatedSpecifier,
102
144
  })
103
145
  }
104
146
  const handleScriptWithSrc = (node, src) => {
105
- const scriptCategory = analyzeScriptNode(node)
147
+ const { type } = analyzeScriptNode(node)
106
148
  const integrity = getHtmlNodeAttribute(node, "integrity")
107
149
  const crossorigin =
108
150
  getHtmlNodeAttribute(node, "crossorigin") !== undefined
@@ -113,7 +155,7 @@ export const jsenvPluginHtmlSupervisor = ({
113
155
  })
114
156
  scriptsToSupervise.push({
115
157
  node,
116
- type: scriptCategory,
158
+ type,
117
159
  src,
118
160
  defer,
119
161
  async,
@@ -123,8 +165,8 @@ export const jsenvPluginHtmlSupervisor = ({
123
165
  }
124
166
  visitHtmlNodes(htmlAst, {
125
167
  script: (node) => {
126
- const scriptCategory = analyzeScriptNode(node)
127
- if (scriptCategory !== "classic" && scriptCategory !== "module") {
168
+ const { type } = analyzeScriptNode(node)
169
+ if (type !== "js_classic" && type !== "js_module") {
128
170
  return
129
171
  }
130
172
  const injectedBy = getHtmlNodeAttribute(node, "injected-by")
@@ -167,9 +209,12 @@ export const jsenvPluginHtmlSupervisor = ({
167
209
  }
168
210
  installHtmlSupervisor(${JSON.stringify(
169
211
  {
212
+ rootDirectoryUrl: context.rootDirectoryUrl,
213
+ errorBaseUrl,
170
214
  logs,
171
215
  measurePerf,
172
- rootDirectoryUrl: context.rootDirectoryUrl,
216
+ errorOverlay,
217
+ openInEditor,
173
218
  },
174
219
  null,
175
220
  " ",
@@ -252,7 +297,7 @@ const generateCodeToSuperviseScript = ({
252
297
  integrity,
253
298
  crossorigin,
254
299
  })
255
- if (type === "module") {
300
+ if (type === "js_module") {
256
301
  return `
257
302
  import { superviseScriptTypeModule } from ${htmlSupervisorInstallerSpecifier}
258
303
  superviseScriptTypeModule(${paramsAsJson})
@@ -20,129 +20,109 @@ export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
20
20
  html: async (urlInfo, context) => {
21
21
  const htmlAst = parseHtmlString(urlInfo.content)
22
22
  const actions = []
23
- const handleInlineStyle = (node) => {
24
- const htmlNodeText = getHtmlNodeText(node)
25
- if (!htmlNodeText) {
26
- return
27
- }
28
- actions.push(async () => {
29
- const { line, column, lineEnd, columnEnd, isOriginal } =
30
- getHtmlNodePosition(node, {
31
- preferOriginal: true,
23
+ visitHtmlNodes(htmlAst, {
24
+ style: (styleNode) => {
25
+ const styleNodeText = getHtmlNodeText(styleNode)
26
+ if (!styleNodeText) {
27
+ return
28
+ }
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,
32
41
  })
33
- const inlineStyleUrl = generateInlineContentUrl({
34
- url: urlInfo.url,
35
- extension: ".css",
36
- line,
37
- column,
38
- lineEnd,
39
- columnEnd,
40
- })
41
- const [inlineStyleReference, inlineStyleUrlInfo] =
42
- context.referenceUtils.foundInline({
43
- type: "link_href",
44
- expectedType: "css",
45
- isOriginalPosition: isOriginal,
46
- // we remove 1 to the line because imagine the following html:
47
- // <style>body { color: red; }</style>
48
- // -> content starts same line as <style>
49
- specifierLine: line - 1,
50
- specifierColumn: column,
51
- specifier: inlineStyleUrl,
52
- contentType: "text/css",
53
- content: htmlNodeText,
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
+ })
57
+ await context.cook(inlineStyleUrlInfo, {
58
+ reference: inlineStyleReference,
54
59
  })
55
- await context.cook(inlineStyleUrlInfo, {
56
- reference: inlineStyleReference,
57
- })
58
- setHtmlNodeText(node, inlineStyleUrlInfo.content)
59
- setHtmlNodeAttributes(node, {
60
- "generated-by": "jsenv:html_inline_content",
61
- })
62
- })
63
- }
64
- const handleInlineScript = (node) => {
65
- const htmlNodeText = getHtmlNodeText(node)
66
- if (!htmlNodeText) {
67
- return
68
- }
69
- // If the inline script was already handled by an other plugin, ignore it
70
- // - we want to preserve inline scripts generated by html supervisor during dev
71
- // - we want to avoid cooking twice a script during build
72
- const generatedBy = getHtmlNodeAttribute(node, "generated-by")
73
- if (
74
- generatedBy === "jsenv:as_js_classic_html" &&
75
- !analyzeConvertedScripts
76
- ) {
77
- return
78
- }
79
- if (generatedBy === "jsenv:html_supervisor") {
80
- return
81
- }
82
- actions.push(async () => {
83
- const scriptCategory = analyzeScriptNode(node)
84
- const { line, column, lineEnd, columnEnd, isOriginal } =
85
- getHtmlNodePosition(node, {
86
- preferOriginal: true,
60
+ setHtmlNodeText(styleNode, inlineStyleUrlInfo.content)
61
+ setHtmlNodeAttributes(styleNode, {
62
+ "generated-by": "jsenv:html_inline_content",
87
63
  })
88
- // from MDN about [type] attribute:
89
- // "Any other value: The embedded content is treated as a data block
90
- // which won't be processed by the browser. Developers must use a valid MIME type
91
- // that is not a JavaScript MIME type to denote data blocks.
92
- // The src attribute will be ignored."
93
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
94
- const isJs =
95
- scriptCategory === "classic" || scriptCategory === "module"
96
- const isImportmap = scriptCategory === "importmap"
97
- const contentType = isJs
98
- ? "text/javascript"
99
- : isImportmap
100
- ? "application/importmap+json"
101
- : scriptCategory
102
-
103
- let inlineScriptUrl = generateInlineContentUrl({
104
- url: urlInfo.url,
105
- extension: CONTENT_TYPE.asFileExtension(contentType),
106
- line,
107
- column,
108
- lineEnd,
109
- columnEnd,
110
64
  })
111
- const [inlineScriptReference, inlineScriptUrlInfo] =
112
- context.referenceUtils.foundInline({
113
- node,
114
- type: "script_src",
115
- expectedType: {
116
- classic: "js_classic",
117
- module: "js_module",
118
- importmap: "importmap",
119
- }[scriptCategory],
120
- // we remove 1 to the line because imagine the following html:
121
- // <script>console.log('ok')</script>
122
- // -> content starts same line as <script>
123
- specifierLine: line - 1,
124
- specifierColumn: column,
125
- isOriginalPosition: isOriginal,
126
- specifier: inlineScriptUrl,
127
- contentType,
128
- content: htmlNodeText,
65
+ },
66
+ script: (scriptNode) => {
67
+ const scriptNodeText = getHtmlNodeText(scriptNode)
68
+ if (!scriptNodeText) {
69
+ return
70
+ }
71
+ // If the inline script was already handled by an other plugin, ignore it
72
+ // - we want to preserve inline scripts generated by html supervisor during dev
73
+ // - we want to avoid cooking twice a script during build
74
+ const generatedBy = getHtmlNodeAttribute(scriptNode, "generated-by")
75
+ if (
76
+ generatedBy === "jsenv:as_js_classic_html" &&
77
+ !analyzeConvertedScripts
78
+ ) {
79
+ return
80
+ }
81
+ if (generatedBy === "jsenv:html_supervisor") {
82
+ return
83
+ }
84
+ actions.push(async () => {
85
+ const { type, contentType, extension } =
86
+ analyzeScriptNode(scriptNode)
87
+ const { line, column, lineEnd, columnEnd, isOriginal } =
88
+ getHtmlNodePosition(scriptNode, {
89
+ preferOriginal: true,
90
+ })
91
+ let inlineScriptUrl = generateInlineContentUrl({
92
+ url: urlInfo.url,
93
+ extension:
94
+ extension || CONTENT_TYPE.asFileExtension(contentType),
95
+ line,
96
+ column,
97
+ lineEnd,
98
+ columnEnd,
99
+ })
100
+ const [inlineScriptReference, inlineScriptUrlInfo] =
101
+ context.referenceUtils.foundInline({
102
+ node: scriptNode,
103
+ type: "script_src",
104
+ expectedType: type,
105
+ // we remove 1 to the line because imagine the following html:
106
+ // <script>console.log('ok')</script>
107
+ // -> content starts same line as <script>
108
+ specifierLine: line - 1,
109
+ specifierColumn: column,
110
+ isOriginalPosition: isOriginal,
111
+ specifier: inlineScriptUrl,
112
+ contentType,
113
+ content: scriptNodeText,
114
+ })
115
+ await context.cook(inlineScriptUrlInfo, {
116
+ reference: inlineScriptReference,
117
+ })
118
+ setHtmlNodeText(scriptNode, inlineScriptUrlInfo.content)
119
+ setHtmlNodeAttributes(scriptNode, {
120
+ "generated-by": "jsenv:html_inline_content",
121
+ ...(extension
122
+ ? { type: type === "js_module" ? "module" : undefined }
123
+ : {}),
129
124
  })
130
-
131
- await context.cook(inlineScriptUrlInfo, {
132
- reference: inlineScriptReference,
133
- })
134
- setHtmlNodeText(node, inlineScriptUrlInfo.content)
135
- setHtmlNodeAttributes(node, {
136
- "generated-by": "jsenv:html_inline_content",
137
125
  })
138
- })
139
- }
140
- visitHtmlNodes(htmlAst, {
141
- style: (node) => {
142
- handleInlineStyle(node)
143
- },
144
- script: (node) => {
145
- handleInlineScript(node)
146
126
  },
147
127
  })
148
128
  if (actions.length === 0) {
@@ -17,72 +17,78 @@ import {
17
17
  } from "@jsenv/node-esm-resolution"
18
18
 
19
19
  export const jsenvPluginNodeEsmResolution = ({
20
- rootDirectoryUrl,
21
- urlGraph,
22
- runtimeCompat,
23
20
  packageConditions,
24
21
  filesInvalidatingCache = ["package.json", "package-lock.json"],
25
22
  }) => {
26
- const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node")
27
- // https://nodejs.org/api/esm.html#resolver-algorithm-specification
28
- packageConditions = packageConditions || [
29
- ...readCustomConditionsFromProcessArgs(),
30
- nodeRuntimeEnabled ? "node" : "browser",
31
- "import",
32
- ]
33
-
34
- const packageScopesCache = new Map()
35
- const lookupPackageScope = (url) => {
36
- const fromCache = packageScopesCache.get(url)
37
- if (fromCache) {
38
- return fromCache
39
- }
40
- const packageScope = defaultLookupPackageScope(url)
41
- packageScopesCache.set(url, packageScope)
42
- return packageScope
43
- }
44
- const packageJsonsCache = new Map()
45
- const readPackageJson = (url) => {
46
- const fromCache = packageJsonsCache.get(url)
47
- if (fromCache) {
48
- return fromCache
49
- }
50
- const packageJson = defaultReadPackageJson(url)
51
- packageJsonsCache.set(url, packageJson)
52
- return packageJson
53
- }
54
-
55
23
  const unregisters = []
56
- const onFileChange = () => {
57
- packageScopesCache.clear()
58
- packageJsonsCache.clear()
59
- urlGraph.urlInfoMap.forEach((urlInfo) => {
60
- if (urlInfo.dependsOnPackageJson) {
61
- urlGraph.considerModified(urlInfo)
62
- }
63
- })
64
- }
65
- filesInvalidatingCache.forEach((file) => {
66
- const unregister = registerFileLifecycle(new URL(file, rootDirectoryUrl), {
67
- added: () => {
68
- onFileChange()
69
- },
70
- updated: () => {
71
- onFileChange()
72
- },
73
- removed: () => {
74
- onFileChange()
75
- },
76
- keepProcessAlive: false,
77
- })
78
- unregisters.push(unregister)
79
- })
24
+ let lookupPackageScope // defined in "init"
25
+ let readPackageJson // defined in "init"
80
26
 
81
27
  return {
82
28
  name: "jsenv:node_esm_resolution",
83
29
  appliesDuring: "*",
30
+ init: ({ rootDirectoryUrl, scenario, runtimeCompat, urlGraph }) => {
31
+ const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node")
32
+ // https://nodejs.org/api/esm.html#resolver-algorithm-specification
33
+ packageConditions = packageConditions || [
34
+ ...readCustomConditionsFromProcessArgs(),
35
+ nodeRuntimeEnabled ? "node" : "browser",
36
+ "import",
37
+ ]
38
+
39
+ const packageScopesCache = new Map()
40
+ lookupPackageScope = (url) => {
41
+ const fromCache = packageScopesCache.get(url)
42
+ if (fromCache) {
43
+ return fromCache
44
+ }
45
+ const packageScope = defaultLookupPackageScope(url)
46
+ packageScopesCache.set(url, packageScope)
47
+ return packageScope
48
+ }
49
+ const packageJsonsCache = new Map()
50
+ readPackageJson = (url) => {
51
+ const fromCache = packageJsonsCache.get(url)
52
+ if (fromCache) {
53
+ return fromCache
54
+ }
55
+ const packageJson = defaultReadPackageJson(url)
56
+ packageJsonsCache.set(url, packageJson)
57
+ return packageJson
58
+ }
59
+
60
+ if (scenario === "dev") {
61
+ const onFileChange = () => {
62
+ packageScopesCache.clear()
63
+ packageJsonsCache.clear()
64
+ urlGraph.urlInfoMap.forEach((urlInfo) => {
65
+ if (urlInfo.dependsOnPackageJson) {
66
+ urlGraph.considerModified(urlInfo)
67
+ }
68
+ })
69
+ }
70
+ filesInvalidatingCache.forEach((file) => {
71
+ const unregister = registerFileLifecycle(
72
+ new URL(file, rootDirectoryUrl),
73
+ {
74
+ added: () => {
75
+ onFileChange()
76
+ },
77
+ updated: () => {
78
+ onFileChange()
79
+ },
80
+ removed: () => {
81
+ onFileChange()
82
+ },
83
+ keepProcessAlive: false,
84
+ },
85
+ )
86
+ unregisters.push(unregister)
87
+ })
88
+ }
89
+ },
84
90
  resolveUrl: {
85
- js_import_export: (reference) => {
91
+ js_import_export: (reference, context) => {
86
92
  const { parentUrl, specifier } = reference
87
93
  const { type, url } = applyNodeEsmResolution({
88
94
  conditions: packageConditions,
@@ -100,7 +106,9 @@ export const jsenvPluginNodeEsmResolution = ({
100
106
  type !== "relative_specifier" &&
101
107
  type !== "absolute_specifier" &&
102
108
  type !== "node_builtin_specifier"
103
- const relatedUrlInfos = urlGraph.getRelatedUrlInfos(reference.parentUrl)
109
+ const relatedUrlInfos = context.urlGraph.getRelatedUrlInfos(
110
+ reference.parentUrl,
111
+ )
104
112
  relatedUrlInfos.forEach((relatedUrlInfo) => {
105
113
  if (relatedUrlInfo.dependsOnPackageJson) {
106
114
  // the url may depend due to an other reference