@jsenv/core 27.0.0-alpha.44 → 27.0.0-alpha.47
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/html_supervisor_installer.js +130 -39
- package/dist/html_supervisor_installer.js.map +32 -17
- package/dist/html_supervisor_setup.js +52 -49
- package/dist/html_supervisor_setup.js.map +11 -11
- package/package.json +4 -4
- package/src/build/start_build_server.js +87 -37
- package/src/dev/start_dev_server.js +95 -21
- package/src/execute/execute.js +1 -2
- package/src/omega/kitchen.js +33 -2
- package/src/omega/omega_server.js +2 -3
- package/src/omega/server/file_service.js +15 -1
- package/src/omega/url_graph/url_info_transformations.js +3 -1
- package/src/omega/url_graph.js +58 -6
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +27 -56
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +4 -4
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +2 -2
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +132 -59
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +51 -49
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +30 -2
- package/src/plugins/plugins.js +6 -6
- package/src/test/execute_plan.js +2 -7
package/src/omega/url_graph.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { createCallbackList } from "@jsenv/abort"
|
|
2
1
|
import { urlToRelativeUrl } from "@jsenv/filesystem"
|
|
3
2
|
|
|
4
|
-
export const createUrlGraph = (
|
|
3
|
+
export const createUrlGraph = ({
|
|
4
|
+
clientFileChangeCallbackList,
|
|
5
|
+
clientFilesPruneCallbackList,
|
|
6
|
+
} = {}) => {
|
|
5
7
|
const urlInfos = {}
|
|
6
8
|
const getUrlInfo = (url) => urlInfos[url]
|
|
7
9
|
const deleteUrlInfo = (url) => {
|
|
@@ -13,6 +15,16 @@ export const createUrlGraph = () => {
|
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
}
|
|
18
|
+
const resetUrlInfo = (urlInfo) => {
|
|
19
|
+
urlInfo.sourcemap = null
|
|
20
|
+
urlInfo.sourcemapReference = null
|
|
21
|
+
urlInfo.content = null
|
|
22
|
+
urlInfo.originalContent = null
|
|
23
|
+
urlInfo.type = null
|
|
24
|
+
urlInfo.subtype = null
|
|
25
|
+
urlInfo.data = {}
|
|
26
|
+
urlInfo.timing = {}
|
|
27
|
+
}
|
|
16
28
|
|
|
17
29
|
const reuseOrCreateUrlInfo = (url) => {
|
|
18
30
|
const existingUrlInfo = urlInfos[url]
|
|
@@ -49,7 +61,6 @@ export const createUrlGraph = () => {
|
|
|
49
61
|
return visitDependents(urlInfo)
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
const prunedCallbackList = createCallbackList()
|
|
53
64
|
const updateReferences = (urlInfo, references) => {
|
|
54
65
|
const dependencyUrls = []
|
|
55
66
|
references.forEach((reference) => {
|
|
@@ -101,7 +112,47 @@ export const createUrlGraph = () => {
|
|
|
101
112
|
if (prunedUrlInfos.length === 0) {
|
|
102
113
|
return
|
|
103
114
|
}
|
|
104
|
-
|
|
115
|
+
prunedUrlInfos.forEach((prunedUrlInfo) => {
|
|
116
|
+
prunedUrlInfo.modifiedTimestamp = Date.now()
|
|
117
|
+
// should we delete?
|
|
118
|
+
// delete urlInfos[prunedUrlInfo.url]
|
|
119
|
+
})
|
|
120
|
+
if (clientFilesPruneCallbackList) {
|
|
121
|
+
clientFilesPruneCallbackList.forEach((callback) => {
|
|
122
|
+
callback({
|
|
123
|
+
firstUrlInfo,
|
|
124
|
+
prunedUrlInfos,
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (clientFileChangeCallbackList) {
|
|
131
|
+
const updateModifiedTimestamp = (urlInfo, modifiedTimestamp) => {
|
|
132
|
+
const seen = []
|
|
133
|
+
const iterate = (urlInfo) => {
|
|
134
|
+
if (seen.includes(urlInfo.url)) {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
seen.push(urlInfo.url)
|
|
138
|
+
urlInfo.modifiedTimestamp = modifiedTimestamp
|
|
139
|
+
urlInfo.dependents.forEach((dependentUrl) => {
|
|
140
|
+
const dependentUrlInfo = urlInfos[dependentUrl]
|
|
141
|
+
const { hotAcceptDependencies = [] } = dependentUrlInfo.data
|
|
142
|
+
if (!hotAcceptDependencies.includes(urlInfo.url)) {
|
|
143
|
+
iterate(dependentUrlInfo)
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
iterate(urlInfo)
|
|
148
|
+
}
|
|
149
|
+
clientFileChangeCallbackList.push(({ url }) => {
|
|
150
|
+
const urlInfo = urlInfos[url]
|
|
151
|
+
if (urlInfo) {
|
|
152
|
+
updateModifiedTimestamp(urlInfo, Date.now())
|
|
153
|
+
urlInfo.contentEtag = null
|
|
154
|
+
}
|
|
155
|
+
})
|
|
105
156
|
}
|
|
106
157
|
|
|
107
158
|
return {
|
|
@@ -109,10 +160,9 @@ export const createUrlGraph = () => {
|
|
|
109
160
|
reuseOrCreateUrlInfo,
|
|
110
161
|
getUrlInfo,
|
|
111
162
|
deleteUrlInfo,
|
|
163
|
+
resetUrlInfo,
|
|
112
164
|
inferReference,
|
|
113
165
|
findDependent,
|
|
114
|
-
|
|
115
|
-
prunedCallbackList,
|
|
116
166
|
updateReferences,
|
|
117
167
|
|
|
118
168
|
toJSON: (rootDirectoryUrl) => {
|
|
@@ -133,6 +183,7 @@ export const createUrlGraph = () => {
|
|
|
133
183
|
|
|
134
184
|
const createUrlInfo = (url) => {
|
|
135
185
|
return {
|
|
186
|
+
modifiedTimestamp: 0,
|
|
136
187
|
data: {}, // plugins can put whatever they want here
|
|
137
188
|
references: [],
|
|
138
189
|
dependencies: new Set(),
|
|
@@ -148,6 +199,7 @@ const createUrlInfo = (url) => {
|
|
|
148
199
|
external: false,
|
|
149
200
|
originalContent: undefined,
|
|
150
201
|
content: undefined,
|
|
202
|
+
contentEtag: null,
|
|
151
203
|
sourcemap: null,
|
|
152
204
|
sourcemapReference: null,
|
|
153
205
|
timing: {},
|
|
@@ -6,10 +6,12 @@ import { createSSEService } from "@jsenv/utils/event_source/sse_service.js"
|
|
|
6
6
|
export const jsenvPluginDevSSEServer = ({
|
|
7
7
|
rootDirectoryUrl,
|
|
8
8
|
urlGraph,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
clientFileChangeCallbackList,
|
|
10
|
+
clientFilesPruneCallbackList,
|
|
11
11
|
}) => {
|
|
12
12
|
const serverEventCallbackList = createCallbackList()
|
|
13
|
+
const sseService = createSSEService({ serverEventCallbackList })
|
|
14
|
+
|
|
13
15
|
const notifyDeclined = ({ cause, reason, declinedBy }) => {
|
|
14
16
|
serverEventCallbackList.notify({
|
|
15
17
|
type: "reload",
|
|
@@ -32,25 +34,6 @@ export const jsenvPluginDevSSEServer = ({
|
|
|
32
34
|
}),
|
|
33
35
|
})
|
|
34
36
|
}
|
|
35
|
-
const updateHmrTimestamp = (urlInfo, hmrTimestamp) => {
|
|
36
|
-
const urlInfos = urlGraph.urlInfos
|
|
37
|
-
const seen = []
|
|
38
|
-
const iterate = (urlInfo) => {
|
|
39
|
-
if (seen.includes(urlInfo.url)) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
seen.push(urlInfo.url)
|
|
43
|
-
urlInfo.data.hmrTimestamp = hmrTimestamp
|
|
44
|
-
urlInfo.dependents.forEach((dependentUrl) => {
|
|
45
|
-
const dependentUrlInfo = urlInfos[dependentUrl]
|
|
46
|
-
const { hotAcceptDependencies = [] } = dependentUrlInfo.data
|
|
47
|
-
if (!hotAcceptDependencies.includes(urlInfo.url)) {
|
|
48
|
-
iterate(dependentUrlInfo, hmrTimestamp)
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
iterate(urlInfo)
|
|
53
|
-
}
|
|
54
37
|
const propagateUpdate = (firstUrlInfo) => {
|
|
55
38
|
const urlInfos = urlGraph.urlInfos
|
|
56
39
|
const iterate = (urlInfo, trace) => {
|
|
@@ -129,41 +112,29 @@ export const jsenvPluginDevSSEServer = ({
|
|
|
129
112
|
const trace = []
|
|
130
113
|
return iterate(firstUrlInfo, trace)
|
|
131
114
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
notifyAccepted({
|
|
154
|
-
cause: `${relativeUrl} ${event}`,
|
|
155
|
-
reason: hotUpdate.reason,
|
|
156
|
-
instructions: hotUpdate.instructions,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
},
|
|
115
|
+
clientFileChangeCallbackList.push(({ url, event }) => {
|
|
116
|
+
const urlInfo = urlGraph.urlInfos[url]
|
|
117
|
+
// file not part of dependency graph
|
|
118
|
+
if (!urlInfo) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
|
|
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
|
+
}
|
|
160
136
|
})
|
|
161
|
-
|
|
162
|
-
prunedUrlInfos.forEach((prunedUrlInfo) => {
|
|
163
|
-
prunedUrlInfo.data.hmrTimestamp = Date.now()
|
|
164
|
-
// should we delete instead?
|
|
165
|
-
// delete urlGraph.urlInfos[prunedUrlInfo.url]
|
|
166
|
-
})
|
|
137
|
+
clientFilesPruneCallbackList.push(({ prunedUrlInfos, firstUrlInfo }) => {
|
|
167
138
|
const mainHotUpdate = propagateUpdate(firstUrlInfo)
|
|
168
139
|
const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
|
|
169
140
|
(prunedUrlInfo) => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
|
|
@@ -207,7 +178,7 @@ export const jsenvPluginDevSSEServer = ({
|
|
|
207
178
|
return {
|
|
208
179
|
name: "jsenv:sse_server",
|
|
209
180
|
appliesDuring: { dev: true },
|
|
210
|
-
serve: (request
|
|
181
|
+
serve: (request) => {
|
|
211
182
|
if (request.ressource === "/__graph__") {
|
|
212
183
|
const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
|
|
213
184
|
return {
|
|
@@ -6,8 +6,8 @@ export const jsenvPluginAutoreload = ({
|
|
|
6
6
|
rootDirectoryUrl,
|
|
7
7
|
urlGraph,
|
|
8
8
|
scenario,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
clientFileChangeCallbackList,
|
|
10
|
+
clientFilesPruneCallbackList,
|
|
11
11
|
}) => {
|
|
12
12
|
if (scenario === "build") {
|
|
13
13
|
return []
|
|
@@ -20,8 +20,8 @@ export const jsenvPluginAutoreload = ({
|
|
|
20
20
|
jsenvPluginDevSSEServer({
|
|
21
21
|
rootDirectoryUrl,
|
|
22
22
|
urlGraph,
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
clientFileChangeCallbackList,
|
|
24
|
+
clientFilesPruneCallbackList,
|
|
25
25
|
}),
|
|
26
26
|
]
|
|
27
27
|
}
|
|
@@ -23,12 +23,12 @@ export const jsenvPluginHmr = () => {
|
|
|
23
23
|
return null
|
|
24
24
|
}
|
|
25
25
|
const urlInfo = context.urlGraph.getUrlInfo(reference.url)
|
|
26
|
-
if (!urlInfo.
|
|
26
|
+
if (!urlInfo.modifiedTimestamp) {
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
29
29
|
return {
|
|
30
30
|
hmr: "",
|
|
31
|
-
v: urlInfo.
|
|
31
|
+
v: urlInfo.modifiedTimestamp,
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
}
|
|
@@ -69,62 +69,135 @@ export const installHtmlSupervisor = ({ logs, measurePerf }) => {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
type,
|
|
72
|
+
const performExecution = async ({
|
|
74
73
|
src,
|
|
74
|
+
type,
|
|
75
75
|
currentScript,
|
|
76
|
-
|
|
76
|
+
execute,
|
|
77
|
+
// https://developer.mozilla.org/en-US/docs/web/html/element/script
|
|
77
78
|
}) => {
|
|
78
79
|
if (logs) {
|
|
79
80
|
console.group(`[jsenv] loading ${type} ${src}`)
|
|
80
81
|
}
|
|
81
82
|
onExecutionStart(src)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
83
|
+
let completed
|
|
84
|
+
let result
|
|
85
|
+
let error
|
|
86
|
+
try {
|
|
87
|
+
result = await execute()
|
|
88
|
+
completed = true
|
|
89
|
+
} catch (e) {
|
|
90
|
+
completed = false
|
|
91
|
+
error = e
|
|
92
|
+
}
|
|
93
|
+
if (completed) {
|
|
94
|
+
const executionResult = {
|
|
95
|
+
status: "completed",
|
|
96
|
+
namespace: result,
|
|
97
|
+
coverage: window.__coverage__,
|
|
98
|
+
}
|
|
99
|
+
onExecutionSettled(src, executionResult)
|
|
100
|
+
if (logs) {
|
|
101
|
+
console.log(`${type} load ended`)
|
|
102
|
+
console.groupEnd()
|
|
103
|
+
}
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
const executionResult = {
|
|
107
|
+
status: "errored",
|
|
108
|
+
coverage: window.__coverage__,
|
|
109
|
+
}
|
|
110
|
+
let errorExposureInConsole = true
|
|
111
|
+
if (error.name === "SyntaxError") {
|
|
112
|
+
// errorExposureInConsole = false
|
|
113
|
+
}
|
|
114
|
+
if (errorTransformer) {
|
|
115
|
+
try {
|
|
116
|
+
error = await errorTransformer(error)
|
|
117
|
+
} catch (e) {}
|
|
118
|
+
}
|
|
119
|
+
executionResult.error = error
|
|
120
|
+
onExecutionSettled(src, executionResult)
|
|
121
|
+
onExecutionError(executionResult, {
|
|
122
|
+
currentScript,
|
|
123
|
+
})
|
|
124
|
+
if (errorExposureInConsole) {
|
|
125
|
+
if (typeof window.reportError === "function") {
|
|
126
|
+
window.reportError(error)
|
|
127
|
+
} else {
|
|
128
|
+
console.error(error)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (logs) {
|
|
132
|
+
console.groupEnd()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const queue = []
|
|
137
|
+
let previousDonePromise = null
|
|
138
|
+
const dequeue = () => {
|
|
139
|
+
const next = queue.shift()
|
|
140
|
+
if (next) {
|
|
141
|
+
__html_supervisor__.addScriptToExecute(next)
|
|
142
|
+
} else {
|
|
143
|
+
const nextDefered = deferQueue.shift()
|
|
144
|
+
if (nextDefered) {
|
|
145
|
+
__html_supervisor__.addScriptToExecute(nextDefered)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const deferQueue = []
|
|
150
|
+
let previousDeferDonePromise = null
|
|
151
|
+
__html_supervisor__.addScriptToExecute = async (scriptToExecute) => {
|
|
152
|
+
if (scriptToExecute.async) {
|
|
153
|
+
performExecution(scriptToExecute)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
const useDeferQueue =
|
|
157
|
+
scriptToExecute.defer || scriptToExecute.type === "js_module"
|
|
158
|
+
if (useDeferQueue) {
|
|
159
|
+
if (document.readyState !== "interactive") {
|
|
160
|
+
deferQueue.push(scriptToExecute)
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
if (previousDonePromise) {
|
|
164
|
+
// defer must wait for the regular script to be done
|
|
165
|
+
deferQueue.push(scriptToExecute)
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
if (previousDeferDonePromise) {
|
|
169
|
+
deferQueue.push(scriptToExecute)
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
previousDeferDonePromise = performExecution(scriptToExecute)
|
|
173
|
+
await previousDeferDonePromise
|
|
174
|
+
previousDeferDonePromise = null
|
|
175
|
+
dequeue()
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
if (previousDonePromise) {
|
|
179
|
+
queue.push(scriptToExecute)
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
previousDonePromise = performExecution(scriptToExecute)
|
|
183
|
+
await previousDonePromise
|
|
184
|
+
previousDonePromise = null
|
|
185
|
+
dequeue()
|
|
186
|
+
}
|
|
187
|
+
if (
|
|
188
|
+
document.readyState !== "intractive" &&
|
|
189
|
+
document.readyState !== "complete"
|
|
190
|
+
) {
|
|
191
|
+
document.addEventListener("readystatechange", () => {
|
|
192
|
+
if (document.readyState === "interactive") {
|
|
193
|
+
const nextDefered = deferQueue.shift()
|
|
194
|
+
if (nextDefered) {
|
|
195
|
+
__html_supervisor__.addScriptToExecute(nextDefered)
|
|
124
196
|
}
|
|
125
|
-
}
|
|
126
|
-
)
|
|
197
|
+
}
|
|
198
|
+
})
|
|
127
199
|
}
|
|
200
|
+
|
|
128
201
|
__html_supervisor__.collectScriptResults = async () => {
|
|
129
202
|
collectCalled = true
|
|
130
203
|
if (pendingExecutionCount === 0) {
|
|
@@ -150,20 +223,20 @@ export const installHtmlSupervisor = ({ logs, measurePerf }) => {
|
|
|
150
223
|
scriptExecutionResults,
|
|
151
224
|
}
|
|
152
225
|
}
|
|
226
|
+
|
|
227
|
+
const { scriptsToExecute } = __html_supervisor__
|
|
228
|
+
const copy = scriptsToExecute.slice()
|
|
229
|
+
scriptsToExecute.length = 0
|
|
230
|
+
copy.forEach((scriptToExecute) => {
|
|
231
|
+
__html_supervisor__.addScriptToExecute(scriptToExecute)
|
|
232
|
+
})
|
|
153
233
|
}
|
|
154
234
|
|
|
155
|
-
export const superviseScriptTypeModule = ({ src }) => {
|
|
156
|
-
__html_supervisor__.
|
|
157
|
-
type: "js_module",
|
|
158
|
-
currentScript: null,
|
|
159
|
-
improveErrorWithFetch: true,
|
|
235
|
+
export const superviseScriptTypeModule = ({ src, isInline }) => {
|
|
236
|
+
__html_supervisor__.addScriptToExecute({
|
|
160
237
|
src,
|
|
161
|
-
|
|
238
|
+
type: "js_module",
|
|
239
|
+
isInline,
|
|
240
|
+
execute: () => import(new URL(src, document.location.href).href),
|
|
162
241
|
})
|
|
163
242
|
}
|
|
164
|
-
|
|
165
|
-
const { executions } = __html_supervisor__
|
|
166
|
-
executions.forEach((execution) => {
|
|
167
|
-
__html_supervisor__.addExecution(execution)
|
|
168
|
-
})
|
|
169
|
-
executions.length = 0
|
|
@@ -1,62 +1,61 @@
|
|
|
1
1
|
window.__html_supervisor__ = {
|
|
2
2
|
// "html_supervisor_installer.js" will implement
|
|
3
|
-
// - "
|
|
4
|
-
// - "collectScriptResults"
|
|
3
|
+
// - "addScriptToExecute"
|
|
5
4
|
// - "superviseScriptTypeModule"
|
|
6
|
-
//
|
|
7
|
-
executions
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
collectScriptResults: () => {
|
|
12
|
-
throw new Error("htmlSupervisor not installed")
|
|
13
|
-
},
|
|
14
|
-
superviseScriptTypeModule: () => {
|
|
15
|
-
throw new Error("htmlSupervisor not installed")
|
|
5
|
+
// - "collectScriptResults"
|
|
6
|
+
// and take all executions in "scriptsToExecute" and implement their supervision
|
|
7
|
+
scriptsToExecute: [],
|
|
8
|
+
addScriptToExecute: (scriptToExecute) => {
|
|
9
|
+
window.__html_supervisor__.scriptsToExecute.push(scriptToExecute)
|
|
16
10
|
},
|
|
17
|
-
superviseScript: ({ src, crossorigin, integrity }) => {
|
|
18
|
-
window.__html_supervisor__.
|
|
11
|
+
superviseScript: ({ src, isInline, crossorigin, integrity }) => {
|
|
12
|
+
window.__html_supervisor__.addScriptToExecute({
|
|
13
|
+
src,
|
|
19
14
|
type: "js_classic",
|
|
20
|
-
|
|
15
|
+
isInline,
|
|
21
16
|
currentScript: document.currentScript,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
const cleanup = () => {
|
|
40
|
-
document.body.removeChild(script)
|
|
41
|
-
window.removeEventListener("error", windowErrorCallback)
|
|
42
|
-
}
|
|
43
|
-
window.addEventListener("error", windowErrorCallback)
|
|
44
|
-
script.addEventListener("error", () => {
|
|
45
|
-
cleanup()
|
|
46
|
-
reject(src)
|
|
47
|
-
})
|
|
48
|
-
script.addEventListener("load", () => {
|
|
49
|
-
cleanup()
|
|
50
|
-
if (lastWindowErrorUrl === scriptUrl) {
|
|
51
|
-
reject(lastWindowError)
|
|
52
|
-
} else {
|
|
53
|
-
resolve()
|
|
17
|
+
execute: () => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const script = document.createElement("script")
|
|
20
|
+
if (crossorigin) {
|
|
21
|
+
script.crossorigin = crossorigin
|
|
22
|
+
}
|
|
23
|
+
if (integrity) {
|
|
24
|
+
script.integrity = integrity
|
|
25
|
+
}
|
|
26
|
+
script.src = src
|
|
27
|
+
const scriptUrl = new URL(src, window.location).href
|
|
28
|
+
let lastWindowErrorUrl
|
|
29
|
+
let lastWindowError
|
|
30
|
+
const windowErrorCallback = (e) => {
|
|
31
|
+
lastWindowErrorUrl = e.filename
|
|
32
|
+
lastWindowError = e.error
|
|
54
33
|
}
|
|
34
|
+
const cleanup = () => {
|
|
35
|
+
document.body.removeChild(script)
|
|
36
|
+
window.removeEventListener("error", windowErrorCallback)
|
|
37
|
+
}
|
|
38
|
+
window.addEventListener("error", windowErrorCallback)
|
|
39
|
+
script.addEventListener("error", () => {
|
|
40
|
+
cleanup()
|
|
41
|
+
reject(src)
|
|
42
|
+
})
|
|
43
|
+
script.addEventListener("load", () => {
|
|
44
|
+
cleanup()
|
|
45
|
+
if (lastWindowErrorUrl === scriptUrl) {
|
|
46
|
+
reject(lastWindowError)
|
|
47
|
+
} else {
|
|
48
|
+
resolve()
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
document.body.appendChild(script)
|
|
55
52
|
})
|
|
56
|
-
|
|
57
|
-
}),
|
|
53
|
+
},
|
|
58
54
|
})
|
|
59
55
|
},
|
|
56
|
+
superviseScriptTypeModule: () => {
|
|
57
|
+
throw new Error("htmlSupervisor not installed")
|
|
58
|
+
},
|
|
60
59
|
getScriptExecutionResults: () => {
|
|
61
60
|
// wait for page to load before collecting script execution results
|
|
62
61
|
const htmlReadyPromise = new Promise((resolve) => {
|
|
@@ -74,4 +73,7 @@ window.__html_supervisor__ = {
|
|
|
74
73
|
return window.__html_supervisor__.collectScriptResults()
|
|
75
74
|
})
|
|
76
75
|
},
|
|
76
|
+
collectScriptResults: () => {
|
|
77
|
+
throw new Error("htmlSupervisor not installed")
|
|
78
|
+
},
|
|
77
79
|
}
|
|
@@ -99,11 +99,17 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
99
99
|
const crossorigin = crossoriginAttribute
|
|
100
100
|
? crossoriginAttribute.value
|
|
101
101
|
: undefined
|
|
102
|
+
const deferAttribute = getHtmlNodeAttributeByName(node, "crossorigin")
|
|
103
|
+
const defer = deferAttribute ? deferAttribute.value : undefined
|
|
104
|
+
const asyncAttribute = getHtmlNodeAttributeByName(node, "crossorigin")
|
|
105
|
+
const async = asyncAttribute ? asyncAttribute.value : undefined
|
|
102
106
|
removeHtmlNodeAttributeByName(node, "src")
|
|
103
107
|
scriptsToSupervise.push({
|
|
104
108
|
node,
|
|
105
109
|
type: scriptCategory,
|
|
106
110
|
src: srcAttribute.value,
|
|
111
|
+
defer,
|
|
112
|
+
async,
|
|
107
113
|
integrity,
|
|
108
114
|
crossorigin,
|
|
109
115
|
})
|
|
@@ -183,11 +189,23 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
183
189
|
}),
|
|
184
190
|
)
|
|
185
191
|
scriptsToSupervise.forEach(
|
|
186
|
-
({
|
|
192
|
+
({
|
|
193
|
+
node,
|
|
194
|
+
isInline,
|
|
195
|
+
type,
|
|
196
|
+
src,
|
|
197
|
+
defer,
|
|
198
|
+
async,
|
|
199
|
+
integrity,
|
|
200
|
+
crossorigin,
|
|
201
|
+
}) => {
|
|
187
202
|
setHtmlNodeGeneratedText(node, {
|
|
188
203
|
generatedText: generateCodeToSuperviseScript({
|
|
189
204
|
type,
|
|
190
205
|
src,
|
|
206
|
+
isInline,
|
|
207
|
+
defer,
|
|
208
|
+
async,
|
|
191
209
|
integrity,
|
|
192
210
|
crossorigin,
|
|
193
211
|
htmlSupervisorInstallerSpecifier:
|
|
@@ -213,11 +231,21 @@ export const jsenvPluginHtmlSupervisor = ({
|
|
|
213
231
|
const generateCodeToSuperviseScript = ({
|
|
214
232
|
type,
|
|
215
233
|
src,
|
|
234
|
+
isInline,
|
|
235
|
+
defer,
|
|
236
|
+
async,
|
|
216
237
|
integrity,
|
|
217
238
|
crossorigin,
|
|
218
239
|
htmlSupervisorInstallerSpecifier,
|
|
219
240
|
}) => {
|
|
220
|
-
const paramsAsJson = JSON.stringify({
|
|
241
|
+
const paramsAsJson = JSON.stringify({
|
|
242
|
+
src,
|
|
243
|
+
isInline,
|
|
244
|
+
defer,
|
|
245
|
+
async,
|
|
246
|
+
integrity,
|
|
247
|
+
crossorigin,
|
|
248
|
+
})
|
|
221
249
|
if (type === "module") {
|
|
222
250
|
return `
|
|
223
251
|
import { superviseScriptTypeModule } from ${htmlSupervisorInstallerSpecifier}
|