@jsenv/core 27.0.0-alpha.5 → 27.0.0-alpha.50

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 (146) hide show
  1. package/dist/event_source_client.js +545 -0
  2. package/dist/event_source_client.js.map +187 -0
  3. package/dist/html_supervisor_installer.js +1236 -0
  4. package/dist/html_supervisor_installer.js.map +337 -0
  5. package/dist/html_supervisor_setup.js +95 -0
  6. package/dist/html_supervisor_setup.js.map +57 -0
  7. package/dist/import_meta_hot.js +86 -0
  8. package/dist/import_meta_hot.js.map +42 -0
  9. package/main.js +8 -1
  10. package/package.json +22 -21
  11. package/readme.md +4 -12
  12. package/src/build/build.js +749 -437
  13. package/src/build/build_urls_generator.js +56 -22
  14. package/src/build/graph_utils.js +31 -0
  15. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +33 -15
  16. package/src/build/inject_service_worker_urls.js +79 -0
  17. package/src/build/resync_ressource_hints.js +68 -0
  18. package/src/build/start_build_server.js +255 -0
  19. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
  20. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  21. package/src/dev/start_dev_server.js +136 -30
  22. package/src/execute/execute.js +31 -6
  23. package/src/execute/run.js +19 -56
  24. package/src/execute/runtimes/browsers/from_playwright.js +201 -147
  25. package/src/execute/runtimes/node/controllable_file.mjs +26 -10
  26. package/src/execute/runtimes/node/node_execution_performance.js +67 -0
  27. package/src/execute/runtimes/node/node_process.js +280 -39
  28. package/src/jsenv_root_directory_url.js +1 -0
  29. package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
  30. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +66 -4
  31. package/src/omega/compat/runtime_compat.js +50 -0
  32. package/src/omega/errors.js +51 -58
  33. package/src/omega/fetched_content_compliance.js +24 -0
  34. package/src/omega/file_url_converter.js +8 -50
  35. package/src/omega/kitchen.js +482 -292
  36. package/src/omega/omega_server.js +2 -3
  37. package/src/omega/server/file_service.js +38 -25
  38. package/src/omega/server/user_agent.js +4 -2
  39. package/src/omega/url_graph/url_graph_load.js +14 -7
  40. package/src/omega/url_graph/url_graph_report.js +17 -15
  41. package/src/omega/url_graph/url_info_transformations.js +26 -9
  42. package/src/omega/url_graph.js +91 -16
  43. package/src/omega/web_workers.js +42 -0
  44. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
  45. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +2 -2
  46. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
  47. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
  48. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +46 -0
  49. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +204 -0
  50. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +27 -0
  51. package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
  52. package/src/plugins/bundling/css/bundle_css.js +21 -0
  53. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  54. package/src/{build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js → plugins/bundling/js_module/bundle_js_module.js} +150 -79
  55. package/src/plugins/bundling/jsenv_plugin_bundling.js +54 -0
  56. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +54 -41
  57. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
  58. package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +8 -5
  59. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  60. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  61. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +242 -0
  62. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +79 -0
  63. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  64. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  65. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +83 -58
  66. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  67. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +4 -5
  68. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +3 -1
  69. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +2 -2
  70. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +105 -0
  71. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +33 -8
  72. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  73. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  74. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +39 -33
  75. package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +67 -0
  76. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  77. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
  78. package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +65 -44
  79. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  80. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
  81. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +296 -0
  82. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  83. package/src/plugins/minification/css/minify_css.js +9 -0
  84. package/src/plugins/minification/html/minify_html.js +15 -0
  85. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  86. package/src/plugins/minification/jsenv_plugin_minification.js +78 -0
  87. package/src/plugins/minification/json/minify_json.js +8 -0
  88. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +146 -0
  89. package/src/{omega → plugins}/plugin_controller.js +42 -11
  90. package/src/plugins/plugins.js +91 -0
  91. package/src/plugins/transpilation/as_js_classic/client/s.js +808 -0
  92. package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
  93. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  94. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  95. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +183 -0
  96. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +256 -0
  97. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +55 -0
  98. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  99. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  100. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  101. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +4 -22
  102. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  103. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +37 -21
  104. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +30 -6
  105. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
  106. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  107. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  108. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  109. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  110. package/src/plugins/transpilation/fetch_original_url_info.js +30 -0
  111. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +181 -0
  112. package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +70 -0
  113. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +44 -0
  114. package/src/plugins/url_analysis/css/css_urls.js +42 -0
  115. package/src/plugins/url_analysis/html/html_urls.js +273 -0
  116. package/src/plugins/url_analysis/js/js_urls.js +67 -0
  117. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +18 -0
  118. package/src/plugins/url_analysis/webmanifest/webmanifest_urls.js +17 -0
  119. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
  120. package/src/{omega/core_plugins → plugins}/url_version/jsenv_plugin_url_version.js +12 -15
  121. package/src/test/execute_plan.js +30 -18
  122. package/src/test/execute_test_plan.js +23 -8
  123. package/src/test/logs_file_execution.js +8 -7
  124. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  125. package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
  126. package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +0 -374
  127. package/src/dev/plugins/autoreload/sse_service.js +0 -149
  128. package/src/execute/runtimes/node/controlled_process.js +0 -316
  129. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  130. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_installer.js +0 -168
  131. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_setup.js +0 -77
  132. package/src/omega/core_plugins/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -98
  133. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  134. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  135. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  136. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  137. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -210
  138. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  139. package/src/omega/core_plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +0 -77
  140. package/src/omega/core_plugins.js +0 -39
  141. package/src/omega/runtime_support/runtime_support.js +0 -20
  142. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  143. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  144. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  145. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  146. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -1,30 +0,0 @@
1
- import { createRequire } from "node:module"
2
-
3
- const require = createRequire(import.meta.url)
4
-
5
- // https://github.com/kangax/html-minifier#options-quick-reference
6
- export const jsenvPluginMinifyHtml = ({
7
- collapseWhitespace = true,
8
- removeComments = true,
9
- } = {}) => {
10
- return {
11
- name: "jsenv:minify_html",
12
- appliesDuring: {
13
- build: true,
14
- },
15
- optimize: {
16
- html: async (htmlUrlInfo) => {
17
- return minifyHtml(htmlUrlInfo.content, {
18
- collapseWhitespace,
19
- removeComments,
20
- })
21
- },
22
- },
23
- }
24
- }
25
-
26
- const minifyHtml = (htmlString, options) => {
27
- const { minify } = require("html-minifier")
28
- const htmlMinified = minify(htmlString, options)
29
- return htmlMinified
30
- }
@@ -1,195 +0,0 @@
1
- export const createEventSourceConnection = (
2
- eventSourceUrl,
3
- events = {},
4
- { retryMaxAttempt = Infinity, retryAllocatedMs = Infinity, lastEventId } = {},
5
- ) => {
6
- const { EventSource } = window
7
- if (typeof EventSource !== "function") {
8
- return () => {}
9
- }
10
-
11
- const eventSourceOrigin = new URL(eventSourceUrl).origin
12
- Object.keys(events).forEach((eventName) => {
13
- const eventCallback = events[eventName]
14
- events[eventName] = (e) => {
15
- if (e.origin === eventSourceOrigin) {
16
- if (e.lastEventId) {
17
- lastEventId = e.lastEventId
18
- }
19
- eventCallback(e)
20
- }
21
- }
22
- })
23
-
24
- const status = {
25
- value: "default",
26
- goTo: (value) => {
27
- if (value === status.value) {
28
- return
29
- }
30
- status.value = value
31
- status.onchange()
32
- },
33
- onchange: () => {},
34
- }
35
- let _disconnect = () => {}
36
-
37
- const attemptConnection = (url) => {
38
- const eventSource = new EventSource(url, {
39
- withCredentials: true,
40
- })
41
- _disconnect = () => {
42
- if (status.value !== "connecting" && status.value !== "connected") {
43
- console.warn(
44
- `disconnect() ignored because connection is ${status.value}`,
45
- )
46
- return
47
- }
48
- eventSource.onerror = undefined
49
- eventSource.close()
50
- Object.keys(events).forEach((eventName) => {
51
- eventSource.removeEventListener(eventName, events[eventName])
52
- })
53
- status.goTo("disconnected")
54
- }
55
- let retryCount = 0
56
- let firstRetryMs = Date.now()
57
- eventSource.onerror = (errorEvent) => {
58
- if (errorEvent.target.readyState === EventSource.CONNECTING) {
59
- if (retryCount > retryMaxAttempt) {
60
- console.info(`could not connect after ${retryMaxAttempt} attempt`)
61
- _disconnect()
62
- return
63
- }
64
-
65
- if (retryCount === 0) {
66
- firstRetryMs = Date.now()
67
- } else {
68
- const allRetryDuration = Date.now() - firstRetryMs
69
- if (retryAllocatedMs && allRetryDuration > retryAllocatedMs) {
70
- console.info(
71
- `could not connect in less than ${retryAllocatedMs} ms`,
72
- )
73
- _disconnect()
74
- return
75
- }
76
- }
77
-
78
- retryCount++
79
- status.goTo("connecting")
80
- return
81
- }
82
-
83
- if (errorEvent.target.readyState === EventSource.CLOSED) {
84
- _disconnect()
85
- return
86
- }
87
- }
88
- eventSource.onopen = () => {
89
- status.goTo("connected")
90
- }
91
- Object.keys(events).forEach((eventName) => {
92
- eventSource.addEventListener(eventName, events[eventName])
93
- })
94
- if (!events.hasOwnProperty("welcome")) {
95
- eventSource.addEventListener("welcome", (e) => {
96
- if (e.origin === eventSourceOrigin && e.lastEventId) {
97
- lastEventId = e.lastEventId
98
- }
99
- })
100
- }
101
- status.goTo("connecting")
102
- }
103
-
104
- let connect = () => {
105
- attemptConnection(eventSourceUrl)
106
- connect = () => {
107
- attemptConnection(
108
- lastEventId
109
- ? addLastEventIdIntoUrlSearchParams(eventSourceUrl, lastEventId)
110
- : eventSourceUrl,
111
- )
112
- }
113
- }
114
-
115
- const removePageUnloadListener = listenPageUnload(() => {
116
- if (status.value === "connecting" || status.value === "connected") {
117
- _disconnect()
118
- }
119
- })
120
-
121
- const destroy = () => {
122
- removePageUnloadListener()
123
- _disconnect()
124
- }
125
-
126
- return {
127
- status,
128
- connect,
129
- disconnect: () => _disconnect(),
130
- destroy,
131
- }
132
- }
133
-
134
- const addLastEventIdIntoUrlSearchParams = (url, lastEventId) => {
135
- if (url.indexOf("?") === -1) {
136
- url += "?"
137
- } else {
138
- url += "&"
139
- }
140
- return `${url}last-event-id=${encodeURIComponent(lastEventId)}`
141
- }
142
-
143
- // const listenPageMightFreeze = (callback) => {
144
- // const removePageHideListener = listenEvent(window, "pagehide", (pageHideEvent) => {
145
- // if (pageHideEvent.persisted === true) {
146
- // callback(pageHideEvent)
147
- // }
148
- // })
149
- // return removePageHideListener
150
- // }
151
-
152
- // const listenPageFreeze = (callback) => {
153
- // const removeFreezeListener = listenEvent(document, "freeze", (freezeEvent) => {
154
- // callback(freezeEvent)
155
- // })
156
- // return removeFreezeListener
157
- // }
158
-
159
- // const listenPageIsRestored = (callback) => {
160
- // const removeResumeListener = listenEvent(document, "resume", (resumeEvent) => {
161
- // removePageshowListener()
162
- // callback(resumeEvent)
163
- // })
164
- // const removePageshowListener = listenEvent(window, "pageshow", (pageshowEvent) => {
165
- // if (pageshowEvent.persisted === true) {
166
- // removePageshowListener()
167
- // removeResumeListener()
168
- // callback(pageshowEvent)
169
- // }
170
- // })
171
- // return () => {
172
- // removeResumeListener()
173
- // removePageshowListener()
174
- // }
175
- // }
176
-
177
- const listenPageUnload = (callback) => {
178
- const removePageHideListener = listenEvent(
179
- window,
180
- "pagehide",
181
- (pageHideEvent) => {
182
- if (pageHideEvent.persisted !== true) {
183
- callback(pageHideEvent)
184
- }
185
- },
186
- )
187
- return removePageHideListener
188
- }
189
-
190
- const listenEvent = (emitter, event, callback) => {
191
- emitter.addEventListener(event, callback)
192
- return () => {
193
- emitter.removeEventListener(event, callback)
194
- }
195
- }
@@ -1,374 +0,0 @@
1
- import { urlToRelativeUrl } from "@jsenv/filesystem"
2
- import { createCallbackList } from "@jsenv/abort"
3
-
4
- import { injectQueryParams } from "@jsenv/utils/urls/url_utils.js"
5
- import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
6
- import {
7
- parseHtmlString,
8
- stringifyHtmlAst,
9
- injectScriptAsEarlyAsPossible,
10
- createHtmlNode,
11
- } from "@jsenv/utils/html_ast/html_ast.js"
12
- import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
13
-
14
- import { createSSEService } from "./sse_service.js"
15
- import { collectHotDataFromHtmlAst } from "./html_hot_dependencies.js"
16
- import { babelPluginMetadataImportMetaHot } from "./babel_plugin_metadata_import_meta_hot.js"
17
-
18
- export const jsenvPluginAutoreload = ({
19
- rootDirectoryUrl,
20
- urlGraph,
21
- autoreloadPatterns,
22
- }) => {
23
- return [
24
- jsenvPluginHot(),
25
- jsenvPluginHotSSE({
26
- rootDirectoryUrl,
27
- urlGraph,
28
- autoreloadPatterns,
29
- }),
30
- ]
31
- }
32
-
33
- const jsenvPluginHot = () => {
34
- const eventSourceClientFileUrl = new URL(
35
- "./client/event_source_client.js",
36
- import.meta.url,
37
- ).href
38
- const importMetaHotClientFileUrl = new URL(
39
- "./client/import_meta_hot.js",
40
- import.meta.url,
41
- ).href
42
-
43
- return {
44
- name: "jsenv:hot",
45
- appliesDuring: { dev: true },
46
- normalize: ({ url, data }) => {
47
- const urlObject = new URL(url)
48
- if (!urlObject.searchParams.has("hmr")) {
49
- data.hmr = false
50
- return null
51
- }
52
- data.hmr = true
53
- // "hmr" search param goal is to mark url as enabling hmr:
54
- // this goal is achieved when we reach this part of the code
55
- // We get rid of this params so that urlGraph and other parts of the code
56
- // recognize the url (it is not considered as a different url)
57
- urlObject.searchParams.delete("hmr")
58
- urlObject.searchParams.delete("v")
59
- return urlObject.href
60
- },
61
- transformReferencedUrl: ({ parentUrl, url, data }, { urlGraph }) => {
62
- const parentUrlInfo = urlGraph.getUrlInfo(parentUrl)
63
- if (!parentUrlInfo || !parentUrlInfo.data.hmr) {
64
- return null
65
- }
66
- if (!data.hmrTimestamp) {
67
- return null
68
- }
69
- return injectQueryParams(url, {
70
- hmr: "",
71
- v: data.hmrTimestamp,
72
- })
73
- },
74
- transform: {
75
- html: ({ data, content }, { referenceUtils }) => {
76
- const htmlAst = parseHtmlString(content)
77
- const { hotReferences } = collectHotDataFromHtmlAst(htmlAst)
78
- data.hotDecline = false
79
- data.hotAcceptSelf = false
80
- data.hotAcceptDependencies = hotReferences.map(
81
- ({ type, specifier }) => {
82
- const [reference] = referenceUtils.inject({
83
- type,
84
- specifier,
85
- })
86
- return reference.url
87
- },
88
- )
89
- const [eventSourceClientReference] = referenceUtils.inject({
90
- type: "script_src",
91
- specifier: eventSourceClientFileUrl,
92
- })
93
- injectScriptAsEarlyAsPossible(
94
- htmlAst,
95
- createHtmlNode({
96
- "tagName": "script",
97
- "type": "module",
98
- "src": eventSourceClientReference.generatedSpecifier,
99
- "injected-by": "jsenv:hot",
100
- }),
101
- )
102
- const htmlModified = stringifyHtmlAst(htmlAst)
103
- return {
104
- content: htmlModified,
105
- }
106
- },
107
- css: ({ data }) => {
108
- data.hotDecline = false
109
- data.hotAcceptSelf = false
110
- data.hotAcceptDependencies = []
111
- },
112
- js_module: async (
113
- { url, generatedUrl, data, content },
114
- { referenceUtils },
115
- ) => {
116
- const { metadata } = await applyBabelPlugins({
117
- babelPlugins: [babelPluginMetadataImportMetaHot],
118
- url,
119
- generatedUrl,
120
- content,
121
- })
122
- const {
123
- importMetaHotDetected,
124
- hotDecline,
125
- hotAcceptSelf,
126
- hotAcceptDependencies,
127
- } = metadata
128
- data.hotDecline = hotDecline
129
- data.hotAcceptSelf = hotAcceptSelf
130
- data.hotAcceptDependencies = hotAcceptDependencies
131
- if (!importMetaHotDetected) {
132
- return null
133
- }
134
- // For some reason using magic source here produce
135
- // better sourcemap than doing the equivalent with babel
136
- // I suspect it's because I was doing injectAstAfterImport(programPath, ast.program.body[0])
137
- // which is likely not well supported by babel
138
- const [importMetaHotClientFileReference] = referenceUtils.inject({
139
- parentUrl: url,
140
- type: "js_import_export",
141
- specifier: importMetaHotClientFileUrl,
142
- })
143
- const magicSource = createMagicSource(content)
144
- magicSource.prepend(
145
- `import { createImportMetaHot } from ${importMetaHotClientFileReference.generatedSpecifier}
146
- import.meta.hot = createImportMetaHot(import.meta.url)
147
- `,
148
- )
149
- return magicSource.toContentAndSourcemap()
150
- },
151
- },
152
- }
153
- }
154
-
155
- const jsenvPluginHotSSE = ({
156
- rootDirectoryUrl,
157
- urlGraph,
158
- autoreloadPatterns,
159
- }) => {
160
- const hotUpdateCallbackList = createCallbackList()
161
- const notifyDeclined = ({ cause, reason, declinedBy }) => {
162
- hotUpdateCallbackList.notify({
163
- declined: true,
164
- cause,
165
- reason,
166
- declinedBy,
167
- })
168
- }
169
- const notifyAccepted = ({ cause, reason, instructions }) => {
170
- hotUpdateCallbackList.notify({
171
- accepted: true,
172
- cause,
173
- reason,
174
- instructions,
175
- })
176
- }
177
- const updateHmrTimestamp = (urlInfo, hmrTimestamp) => {
178
- const urlInfos = urlGraph.urlInfos
179
- const seen = []
180
- const iterate = (urlInfo) => {
181
- if (seen.includes(urlInfo.url)) {
182
- return
183
- }
184
- seen.push(urlInfo.url)
185
- urlInfo.data.hmrTimestamp = hmrTimestamp
186
- urlInfo.dependents.forEach((dependentUrl) => {
187
- const dependentUrlInfo = urlInfos[dependentUrl]
188
- if (
189
- !dependentUrlInfo.data.hotAcceptDependencies.includes(urlInfo.url)
190
- ) {
191
- iterate(dependentUrlInfo, hmrTimestamp)
192
- }
193
- })
194
- }
195
- iterate(urlInfo)
196
- }
197
- const propagateUpdate = (firstUrlInfo) => {
198
- const urlInfos = urlGraph.urlInfos
199
- const iterate = (urlInfo, trace) => {
200
- if (urlInfo.data.hotAcceptSelf) {
201
- return {
202
- accepted: true,
203
- reason:
204
- urlInfo === firstUrlInfo
205
- ? `file accepts hot reload`
206
- : `a dependent file accepts hot reload`,
207
- instructions: [
208
- {
209
- type: urlInfo.type,
210
- boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
211
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
212
- },
213
- ],
214
- }
215
- }
216
- const { dependents } = urlInfo
217
- const instructions = []
218
- for (const dependentUrl of dependents) {
219
- const dependentUrlInfo = urlInfos[dependentUrl]
220
- if (dependentUrlInfo.data.hotDecline) {
221
- return {
222
- declined: true,
223
- reason: `a dependent file declines hot reload`,
224
- declinedBy: dependentUrl,
225
- }
226
- }
227
- if (dependentUrlInfo.data.hotAcceptDependencies.includes(urlInfo.url)) {
228
- instructions.push({
229
- type: dependentUrlInfo.type,
230
- boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
231
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
232
- })
233
- continue
234
- }
235
- if (trace.includes(dependentUrl)) {
236
- return {
237
- declined: true,
238
- reason: "circular dependency",
239
- declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
240
- }
241
- }
242
- const dependentPropagationResult = iterate(dependentUrlInfo, [
243
- ...trace,
244
- dependentUrl,
245
- ])
246
- if (dependentPropagationResult.accepted) {
247
- instructions.push(...dependentPropagationResult.instructions)
248
- continue
249
- }
250
- if (
251
- // declined explicitely by an other file, it must decline the whole update
252
- dependentPropagationResult.declinedBy
253
- ) {
254
- return dependentPropagationResult
255
- }
256
- // declined by absence of boundary, we can keep searching
257
- continue
258
- }
259
- if (instructions.length === 0) {
260
- return {
261
- declined: true,
262
- reason: `there is no file accepting hot reload while propagating update`,
263
- }
264
- }
265
- return {
266
- accepted: true,
267
- reason: `${instructions.length} dependent file(s) accepts hot reload`,
268
- instructions,
269
- }
270
- }
271
- const trace = []
272
- return iterate(firstUrlInfo, trace)
273
- }
274
- const sseService = createSSEService({
275
- rootDirectoryUrl,
276
- autoreloadPatterns,
277
- onFileChange: ({ relativeUrl, event }) => {
278
- const url = new URL(relativeUrl, rootDirectoryUrl).href
279
- const urlInfo = urlGraph.urlInfos[url]
280
- // file not part of dependency graph
281
- if (!urlInfo) {
282
- return
283
- }
284
- updateHmrTimestamp(urlInfo, Date.now())
285
- const hotUpdate = propagateUpdate(urlInfo)
286
- if (hotUpdate.declined) {
287
- notifyDeclined({
288
- cause: `${relativeUrl} ${event}`,
289
- reason: hotUpdate.reason,
290
- declinedBy: hotUpdate.declinedBy,
291
- })
292
- } else {
293
- notifyAccepted({
294
- cause: `${relativeUrl} ${event}`,
295
- reason: hotUpdate.reason,
296
- instructions: hotUpdate.instructions,
297
- })
298
- }
299
- },
300
- hotUpdateCallbackList,
301
- })
302
- urlGraph.prunedCallbackList.add(({ prunedUrlInfos, firstUrlInfo }) => {
303
- prunedUrlInfos.forEach((prunedUrlInfo) => {
304
- prunedUrlInfo.data.hmrTimestamp = Date.now()
305
- // should we delete instead?
306
- // delete urlGraph.urlInfos[prunedUrlInfo.url]
307
- })
308
- const mainHotUpdate = propagateUpdate(firstUrlInfo)
309
- const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
310
- (prunedUrlInfo) => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
311
- )}`
312
- // now check if we can hot update the main ressource
313
- // then if we can hot update all dependencies
314
- if (mainHotUpdate.declined) {
315
- notifyDeclined({
316
- cause,
317
- reason: mainHotUpdate.reason,
318
- declinedBy: mainHotUpdate.declinedBy,
319
- })
320
- return
321
- }
322
- // main can hot update
323
- let i = 0
324
- const instructions = []
325
- while (i < prunedUrlInfos.length) {
326
- const prunedUrlInfo = prunedUrlInfos[i++]
327
- if (prunedUrlInfo.data.hotDecline) {
328
- notifyDeclined({
329
- cause,
330
- reason: `a pruned file declines hot reload`,
331
- declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
332
- })
333
- return
334
- }
335
- instructions.push({
336
- type: "prune",
337
- boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
338
- acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl),
339
- })
340
- }
341
- notifyAccepted({
342
- cause,
343
- reason: mainHotUpdate.reason,
344
- instructions,
345
- })
346
- })
347
-
348
- return {
349
- name: "jsenv:hot_sse",
350
- appliesDuring: { dev: true },
351
- serve: (request, { urlGraph, rootDirectoryUrl }) => {
352
- if (request.ressource === "/__graph__") {
353
- const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
354
- return {
355
- status: 200,
356
- headers: {
357
- "content-type": "application/json",
358
- "content-length": Buffer.byteLength(graphJson),
359
- },
360
- body: graphJson,
361
- }
362
- }
363
- const { accept } = request.headers
364
- if (accept && accept.includes("text/event-stream")) {
365
- const room = sseService.getOrCreateSSERoom(request)
366
- return room.join(request)
367
- }
368
- return null
369
- },
370
- destroy: () => {
371
- sseService.destroy()
372
- },
373
- }
374
- }