@jsenv/core 27.0.0-alpha.52 → 27.0.0-alpha.55
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/package.json +2 -2
- package/src/build/build.js +32 -30
- package/src/build/build_urls_generator.js +1 -1
- package/src/build/start_build_server.js +1 -0
- package/src/execute/runtimes/browsers/from_playwright.js +3 -0
- package/src/omega/kitchen.js +18 -30
- package/src/omega/server/file_service.js +19 -4
- package/src/omega/url_graph/url_graph_load.js +7 -0
- package/src/omega/url_graph.js +0 -11
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
- package/src/plugins/bundling/js_module/bundle_js_module.js +1 -12
- package/src/plugins/cache_control/jsenv_plugin_cache_control.js +34 -0
- package/src/plugins/filesystem_magic/jsenv_plugin_filesystem_magic.js +1 -1
- package/src/plugins/inline/jsenv_plugin_js_inline_content.js +3 -2
- package/src/plugins/plugin_controller.js +2 -2
- package/src/plugins/plugins.js +2 -1
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +40 -24
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +24 -10
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +1 -1
- package/src/plugins/transpilation/babel/helpers/babel_plugin_structure.js +12 -1
- package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +11 -9
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +3 -3
- package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +10 -0
- package/src/plugins/url_analysis/html/html_urls.js +24 -28
- package/src/plugins/url_version/jsenv_plugin_url_version.js +3 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "27.0.0-alpha.
|
|
3
|
+
"version": "27.0.0-alpha.55",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@jsenv/node-esm-resolution": "0.0.6",
|
|
69
69
|
"@jsenv/server": "12.6.2",
|
|
70
70
|
"@jsenv/uneval": "1.6.0",
|
|
71
|
-
"@jsenv/utils": "1.7.
|
|
71
|
+
"@jsenv/utils": "1.7.3",
|
|
72
72
|
"construct-style-sheets-polyfill": "3.1.0",
|
|
73
73
|
"cssnano": "5.1.7",
|
|
74
74
|
"cssnano-preset-default": "5.2.7",
|
package/src/build/build.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
injectQueryParams,
|
|
23
23
|
setUrlFilename,
|
|
24
24
|
asUrlUntilPathname,
|
|
25
|
+
normalizeUrl,
|
|
25
26
|
} from "@jsenv/utils/urls/url_utils.js"
|
|
26
27
|
import { createVersionGenerator } from "@jsenv/utils/versioning/version_generator.js"
|
|
27
28
|
import { generateSourcemapUrl } from "@jsenv/utils/sourcemap/sourcemap_utils.js"
|
|
@@ -223,9 +224,6 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
223
224
|
})
|
|
224
225
|
})
|
|
225
226
|
const addToBundlerIfAny = (rawUrlInfo) => {
|
|
226
|
-
// if (rawUrlInfo.dependencies.size === 0) {
|
|
227
|
-
// return
|
|
228
|
-
// }
|
|
229
227
|
const bundler = bundlers[rawUrlInfo.type]
|
|
230
228
|
if (bundler) {
|
|
231
229
|
bundler.urlInfos.push(rawUrlInfo)
|
|
@@ -253,6 +251,21 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
253
251
|
}
|
|
254
252
|
addToBundlerIfAny(dependencyUrlInfo)
|
|
255
253
|
})
|
|
254
|
+
rawUrlInfo.references.forEach((reference) => {
|
|
255
|
+
if (
|
|
256
|
+
reference.isRessourceHint &&
|
|
257
|
+
reference.expectedType === "js_module"
|
|
258
|
+
) {
|
|
259
|
+
const referencedUrlInfo = rawGraph.getUrlInfo(reference.url)
|
|
260
|
+
if (
|
|
261
|
+
referencedUrlInfo &&
|
|
262
|
+
// something else than the ressource hint is using this url
|
|
263
|
+
referencedUrlInfo.dependents.size > 0
|
|
264
|
+
) {
|
|
265
|
+
addToBundlerIfAny(referencedUrlInfo)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
})
|
|
256
269
|
return
|
|
257
270
|
}
|
|
258
271
|
}
|
|
@@ -361,25 +374,10 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
361
374
|
if (urlRedirectedByBundle) {
|
|
362
375
|
return urlRedirectedByBundle
|
|
363
376
|
}
|
|
364
|
-
const parentIsFromBundle = Boolean(
|
|
365
|
-
bundleUrlInfos[reference.parentUrl],
|
|
366
|
-
)
|
|
367
|
-
// urls inside css bundled by parcel
|
|
368
|
-
// contains url relative to the bundle file (which is considered inside build directory)
|
|
369
|
-
// if the file is not itself a bundle file it must be resolved against
|
|
370
|
-
// the original css url
|
|
371
|
-
if (
|
|
372
|
-
parentIsFromBundle &&
|
|
373
|
-
!bundleUrlInfos[url] &&
|
|
374
|
-
urlIsInsideOf(url, buildDirectoryUrl)
|
|
375
|
-
) {
|
|
376
|
-
const parentRawUrl = rawUrls[reference.parentUrl]
|
|
377
|
-
url = new URL(reference.specifier, parentRawUrl).href
|
|
378
|
-
}
|
|
379
377
|
const urlRedirected = rawUrlRedirections[url]
|
|
380
378
|
return urlRedirected || url
|
|
381
379
|
},
|
|
382
|
-
|
|
380
|
+
redirectUrl: (reference) => {
|
|
383
381
|
if (!reference.url.startsWith("file:")) {
|
|
384
382
|
return null
|
|
385
383
|
}
|
|
@@ -618,6 +616,7 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
618
616
|
urlGraph: finalGraph,
|
|
619
617
|
kitchen: finalGraphKitchen,
|
|
620
618
|
outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
|
|
619
|
+
skipRessourceHint: true,
|
|
621
620
|
startLoading: (cookEntryFile) => {
|
|
622
621
|
entryUrls.forEach((entryUrl) => {
|
|
623
622
|
const [, postBuildEntryUrlInfo] = cookEntryFile({
|
|
@@ -698,7 +697,7 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
|
|
|
698
697
|
urlInfo.dependents.size === 0
|
|
699
698
|
) {
|
|
700
699
|
cleanupActions.push(() => {
|
|
701
|
-
|
|
700
|
+
finalGraph.deleteUrlInfo(urlInfo.url)
|
|
702
701
|
})
|
|
703
702
|
}
|
|
704
703
|
})
|
|
@@ -731,12 +730,12 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
|
|
|
731
730
|
buildInlineContents[buildRelativeUrl] = urlInfo.content
|
|
732
731
|
} else {
|
|
733
732
|
buildFileContents[buildRelativeUrl] = urlInfo.content
|
|
733
|
+
const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
|
|
734
|
+
urlInfo.url,
|
|
735
|
+
buildDirectoryUrl,
|
|
736
|
+
)
|
|
737
|
+
buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
|
|
734
738
|
}
|
|
735
|
-
const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
|
|
736
|
-
urlInfo.url,
|
|
737
|
-
buildDirectoryUrl,
|
|
738
|
-
)
|
|
739
|
-
buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
|
|
740
739
|
})
|
|
741
740
|
if (writeOnFileSystem) {
|
|
742
741
|
if (buildDirectoryClean) {
|
|
@@ -859,11 +858,13 @@ const applyUrlVersioning = async ({
|
|
|
859
858
|
})
|
|
860
859
|
urlInfo.data.version = versionGenerator.generate()
|
|
861
860
|
|
|
862
|
-
urlInfo.data.versionedUrl =
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
861
|
+
urlInfo.data.versionedUrl = normalizeUrl(
|
|
862
|
+
injectVersionIntoBuildUrl({
|
|
863
|
+
buildUrl: urlInfo.url,
|
|
864
|
+
version: urlInfo.data.version,
|
|
865
|
+
versioningMethod,
|
|
866
|
+
}),
|
|
867
|
+
)
|
|
867
868
|
})
|
|
868
869
|
const versionMappings = {}
|
|
869
870
|
const usedVersionMappings = []
|
|
@@ -969,6 +970,7 @@ const applyUrlVersioning = async ({
|
|
|
969
970
|
await loadUrlGraph({
|
|
970
971
|
urlGraph: finalGraph,
|
|
971
972
|
kitchen: versioningKitchen,
|
|
973
|
+
skipRessourceHint: true,
|
|
972
974
|
startLoading: (cookEntryFile) => {
|
|
973
975
|
postBuildEntryUrls.forEach((postBuildEntryUrl) => {
|
|
974
976
|
cookEntryFile({
|
|
@@ -56,8 +56,8 @@ export const createBuilUrlsGenerator = ({ buildDirectoryUrl }) => {
|
|
|
56
56
|
// To keep in mind: if you have "user.jsx" and "user.js" AND both file are not bundled
|
|
57
57
|
// you end up with "dist/js/user.js" and "dist/js/user2.js"
|
|
58
58
|
const extensionMappings = {
|
|
59
|
-
".ts": ".js",
|
|
60
59
|
".jsx": ".js",
|
|
60
|
+
".ts": ".js",
|
|
61
61
|
".tsx": ".js",
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -280,6 +280,9 @@ export const createRuntimeFromPlaywright = ({
|
|
|
280
280
|
/* eslint-disable no-undef */
|
|
281
281
|
/* istanbul ignore next */
|
|
282
282
|
() => {
|
|
283
|
+
if (!window.__html_supervisor__) {
|
|
284
|
+
throw new Error(`window.__html_supervisor__ not found`)
|
|
285
|
+
}
|
|
283
286
|
return window.__html_supervisor__.getScriptExecutionResults()
|
|
284
287
|
},
|
|
285
288
|
/* eslint-enable no-undef */
|
package/src/omega/kitchen.js
CHANGED
|
@@ -10,7 +10,7 @@ import { createDetailedMessage } from "@jsenv/logger"
|
|
|
10
10
|
|
|
11
11
|
import { stringifyUrlSite } from "@jsenv/utils/urls/url_trace.js"
|
|
12
12
|
import { CONTENT_TYPE } from "@jsenv/utils/content_type/content_type.js"
|
|
13
|
-
import { setUrlFilename } from "@jsenv/utils/urls/url_utils.js"
|
|
13
|
+
import { normalizeUrl, setUrlFilename } from "@jsenv/utils/urls/url_utils.js"
|
|
14
14
|
|
|
15
15
|
import { createPluginController } from "../plugins/plugin_controller.js"
|
|
16
16
|
import { createUrlInfoTransformer } from "./url_graph/url_info_transformations.js"
|
|
@@ -142,7 +142,7 @@ export const createKitchen = ({
|
|
|
142
142
|
}
|
|
143
143
|
const resolveReference = (reference) => {
|
|
144
144
|
try {
|
|
145
|
-
|
|
145
|
+
let resolvedUrl = pluginController.callHooksUntil(
|
|
146
146
|
"resolveUrl",
|
|
147
147
|
reference,
|
|
148
148
|
baseContext,
|
|
@@ -150,6 +150,7 @@ export const createKitchen = ({
|
|
|
150
150
|
if (!resolvedUrl) {
|
|
151
151
|
throw new Error(`NO_RESOLVE`)
|
|
152
152
|
}
|
|
153
|
+
resolvedUrl = normalizeUrl(resolvedUrl)
|
|
153
154
|
reference.url = resolvedUrl
|
|
154
155
|
if (reference.external) {
|
|
155
156
|
reference.generatedUrl = resolvedUrl
|
|
@@ -157,29 +158,20 @@ export const createKitchen = ({
|
|
|
157
158
|
return urlGraph.reuseOrCreateUrlInfo(reference.url)
|
|
158
159
|
}
|
|
159
160
|
pluginController.callHooks(
|
|
160
|
-
"
|
|
161
|
+
"redirectUrl",
|
|
161
162
|
reference,
|
|
162
163
|
baseContext,
|
|
163
164
|
(returnValue) => {
|
|
164
|
-
|
|
165
|
+
const normalizedReturnValue = normalizeUrl(returnValue)
|
|
166
|
+
if (normalizedReturnValue === reference.url) {
|
|
165
167
|
return
|
|
166
168
|
}
|
|
167
169
|
const previousReference = { ...reference }
|
|
168
|
-
reference.url =
|
|
170
|
+
reference.url = normalizedReturnValue
|
|
169
171
|
mutateReference(previousReference, reference)
|
|
170
172
|
},
|
|
171
173
|
)
|
|
172
|
-
|
|
173
|
-
// some plugin use URLSearchParams to alter the url search params
|
|
174
|
-
// which can result into "file:///file.css?css_module"
|
|
175
|
-
// becoming "file:///file.css?css_module="
|
|
176
|
-
// we want to get rid of the "=" and consider it's the same url
|
|
177
|
-
if (
|
|
178
|
-
// disable on data urls (would mess up base64 encoding)
|
|
179
|
-
!reference.url.startsWith("data:")
|
|
180
|
-
) {
|
|
181
|
-
reference.url = reference.url.replace(/[=](?=&|$)/g, "")
|
|
182
|
-
}
|
|
174
|
+
|
|
183
175
|
const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url)
|
|
184
176
|
applyReferenceEffectsOnUrlInfo(reference, urlInfo, baseContext)
|
|
185
177
|
|
|
@@ -200,10 +192,7 @@ export const createKitchen = ({
|
|
|
200
192
|
Object.keys(returnValue).forEach((key) => {
|
|
201
193
|
referenceUrlObject.searchParams.set(key, returnValue[key])
|
|
202
194
|
})
|
|
203
|
-
reference.generatedUrl = referenceUrlObject.href
|
|
204
|
-
/[=](?=&|$)/g,
|
|
205
|
-
"",
|
|
206
|
-
)
|
|
195
|
+
reference.generatedUrl = normalizeUrl(referenceUrlObject.href)
|
|
207
196
|
},
|
|
208
197
|
)
|
|
209
198
|
const returnValue = pluginController.callHooksUntil(
|
|
@@ -275,12 +264,13 @@ export const createKitchen = ({
|
|
|
275
264
|
return
|
|
276
265
|
}
|
|
277
266
|
try {
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
267
|
+
const fetchUrlContentReturnValue =
|
|
268
|
+
await pluginController.callAsyncHooksUntil(
|
|
269
|
+
"fetchUrlContent",
|
|
270
|
+
urlInfo,
|
|
271
|
+
context,
|
|
272
|
+
)
|
|
273
|
+
if (!fetchUrlContentReturnValue) {
|
|
284
274
|
logger.warn(
|
|
285
275
|
createDetailedMessage(
|
|
286
276
|
`no plugin has handled the url during "fetchUrlContent" hook -> consider url as external (ignore it)`,
|
|
@@ -293,7 +283,7 @@ export const createKitchen = ({
|
|
|
293
283
|
urlInfo.external = true
|
|
294
284
|
return
|
|
295
285
|
}
|
|
296
|
-
if (
|
|
286
|
+
if (fetchUrlContentReturnValue.external) {
|
|
297
287
|
urlInfo.external = true
|
|
298
288
|
return
|
|
299
289
|
}
|
|
@@ -306,7 +296,7 @@ export const createKitchen = ({
|
|
|
306
296
|
content,
|
|
307
297
|
sourcemap,
|
|
308
298
|
filename,
|
|
309
|
-
} =
|
|
299
|
+
} = fetchUrlContentReturnValue
|
|
310
300
|
urlInfo.type =
|
|
311
301
|
type ||
|
|
312
302
|
reference.expectedType ||
|
|
@@ -661,8 +651,6 @@ export const createKitchen = ({
|
|
|
661
651
|
const prepareEntryPoint = (params) => {
|
|
662
652
|
const entryReference = createReference(params)
|
|
663
653
|
const entryUrlInfo = resolveReference(entryReference)
|
|
664
|
-
// I should likely delete urlInfo.sourcemap
|
|
665
|
-
// otherwise it is reused when page is reloaded
|
|
666
654
|
return [entryReference, entryUrlInfo]
|
|
667
655
|
}
|
|
668
656
|
|
|
@@ -20,6 +20,11 @@ export const createFileService = ({
|
|
|
20
20
|
urlGraph,
|
|
21
21
|
scenario,
|
|
22
22
|
}
|
|
23
|
+
const augmentResponseContext = {
|
|
24
|
+
rootDirectoryUrl,
|
|
25
|
+
urlGraph,
|
|
26
|
+
scenario,
|
|
27
|
+
}
|
|
23
28
|
|
|
24
29
|
const getResponse = async (request) => {
|
|
25
30
|
// serve file inside ".jsenv" directory
|
|
@@ -58,9 +63,19 @@ export const createFileService = ({
|
|
|
58
63
|
reference.parentUrl,
|
|
59
64
|
)
|
|
60
65
|
try {
|
|
61
|
-
// urlInfo objects are reused, they must be "reset" before cooking
|
|
62
|
-
if (
|
|
63
|
-
|
|
66
|
+
// urlInfo objects are reused, they must be "reset" before cooking them again
|
|
67
|
+
if (
|
|
68
|
+
urlInfo.contentEtag &&
|
|
69
|
+
!urlInfo.isInline &&
|
|
70
|
+
urlInfo.type !== "sourcemap"
|
|
71
|
+
) {
|
|
72
|
+
urlInfo.sourcemap = null
|
|
73
|
+
urlInfo.sourcemapReference = null
|
|
74
|
+
urlInfo.content = null
|
|
75
|
+
urlInfo.originalContent = null
|
|
76
|
+
urlInfo.type = null
|
|
77
|
+
urlInfo.subtype = null
|
|
78
|
+
urlInfo.timing = {}
|
|
64
79
|
}
|
|
65
80
|
const { runtimeName, runtimeVersion } = parseUserAgentHeader(
|
|
66
81
|
request.headers["user-agent"],
|
|
@@ -92,7 +107,7 @@ export const createFileService = ({
|
|
|
92
107
|
kitchen.pluginController.callHooks(
|
|
93
108
|
"augmentResponse",
|
|
94
109
|
{ reference, urlInfo },
|
|
95
|
-
|
|
110
|
+
augmentResponseContext,
|
|
96
111
|
(returnValue) => {
|
|
97
112
|
response = composeTwoResponses(response, returnValue)
|
|
98
113
|
},
|
|
@@ -33,6 +33,13 @@ export const loadUrlGraph = async ({
|
|
|
33
33
|
})
|
|
34
34
|
const { references } = urlInfo
|
|
35
35
|
references.forEach((reference) => {
|
|
36
|
+
// we don't cook ressource hints
|
|
37
|
+
// because they might refer to ressource that will be modified during build
|
|
38
|
+
// It also means something else have to reference that url in order to cook it
|
|
39
|
+
// so that the preload is deleted by "resync_ressource_hints.js" otherwise
|
|
40
|
+
if (reference.isRessourceHint) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
36
43
|
// we use reference.generatedUrl to mimic what a browser would do:
|
|
37
44
|
// do a fetch to the specifier as found in the file
|
|
38
45
|
const referencedUrlInfo = urlGraph.reuseOrCreateUrlInfo(
|
package/src/omega/url_graph.js
CHANGED
|
@@ -15,16 +15,6 @@ export const createUrlGraph = ({
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
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
|
-
}
|
|
28
18
|
|
|
29
19
|
const reuseOrCreateUrlInfo = (url) => {
|
|
30
20
|
const existingUrlInfo = urlInfos[url]
|
|
@@ -160,7 +150,6 @@ export const createUrlGraph = ({
|
|
|
160
150
|
reuseOrCreateUrlInfo,
|
|
161
151
|
getUrlInfo,
|
|
162
152
|
deleteUrlInfo,
|
|
163
|
-
resetUrlInfo,
|
|
164
153
|
inferReference,
|
|
165
154
|
findDependent,
|
|
166
155
|
updateReferences,
|
|
@@ -2,7 +2,7 @@ export const jsenvPluginHmr = () => {
|
|
|
2
2
|
return {
|
|
3
3
|
name: "jsenv:hmr",
|
|
4
4
|
appliesDuring: { dev: true },
|
|
5
|
-
|
|
5
|
+
redirectUrl: (reference) => {
|
|
6
6
|
const urlObject = new URL(reference.url)
|
|
7
7
|
if (!urlObject.searchParams.has("hmr")) {
|
|
8
8
|
reference.data.hmr = false
|
|
@@ -247,20 +247,9 @@ const rollupPluginJsenv = ({
|
|
|
247
247
|
code: urlInfo.content,
|
|
248
248
|
map: urlInfo.sourcemap
|
|
249
249
|
? sourcemapConverter.toFilePaths(urlInfo.sourcemap)
|
|
250
|
-
:
|
|
250
|
+
: null,
|
|
251
251
|
}
|
|
252
252
|
},
|
|
253
|
-
// resolveFileUrl: ({ moduleId }) => {
|
|
254
|
-
// return `${fileUrlConverter.asFileUrl(moduleId)}`
|
|
255
|
-
// },
|
|
256
|
-
renderChunk: (code, chunkInfo) => {
|
|
257
|
-
const { facadeModuleId } = chunkInfo
|
|
258
|
-
if (!facadeModuleId) {
|
|
259
|
-
// happens for inline module scripts for instance
|
|
260
|
-
return null
|
|
261
|
-
}
|
|
262
|
-
return null
|
|
263
|
-
},
|
|
264
253
|
}
|
|
265
254
|
}
|
|
266
255
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const jsenvPluginCacheControl = () => {
|
|
2
|
+
return {
|
|
3
|
+
name: "jsenv:cache_control",
|
|
4
|
+
appliesDuring: {
|
|
5
|
+
dev: true,
|
|
6
|
+
test: true,
|
|
7
|
+
},
|
|
8
|
+
augmentResponse: ({ reference }, context) => {
|
|
9
|
+
if (context.scenario === "dev") {
|
|
10
|
+
// During dev, all files are put into browser cache for 1 hour because:
|
|
11
|
+
// 1: Browser cache is a temporary directory created by playwright
|
|
12
|
+
// 2: We assume source files won't be modified while tests are running
|
|
13
|
+
return {
|
|
14
|
+
headers: {
|
|
15
|
+
"cache-control": `private,max-age=3600,immutable`,
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (
|
|
20
|
+
reference.searchParams.has("v") &&
|
|
21
|
+
!reference.searchParams.has("hmr")
|
|
22
|
+
) {
|
|
23
|
+
return {
|
|
24
|
+
headers: {
|
|
25
|
+
"cache-control": `private,max-age=${SECONDS_IN_30_DAYS},immutable`,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30
|
|
@@ -13,7 +13,7 @@ export const jsenvPluginFileSystemMagic = ({
|
|
|
13
13
|
return {
|
|
14
14
|
name: "jsenv:filesystem_magic",
|
|
15
15
|
appliesDuring: "*",
|
|
16
|
-
|
|
16
|
+
redirectUrl: (reference) => {
|
|
17
17
|
// http, https, data, about, etc
|
|
18
18
|
if (!reference.url.startsWith("file:")) {
|
|
19
19
|
return null
|
|
@@ -274,8 +274,9 @@ const getOriginalName = (path, name) => {
|
|
|
274
274
|
return getOriginalName(path, importedName)
|
|
275
275
|
}
|
|
276
276
|
if (binding.path.type === "VariableDeclarator") {
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
const { init } = binding.path.node
|
|
278
|
+
if (init && init.type === "Identifier") {
|
|
279
|
+
const previousName = init.name
|
|
279
280
|
return getOriginalName(path, previousName)
|
|
280
281
|
}
|
|
281
282
|
}
|
|
@@ -5,7 +5,7 @@ export const createPluginController = ({
|
|
|
5
5
|
scenario,
|
|
6
6
|
hooks = [
|
|
7
7
|
"resolveUrl",
|
|
8
|
-
"
|
|
8
|
+
"redirectUrl",
|
|
9
9
|
"fetchUrlContent",
|
|
10
10
|
"transformUrlContent",
|
|
11
11
|
"transformUrlSearchParams",
|
|
@@ -226,7 +226,7 @@ const assertAndNormalizeReturnValue = (hookName, returnValue) => {
|
|
|
226
226
|
const returnValueAssertions = [
|
|
227
227
|
{
|
|
228
228
|
name: "url_assertion",
|
|
229
|
-
appliesTo: ["resolveUrl", "
|
|
229
|
+
appliesTo: ["resolveUrl", "redirectUrl"],
|
|
230
230
|
assertion: (valueReturned) => {
|
|
231
231
|
if (valueReturned instanceof URL) {
|
|
232
232
|
return valueReturned.href
|
package/src/plugins/plugins.js
CHANGED
|
@@ -17,6 +17,7 @@ import { jsenvPluginBundling } from "./bundling/jsenv_plugin_bundling.js"
|
|
|
17
17
|
import { jsenvPluginMinification } from "./minification/jsenv_plugin_minification.js"
|
|
18
18
|
import { jsenvPluginImportMetaHot } from "./import_meta_hot/jsenv_plugin_import_meta_hot.js"
|
|
19
19
|
import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js"
|
|
20
|
+
import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js"
|
|
20
21
|
|
|
21
22
|
export const getCorePlugins = ({
|
|
22
23
|
rootDirectoryUrl,
|
|
@@ -68,7 +69,6 @@ export const getCorePlugins = ({
|
|
|
68
69
|
jsenvPluginInjectGlobals(injectedGlobals),
|
|
69
70
|
jsenvPluginCommonJsGlobals(),
|
|
70
71
|
jsenvPluginImportMetaScenarios(),
|
|
71
|
-
// jsenvPluginWorkers(),
|
|
72
72
|
|
|
73
73
|
jsenvPluginBundling(bundling),
|
|
74
74
|
jsenvPluginMinification(minification),
|
|
@@ -87,5 +87,6 @@ export const getCorePlugins = ({
|
|
|
87
87
|
}),
|
|
88
88
|
]
|
|
89
89
|
: []),
|
|
90
|
+
jsenvPluginCacheControl(),
|
|
90
91
|
]
|
|
91
92
|
}
|
|
@@ -44,34 +44,42 @@ export const jsenvPluginAsJsClassic = ({ systemJsInjection }) => {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const asJsClassic = ({ systemJsInjection, systemJsClientFileUrl }) => {
|
|
47
|
+
const propagateJsClassicSearchParam = (reference, context) => {
|
|
48
|
+
const parentUrlInfo = context.urlGraph.getUrlInfo(reference.parentUrl)
|
|
49
|
+
if (
|
|
50
|
+
!parentUrlInfo ||
|
|
51
|
+
!new URL(parentUrlInfo.url).searchParams.has("as_js_classic")
|
|
52
|
+
) {
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
const urlTransformed = injectQueryParams(reference.url, {
|
|
56
|
+
as_js_classic: "",
|
|
57
|
+
})
|
|
58
|
+
reference.filename = generateJsClassicFilename(reference.url)
|
|
59
|
+
return urlTransformed
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
return {
|
|
48
63
|
name: "jsenv:as_js_classic",
|
|
49
64
|
appliesDuring: "*",
|
|
50
65
|
// forward ?as_js_classic to referenced urls
|
|
51
|
-
|
|
52
|
-
// We want to propagate transformation of js module to js classic
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
!new URL(parentUrlInfo.url).searchParams.has("as_js_classic")
|
|
67
|
-
) {
|
|
66
|
+
redirectUrl: {
|
|
67
|
+
// We want to propagate transformation of js module to js classic to:
|
|
68
|
+
// - import specifier (static/dynamic import + re-export)
|
|
69
|
+
// - url specifier when inside System.register/_context.import()
|
|
70
|
+
// (because it's the transpiled equivalent of static and dynamic imports)
|
|
71
|
+
// And not other references otherwise we could try to transform inline ressources
|
|
72
|
+
// or specifiers inside new URL()...
|
|
73
|
+
js_import_export: propagateJsClassicSearchParam,
|
|
74
|
+
js_url_specifier: (reference, context) => {
|
|
75
|
+
if (
|
|
76
|
+
reference.subtype === "system_register_arg" ||
|
|
77
|
+
reference.subtype === "system_import_arg"
|
|
78
|
+
) {
|
|
79
|
+
return propagateJsClassicSearchParam(reference, context)
|
|
80
|
+
}
|
|
68
81
|
return null
|
|
69
|
-
}
|
|
70
|
-
const urlTransformed = injectQueryParams(reference.url, {
|
|
71
|
-
as_js_classic: "",
|
|
72
|
-
})
|
|
73
|
-
reference.filename = generateJsClassicFilename(reference.url)
|
|
74
|
-
return urlTransformed
|
|
82
|
+
},
|
|
75
83
|
},
|
|
76
84
|
fetchUrlContent: async (urlInfo, context) => {
|
|
77
85
|
const originalUrlInfo = await fetchOriginalUrlInfo({
|
|
@@ -119,7 +127,15 @@ const asJsClassic = ({ systemJsInjection, systemJsClientFileUrl }) => {
|
|
|
119
127
|
|
|
120
128
|
const generateJsClassicFilename = (url) => {
|
|
121
129
|
const filename = urlToFilename(url)
|
|
122
|
-
|
|
130
|
+
let [basename, extension] = splitFileExtension(filename)
|
|
131
|
+
const { searchParams } = new URL(url)
|
|
132
|
+
if (
|
|
133
|
+
searchParams.has("as_json_module") ||
|
|
134
|
+
searchParams.has("as_css_module") ||
|
|
135
|
+
searchParams.has("as_text_module")
|
|
136
|
+
) {
|
|
137
|
+
extension = ".js"
|
|
138
|
+
}
|
|
123
139
|
return `${basename}.es5${extension}`
|
|
124
140
|
}
|
|
125
141
|
|
package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js
CHANGED
|
@@ -98,7 +98,16 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
98
98
|
})
|
|
99
99
|
|
|
100
100
|
const jsModuleUrls = []
|
|
101
|
-
const getReferenceAsJsClassic = async (
|
|
101
|
+
const getReferenceAsJsClassic = async (
|
|
102
|
+
reference,
|
|
103
|
+
{
|
|
104
|
+
// we don't cook ressource hints
|
|
105
|
+
// because they might refer to ressource that will be modified during build
|
|
106
|
+
// It also means something else HAVE to reference that url in order to cook it
|
|
107
|
+
// so that the preload is deleted by "resync_ressource_hints.js" otherwise
|
|
108
|
+
cookIt = false,
|
|
109
|
+
} = {},
|
|
110
|
+
) => {
|
|
102
111
|
const [newReference, newUrlInfo] = context.referenceUtils.update(
|
|
103
112
|
reference,
|
|
104
113
|
{
|
|
@@ -112,6 +121,8 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
112
121
|
const jsModuleUrl = newUrlInfo.url
|
|
113
122
|
if (!jsModuleUrls.includes(jsModuleUrl)) {
|
|
114
123
|
jsModuleUrls.push(newUrlInfo.url)
|
|
124
|
+
}
|
|
125
|
+
if (cookIt) {
|
|
115
126
|
// during dev it means js modules will be cooked before server sends the HTML
|
|
116
127
|
// it's ok because:
|
|
117
128
|
// - during dev script_type_module are supported (dev use a recent browser)
|
|
@@ -141,9 +152,9 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
141
152
|
// but it's unlikely to happen and people should use "modulepreload" in that case anyway
|
|
142
153
|
if (expectedScriptType === "module") {
|
|
143
154
|
actions.push(async () => {
|
|
144
|
-
const
|
|
145
|
-
context.referenceUtils.findByGeneratedSpecifier(href)
|
|
146
|
-
)
|
|
155
|
+
const reference =
|
|
156
|
+
context.referenceUtils.findByGeneratedSpecifier(href)
|
|
157
|
+
const [newReference] = await getReferenceAsJsClassic(reference)
|
|
147
158
|
assignHtmlNodeAttributes(preloadAsScriptNode, {
|
|
148
159
|
href: newReference.generatedSpecifier,
|
|
149
160
|
})
|
|
@@ -158,9 +169,9 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
158
169
|
)
|
|
159
170
|
const href = hrefAttribute.value
|
|
160
171
|
actions.push(async () => {
|
|
161
|
-
const
|
|
162
|
-
context.referenceUtils.findByGeneratedSpecifier(href)
|
|
163
|
-
)
|
|
172
|
+
const reference =
|
|
173
|
+
context.referenceUtils.findByGeneratedSpecifier(href)
|
|
174
|
+
const [newReference] = await getReferenceAsJsClassic(reference)
|
|
164
175
|
assignHtmlNodeAttributes(modulePreloadNode, {
|
|
165
176
|
rel: "preload",
|
|
166
177
|
as: "script",
|
|
@@ -176,9 +187,11 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
176
187
|
if (srcAttribute) {
|
|
177
188
|
actions.push(async () => {
|
|
178
189
|
const specifier = srcAttribute.value
|
|
179
|
-
const
|
|
180
|
-
context.referenceUtils.findByGeneratedSpecifier(specifier)
|
|
181
|
-
|
|
190
|
+
const reference =
|
|
191
|
+
context.referenceUtils.findByGeneratedSpecifier(specifier)
|
|
192
|
+
const [newReference] = await getReferenceAsJsClassic(reference, {
|
|
193
|
+
cookIt: true,
|
|
194
|
+
})
|
|
182
195
|
removeHtmlNodeAttributeByName(moduleScriptNode, "type")
|
|
183
196
|
srcAttribute.value = newReference.generatedSpecifier
|
|
184
197
|
})
|
|
@@ -214,6 +227,7 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
214
227
|
})
|
|
215
228
|
const [, newUrlInfo] = await getReferenceAsJsClassic(
|
|
216
229
|
inlineReference,
|
|
230
|
+
{ cookIt: true },
|
|
217
231
|
)
|
|
218
232
|
removeHtmlNodeAttributeByName(moduleScriptNode, "type")
|
|
219
233
|
setHtmlNodeGeneratedText(moduleScriptNode, {
|
package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js
CHANGED
|
@@ -21,7 +21,7 @@ export const jsenvPluginWorkersTypeModuleAsClassic = ({
|
|
|
21
21
|
return {
|
|
22
22
|
name: "jsenv:workers_type_module_as_classic",
|
|
23
23
|
appliesDuring: "*",
|
|
24
|
-
|
|
24
|
+
redirectUrl: {
|
|
25
25
|
js_url_specifier: (reference, context) => {
|
|
26
26
|
if (reference.expectedType !== "js_module") {
|
|
27
27
|
return null
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { getBabelHelperFileUrl, requireBabelPlugin } from "@jsenv/babel-plugins"
|
|
2
2
|
import { babelPluginCompatMap } from "./babel_plugins_compatibility.js"
|
|
3
3
|
|
|
4
|
-
export const getBaseBabelPluginStructure = ({
|
|
4
|
+
export const getBaseBabelPluginStructure = ({
|
|
5
|
+
url,
|
|
6
|
+
isSupported,
|
|
7
|
+
// isJsModule,
|
|
8
|
+
// getImportSpecifier,
|
|
9
|
+
}) => {
|
|
5
10
|
const isBabelPluginNeeded = (babelPluginName) => {
|
|
6
11
|
return !isSupported(babelPluginCompatMap[babelPluginName])
|
|
7
12
|
}
|
|
@@ -35,6 +40,12 @@ export const getBaseBabelPluginStructure = ({ url, isSupported }) => {
|
|
|
35
40
|
requireBabelPlugin("babel-plugin-transform-async-to-promises"),
|
|
36
41
|
{
|
|
37
42
|
topLevelAwait: "ignore", // will be handled by "jsenv:top_level_await" plugin
|
|
43
|
+
externalHelpers: false,
|
|
44
|
+
// enable once https://github.com/rpetrich/babel-plugin-transform-async-to-promises/pull/83
|
|
45
|
+
// externalHelpers: isJsModule,
|
|
46
|
+
// externalHelpersPath: isJsModule ? getImportSpecifier(
|
|
47
|
+
// "babel-plugin-transform-async-to-promises/helpers.mjs",
|
|
48
|
+
// ) : null
|
|
38
49
|
},
|
|
39
50
|
]
|
|
40
51
|
}
|
|
@@ -33,27 +33,29 @@ export const jsenvPluginBabel = ({ getCustomBabelPlugins } = {}) => {
|
|
|
33
33
|
)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const { referenceUtils } = context
|
|
37
36
|
const isSupported = (feature) =>
|
|
38
37
|
RUNTIME_COMPAT.isSupported(clientRuntimeCompat, feature)
|
|
38
|
+
const getImportSpecifier = (clientFileUrl) => {
|
|
39
|
+
const [reference] = context.referenceUtils.inject({
|
|
40
|
+
type: "js_import_export",
|
|
41
|
+
expectedType: "js_module",
|
|
42
|
+
specifier: clientFileUrl,
|
|
43
|
+
})
|
|
44
|
+
return JSON.parse(reference.generatedSpecifier)
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
const babelPluginStructure = getBaseBabelPluginStructure({
|
|
40
48
|
url: urlInfo.url,
|
|
41
49
|
isSupported,
|
|
42
50
|
isWorkerContext,
|
|
51
|
+
isJsModule,
|
|
52
|
+
getImportSpecifier,
|
|
43
53
|
})
|
|
44
54
|
if (getCustomBabelPlugins) {
|
|
45
55
|
Object.assign(babelPluginStructure, getCustomBabelPlugins(context))
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
if (isJsModule) {
|
|
49
|
-
const getImportSpecifier = (clientFileUrl) => {
|
|
50
|
-
const [reference] = referenceUtils.inject({
|
|
51
|
-
type: "js_import_export",
|
|
52
|
-
expectedType: "js_module",
|
|
53
|
-
specifier: clientFileUrl,
|
|
54
|
-
})
|
|
55
|
-
return JSON.parse(reference.generatedSpecifier)
|
|
56
|
-
}
|
|
57
59
|
if (!isSupported("global_this")) {
|
|
58
60
|
babelPluginStructure["global-this-as-jsenv-import"] = [
|
|
59
61
|
babelPluginGlobalThisAsJsenvImport,
|
|
@@ -27,16 +27,16 @@ export const jsenvPluginImportAssertions = () => {
|
|
|
27
27
|
end: reference.assertNode.end,
|
|
28
28
|
})
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
return injectQueryParams(reference.url, {
|
|
30
|
+
const newUrl = injectQueryParams(reference.url, {
|
|
32
31
|
[searchParam]: "",
|
|
33
32
|
})
|
|
33
|
+
return newUrl
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const importAssertions = {
|
|
37
37
|
name: "jsenv:import_assertions",
|
|
38
38
|
appliesDuring: "*",
|
|
39
|
-
|
|
39
|
+
redirectUrl: {
|
|
40
40
|
js_import_export: (reference, context) => {
|
|
41
41
|
if (!reference.assert) {
|
|
42
42
|
return null
|
|
@@ -24,6 +24,16 @@ export const jsenvPluginTopLevelAwait = () => {
|
|
|
24
24
|
// Maybe we could pass target: "es6" when we support arrow function
|
|
25
25
|
// https://github.com/rpetrich/babel-plugin-transform-async-to-promises/blob/92755ff8c943c97596523e586b5fa515c2e99326/async-to-promises.ts#L55
|
|
26
26
|
topLevelAwait: "simple",
|
|
27
|
+
// enable once https://github.com/rpetrich/babel-plugin-transform-async-to-promises/pull/83
|
|
28
|
+
// externalHelpers: true,
|
|
29
|
+
// externalHelpersPath: JSON.parse(
|
|
30
|
+
// context.referenceUtils.inject({
|
|
31
|
+
// type: "js_import_export",
|
|
32
|
+
// expectedType: "js_module",
|
|
33
|
+
// specifier:
|
|
34
|
+
// "babel-plugin-transform-async-to-promises/helpers.mjs",
|
|
35
|
+
// })[0],
|
|
36
|
+
// ),
|
|
27
37
|
},
|
|
28
38
|
],
|
|
29
39
|
],
|
|
@@ -96,8 +96,8 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
96
96
|
...readFetchMetas(node),
|
|
97
97
|
})
|
|
98
98
|
}
|
|
99
|
-
const
|
|
100
|
-
|
|
99
|
+
const visitors = {
|
|
100
|
+
link: (node) => {
|
|
101
101
|
const relAttribute = getHtmlNodeAttributeByName(node, "rel")
|
|
102
102
|
const rel = relAttribute ? relAttribute.value : undefined
|
|
103
103
|
const typeAttribute = getHtmlNodeAttributeByName(node, "type")
|
|
@@ -114,13 +114,9 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
114
114
|
stylesheet: "css",
|
|
115
115
|
}[rel],
|
|
116
116
|
})
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// // styles.push(node)
|
|
121
|
-
// return
|
|
122
|
-
// }
|
|
123
|
-
if (node.nodeName === "script") {
|
|
117
|
+
},
|
|
118
|
+
// style: () => {},
|
|
119
|
+
script: (node) => {
|
|
124
120
|
const typeAttributeNode = getHtmlNodeAttributeByName(node, "type")
|
|
125
121
|
visitAttributeAsUrlSpecifier({
|
|
126
122
|
type: "script_src",
|
|
@@ -133,23 +129,22 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
133
129
|
node,
|
|
134
130
|
attributeName: "src",
|
|
135
131
|
})
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (node.nodeName === "a") {
|
|
132
|
+
},
|
|
133
|
+
a: (node) => {
|
|
139
134
|
visitAttributeAsUrlSpecifier({
|
|
140
135
|
type: "a_href",
|
|
141
136
|
node,
|
|
142
137
|
attributeName: "href",
|
|
143
138
|
})
|
|
144
|
-
}
|
|
145
|
-
|
|
139
|
+
},
|
|
140
|
+
iframe: (node) => {
|
|
146
141
|
visitAttributeAsUrlSpecifier({
|
|
147
142
|
type: "iframe_src",
|
|
148
143
|
node,
|
|
149
144
|
attributeName: "src",
|
|
150
145
|
})
|
|
151
|
-
}
|
|
152
|
-
|
|
146
|
+
},
|
|
147
|
+
img: (node) => {
|
|
153
148
|
visitAttributeAsUrlSpecifier({
|
|
154
149
|
type: "img_src",
|
|
155
150
|
node,
|
|
@@ -159,9 +154,8 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
159
154
|
type: "img_srcset",
|
|
160
155
|
node,
|
|
161
156
|
})
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (node.nodeName === "source") {
|
|
157
|
+
},
|
|
158
|
+
souce: (node) => {
|
|
165
159
|
visitAttributeAsUrlSpecifier({
|
|
166
160
|
type: "source_src",
|
|
167
161
|
node,
|
|
@@ -171,25 +165,22 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
171
165
|
type: "source_srcset",
|
|
172
166
|
node,
|
|
173
167
|
})
|
|
174
|
-
|
|
175
|
-
}
|
|
168
|
+
},
|
|
176
169
|
// svg <image> tag
|
|
177
|
-
|
|
170
|
+
image: (node) => {
|
|
178
171
|
visitAttributeAsUrlSpecifier({
|
|
179
172
|
type: "image_href",
|
|
180
173
|
node,
|
|
181
174
|
attributeName: "href",
|
|
182
175
|
})
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (node.nodeName === "use") {
|
|
176
|
+
},
|
|
177
|
+
use: (node) => {
|
|
186
178
|
visitAttributeAsUrlSpecifier({
|
|
187
179
|
type: "use_href",
|
|
188
180
|
node,
|
|
189
181
|
attributeName: "href",
|
|
190
182
|
})
|
|
191
|
-
|
|
192
|
-
}
|
|
183
|
+
},
|
|
193
184
|
}
|
|
194
185
|
const visitAttributeAsUrlSpecifier = ({
|
|
195
186
|
type,
|
|
@@ -252,7 +243,12 @@ const visitHtmlUrls = ({ url, htmlAst, onUrl }) => {
|
|
|
252
243
|
})
|
|
253
244
|
}
|
|
254
245
|
}
|
|
255
|
-
visitHtmlAst(htmlAst,
|
|
246
|
+
visitHtmlAst(htmlAst, (node) => {
|
|
247
|
+
const visitor = visitors[node.nodeName]
|
|
248
|
+
if (visitor) {
|
|
249
|
+
visitor(node)
|
|
250
|
+
}
|
|
251
|
+
})
|
|
256
252
|
}
|
|
257
253
|
|
|
258
254
|
const crossOriginCompatibleTagNames = ["script", "link", "img", "source"]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export const jsenvPluginUrlVersion = (
|
|
1
|
+
export const jsenvPluginUrlVersion = () => {
|
|
2
2
|
return {
|
|
3
3
|
name: "jsenv:url_version",
|
|
4
|
-
appliesDuring: "*",
|
|
5
|
-
|
|
4
|
+
appliesDuring: "*",
|
|
5
|
+
redirectUrl: (reference) => {
|
|
6
6
|
// "v" search param goal is to enable long-term cache
|
|
7
7
|
// for server response headers
|
|
8
8
|
// it is also used by hmr to bypass browser cache
|
|
@@ -24,24 +24,5 @@ export const jsenvPluginUrlVersion = ({ longTermCache = true } = {}) => {
|
|
|
24
24
|
v: reference.data.version,
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
augmentResponse: ({ reference }) => {
|
|
28
|
-
if (!longTermCache) {
|
|
29
|
-
return null
|
|
30
|
-
}
|
|
31
|
-
if (!reference.searchParams.has("v")) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
if (reference.searchParams.has("hmr")) {
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
// When url is versioned put it in browser cache for 30 days
|
|
38
|
-
return {
|
|
39
|
-
headers: {
|
|
40
|
-
"cache-control": `private,max-age=${SECONDS_IN_30_DAYS},immutable`,
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
27
|
}
|
|
45
28
|
}
|
|
46
|
-
|
|
47
|
-
const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30
|