@jsenv/core 28.1.2 → 28.2.1
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/script_type_module_supervisor.js +8 -13
- package/dist/js/supervisor.js +690 -504
- package/dist/main.js +13384 -13228
- package/package.json +6 -6
- package/readme.md +3 -3
- package/src/build/build.js +980 -713
- package/src/build/inject_global_version_mappings.js +5 -20
- package/src/build/start_build_server.js +2 -2
- package/src/dev/start_dev_server.js +6 -3
- package/src/execute/run.js +1 -1
- package/src/omega/compat/runtime_compat.js +9 -6
- package/src/omega/errors.js +3 -0
- package/src/omega/fetched_content_compliance.js +2 -2
- package/src/omega/kitchen.js +191 -146
- package/src/omega/server/file_service.js +104 -71
- package/src/omega/url_graph/url_graph_loader.js +77 -0
- package/src/omega/url_graph/url_info_transformations.js +12 -15
- package/src/omega/url_graph.js +118 -101
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +34 -36
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +3 -2
- package/src/plugins/bundling/js_module/{bundle_js_module.js → bundle_js_modules.js} +51 -14
- package/src/plugins/bundling/jsenv_plugin_bundling.js +2 -2
- package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +11 -0
- package/src/plugins/inline/jsenv_plugin_html_inline_content.js +73 -62
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +77 -89
- package/src/plugins/plugin_controller.js +26 -22
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +1 -0
- package/src/plugins/supervisor/client/script_type_module_supervisor.js +7 -9
- package/src/plugins/supervisor/client/supervisor.js +99 -52
- package/src/plugins/supervisor/jsenv_plugin_supervisor.js +2 -4
- package/src/plugins/transpilation/as_js_classic/async-to-promises.js +16 -0
- package/src/plugins/transpilation/as_js_classic/convert_js_module_to_js_classic.js +85 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +48 -190
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_conversion.js +104 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +161 -240
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_library.js +91 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_workers.js +19 -12
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +1 -24
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +82 -52
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +12 -13
- package/src/plugins/url_analysis/html/html_urls.js +91 -34
- package/src/plugins/url_analysis/js/js_urls.js +5 -4
- package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +1 -0
- package/src/test/execute_plan.js +3 -8
- package/src/test/execute_test_plan.js +1 -1
- package/src/build/inject_service_worker_urls.js +0 -78
- package/src/build/resync_resource_hints.js +0 -112
- package/src/omega/url_graph/url_graph_load.js +0 -74
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs"
|
|
1
2
|
import {
|
|
2
3
|
fetchFileSystem,
|
|
3
4
|
serveDirectory,
|
|
4
5
|
composeTwoResponses,
|
|
5
6
|
} from "@jsenv/server"
|
|
6
|
-
import { registerDirectoryLifecycle } from "@jsenv/filesystem"
|
|
7
|
+
import { registerDirectoryLifecycle, bufferToEtag } from "@jsenv/filesystem"
|
|
7
8
|
import { urlIsInsideOf, moveUrl } from "@jsenv/urls"
|
|
8
9
|
import { URL_META } from "@jsenv/url-meta"
|
|
9
10
|
|
|
@@ -42,38 +43,41 @@ export const createFileService = ({
|
|
|
42
43
|
|
|
43
44
|
const clientFileChangeCallbackList = []
|
|
44
45
|
const clientFilesPruneCallbackList = []
|
|
45
|
-
const clientFileChangeCallback = ({ relativeUrl, event }) => {
|
|
46
|
-
const url = new URL(relativeUrl, rootDirectoryUrl).href
|
|
47
|
-
clientFileChangeCallbackList.forEach((callback) => {
|
|
48
|
-
callback({ url, event })
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
46
|
const clientFilePatterns = {
|
|
52
47
|
...clientFiles,
|
|
53
48
|
".jsenv/": false,
|
|
54
49
|
}
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
watchPatterns: clientFilePatterns,
|
|
61
|
-
cooldownBetweenFileEvents,
|
|
62
|
-
keepProcessAlive: false,
|
|
63
|
-
recursive: true,
|
|
64
|
-
added: ({ relativeUrl }) => {
|
|
65
|
-
clientFileChangeCallback({ event: "added", relativeUrl })
|
|
66
|
-
},
|
|
67
|
-
updated: ({ relativeUrl }) => {
|
|
68
|
-
clientFileChangeCallback({ event: "modified", relativeUrl })
|
|
69
|
-
},
|
|
70
|
-
removed: ({ relativeUrl }) => {
|
|
71
|
-
clientFileChangeCallback({ event: "removed", relativeUrl })
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
)
|
|
75
|
-
serverStopCallbacks.push(stopWatchingClientFiles)
|
|
51
|
+
const onFileChange = (url) => {
|
|
52
|
+
clientFileChangeCallbackList.forEach((callback) => {
|
|
53
|
+
callback(url)
|
|
54
|
+
})
|
|
76
55
|
}
|
|
56
|
+
const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
|
|
57
|
+
watchPatterns: clientFilePatterns,
|
|
58
|
+
cooldownBetweenFileEvents,
|
|
59
|
+
keepProcessAlive: false,
|
|
60
|
+
recursive: true,
|
|
61
|
+
added: ({ relativeUrl }) => {
|
|
62
|
+
onFileChange({
|
|
63
|
+
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
64
|
+
event: "added",
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
updated: ({ relativeUrl }) => {
|
|
68
|
+
onFileChange({
|
|
69
|
+
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
70
|
+
event: "modified",
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
removed: ({ relativeUrl }) => {
|
|
74
|
+
onFileChange({
|
|
75
|
+
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
76
|
+
event: "removed",
|
|
77
|
+
})
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
serverStopCallbacks.push(stopWatchingClientFiles)
|
|
77
81
|
|
|
78
82
|
const contextCache = new Map()
|
|
79
83
|
const getOrCreateContext = (request) => {
|
|
@@ -89,17 +93,12 @@ export const createFileService = ({
|
|
|
89
93
|
{ watch: clientFilePatterns },
|
|
90
94
|
rootDirectoryUrl,
|
|
91
95
|
)
|
|
92
|
-
const urlGraph = createUrlGraph(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
associations: watchAssociations,
|
|
99
|
-
})
|
|
100
|
-
urlInfo.isValid = () => watch
|
|
101
|
-
},
|
|
102
|
-
includeOriginalUrls: scenarios.dev,
|
|
96
|
+
const urlGraph = createUrlGraph()
|
|
97
|
+
clientFileChangeCallbackList.push(({ url }) => {
|
|
98
|
+
const urlInfo = urlGraph.getUrlInfo(url)
|
|
99
|
+
if (urlInfo) {
|
|
100
|
+
urlGraph.considerModified(urlInfo)
|
|
101
|
+
}
|
|
103
102
|
})
|
|
104
103
|
const kitchen = createKitchen({
|
|
105
104
|
signal,
|
|
@@ -133,7 +132,51 @@ export const createFileService = ({
|
|
|
133
132
|
sourcemapsSourcesProtocol,
|
|
134
133
|
sourcemapsSourcesContent,
|
|
135
134
|
writeGeneratedFiles,
|
|
135
|
+
outDirectoryUrl: scenarios.dev
|
|
136
|
+
? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/`
|
|
137
|
+
: `${rootDirectoryUrl}.jsenv/${
|
|
138
|
+
scenarios.test ? "test" : "build"
|
|
139
|
+
}/${runtimeName}@${runtimeVersion}/`,
|
|
136
140
|
})
|
|
141
|
+
urlGraph.createUrlInfoCallbackRef.current = (urlInfo) => {
|
|
142
|
+
const { watch } = URL_META.applyAssociations({
|
|
143
|
+
url: urlInfo.url,
|
|
144
|
+
associations: watchAssociations,
|
|
145
|
+
})
|
|
146
|
+
urlInfo.isWatched = watch
|
|
147
|
+
// si une urlInfo dépends de pleins d'autres alors
|
|
148
|
+
// on voudrait check chacune de ces url infos (package.json dans mon cas)
|
|
149
|
+
urlInfo.isValid = () => {
|
|
150
|
+
if (!urlInfo.url.startsWith("file:")) {
|
|
151
|
+
return false
|
|
152
|
+
}
|
|
153
|
+
if (watch && urlInfo.contentEtag === undefined) {
|
|
154
|
+
// we trust the watching mecanism
|
|
155
|
+
// doing urlInfo.contentEtag = undefined
|
|
156
|
+
// when file is modified
|
|
157
|
+
return false
|
|
158
|
+
}
|
|
159
|
+
if (!watch) {
|
|
160
|
+
const fileContentAsBuffer = readFileSync(new URL(urlInfo.url))
|
|
161
|
+
const fileContentEtag = bufferToEtag(fileContentAsBuffer)
|
|
162
|
+
if (fileContentEtag !== urlInfo.originalContentEtag) {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const implicitUrl of urlInfo.implicitUrls) {
|
|
167
|
+
const implicitUrlInfo = context.urlGraph.getUrlInfo(implicitUrl)
|
|
168
|
+
if (implicitUrlInfo && !implicitUrlInfo.isValid()) {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return true
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
urlGraph.prunedUrlInfosCallbackRef.current = (urlInfos, firstUrlInfo) => {
|
|
176
|
+
clientFilesPruneCallbackList.forEach((callback) => {
|
|
177
|
+
callback(urlInfos, firstUrlInfo)
|
|
178
|
+
})
|
|
179
|
+
}
|
|
137
180
|
serverStopCallbacks.push(() => {
|
|
138
181
|
kitchen.pluginController.callHooks("destroy", kitchen.kitchenContext)
|
|
139
182
|
})
|
|
@@ -192,8 +235,7 @@ export const createFileService = ({
|
|
|
192
235
|
headers: request.headers,
|
|
193
236
|
})
|
|
194
237
|
}
|
|
195
|
-
const {
|
|
196
|
-
getOrCreateContext(request)
|
|
238
|
+
const { urlGraph, kitchen } = getOrCreateContext(request)
|
|
197
239
|
const responseFromPlugin =
|
|
198
240
|
await kitchen.pluginController.callAsyncHooksUntil(
|
|
199
241
|
"serve",
|
|
@@ -218,25 +260,21 @@ export const createFileService = ({
|
|
|
218
260
|
reference = entryPoint[0]
|
|
219
261
|
}
|
|
220
262
|
const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url)
|
|
221
|
-
|
|
222
263
|
const ifNoneMatch = request.headers["if-none-match"]
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
"cache-control": `private,max-age=0,must-revalidate`,
|
|
238
|
-
...urlInfo.headers,
|
|
239
|
-
},
|
|
264
|
+
const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo)
|
|
265
|
+
|
|
266
|
+
if (ifNoneMatch) {
|
|
267
|
+
if (
|
|
268
|
+
urlInfoTargetedByCache.contentEtag === ifNoneMatch &&
|
|
269
|
+
urlInfoTargetedByCache.isValid()
|
|
270
|
+
) {
|
|
271
|
+
return {
|
|
272
|
+
status: 304,
|
|
273
|
+
headers: {
|
|
274
|
+
"cache-control": `private,max-age=0,must-revalidate`,
|
|
275
|
+
...urlInfo.headers,
|
|
276
|
+
},
|
|
277
|
+
}
|
|
240
278
|
}
|
|
241
279
|
}
|
|
242
280
|
try {
|
|
@@ -253,17 +291,11 @@ export const createFileService = ({
|
|
|
253
291
|
urlInfo.originalContent = null
|
|
254
292
|
urlInfo.type = null
|
|
255
293
|
urlInfo.subtype = null
|
|
256
|
-
urlInfo.dependsOnPackageJson = false
|
|
257
294
|
urlInfo.timing = {}
|
|
258
295
|
}
|
|
259
296
|
await kitchen.cook(urlInfo, {
|
|
260
297
|
request,
|
|
261
298
|
reference,
|
|
262
|
-
outDirectoryUrl: scenarios.dev
|
|
263
|
-
? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/`
|
|
264
|
-
: `${rootDirectoryUrl}.jsenv/${
|
|
265
|
-
scenarios.test ? "test" : "build"
|
|
266
|
-
}/${runtimeName}@${runtimeVersion}/`,
|
|
267
299
|
})
|
|
268
300
|
let { response } = urlInfo
|
|
269
301
|
if (response) {
|
|
@@ -275,7 +307,7 @@ export const createFileService = ({
|
|
|
275
307
|
headers: {
|
|
276
308
|
"content-length": Buffer.byteLength(urlInfo.content),
|
|
277
309
|
"cache-control": `private,max-age=0,must-revalidate`,
|
|
278
|
-
"eTag":
|
|
310
|
+
"eTag": urlInfoTargetedByCache.contentEtag,
|
|
279
311
|
...urlInfo.headers,
|
|
280
312
|
"content-type": urlInfo.contentType,
|
|
281
313
|
},
|
|
@@ -293,13 +325,14 @@ export const createFileService = ({
|
|
|
293
325
|
return response
|
|
294
326
|
} catch (e) {
|
|
295
327
|
urlInfo.error = e
|
|
296
|
-
const
|
|
328
|
+
const originalError = e ? e.cause || e : e
|
|
329
|
+
const code = originalError.code
|
|
297
330
|
if (code === "PARSE_ERROR") {
|
|
298
331
|
return {
|
|
299
332
|
url: reference.url,
|
|
300
333
|
status: 200, // let the browser re-throw the syntax error
|
|
301
|
-
statusText:
|
|
302
|
-
statusMessage:
|
|
334
|
+
statusText: originalError.reason,
|
|
335
|
+
statusMessage: originalError.message,
|
|
303
336
|
headers: {
|
|
304
337
|
"content-type": urlInfo.contentType,
|
|
305
338
|
"content-length": Buffer.byteLength(urlInfo.content),
|
|
@@ -321,15 +354,15 @@ export const createFileService = ({
|
|
|
321
354
|
return {
|
|
322
355
|
url: reference.url,
|
|
323
356
|
status: 403,
|
|
324
|
-
statusText:
|
|
357
|
+
statusText: originalError.reason,
|
|
325
358
|
}
|
|
326
359
|
}
|
|
327
360
|
if (code === "NOT_FOUND") {
|
|
328
361
|
return {
|
|
329
362
|
url: reference.url,
|
|
330
363
|
status: 404,
|
|
331
|
-
statusText:
|
|
332
|
-
statusMessage:
|
|
364
|
+
statusText: originalError.reason,
|
|
365
|
+
statusMessage: originalError.message,
|
|
333
366
|
}
|
|
334
367
|
}
|
|
335
368
|
return {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const createUrlGraphLoader = (context) => {
|
|
2
|
+
const promises = []
|
|
3
|
+
const promiseMap = new Map()
|
|
4
|
+
const load = (
|
|
5
|
+
urlInfo,
|
|
6
|
+
dishContext,
|
|
7
|
+
{ ignoreRessourceHint = true, ignoreDynamicImport = false } = {},
|
|
8
|
+
) => {
|
|
9
|
+
const promiseFromData = promiseMap.get(urlInfo)
|
|
10
|
+
if (promiseFromData) return promiseFromData
|
|
11
|
+
const promise = (async () => {
|
|
12
|
+
await context.cook(urlInfo, {
|
|
13
|
+
cookDuringCook: load,
|
|
14
|
+
...dishContext,
|
|
15
|
+
})
|
|
16
|
+
loadReferencedUrlInfos(urlInfo, {
|
|
17
|
+
ignoreRessourceHint,
|
|
18
|
+
ignoreDynamicImport,
|
|
19
|
+
})
|
|
20
|
+
})()
|
|
21
|
+
promises.push(promise)
|
|
22
|
+
promiseMap.set(urlInfo, promise)
|
|
23
|
+
return promise
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const loadReferencedUrlInfos = (
|
|
27
|
+
urlInfo,
|
|
28
|
+
{ ignoreRessourceHint, ignoreDynamicImport },
|
|
29
|
+
) => {
|
|
30
|
+
const { references } = urlInfo
|
|
31
|
+
references.forEach((reference) => {
|
|
32
|
+
// we don't cook resource hints
|
|
33
|
+
// because they might refer to resource that will be modified during build
|
|
34
|
+
// It also means something else have to reference that url in order to cook it
|
|
35
|
+
// so that the preload is deleted by "resync_resource_hints.js" otherwise
|
|
36
|
+
if (ignoreRessourceHint && reference.isResourceHint) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
if (ignoreDynamicImport && reference.subtype === "import_dynamic") {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
// we use reference.generatedUrl to mimic what a browser would do:
|
|
43
|
+
// do a fetch to the specifier as found in the file
|
|
44
|
+
const referencedUrlInfo = context.urlGraph.reuseOrCreateUrlInfo(
|
|
45
|
+
reference.generatedUrl,
|
|
46
|
+
)
|
|
47
|
+
load(referencedUrlInfo, {
|
|
48
|
+
reference,
|
|
49
|
+
ignoreRessourceHint,
|
|
50
|
+
ignoreDynamicImport,
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const getAllLoadDonePromise = async (operation) => {
|
|
56
|
+
const waitAll = async () => {
|
|
57
|
+
if (operation) {
|
|
58
|
+
operation.throwIfAborted()
|
|
59
|
+
}
|
|
60
|
+
if (promises.length === 0) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
const promisesToWait = promises.slice()
|
|
64
|
+
promises.length = 0
|
|
65
|
+
await Promise.all(promisesToWait)
|
|
66
|
+
await waitAll()
|
|
67
|
+
}
|
|
68
|
+
await waitAll()
|
|
69
|
+
promiseMap.clear()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
load,
|
|
74
|
+
loadReferencedUrlInfos,
|
|
75
|
+
getAllLoadDonePromise,
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -15,23 +15,14 @@ export const createUrlInfoTransformer = ({
|
|
|
15
15
|
sourcemapsSourcesContent,
|
|
16
16
|
sourcemapsRelativeSources,
|
|
17
17
|
urlGraph,
|
|
18
|
-
clientRuntimeCompat,
|
|
19
18
|
injectSourcemapPlaceholder,
|
|
20
19
|
foundSourcemap,
|
|
21
20
|
}) => {
|
|
22
|
-
const runtimeNames = Object.keys(clientRuntimeCompat)
|
|
23
|
-
const chromeAsSingleRuntime =
|
|
24
|
-
runtimeNames.length === 1 && runtimeNames[0] === "chrome"
|
|
25
21
|
if (sourcemapsSourcesProtocol === undefined) {
|
|
26
22
|
sourcemapsSourcesProtocol = "file:///"
|
|
27
23
|
}
|
|
28
24
|
if (sourcemapsSourcesContent === undefined) {
|
|
29
|
-
|
|
30
|
-
// chrome is able to fetch source when referenced with "file:"
|
|
31
|
-
sourcemapsSourcesContent = false
|
|
32
|
-
} else {
|
|
33
|
-
sourcemapsSourcesContent = true
|
|
34
|
-
}
|
|
25
|
+
sourcemapsSourcesContent = true
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
const sourcemapsEnabled =
|
|
@@ -75,6 +66,9 @@ export const createUrlInfoTransformer = ({
|
|
|
75
66
|
}
|
|
76
67
|
|
|
77
68
|
const initTransformations = async (urlInfo, context) => {
|
|
69
|
+
urlInfo.originalContentEtag =
|
|
70
|
+
urlInfo.originalContentEtag ||
|
|
71
|
+
bufferToEtag(Buffer.from(urlInfo.originalContent))
|
|
78
72
|
if (!sourcemapsEnabled) {
|
|
79
73
|
return
|
|
80
74
|
}
|
|
@@ -133,7 +127,7 @@ export const createUrlInfoTransformer = ({
|
|
|
133
127
|
}
|
|
134
128
|
}
|
|
135
129
|
|
|
136
|
-
const applyIntermediateTransformations =
|
|
130
|
+
const applyIntermediateTransformations = (urlInfo, transformations) => {
|
|
137
131
|
if (!transformations) {
|
|
138
132
|
return
|
|
139
133
|
}
|
|
@@ -150,7 +144,7 @@ export const createUrlInfoTransformer = ({
|
|
|
150
144
|
}
|
|
151
145
|
if (sourcemapsEnabled && sourcemap) {
|
|
152
146
|
const sourcemapNormalized = normalizeSourcemap(urlInfo, sourcemap)
|
|
153
|
-
const finalSourcemap =
|
|
147
|
+
const finalSourcemap = composeTwoSourcemaps(
|
|
154
148
|
urlInfo.sourcemap,
|
|
155
149
|
sourcemapNormalized,
|
|
156
150
|
)
|
|
@@ -172,9 +166,9 @@ export const createUrlInfoTransformer = ({
|
|
|
172
166
|
}
|
|
173
167
|
}
|
|
174
168
|
|
|
175
|
-
const applyFinalTransformations =
|
|
169
|
+
const applyFinalTransformations = (urlInfo, transformations) => {
|
|
176
170
|
if (transformations) {
|
|
177
|
-
|
|
171
|
+
applyIntermediateTransformations(urlInfo, transformations)
|
|
178
172
|
}
|
|
179
173
|
if (
|
|
180
174
|
sourcemapsEnabled &&
|
|
@@ -227,7 +221,10 @@ export const createUrlInfoTransformer = ({
|
|
|
227
221
|
// in the end we don't use the sourcemap placeholder
|
|
228
222
|
urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url)
|
|
229
223
|
}
|
|
230
|
-
urlInfo.contentEtag =
|
|
224
|
+
urlInfo.contentEtag =
|
|
225
|
+
urlInfo.content === urlInfo.originalContent
|
|
226
|
+
? urlInfo.originalContentEtag
|
|
227
|
+
: bufferToEtag(Buffer.from(urlInfo.content))
|
|
231
228
|
}
|
|
232
229
|
|
|
233
230
|
return {
|