@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.
- package/dist/js/autoreload.js +359 -0
- package/dist/js/execute_using_dynamic_import.js +1 -1
- package/dist/js/html_supervisor_installer.js +524 -147
- package/dist/js/html_supervisor_setup.js +3 -4
- package/dist/js/new_stylesheet.js +26 -58
- package/dist/js/server_events_client.js +307 -0
- package/dist/main.js +7699 -7307
- package/package.json +15 -15
- package/{README.md → readme.md} +18 -7
- package/src/build/build.js +16 -18
- package/src/build/start_build_server.js +24 -28
- package/src/dev/start_dev_server.js +30 -94
- package/src/execute/execute.js +17 -35
- package/src/execute/run.js +2 -0
- package/src/omega/errors.js +43 -9
- package/src/omega/kitchen.js +42 -25
- package/src/omega/omega_server.js +96 -74
- package/src/omega/server/file_service.js +256 -28
- package/src/omega/url_graph.js +39 -20
- package/src/plugins/autoreload/client/autoreload.js +201 -0
- package/src/plugins/autoreload/{dev_sse/client → client}/autoreload_preference.js +0 -0
- package/src/plugins/autoreload/{dev_sse/client → client}/reload.js +29 -10
- package/src/plugins/autoreload/{dev_sse/client → client}/url_helpers.js +0 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -8
- package/src/plugins/autoreload/{dev_sse/jsenv_plugin_dev_sse_client.js → jsenv_plugin_autoreload_client.js} +8 -8
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +196 -0
- package/src/{dev/plugins → plugins}/explorer/client/explorer.html +0 -0
- package/src/{dev/plugins → plugins}/explorer/client/jsenv.png +0 -0
- package/src/{dev/plugins → plugins}/explorer/jsenv_plugin_explorer.js +1 -3
- package/src/plugins/html_supervisor/client/error_overlay.js +401 -0
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +138 -23
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +3 -4
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +55 -23
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +97 -117
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +66 -58
- package/src/plugins/plugin_controller.js +102 -67
- package/src/plugins/plugins.js +10 -10
- package/src/{helpers/event_source/event_source.js → plugins/server_events/client/event_source_connection.js} +125 -33
- package/src/plugins/server_events/client/server_events_client.js +17 -0
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +48 -0
- package/src/plugins/server_events/server_events_dispatcher.js +69 -0
- package/src/{dev/plugins → plugins}/toolbar/client/animation/toolbar_animation.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/eventsource/eventsource.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/eventsource/toolbar_eventsource.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/execution/execution.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/execution/toolbar_execution.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/focus/focus.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/focus/toolbar_focus.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/jsenv_logo.svg +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/notification/toolbar_notification.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/responsive/overflow_menu.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/responsive/toolbar_responsive.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/settings/settings.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/settings/toolbar_settings.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/jsenv_theme.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/light_theme.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/theme/toolbar_theme.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar.html +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_injector.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/toolbar_main.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.css +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/tooltip/tooltip.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/animation.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/dom.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/fetch_using_xhr.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/fetching.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/iframe_to_parent_href.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/jsenv_logger.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/preferences.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/responsive.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/util/util.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/client/variant/variant.js +0 -0
- package/src/{dev/plugins → plugins}/toolbar/jsenv_plugin_toolbar.js +0 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +4 -3
- package/src/plugins/transpilation/babel/new_stylesheet/client/new_stylesheet.js +25 -55
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +44 -24
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +6 -1
- package/src/plugins/url_analysis/html/html_urls.js +8 -8
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
- package/src/test/execute_plan.js +36 -54
- package/src/test/execute_test_plan.js +2 -2
- package/src/test/logs_file_execution.js +60 -27
- package/src/test/logs_file_execution.test.mjs +41 -0
- package/dist/js/event_source_client.js +0 -528
- package/src/helpers/event_source/sse_service.js +0 -53
- package/src/plugins/autoreload/dev_sse/client/event_source_client.js +0 -193
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +0 -203
- package/src/plugins/html_supervisor/client/error_in_document.js +0 -198
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { createSSERoom } from "@jsenv/server"
|
|
2
|
-
import { createCallbackListNotifiedOnce } from "@jsenv/abort"
|
|
3
|
-
|
|
4
|
-
export const createSSEService = ({ serverEventCallbackList }) => {
|
|
5
|
-
const destroyCallbackList = createCallbackListNotifiedOnce()
|
|
6
|
-
|
|
7
|
-
const cache = []
|
|
8
|
-
const sseRoomLimit = 100
|
|
9
|
-
const getOrCreateSSERoom = (request) => {
|
|
10
|
-
const htmlFileRelativeUrl = request.ressource.slice(1)
|
|
11
|
-
const cacheEntry = cache.find(
|
|
12
|
-
(cacheEntryCandidate) =>
|
|
13
|
-
cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl,
|
|
14
|
-
)
|
|
15
|
-
if (cacheEntry) {
|
|
16
|
-
return cacheEntry.sseRoom
|
|
17
|
-
}
|
|
18
|
-
const sseRoom = createSSERoom({
|
|
19
|
-
retryDuration: 2000,
|
|
20
|
-
historyLength: 100,
|
|
21
|
-
welcomeEventEnabled: true,
|
|
22
|
-
effect: () => {
|
|
23
|
-
return serverEventCallbackList.add((event) => {
|
|
24
|
-
sseRoom.sendEvent(event)
|
|
25
|
-
})
|
|
26
|
-
},
|
|
27
|
-
})
|
|
28
|
-
const removeSSECleanupCallback = destroyCallbackList.add(() => {
|
|
29
|
-
removeSSECleanupCallback()
|
|
30
|
-
sseRoom.close()
|
|
31
|
-
})
|
|
32
|
-
cache.push({
|
|
33
|
-
htmlFileRelativeUrl,
|
|
34
|
-
sseRoom,
|
|
35
|
-
cleanup: () => {
|
|
36
|
-
removeSSECleanupCallback()
|
|
37
|
-
sseRoom.close()
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
if (cache.length >= sseRoomLimit) {
|
|
41
|
-
const firstCacheEntry = cache.shift()
|
|
42
|
-
firstCacheEntry.cleanup()
|
|
43
|
-
}
|
|
44
|
-
return sseRoom
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
getOrCreateSSERoom,
|
|
49
|
-
destroy: () => {
|
|
50
|
-
destroyCallbackList.notify()
|
|
51
|
-
},
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { createEventSourceConnection } from "@jsenv/core/src/helpers/event_source/event_source.js"
|
|
2
|
-
import { urlHotMetas } from "../../../import_meta_hot/client/import_meta_hot.js"
|
|
3
|
-
import {
|
|
4
|
-
isAutoreloadEnabled,
|
|
5
|
-
setAutoreloadPreference,
|
|
6
|
-
} from "./autoreload_preference.js"
|
|
7
|
-
import { compareTwoUrlPaths } from "./url_helpers.js"
|
|
8
|
-
import {
|
|
9
|
-
reloadHtmlPage,
|
|
10
|
-
reloadDOMNodesUsingUrl,
|
|
11
|
-
reloadJsImport,
|
|
12
|
-
} from "./reload.js"
|
|
13
|
-
|
|
14
|
-
const reloadMessages = []
|
|
15
|
-
const reloadMessagesSignal = { onchange: () => {} }
|
|
16
|
-
let pendingCallbacks = []
|
|
17
|
-
let running = false
|
|
18
|
-
const addToHotQueue = async (callback) => {
|
|
19
|
-
pendingCallbacks.push(callback)
|
|
20
|
-
dequeue()
|
|
21
|
-
}
|
|
22
|
-
const dequeue = async () => {
|
|
23
|
-
if (running) {
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
const callbacks = pendingCallbacks.slice()
|
|
27
|
-
pendingCallbacks = []
|
|
28
|
-
running = true
|
|
29
|
-
try {
|
|
30
|
-
await callbacks.reduce(async (previous, callback) => {
|
|
31
|
-
await previous
|
|
32
|
-
await callback()
|
|
33
|
-
}, Promise.resolve())
|
|
34
|
-
} finally {
|
|
35
|
-
running = false
|
|
36
|
-
if (pendingCallbacks.length) {
|
|
37
|
-
dequeue()
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const applyReloadMessageEffects = async () => {
|
|
43
|
-
const someEffectIsFullReload = reloadMessages.some(
|
|
44
|
-
(reloadMessage) => reloadMessage.type === "full",
|
|
45
|
-
)
|
|
46
|
-
if (someEffectIsFullReload) {
|
|
47
|
-
reloadHtmlPage()
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const onApplied = (reloadMessage) => {
|
|
52
|
-
const index = reloadMessages.indexOf(reloadMessage)
|
|
53
|
-
reloadMessages.splice(index, 1)
|
|
54
|
-
reloadMessagesSignal.onchange()
|
|
55
|
-
}
|
|
56
|
-
const setReloadMessagePromise = (reloadMessage, promise) => {
|
|
57
|
-
reloadMessage.status = "pending"
|
|
58
|
-
promise.then(
|
|
59
|
-
() => {
|
|
60
|
-
onApplied(reloadMessage)
|
|
61
|
-
},
|
|
62
|
-
(e) => {
|
|
63
|
-
// TODO: reuse error display from html supervisor
|
|
64
|
-
console.error(e)
|
|
65
|
-
console.error(
|
|
66
|
-
`[hmr] Failed to reload after ${reloadMessage.reason}.
|
|
67
|
-
This could be due to syntax errors or importing non-existent modules (see errors above)`,
|
|
68
|
-
)
|
|
69
|
-
reloadMessage.status = "failed"
|
|
70
|
-
reloadMessagesSignal.onchange()
|
|
71
|
-
},
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
reloadMessages.forEach((reloadMessage) => {
|
|
75
|
-
if (reloadMessage.type === "hot") {
|
|
76
|
-
const promise = addToHotQueue(() => {
|
|
77
|
-
return applyHotReload(reloadMessage)
|
|
78
|
-
})
|
|
79
|
-
setReloadMessagePromise(reloadMessage, promise)
|
|
80
|
-
} else {
|
|
81
|
-
setReloadMessagePromise(reloadMessage, Promise.resolve())
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
reloadMessagesSignal.onchange() // reload status is "pending"
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const applyHotReload = async ({ hotInstructions }) => {
|
|
88
|
-
await hotInstructions.reduce(
|
|
89
|
-
async (previous, { type, boundary, acceptedBy }) => {
|
|
90
|
-
await previous
|
|
91
|
-
|
|
92
|
-
const urlToFetch = new URL(boundary, `${window.location.origin}/`).href
|
|
93
|
-
const urlHotMeta = urlHotMetas[urlToFetch]
|
|
94
|
-
// TODO: we should return when there is no url hot meta because
|
|
95
|
-
// it means code was not executed (code splitting with dynamic import)
|
|
96
|
-
// if (!urlHotMeta) {return }
|
|
97
|
-
|
|
98
|
-
if (type === "prune") {
|
|
99
|
-
console.groupCollapsed(
|
|
100
|
-
`[jsenv] prune: ${boundary} (inside ${acceptedBy})`,
|
|
101
|
-
)
|
|
102
|
-
} else if (acceptedBy === boundary) {
|
|
103
|
-
console.groupCollapsed(`[jsenv] hot reloading: ${boundary}`)
|
|
104
|
-
} else {
|
|
105
|
-
console.groupCollapsed(
|
|
106
|
-
`[jsenv] hot reloading: ${acceptedBy} inside ${boundary}`,
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
if (urlHotMeta && urlHotMeta.disposeCallback) {
|
|
110
|
-
console.log(`call dispose callback`)
|
|
111
|
-
await urlHotMeta.disposeCallback()
|
|
112
|
-
}
|
|
113
|
-
if (type === "prune") {
|
|
114
|
-
delete urlHotMetas[urlToFetch]
|
|
115
|
-
console.log(`cleanup pruned url`)
|
|
116
|
-
console.groupEnd()
|
|
117
|
-
return null
|
|
118
|
-
}
|
|
119
|
-
if (type === "js_module") {
|
|
120
|
-
console.log(`importing js module`)
|
|
121
|
-
const namespace = await reloadJsImport(urlToFetch)
|
|
122
|
-
if (urlHotMeta && urlHotMeta.acceptCallback) {
|
|
123
|
-
await urlHotMeta.acceptCallback(namespace)
|
|
124
|
-
}
|
|
125
|
-
console.log(`js module import done`)
|
|
126
|
-
console.groupEnd()
|
|
127
|
-
return namespace
|
|
128
|
-
}
|
|
129
|
-
if (type === "html") {
|
|
130
|
-
if (!compareTwoUrlPaths(urlToFetch, window.location.href)) {
|
|
131
|
-
// we are not in that HTML page
|
|
132
|
-
return null
|
|
133
|
-
}
|
|
134
|
-
console.log(`reloading url`)
|
|
135
|
-
const urlToReload = new URL(acceptedBy, `${window.location.origin}/`)
|
|
136
|
-
.href
|
|
137
|
-
reloadDOMNodesUsingUrl(urlToReload)
|
|
138
|
-
console.log(`url reloaded`)
|
|
139
|
-
console.groupEnd()
|
|
140
|
-
return null
|
|
141
|
-
}
|
|
142
|
-
console.warn(`unknown update type: "${type}"`)
|
|
143
|
-
return null
|
|
144
|
-
},
|
|
145
|
-
Promise.resolve(),
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const addReloadMessage = (reloadMessage) => {
|
|
150
|
-
reloadMessages.push(reloadMessage)
|
|
151
|
-
if (isAutoreloadEnabled()) {
|
|
152
|
-
applyReloadMessageEffects()
|
|
153
|
-
} else {
|
|
154
|
-
reloadMessagesSignal.onchange()
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const eventsourceConnection = createEventSourceConnection(
|
|
159
|
-
document.location.href,
|
|
160
|
-
{
|
|
161
|
-
reload: ({ data }) => {
|
|
162
|
-
const reloadMessage = JSON.parse(data)
|
|
163
|
-
addReloadMessage(reloadMessage)
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
retryMaxAttempt: Infinity,
|
|
168
|
-
retryAllocatedMs: 20 * 1000,
|
|
169
|
-
},
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
const { status, connect, disconnect } = eventsourceConnection
|
|
173
|
-
connect()
|
|
174
|
-
window.__jsenv_event_source_client__ = {
|
|
175
|
-
status,
|
|
176
|
-
connect,
|
|
177
|
-
disconnect,
|
|
178
|
-
isAutoreloadEnabled,
|
|
179
|
-
setAutoreloadPreference,
|
|
180
|
-
urlHotMetas,
|
|
181
|
-
reloadMessages,
|
|
182
|
-
reloadMessagesSignal,
|
|
183
|
-
applyReloadMessageEffects,
|
|
184
|
-
addReloadMessage,
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// const findHotMetaUrl = (originalFileRelativeUrl) => {
|
|
188
|
-
// return Object.keys(urlHotMetas).find((compileUrl) => {
|
|
189
|
-
// return (
|
|
190
|
-
// parseCompiledUrl(compileUrl).fileRelativeUrl === originalFileRelativeUrl
|
|
191
|
-
// )
|
|
192
|
-
// })
|
|
193
|
-
// }
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { urlToRelativeUrl } from "@jsenv/urls"
|
|
2
|
-
import { createCallbackList } from "@jsenv/abort"
|
|
3
|
-
|
|
4
|
-
import { createSSEService } from "@jsenv/core/src/helpers/event_source/sse_service.js"
|
|
5
|
-
|
|
6
|
-
export const jsenvPluginDevSSEServer = ({
|
|
7
|
-
rootDirectoryUrl,
|
|
8
|
-
urlGraph,
|
|
9
|
-
clientFileChangeCallbackList,
|
|
10
|
-
clientFilesPruneCallbackList,
|
|
11
|
-
}) => {
|
|
12
|
-
const serverEventCallbackList = createCallbackList()
|
|
13
|
-
const sseService = createSSEService({ serverEventCallbackList })
|
|
14
|
-
|
|
15
|
-
const notifyDeclined = ({ cause, reason, declinedBy }) => {
|
|
16
|
-
serverEventCallbackList.notify({
|
|
17
|
-
type: "reload",
|
|
18
|
-
data: JSON.stringify({
|
|
19
|
-
cause,
|
|
20
|
-
type: "full",
|
|
21
|
-
typeReason: reason,
|
|
22
|
-
declinedBy,
|
|
23
|
-
}),
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
const notifyAccepted = ({ cause, reason, instructions }) => {
|
|
27
|
-
serverEventCallbackList.notify({
|
|
28
|
-
type: "reload",
|
|
29
|
-
data: JSON.stringify({
|
|
30
|
-
cause,
|
|
31
|
-
type: "hot",
|
|
32
|
-
typeReason: reason,
|
|
33
|
-
hotInstructions: instructions,
|
|
34
|
-
}),
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
const propagateUpdate = (firstUrlInfo) => {
|
|
38
|
-
const iterate = (urlInfo, trace) => {
|
|
39
|
-
if (urlInfo.data.hotAcceptSelf) {
|
|
40
|
-
return {
|
|
41
|
-
accepted: true,
|
|
42
|
-
reason:
|
|
43
|
-
urlInfo === firstUrlInfo
|
|
44
|
-
? `file accepts hot reload`
|
|
45
|
-
: `a dependent file accepts hot reload`,
|
|
46
|
-
instructions: [
|
|
47
|
-
{
|
|
48
|
-
type: urlInfo.type,
|
|
49
|
-
boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
|
|
50
|
-
acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const { dependents } = urlInfo
|
|
56
|
-
const instructions = []
|
|
57
|
-
for (const dependentUrl of dependents) {
|
|
58
|
-
const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl)
|
|
59
|
-
if (dependentUrlInfo.data.hotDecline) {
|
|
60
|
-
return {
|
|
61
|
-
declined: true,
|
|
62
|
-
reason: `a dependent file declines hot reload`,
|
|
63
|
-
declinedBy: dependentUrl,
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const { hotAcceptDependencies = [] } = dependentUrlInfo.data
|
|
67
|
-
if (hotAcceptDependencies.includes(urlInfo.url)) {
|
|
68
|
-
instructions.push({
|
|
69
|
-
type: dependentUrlInfo.type,
|
|
70
|
-
boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
|
|
71
|
-
acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
|
|
72
|
-
})
|
|
73
|
-
continue
|
|
74
|
-
}
|
|
75
|
-
if (trace.includes(dependentUrl)) {
|
|
76
|
-
return {
|
|
77
|
-
declined: true,
|
|
78
|
-
reason: "circular dependency",
|
|
79
|
-
declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const dependentPropagationResult = iterate(dependentUrlInfo, [
|
|
83
|
-
...trace,
|
|
84
|
-
dependentUrl,
|
|
85
|
-
])
|
|
86
|
-
if (dependentPropagationResult.accepted) {
|
|
87
|
-
instructions.push(...dependentPropagationResult.instructions)
|
|
88
|
-
continue
|
|
89
|
-
}
|
|
90
|
-
if (
|
|
91
|
-
// declined explicitely by an other file, it must decline the whole update
|
|
92
|
-
dependentPropagationResult.declinedBy
|
|
93
|
-
) {
|
|
94
|
-
return dependentPropagationResult
|
|
95
|
-
}
|
|
96
|
-
// declined by absence of boundary, we can keep searching
|
|
97
|
-
continue
|
|
98
|
-
}
|
|
99
|
-
if (instructions.length === 0) {
|
|
100
|
-
return {
|
|
101
|
-
declined: true,
|
|
102
|
-
reason: `there is no file accepting hot reload while propagating update`,
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
accepted: true,
|
|
107
|
-
reason: `${instructions.length} dependent file(s) accepts hot reload`,
|
|
108
|
-
instructions,
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
const trace = []
|
|
112
|
-
return iterate(firstUrlInfo, trace)
|
|
113
|
-
}
|
|
114
|
-
clientFileChangeCallbackList.push(({ url, event }) => {
|
|
115
|
-
const urlInfo = urlGraph.getUrlInfo(url)
|
|
116
|
-
// file not part of dependency graph
|
|
117
|
-
if (!urlInfo) {
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
|
|
121
|
-
const hotUpdate = propagateUpdate(urlInfo)
|
|
122
|
-
if (hotUpdate.declined) {
|
|
123
|
-
notifyDeclined({
|
|
124
|
-
cause: `${relativeUrl} ${event}`,
|
|
125
|
-
reason: hotUpdate.reason,
|
|
126
|
-
declinedBy: hotUpdate.declinedBy,
|
|
127
|
-
})
|
|
128
|
-
} else {
|
|
129
|
-
notifyAccepted({
|
|
130
|
-
cause: `${relativeUrl} ${event}`,
|
|
131
|
-
reason: hotUpdate.reason,
|
|
132
|
-
instructions: hotUpdate.instructions,
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
clientFilesPruneCallbackList.push(({ prunedUrlInfos, firstUrlInfo }) => {
|
|
137
|
-
const mainHotUpdate = propagateUpdate(firstUrlInfo)
|
|
138
|
-
const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
|
|
139
|
-
(prunedUrlInfo) => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
|
|
140
|
-
)}`
|
|
141
|
-
// now check if we can hot update the main ressource
|
|
142
|
-
// then if we can hot update all dependencies
|
|
143
|
-
if (mainHotUpdate.declined) {
|
|
144
|
-
notifyDeclined({
|
|
145
|
-
cause,
|
|
146
|
-
reason: mainHotUpdate.reason,
|
|
147
|
-
declinedBy: mainHotUpdate.declinedBy,
|
|
148
|
-
})
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
// main can hot update
|
|
152
|
-
let i = 0
|
|
153
|
-
const instructions = []
|
|
154
|
-
while (i < prunedUrlInfos.length) {
|
|
155
|
-
const prunedUrlInfo = prunedUrlInfos[i++]
|
|
156
|
-
if (prunedUrlInfo.data.hotDecline) {
|
|
157
|
-
notifyDeclined({
|
|
158
|
-
cause,
|
|
159
|
-
reason: `a pruned file declines hot reload`,
|
|
160
|
-
declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
|
|
161
|
-
})
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
instructions.push({
|
|
165
|
-
type: "prune",
|
|
166
|
-
boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
|
|
167
|
-
acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl),
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
notifyAccepted({
|
|
171
|
-
cause,
|
|
172
|
-
reason: mainHotUpdate.reason,
|
|
173
|
-
instructions,
|
|
174
|
-
})
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
name: "jsenv:sse_server",
|
|
179
|
-
appliesDuring: { dev: true },
|
|
180
|
-
serve: (request) => {
|
|
181
|
-
if (request.ressource === "/__graph__") {
|
|
182
|
-
const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
|
|
183
|
-
return {
|
|
184
|
-
status: 200,
|
|
185
|
-
headers: {
|
|
186
|
-
"content-type": "application/json",
|
|
187
|
-
"content-length": Buffer.byteLength(graphJson),
|
|
188
|
-
},
|
|
189
|
-
body: graphJson,
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
const { accept } = request.headers
|
|
193
|
-
if (accept && accept.includes("text/event-stream")) {
|
|
194
|
-
const room = sseService.getOrCreateSSERoom(request)
|
|
195
|
-
return room.join(request)
|
|
196
|
-
}
|
|
197
|
-
return null
|
|
198
|
-
},
|
|
199
|
-
destroy: () => {
|
|
200
|
-
sseService.destroy()
|
|
201
|
-
},
|
|
202
|
-
}
|
|
203
|
-
}
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
export const displayErrorInDocument = (error) => {
|
|
2
|
-
const title = "An error occured"
|
|
3
|
-
let theme =
|
|
4
|
-
error && error.cause && error.cause.code === "PARSE_ERROR"
|
|
5
|
-
? "light"
|
|
6
|
-
: "dark"
|
|
7
|
-
let message = errorToHTML(error)
|
|
8
|
-
const css = `
|
|
9
|
-
.jsenv-console {
|
|
10
|
-
background: rgba(0, 0, 0, 0.95);
|
|
11
|
-
position: absolute;
|
|
12
|
-
top: 0;
|
|
13
|
-
left: 0;
|
|
14
|
-
width: 100%;
|
|
15
|
-
height: 100%;
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
align-items: center;
|
|
19
|
-
z-index: 1000;
|
|
20
|
-
box-sizing: border-box;
|
|
21
|
-
padding: 1em;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.jsenv-console h1 {
|
|
25
|
-
color: red;
|
|
26
|
-
display: flex;
|
|
27
|
-
align-items: center;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#button-close-jsenv-console {
|
|
31
|
-
margin-left: 10px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.jsenv-console pre {
|
|
35
|
-
overflow: auto;
|
|
36
|
-
max-width: 70em;
|
|
37
|
-
/* avoid scrollbar to hide the text behind it */
|
|
38
|
-
padding: 20px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.jsenv-console pre[data-theme="dark"] {
|
|
42
|
-
background: #111;
|
|
43
|
-
border: 1px solid #333;
|
|
44
|
-
color: #eee;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.jsenv-console pre[data-theme="light"] {
|
|
48
|
-
background: #1E1E1E;
|
|
49
|
-
border: 1px solid white;
|
|
50
|
-
color: #EEEEEE;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.jsenv-console pre a {
|
|
54
|
-
color: inherit;
|
|
55
|
-
}
|
|
56
|
-
`
|
|
57
|
-
const html = `
|
|
58
|
-
<style type="text/css">${css}></style>
|
|
59
|
-
<div class="jsenv-console">
|
|
60
|
-
<h1>${title} <button id="button-close-jsenv-console">X</button></h1>
|
|
61
|
-
<pre data-theme="${theme}">${message}</pre>
|
|
62
|
-
</div>
|
|
63
|
-
`
|
|
64
|
-
const removeJsenvConsole = appendHMTLInside(html, document.body)
|
|
65
|
-
|
|
66
|
-
document.querySelector("#button-close-jsenv-console").onclick = () => {
|
|
67
|
-
removeJsenvConsole()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const escapeHtml = (string) => {
|
|
72
|
-
return string
|
|
73
|
-
.replace(/&/g, "&")
|
|
74
|
-
.replace(/</g, "<")
|
|
75
|
-
.replace(/>/g, ">")
|
|
76
|
-
.replace(/"/g, """)
|
|
77
|
-
.replace(/'/g, "'")
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const errorToHTML = (error) => {
|
|
81
|
-
let html
|
|
82
|
-
|
|
83
|
-
if (error && error instanceof Error) {
|
|
84
|
-
if (error.cause && error.cause.code === "PARSE_ERROR") {
|
|
85
|
-
html = error.messageHTML || escapeHtml(error.message)
|
|
86
|
-
}
|
|
87
|
-
// stackTrace formatted by V8
|
|
88
|
-
else if (Error.captureStackTrace) {
|
|
89
|
-
html = escapeHtml(error.stack)
|
|
90
|
-
} else {
|
|
91
|
-
// other stack trace such as firefox do not contain error.message
|
|
92
|
-
html = escapeHtml(`${error.message}
|
|
93
|
-
${error.stack}`)
|
|
94
|
-
}
|
|
95
|
-
} else if (typeof error === "string") {
|
|
96
|
-
html = error
|
|
97
|
-
} else if (error === undefined) {
|
|
98
|
-
html = "undefined"
|
|
99
|
-
} else {
|
|
100
|
-
html = JSON.stringify(error)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const htmlWithCorrectLineBreaks = html.replace(/\n/g, "\n")
|
|
104
|
-
const htmlWithLinks = stringToStringWithLink(htmlWithCorrectLineBreaks, {
|
|
105
|
-
transform: (url) => {
|
|
106
|
-
return { href: url, text: url }
|
|
107
|
-
},
|
|
108
|
-
})
|
|
109
|
-
return htmlWithLinks
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// `Error: yo
|
|
113
|
-
// at Object.execute (http://127.0.0.1:57300/build/src/__test__/file-throw.js:9:13)
|
|
114
|
-
// at doExec (http://127.0.0.1:3000/src/__test__/file-throw.js:452:38)
|
|
115
|
-
// at postOrderExec (http://127.0.0.1:3000/src/__test__/file-throw.js:448:16)
|
|
116
|
-
// at http://127.0.0.1:3000/src/__test__/file-throw.js:399:18`.replace(/(?:https?|ftp|file):\/\/(.*+)$/gm, (...args) => {
|
|
117
|
-
// debugger
|
|
118
|
-
// })
|
|
119
|
-
const stringToStringWithLink = (
|
|
120
|
-
source,
|
|
121
|
-
{
|
|
122
|
-
transform = (url) => {
|
|
123
|
-
return {
|
|
124
|
-
href: url,
|
|
125
|
-
text: url,
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
} = {},
|
|
129
|
-
) => {
|
|
130
|
-
return source.replace(/(?:https?|ftp|file):\/\/\S+/gm, (match) => {
|
|
131
|
-
let linkHTML = ""
|
|
132
|
-
|
|
133
|
-
const lastChar = match[match.length - 1]
|
|
134
|
-
|
|
135
|
-
// hotfix because our url regex sucks a bit
|
|
136
|
-
const endsWithSeparationChar = lastChar === ")" || lastChar === ":"
|
|
137
|
-
if (endsWithSeparationChar) {
|
|
138
|
-
match = match.slice(0, -1)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const lineAndColumnPattern = /:([0-9]+):([0-9]+)$/
|
|
142
|
-
const lineAndColumMatch = match.match(lineAndColumnPattern)
|
|
143
|
-
if (lineAndColumMatch) {
|
|
144
|
-
const lineAndColumnString = lineAndColumMatch[0]
|
|
145
|
-
const lineNumber = lineAndColumMatch[1]
|
|
146
|
-
const columnNumber = lineAndColumMatch[2]
|
|
147
|
-
const url = match.slice(0, -lineAndColumnString.length)
|
|
148
|
-
const { href, text } = transform(url)
|
|
149
|
-
linkHTML = link({ href, text: `${text}:${lineNumber}:${columnNumber}` })
|
|
150
|
-
} else {
|
|
151
|
-
const linePattern = /:([0-9]+)$/
|
|
152
|
-
const lineMatch = match.match(linePattern)
|
|
153
|
-
if (lineMatch) {
|
|
154
|
-
const lineString = lineMatch[0]
|
|
155
|
-
const lineNumber = lineMatch[1]
|
|
156
|
-
const url = match.slice(0, -lineString.length)
|
|
157
|
-
const { href, text } = transform(url)
|
|
158
|
-
linkHTML = link({
|
|
159
|
-
href,
|
|
160
|
-
text: `${text}:${lineNumber}`,
|
|
161
|
-
})
|
|
162
|
-
} else {
|
|
163
|
-
const url = match
|
|
164
|
-
const { href, text } = transform(url)
|
|
165
|
-
linkHTML = link({ href, text })
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (endsWithSeparationChar) {
|
|
170
|
-
return `${linkHTML}${lastChar}`
|
|
171
|
-
}
|
|
172
|
-
return linkHTML
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const link = ({ href, text = href }) => `<a href="${href}">${text}</a>`
|
|
177
|
-
|
|
178
|
-
const appendHMTLInside = (html, parentNode) => {
|
|
179
|
-
const temoraryParent = document.createElement("div")
|
|
180
|
-
temoraryParent.innerHTML = html
|
|
181
|
-
return transferChildren(temoraryParent, parentNode)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const transferChildren = (fromNode, toNode) => {
|
|
185
|
-
const childNodes = [].slice.call(fromNode.childNodes, 0)
|
|
186
|
-
let i = 0
|
|
187
|
-
while (i < childNodes.length) {
|
|
188
|
-
toNode.appendChild(childNodes[i])
|
|
189
|
-
i++
|
|
190
|
-
}
|
|
191
|
-
return () => {
|
|
192
|
-
let c = 0
|
|
193
|
-
while (c < childNodes.length) {
|
|
194
|
-
fromNode.appendChild(childNodes[c])
|
|
195
|
-
c++
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|