@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.
@@ -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
- prunedCallbackList.notify({ prunedUrlInfos, firstUrlInfo })
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
- watchedFilePatterns,
10
- cooldownBetweenFileEvents,
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
- const sseService = createSSEService({
133
- rootDirectoryUrl,
134
- watchedFilePatterns,
135
- cooldownBetweenFileEvents,
136
- serverEventCallbackList,
137
- onFileChange: ({ url, event }) => {
138
- const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
139
- const urlInfo = urlGraph.urlInfos[url]
140
- // file not part of dependency graph
141
- if (!urlInfo) {
142
- return
143
- }
144
- updateHmrTimestamp(urlInfo, Date.now())
145
- const hotUpdate = propagateUpdate(urlInfo)
146
- if (hotUpdate.declined) {
147
- notifyDeclined({
148
- cause: `${relativeUrl} ${event}`,
149
- reason: hotUpdate.reason,
150
- declinedBy: hotUpdate.declinedBy,
151
- })
152
- } else {
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
- urlGraph.prunedCallbackList.add(({ prunedUrlInfos, firstUrlInfo }) => {
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, { urlGraph, rootDirectoryUrl }) => {
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
- watchedFilePatterns,
10
- cooldownBetweenFileEvents,
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
- watchedFilePatterns,
24
- cooldownBetweenFileEvents,
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.data.hmrTimestamp) {
26
+ if (!urlInfo.modifiedTimestamp) {
27
27
  return null
28
28
  }
29
29
  return {
30
30
  hmr: "",
31
- v: urlInfo.data.hmrTimestamp,
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
- __html_supervisor__.addExecution = async ({
73
- type,
72
+ const performExecution = async ({
74
73
  src,
74
+ type,
75
75
  currentScript,
76
- promise,
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
- promise.then(
83
- (namespace) => {
84
- const executionResult = {
85
- status: "completed",
86
- namespace,
87
- coverage: window.__coverage__,
88
- }
89
- onExecutionSettled(src, executionResult)
90
- if (logs) {
91
- console.log(`${type} load ended`)
92
- console.groupEnd()
93
- }
94
- },
95
- async (e) => {
96
- let error = e
97
- const executionResult = {
98
- status: "errored",
99
- coverage: window.__coverage__,
100
- }
101
- let errorExposureInConsole = true
102
- if (e.name === "SyntaxError") {
103
- // errorExposureInConsole = false
104
- }
105
- if (errorTransformer) {
106
- try {
107
- error = await errorTransformer(e)
108
- } catch (e) {}
109
- }
110
- executionResult.error = error
111
- onExecutionSettled(src, executionResult)
112
- onExecutionError(executionResult, {
113
- currentScript,
114
- })
115
- if (errorExposureInConsole) {
116
- if (typeof window.reportError === "function") {
117
- window.reportError(error)
118
- } else {
119
- console.error(error)
120
- }
121
- }
122
- if (logs) {
123
- console.groupEnd()
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__.addExecution({
157
- type: "js_module",
158
- currentScript: null,
159
- improveErrorWithFetch: true,
235
+ export const superviseScriptTypeModule = ({ src, isInline }) => {
236
+ __html_supervisor__.addScriptToExecute({
160
237
  src,
161
- promise: import(new URL(src, document.location.href).href),
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
- // - "addExecution"
4
- // - "collectScriptResults"
3
+ // - "addScriptToExecute"
5
4
  // - "superviseScriptTypeModule"
6
- // and take all executions in "executions" and implement their supervision
7
- executions: [],
8
- addExecution: (execution) => {
9
- window.__html_supervisor__.executions.push(execution)
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__.addExecution({
11
+ superviseScript: ({ src, isInline, crossorigin, integrity }) => {
12
+ window.__html_supervisor__.addScriptToExecute({
13
+ src,
19
14
  type: "js_classic",
20
- improveErrorWithFetch: true,
15
+ isInline,
21
16
  currentScript: document.currentScript,
22
- src,
23
- promise: new Promise((resolve, reject) => {
24
- const script = document.createElement("script")
25
- if (crossorigin) {
26
- script.crossorigin = crossorigin
27
- }
28
- if (integrity) {
29
- script.integrity = integrity
30
- }
31
- script.src = src
32
- const scriptUrl = new URL(src, window.location).href
33
- let lastWindowErrorUrl
34
- let lastWindowError
35
- const windowErrorCallback = (e) => {
36
- lastWindowErrorUrl = e.filename
37
- lastWindowError = e.error
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
- document.body.appendChild(script)
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
- ({ node, isInline, type, src, integrity, crossorigin }) => {
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({ src, integrity, crossorigin })
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}