@jsenv/core 27.3.3 → 27.5.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 (89) 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 +524 -147
  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 +7699 -7307
  8. package/package.json +15 -15
  9. package/{README.md → readme.md} +18 -7
  10. package/src/build/build.js +16 -18
  11. package/src/build/start_build_server.js +24 -28
  12. package/src/dev/start_dev_server.js +30 -94
  13. package/src/execute/execute.js +17 -35
  14. package/src/execute/run.js +2 -0
  15. package/src/omega/errors.js +43 -9
  16. package/src/omega/kitchen.js +42 -25
  17. package/src/omega/omega_server.js +96 -74
  18. package/src/omega/server/file_service.js +256 -28
  19. package/src/omega/url_graph.js +39 -20
  20. package/src/plugins/autoreload/client/autoreload.js +201 -0
  21. package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
  22. package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
  23. package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
  24. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -8
  25. package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
  26. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
  27. package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
  28. package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
  29. package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
  30. package/src/plugins/html_supervisor/client/error_overlay.js +401 -0
  31. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +138 -23
  32. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
  33. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +55 -23
  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 -10
  38. package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +125 -33
  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/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
  81. package/src/test/execute_plan.js +36 -54
  82. package/src/test/execute_test_plan.js +2 -2
  83. package/src/test/logs_file_execution.js +60 -27
  84. package/src/test/logs_file_execution.test.mjs +41 -0
  85. package/dist/js/event_source_client.js +0 -528
  86. package/src/helpers/event_source/sse_service.js +0 -53
  87. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
  88. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -203
  89. package/src/plugins/html_supervisor/client/error_in_document.js +0 -198
@@ -13,8 +13,8 @@ export const reloadHtmlPage = () => {
13
13
  // - no need to check [hot-accept]and [hot-decline] attributes for instance
14
14
  // This is because if something should full reload, we receive "full_reload"
15
15
  // from server and this function is not called
16
- export const reloadDOMNodesUsingUrl = (urlToReload) => {
17
- const mutations = []
16
+ export const getDOMNodesUsingUrl = (urlToReload) => {
17
+ const nodes = []
18
18
  const shouldReloadUrl = (urlCandidate) => {
19
19
  return compareTwoUrlPaths(urlCandidate, urlToReload)
20
20
  }
@@ -29,8 +29,11 @@ export const reloadDOMNodesUsingUrl = (urlToReload) => {
29
29
  if (!shouldReloadUrl(attribute)) {
30
30
  return
31
31
  }
32
- mutations.push(() => {
33
- node[attributeName] = injectQuery(attribute, { hmr: Date.now() })
32
+ nodes.push({
33
+ node,
34
+ reload: () => {
35
+ node[attributeName] = injectQuery(attribute, { hmr: Date.now() })
36
+ },
34
37
  })
35
38
  }
36
39
  Array.from(document.querySelectorAll(`link[rel="stylesheet"]`)).forEach(
@@ -41,8 +44,23 @@ export const reloadDOMNodesUsingUrl = (urlToReload) => {
41
44
  Array.from(document.querySelectorAll(`link[rel="icon"]`)).forEach((link) => {
42
45
  visitNodeAttributeAsUrl(link, "href")
43
46
  })
44
- Array.from(document.querySelector("script")).forEach((script) => {
47
+ Array.from(document.querySelectorAll("script")).forEach((script) => {
45
48
  visitNodeAttributeAsUrl(script, "src")
49
+ const generatedFromSrc = script.getAttribute("generated-from-src")
50
+ if (generatedFromSrc) {
51
+ const generatedFromUrl = new URL(generatedFromSrc, window.location.origin)
52
+ .href
53
+ if (shouldReloadUrl(generatedFromUrl)) {
54
+ nodes.push({
55
+ node: script,
56
+ reload: () =>
57
+ window.__html_supervisor__.reloadSupervisedScript({
58
+ type: script.type,
59
+ src: generatedFromSrc,
60
+ }),
61
+ })
62
+ }
63
+ }
46
64
  })
47
65
  // There is no real need to update a.href because the ressource will be fetched when clicked.
48
66
  // But in a scenario where the ressource was already visited and is in browser cache, adding
@@ -67,8 +85,11 @@ export const reloadDOMNodesUsingUrl = (urlToReload) => {
67
85
  srcCandidate.specifier = injectQuery(url, { hmr: Date.now() })
68
86
  }
69
87
  })
70
- mutations.push(() => {
71
- img.srcset = stringifySrcSet(srcCandidates)
88
+ nodes.push({
89
+ node: img,
90
+ reload: () => {
91
+ img.srcset = stringifySrcSet(srcCandidates)
92
+ },
72
93
  })
73
94
  }
74
95
  })
@@ -83,9 +104,7 @@ export const reloadDOMNodesUsingUrl = (urlToReload) => {
83
104
  Array.from(document.querySelectorAll("use")).forEach((use) => {
84
105
  visitNodeAttributeAsUrl(use, "href")
85
106
  })
86
- mutations.forEach((mutation) => {
87
- mutation()
88
- })
107
+ return nodes
89
108
  }
90
109
 
91
110
  export const reloadJsImport = async (url) => {
@@ -1,10 +1,8 @@
1
1
  import { jsenvPluginHmr } from "./jsenv_plugin_hmr.js"
2
- import { jsenvPluginDevSSEClient } from "./dev_sse/jsenv_plugin_dev_sse_client.js"
3
- import { jsenvPluginDevSSEServer } from "./dev_sse/jsenv_plugin_dev_sse_server.js"
2
+ import { jsenvPluginAutoreloadClient } from "./jsenv_plugin_autoreload_client.js"
3
+ import { jsenvPluginAutoreloadServer } from "./jsenv_plugin_autoreload_server.js"
4
4
 
5
5
  export const jsenvPluginAutoreload = ({
6
- rootDirectoryUrl,
7
- urlGraph,
8
6
  scenario,
9
7
  clientFileChangeCallbackList,
10
8
  clientFilesPruneCallbackList,
@@ -14,10 +12,8 @@ export const jsenvPluginAutoreload = ({
14
12
  }
15
13
  return [
16
14
  jsenvPluginHmr(),
17
- jsenvPluginDevSSEClient(),
18
- jsenvPluginDevSSEServer({
19
- rootDirectoryUrl,
20
- urlGraph,
15
+ jsenvPluginAutoreloadClient(),
16
+ jsenvPluginAutoreloadServer({
21
17
  clientFileChangeCallbackList,
22
18
  clientFilesPruneCallbackList,
23
19
  }),
@@ -5,30 +5,30 @@ import {
5
5
  createHtmlNode,
6
6
  } from "@jsenv/ast"
7
7
 
8
- export const jsenvPluginDevSSEClient = () => {
9
- const eventSourceClientFileUrl = new URL(
10
- "./client/event_source_client.js",
8
+ export const jsenvPluginAutoreloadClient = () => {
9
+ const autoreloadClientFileUrl = new URL(
10
+ "./client/autoreload.js",
11
11
  import.meta.url,
12
12
  ).href
13
13
 
14
14
  return {
15
- name: "jsenv:dev_sse_client",
15
+ name: "jsenv:autoreload_client",
16
16
  appliesDuring: { dev: true },
17
17
  transformUrlContent: {
18
18
  html: (htmlUrlInfo, context) => {
19
19
  const htmlAst = parseHtmlString(htmlUrlInfo.content)
20
- const [eventSourceClientReference] = context.referenceUtils.inject({
20
+ const [autoreloadClientReference] = context.referenceUtils.inject({
21
21
  type: "script_src",
22
22
  expectedType: "js_module",
23
- specifier: eventSourceClientFileUrl,
23
+ specifier: autoreloadClientFileUrl,
24
24
  })
25
25
  injectScriptNodeAsEarlyAsPossible(
26
26
  htmlAst,
27
27
  createHtmlNode({
28
28
  "tagName": "script",
29
29
  "type": "module",
30
- "src": eventSourceClientReference.generatedSpecifier,
31
- "injected-by": "jsenv:dev_sse_client",
30
+ "src": autoreloadClientReference.generatedSpecifier,
31
+ "injected-by": "jsenv:autoreload_client",
32
32
  }),
33
33
  )
34
34
  const htmlModified = stringifyHtmlAst(htmlAst)
@@ -0,0 +1,196 @@
1
+ import { urlIsInsideOf, urlToRelativeUrl } from "@jsenv/urls"
2
+
3
+ export const jsenvPluginAutoreloadServer = ({
4
+ clientFileChangeCallbackList,
5
+ clientFilesPruneCallbackList,
6
+ }) => {
7
+ return {
8
+ name: "jsenv:autoreload_server",
9
+ appliesDuring: { dev: true },
10
+ serverEvents: {
11
+ reload: ({ sendServerEvent, rootDirectoryUrl, urlGraph }) => {
12
+ const formatUrlForClient = (url) => {
13
+ if (urlIsInsideOf(url, rootDirectoryUrl)) {
14
+ return urlToRelativeUrl(url, rootDirectoryUrl)
15
+ }
16
+ if (url.startsWith("file:")) {
17
+ return `/@fs/${url.slice("file:///".length)}`
18
+ }
19
+ return url
20
+ }
21
+
22
+ const notifyDeclined = ({ cause, reason, declinedBy }) => {
23
+ sendServerEvent({
24
+ cause,
25
+ type: "full",
26
+ typeReason: reason,
27
+ declinedBy,
28
+ })
29
+ }
30
+ const notifyAccepted = ({ cause, reason, instructions }) => {
31
+ sendServerEvent({
32
+ cause,
33
+ type: "hot",
34
+ typeReason: reason,
35
+ hotInstructions: instructions,
36
+ })
37
+ }
38
+ const propagateUpdate = (firstUrlInfo) => {
39
+ const iterate = (urlInfo, seen) => {
40
+ if (urlInfo.data.hotAcceptSelf) {
41
+ return {
42
+ accepted: true,
43
+ reason:
44
+ urlInfo === firstUrlInfo
45
+ ? `file accepts hot reload`
46
+ : `a dependent file accepts hot reload`,
47
+ instructions: [
48
+ {
49
+ type: urlInfo.type,
50
+ boundary: formatUrlForClient(urlInfo.url),
51
+ acceptedBy: formatUrlForClient(urlInfo.url),
52
+ },
53
+ ],
54
+ }
55
+ }
56
+ const { dependents } = urlInfo
57
+ const instructions = []
58
+ for (const dependentUrl of dependents) {
59
+ const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl)
60
+ if (dependentUrlInfo.data.hotDecline) {
61
+ return {
62
+ declined: true,
63
+ reason: `a dependent file declines hot reload`,
64
+ declinedBy: dependentUrl,
65
+ }
66
+ }
67
+ const { hotAcceptDependencies = [] } = dependentUrlInfo.data
68
+ if (hotAcceptDependencies.includes(urlInfo.url)) {
69
+ instructions.push({
70
+ type: dependentUrlInfo.type,
71
+ boundary: formatUrlForClient(dependentUrl),
72
+ acceptedBy: formatUrlForClient(urlInfo.url),
73
+ })
74
+ continue
75
+ }
76
+ if (seen.includes(dependentUrl)) {
77
+ return {
78
+ declined: true,
79
+ reason: "circular dependency",
80
+ declinedBy: formatUrlForClient(dependentUrl),
81
+ }
82
+ }
83
+ const dependentPropagationResult = iterate(dependentUrlInfo, [
84
+ ...seen,
85
+ dependentUrl,
86
+ ])
87
+ if (dependentPropagationResult.accepted) {
88
+ instructions.push(...dependentPropagationResult.instructions)
89
+ continue
90
+ }
91
+ if (
92
+ // declined explicitely by an other file, it must decline the whole update
93
+ dependentPropagationResult.declinedBy
94
+ ) {
95
+ return dependentPropagationResult
96
+ }
97
+ // declined by absence of boundary, we can keep searching
98
+ continue
99
+ }
100
+ if (instructions.length === 0) {
101
+ return {
102
+ declined: true,
103
+ reason: `there is no file accepting hot reload while propagating update`,
104
+ }
105
+ }
106
+ return {
107
+ accepted: true,
108
+ reason: `${instructions.length} dependent file(s) accepts hot reload`,
109
+ instructions,
110
+ }
111
+ }
112
+ const seen = []
113
+ return iterate(firstUrlInfo, seen)
114
+ }
115
+ clientFileChangeCallbackList.push(({ url, event }) => {
116
+ const urlInfo = urlGraph.getUrlInfo(url)
117
+ // file not part of dependency graph
118
+ if (!urlInfo) {
119
+ return
120
+ }
121
+ const relativeUrl = formatUrlForClient(url)
122
+ const hotUpdate = propagateUpdate(urlInfo)
123
+ if (hotUpdate.declined) {
124
+ notifyDeclined({
125
+ cause: `${relativeUrl} ${event}`,
126
+ reason: hotUpdate.reason,
127
+ declinedBy: hotUpdate.declinedBy,
128
+ })
129
+ } else {
130
+ notifyAccepted({
131
+ cause: `${relativeUrl} ${event}`,
132
+ reason: hotUpdate.reason,
133
+ instructions: hotUpdate.instructions,
134
+ })
135
+ }
136
+ })
137
+ clientFilesPruneCallbackList.push(
138
+ ({ prunedUrlInfos, firstUrlInfo }) => {
139
+ const mainHotUpdate = propagateUpdate(firstUrlInfo)
140
+ const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
141
+ (prunedUrlInfo) => formatUrlForClient(prunedUrlInfo.url),
142
+ )}`
143
+ // now check if we can hot update the main ressource
144
+ // then if we can hot update all dependencies
145
+ if (mainHotUpdate.declined) {
146
+ notifyDeclined({
147
+ cause,
148
+ reason: mainHotUpdate.reason,
149
+ declinedBy: mainHotUpdate.declinedBy,
150
+ })
151
+ return
152
+ }
153
+ // main can hot update
154
+ let i = 0
155
+ const instructions = []
156
+ while (i < prunedUrlInfos.length) {
157
+ const prunedUrlInfo = prunedUrlInfos[i++]
158
+ if (prunedUrlInfo.data.hotDecline) {
159
+ notifyDeclined({
160
+ cause,
161
+ reason: `a pruned file declines hot reload`,
162
+ declinedBy: formatUrlForClient(prunedUrlInfo.url),
163
+ })
164
+ return
165
+ }
166
+ instructions.push({
167
+ type: "prune",
168
+ boundary: formatUrlForClient(prunedUrlInfo.url),
169
+ acceptedBy: formatUrlForClient(firstUrlInfo.url),
170
+ })
171
+ }
172
+ notifyAccepted({
173
+ cause,
174
+ reason: mainHotUpdate.reason,
175
+ instructions,
176
+ })
177
+ },
178
+ )
179
+ },
180
+ },
181
+ serve: (request, { rootDirectoryUrl, urlGraph }) => {
182
+ if (request.ressource === "/__graph__") {
183
+ const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
184
+ return {
185
+ status: 200,
186
+ headers: {
187
+ "content-type": "application/json",
188
+ "content-length": Buffer.byteLength(graphJson),
189
+ },
190
+ body: graphJson,
191
+ }
192
+ }
193
+ return null
194
+ },
195
+ }
196
+ }
@@ -9,9 +9,7 @@ export const jsenvPluginExplorer = ({ groups }) => {
9
9
 
10
10
  return {
11
11
  name: "jsenv:explorer",
12
- appliesDuring: {
13
- dev: true,
14
- },
12
+ appliesDuring: "dev",
15
13
  serve: async (request, { rootDirectoryUrl }) => {
16
14
  if (request.ressource !== "/") {
17
15
  return null