@jsenv/core 28.2.3 → 28.3.3
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/main.js +118 -88
- package/package.json +1 -1
- package/src/helpers/replace_placeholders.js +15 -0
- package/src/main.js +1 -0
- package/src/omega/kitchen.js +19 -27
- package/src/omega/server/file_service.js +30 -13
- package/src/omega/url_graph/url_info_transformations.js +50 -47
- package/src/plugins/importmap/jsenv_plugin_importmap.js +3 -2
package/dist/main.js
CHANGED
|
@@ -11940,7 +11940,7 @@ const jsenvPluginImportmap = () => {
|
|
|
11940
11940
|
// We must precook the importmap to know its content and inline it into the HTML
|
|
11941
11941
|
// In this situation the ref to the importmap was already discovered
|
|
11942
11942
|
// when parsing the HTML
|
|
11943
|
-
const importmapReference = context.referenceUtils.
|
|
11943
|
+
const importmapReference = context.referenceUtils.find(ref => ref.generatedSpecifier === src);
|
|
11944
11944
|
const importmapUrlInfo = context.urlGraph.getUrlInfo(importmapReference.url);
|
|
11945
11945
|
await context.cook(importmapUrlInfo, {
|
|
11946
11946
|
reference: importmapReference
|
|
@@ -17800,7 +17800,7 @@ const createUrlInfoTransformer = ({
|
|
|
17800
17800
|
// jsenv won't emit a warning and use the following strategy:
|
|
17801
17801
|
// "no sourcemap is better than wrong sourcemap"
|
|
17802
17802
|
|
|
17803
|
-
urlInfo.sourcemapIsWrong = sourcemapIsWrong;
|
|
17803
|
+
urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
|
|
17804
17804
|
}
|
|
17805
17805
|
};
|
|
17806
17806
|
|
|
@@ -17809,52 +17809,54 @@ const createUrlInfoTransformer = ({
|
|
|
17809
17809
|
applyIntermediateTransformations(urlInfo, transformations);
|
|
17810
17810
|
}
|
|
17811
17811
|
|
|
17812
|
-
if (
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17812
|
+
if (urlInfo.sourcemapReference) {
|
|
17813
|
+
if (sourcemapsEnabled && urlInfo.sourcemap && !urlInfo.generatedUrl.startsWith("data:")) {
|
|
17814
|
+
// during build this function can be called after the file is cooked
|
|
17815
|
+
// - to update content and sourcemap after "optimize" hook
|
|
17816
|
+
// - to inject versioning into the entry point content
|
|
17817
|
+
// in this scenarion we don't want to call injectSourcemap
|
|
17818
|
+
// just update the content and the
|
|
17819
|
+
const sourcemapReference = urlInfo.sourcemapReference;
|
|
17820
|
+
const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url);
|
|
17821
|
+
sourcemapUrlInfo.contentType = "application/json";
|
|
17822
|
+
const sourcemap = urlInfo.sourcemap;
|
|
17823
|
+
|
|
17824
|
+
if (sourcemapsRelativeSources) {
|
|
17825
|
+
sourcemap.sources = sourcemap.sources.map(source => {
|
|
17826
|
+
const sourceRelative = urlToRelativeUrl(source, urlInfo.url);
|
|
17827
|
+
return sourceRelative || ".";
|
|
17828
|
+
});
|
|
17829
|
+
}
|
|
17829
17830
|
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
|
|
17831
|
+
if (sourcemapsSourcesProtocol !== "file:///") {
|
|
17832
|
+
sourcemap.sources = sourcemap.sources.map(source => {
|
|
17833
|
+
if (source.startsWith("file:///")) {
|
|
17834
|
+
return `${sourcemapsSourcesProtocol}${source.slice("file:///".length)}`;
|
|
17835
|
+
}
|
|
17835
17836
|
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
|
|
17837
|
+
return source;
|
|
17838
|
+
});
|
|
17839
|
+
}
|
|
17839
17840
|
|
|
17840
|
-
|
|
17841
|
+
sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
|
|
17841
17842
|
|
|
17842
|
-
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17843
|
+
if (!urlInfo.sourcemapIsWrong) {
|
|
17844
|
+
if (sourcemaps === "inline") {
|
|
17845
|
+
sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
|
|
17846
|
+
}
|
|
17846
17847
|
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
|
|
17848
|
+
if (sourcemaps === "file" || sourcemaps === "inline") {
|
|
17849
|
+
urlInfo.content = SOURCEMAP.writeComment({
|
|
17850
|
+
contentType: urlInfo.contentType,
|
|
17851
|
+
content: urlInfo.content,
|
|
17852
|
+
specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
|
|
17853
|
+
});
|
|
17854
|
+
}
|
|
17853
17855
|
}
|
|
17856
|
+
} else {
|
|
17857
|
+
// in the end we don't use the sourcemap placeholder
|
|
17858
|
+
urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
|
|
17854
17859
|
}
|
|
17855
|
-
} else if (urlInfo.sourcemapReference) {
|
|
17856
|
-
// in the end we don't use the sourcemap placeholder
|
|
17857
|
-
urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
|
|
17858
17860
|
}
|
|
17859
17861
|
|
|
17860
17862
|
urlInfo.contentEtag = urlInfo.content === urlInfo.originalContent ? urlInfo.originalContentEtag : bufferToEtag$1(Buffer.from(urlInfo.content));
|
|
@@ -18632,6 +18634,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
18632
18634
|
const references = [];
|
|
18633
18635
|
context.referenceUtils = {
|
|
18634
18636
|
_references: references,
|
|
18637
|
+
find: predicate => references.find(predicate),
|
|
18638
|
+
readGeneratedSpecifier,
|
|
18635
18639
|
add: props => {
|
|
18636
18640
|
const [reference, referencedUrlInfo] = resolveReference(createReference({
|
|
18637
18641
|
parentUrl: urlInfo.url,
|
|
@@ -18640,8 +18644,6 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
18640
18644
|
references.push(reference);
|
|
18641
18645
|
return [reference, referencedUrlInfo];
|
|
18642
18646
|
},
|
|
18643
|
-
find: predicate => references.find(predicate),
|
|
18644
|
-
readGeneratedSpecifier,
|
|
18645
18647
|
found: ({
|
|
18646
18648
|
trace,
|
|
18647
18649
|
...rest
|
|
@@ -18703,6 +18705,29 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
18703
18705
|
|
|
18704
18706
|
return [newReference, newUrlInfo];
|
|
18705
18707
|
},
|
|
18708
|
+
inject: ({
|
|
18709
|
+
trace,
|
|
18710
|
+
...rest
|
|
18711
|
+
}) => {
|
|
18712
|
+
if (trace === undefined) {
|
|
18713
|
+
const {
|
|
18714
|
+
url,
|
|
18715
|
+
line,
|
|
18716
|
+
column
|
|
18717
|
+
} = getCallerPosition();
|
|
18718
|
+
trace = traceFromUrlSite({
|
|
18719
|
+
url,
|
|
18720
|
+
line,
|
|
18721
|
+
column
|
|
18722
|
+
});
|
|
18723
|
+
}
|
|
18724
|
+
|
|
18725
|
+
return context.referenceUtils.add({
|
|
18726
|
+
trace,
|
|
18727
|
+
injected: true,
|
|
18728
|
+
...rest
|
|
18729
|
+
});
|
|
18730
|
+
},
|
|
18706
18731
|
becomesInline: (reference, {
|
|
18707
18732
|
isOriginalPosition,
|
|
18708
18733
|
specifier,
|
|
@@ -18729,37 +18754,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
18729
18754
|
content
|
|
18730
18755
|
});
|
|
18731
18756
|
},
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
...rest
|
|
18735
|
-
}) => {
|
|
18736
|
-
if (trace === undefined) {
|
|
18737
|
-
const {
|
|
18738
|
-
url,
|
|
18739
|
-
line,
|
|
18740
|
-
column
|
|
18741
|
-
} = getCallerPosition();
|
|
18742
|
-
trace = traceFromUrlSite({
|
|
18743
|
-
url,
|
|
18744
|
-
line,
|
|
18745
|
-
column
|
|
18746
|
-
});
|
|
18747
|
-
}
|
|
18748
|
-
|
|
18749
|
-
return context.referenceUtils.add({
|
|
18750
|
-
trace,
|
|
18751
|
-
injected: true,
|
|
18752
|
-
...rest
|
|
18753
|
-
});
|
|
18754
|
-
},
|
|
18755
|
-
findByGeneratedSpecifier: generatedSpecifier => {
|
|
18756
|
-
const reference = references.find(ref => ref.generatedSpecifier === generatedSpecifier);
|
|
18757
|
-
|
|
18758
|
-
if (!reference) {
|
|
18759
|
-
throw new Error(`No reference found using the following generatedSpecifier: "${generatedSpecifier}"`);
|
|
18760
|
-
}
|
|
18761
|
-
|
|
18762
|
-
return reference;
|
|
18757
|
+
becomesExternal: () => {
|
|
18758
|
+
throw new Error("not implemented yet");
|
|
18763
18759
|
}
|
|
18764
18760
|
}; // "fetchUrlContent" hook
|
|
18765
18761
|
|
|
@@ -25305,11 +25301,17 @@ const createFileService = ({
|
|
|
25305
25301
|
clientFileChangeCallbackList.push(({
|
|
25306
25302
|
url
|
|
25307
25303
|
}) => {
|
|
25308
|
-
|
|
25304
|
+
urlGraph.urlInfoMap.forEach(urlInfo => {
|
|
25305
|
+
if (urlInfo.url === url) {
|
|
25306
|
+
urlGraph.considerModified(urlInfo);
|
|
25307
|
+
} else {
|
|
25308
|
+
const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url);
|
|
25309
25309
|
|
|
25310
|
-
|
|
25311
|
-
|
|
25312
|
-
|
|
25310
|
+
if (urlWithoutSearch === url) {
|
|
25311
|
+
urlGraph.considerModified(urlInfo);
|
|
25312
|
+
}
|
|
25313
|
+
}
|
|
25314
|
+
});
|
|
25313
25315
|
});
|
|
25314
25316
|
const kitchen = createKitchen({
|
|
25315
25317
|
signal,
|
|
@@ -25486,22 +25488,30 @@ const createFileService = ({
|
|
|
25486
25488
|
const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo);
|
|
25487
25489
|
|
|
25488
25490
|
if (ifNoneMatch) {
|
|
25489
|
-
|
|
25491
|
+
const [clientOriginalContentEtag, clientContentEtag] = ifNoneMatch.split("_");
|
|
25492
|
+
|
|
25493
|
+
if (urlInfoTargetedByCache.originalContentEtag === clientOriginalContentEtag && urlInfoTargetedByCache.contentEtag === clientContentEtag && urlInfoTargetedByCache.isValid()) {
|
|
25494
|
+
const headers = {
|
|
25495
|
+
"cache-control": `private,max-age=0,must-revalidate`
|
|
25496
|
+
};
|
|
25497
|
+
Object.keys(urlInfo.headers).forEach(key => {
|
|
25498
|
+
if (key !== "content-length") {
|
|
25499
|
+
headers[key] = urlInfo.headers[key];
|
|
25500
|
+
}
|
|
25501
|
+
});
|
|
25490
25502
|
return {
|
|
25491
25503
|
status: 304,
|
|
25492
|
-
headers
|
|
25493
|
-
"cache-control": `private,max-age=0,must-revalidate`,
|
|
25494
|
-
...urlInfo.headers
|
|
25495
|
-
}
|
|
25504
|
+
headers
|
|
25496
25505
|
};
|
|
25497
25506
|
}
|
|
25498
25507
|
}
|
|
25499
25508
|
|
|
25500
25509
|
try {
|
|
25501
25510
|
// urlInfo objects are reused, they must be "reset" before cooking them again
|
|
25502
|
-
if (urlInfo.contentEtag && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
|
|
25511
|
+
if ((urlInfo.error || urlInfo.contentEtag) && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
|
|
25503
25512
|
urlInfo.error = null;
|
|
25504
25513
|
urlInfo.sourcemap = null;
|
|
25514
|
+
urlInfo.sourcemapIsWrong = null;
|
|
25505
25515
|
urlInfo.sourcemapReference = null;
|
|
25506
25516
|
urlInfo.content = null;
|
|
25507
25517
|
urlInfo.originalContent = null;
|
|
@@ -25526,11 +25536,12 @@ const createFileService = ({
|
|
|
25526
25536
|
url: reference.url,
|
|
25527
25537
|
status: 200,
|
|
25528
25538
|
headers: {
|
|
25529
|
-
"content-length": Buffer.byteLength(urlInfo.content),
|
|
25530
25539
|
"cache-control": `private,max-age=0,must-revalidate`,
|
|
25531
|
-
"
|
|
25540
|
+
// it's safe to use "_" separator because etag is encoded with base64 (see https://stackoverflow.com/a/13195197)
|
|
25541
|
+
"eTag": `${urlInfoTargetedByCache.originalContentEtag}_${urlInfoTargetedByCache.contentEtag}`,
|
|
25532
25542
|
...urlInfo.headers,
|
|
25533
|
-
"content-type": urlInfo.contentType
|
|
25543
|
+
"content-type": urlInfo.contentType,
|
|
25544
|
+
"content-length": Buffer.byteLength(urlInfo.content)
|
|
25534
25545
|
},
|
|
25535
25546
|
body: urlInfo.content,
|
|
25536
25547
|
timing: urlInfo.timing
|
|
@@ -29611,6 +29622,25 @@ const createBuildFilesService = ({
|
|
|
29611
29622
|
|
|
29612
29623
|
const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
|
|
29613
29624
|
|
|
29625
|
+
const replacePlaceholders = (content, replacements) => {
|
|
29626
|
+
const magicSource = createMagicSource(content);
|
|
29627
|
+
Object.keys(replacements).forEach(key => {
|
|
29628
|
+
let index = content.indexOf(key);
|
|
29629
|
+
|
|
29630
|
+
while (index !== -1) {
|
|
29631
|
+
const start = index;
|
|
29632
|
+
const end = index + key.length;
|
|
29633
|
+
magicSource.replace({
|
|
29634
|
+
start,
|
|
29635
|
+
end,
|
|
29636
|
+
replacement: replacements[key]
|
|
29637
|
+
});
|
|
29638
|
+
index = content.indexOf(key, end);
|
|
29639
|
+
}
|
|
29640
|
+
});
|
|
29641
|
+
return magicSource.toContentAndSourcemap();
|
|
29642
|
+
};
|
|
29643
|
+
|
|
29614
29644
|
const execute = async ({
|
|
29615
29645
|
signal = new AbortController().signal,
|
|
29616
29646
|
handleSIGINT = true,
|
|
@@ -29783,4 +29813,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
|
|
|
29783
29813
|
};
|
|
29784
29814
|
};
|
|
29785
29815
|
|
|
29786
|
-
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|
|
29816
|
+
export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, replacePlaceholders, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createMagicSource } from "@jsenv/sourcemap"
|
|
2
|
+
|
|
3
|
+
export const replacePlaceholders = (content, replacements) => {
|
|
4
|
+
const magicSource = createMagicSource(content)
|
|
5
|
+
Object.keys(replacements).forEach((key) => {
|
|
6
|
+
let index = content.indexOf(key)
|
|
7
|
+
while (index !== -1) {
|
|
8
|
+
const start = index
|
|
9
|
+
const end = index + key.length
|
|
10
|
+
magicSource.replace({ start, end, replacement: replacements[key] })
|
|
11
|
+
index = content.indexOf(key, end)
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
return magicSource.toContentAndSourcemap()
|
|
15
|
+
}
|
package/src/main.js
CHANGED
|
@@ -23,6 +23,7 @@ export { startBuildServer } from "./build/start_build_server.js"
|
|
|
23
23
|
|
|
24
24
|
// helpers
|
|
25
25
|
export { pingServer } from "./ping_server.js"
|
|
26
|
+
export { replacePlaceholders } from "./helpers/replace_placeholders.js"
|
|
26
27
|
|
|
27
28
|
// advanced
|
|
28
29
|
export { execute } from "./execute/execute.js"
|
package/src/omega/kitchen.js
CHANGED
|
@@ -429,6 +429,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
429
429
|
const references = []
|
|
430
430
|
context.referenceUtils = {
|
|
431
431
|
_references: references,
|
|
432
|
+
find: (predicate) => references.find(predicate),
|
|
433
|
+
readGeneratedSpecifier,
|
|
432
434
|
add: (props) => {
|
|
433
435
|
const [reference, referencedUrlInfo] = resolveReference(
|
|
434
436
|
createReference({
|
|
@@ -440,8 +442,6 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
440
442
|
references.push(reference)
|
|
441
443
|
return [reference, referencedUrlInfo]
|
|
442
444
|
},
|
|
443
|
-
find: (predicate) => references.find(predicate),
|
|
444
|
-
readGeneratedSpecifier,
|
|
445
445
|
found: ({ trace, ...rest }) => {
|
|
446
446
|
if (trace === undefined) {
|
|
447
447
|
trace = traceFromUrlSite(
|
|
@@ -511,6 +511,21 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
511
511
|
}
|
|
512
512
|
return [newReference, newUrlInfo]
|
|
513
513
|
},
|
|
514
|
+
inject: ({ trace, ...rest }) => {
|
|
515
|
+
if (trace === undefined) {
|
|
516
|
+
const { url, line, column } = getCallerPosition()
|
|
517
|
+
trace = traceFromUrlSite({
|
|
518
|
+
url,
|
|
519
|
+
line,
|
|
520
|
+
column,
|
|
521
|
+
})
|
|
522
|
+
}
|
|
523
|
+
return context.referenceUtils.add({
|
|
524
|
+
trace,
|
|
525
|
+
injected: true,
|
|
526
|
+
...rest,
|
|
527
|
+
})
|
|
528
|
+
},
|
|
514
529
|
becomesInline: (
|
|
515
530
|
reference,
|
|
516
531
|
{
|
|
@@ -544,31 +559,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
544
559
|
content,
|
|
545
560
|
})
|
|
546
561
|
},
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const { url, line, column } = getCallerPosition()
|
|
550
|
-
trace = traceFromUrlSite({
|
|
551
|
-
url,
|
|
552
|
-
line,
|
|
553
|
-
column,
|
|
554
|
-
})
|
|
555
|
-
}
|
|
556
|
-
return context.referenceUtils.add({
|
|
557
|
-
trace,
|
|
558
|
-
injected: true,
|
|
559
|
-
...rest,
|
|
560
|
-
})
|
|
561
|
-
},
|
|
562
|
-
findByGeneratedSpecifier: (generatedSpecifier) => {
|
|
563
|
-
const reference = references.find(
|
|
564
|
-
(ref) => ref.generatedSpecifier === generatedSpecifier,
|
|
565
|
-
)
|
|
566
|
-
if (!reference) {
|
|
567
|
-
throw new Error(
|
|
568
|
-
`No reference found using the following generatedSpecifier: "${generatedSpecifier}"`,
|
|
569
|
-
)
|
|
570
|
-
}
|
|
571
|
-
return reference
|
|
562
|
+
becomesExternal: () => {
|
|
563
|
+
throw new Error("not implemented yet")
|
|
572
564
|
},
|
|
573
565
|
}
|
|
574
566
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
composeTwoResponses,
|
|
6
6
|
} from "@jsenv/server"
|
|
7
7
|
import { registerDirectoryLifecycle, bufferToEtag } from "@jsenv/filesystem"
|
|
8
|
-
import { urlIsInsideOf, moveUrl } from "@jsenv/urls"
|
|
8
|
+
import { urlIsInsideOf, moveUrl, asUrlWithoutSearch } from "@jsenv/urls"
|
|
9
9
|
import { URL_META } from "@jsenv/url-meta"
|
|
10
10
|
|
|
11
11
|
import { getCorePlugins } from "@jsenv/core/src/plugins/plugins.js"
|
|
@@ -95,10 +95,16 @@ export const createFileService = ({
|
|
|
95
95
|
)
|
|
96
96
|
const urlGraph = createUrlGraph()
|
|
97
97
|
clientFileChangeCallbackList.push(({ url }) => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
urlGraph.urlInfoMap.forEach((urlInfo) => {
|
|
99
|
+
if (urlInfo.url === url) {
|
|
100
|
+
urlGraph.considerModified(urlInfo)
|
|
101
|
+
} else {
|
|
102
|
+
const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url)
|
|
103
|
+
if (urlWithoutSearch === url) {
|
|
104
|
+
urlGraph.considerModified(urlInfo)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})
|
|
102
108
|
})
|
|
103
109
|
const kitchen = createKitchen({
|
|
104
110
|
signal,
|
|
@@ -264,28 +270,38 @@ export const createFileService = ({
|
|
|
264
270
|
const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo)
|
|
265
271
|
|
|
266
272
|
if (ifNoneMatch) {
|
|
273
|
+
const [clientOriginalContentEtag, clientContentEtag] =
|
|
274
|
+
ifNoneMatch.split("_")
|
|
267
275
|
if (
|
|
268
|
-
urlInfoTargetedByCache.
|
|
276
|
+
urlInfoTargetedByCache.originalContentEtag ===
|
|
277
|
+
clientOriginalContentEtag &&
|
|
278
|
+
urlInfoTargetedByCache.contentEtag === clientContentEtag &&
|
|
269
279
|
urlInfoTargetedByCache.isValid()
|
|
270
280
|
) {
|
|
281
|
+
const headers = {
|
|
282
|
+
"cache-control": `private,max-age=0,must-revalidate`,
|
|
283
|
+
}
|
|
284
|
+
Object.keys(urlInfo.headers).forEach((key) => {
|
|
285
|
+
if (key !== "content-length") {
|
|
286
|
+
headers[key] = urlInfo.headers[key]
|
|
287
|
+
}
|
|
288
|
+
})
|
|
271
289
|
return {
|
|
272
290
|
status: 304,
|
|
273
|
-
headers
|
|
274
|
-
"cache-control": `private,max-age=0,must-revalidate`,
|
|
275
|
-
...urlInfo.headers,
|
|
276
|
-
},
|
|
291
|
+
headers,
|
|
277
292
|
}
|
|
278
293
|
}
|
|
279
294
|
}
|
|
280
295
|
try {
|
|
281
296
|
// urlInfo objects are reused, they must be "reset" before cooking them again
|
|
282
297
|
if (
|
|
283
|
-
urlInfo.contentEtag &&
|
|
298
|
+
(urlInfo.error || urlInfo.contentEtag) &&
|
|
284
299
|
!urlInfo.isInline &&
|
|
285
300
|
urlInfo.type !== "sourcemap"
|
|
286
301
|
) {
|
|
287
302
|
urlInfo.error = null
|
|
288
303
|
urlInfo.sourcemap = null
|
|
304
|
+
urlInfo.sourcemapIsWrong = null
|
|
289
305
|
urlInfo.sourcemapReference = null
|
|
290
306
|
urlInfo.content = null
|
|
291
307
|
urlInfo.originalContent = null
|
|
@@ -305,11 +321,12 @@ export const createFileService = ({
|
|
|
305
321
|
url: reference.url,
|
|
306
322
|
status: 200,
|
|
307
323
|
headers: {
|
|
308
|
-
"content-length": Buffer.byteLength(urlInfo.content),
|
|
309
324
|
"cache-control": `private,max-age=0,must-revalidate`,
|
|
310
|
-
"
|
|
325
|
+
// it's safe to use "_" separator because etag is encoded with base64 (see https://stackoverflow.com/a/13195197)
|
|
326
|
+
"eTag": `${urlInfoTargetedByCache.originalContentEtag}_${urlInfoTargetedByCache.contentEtag}`,
|
|
311
327
|
...urlInfo.headers,
|
|
312
328
|
"content-type": urlInfo.contentType,
|
|
329
|
+
"content-length": Buffer.byteLength(urlInfo.content),
|
|
313
330
|
},
|
|
314
331
|
body: urlInfo.content,
|
|
315
332
|
timing: urlInfo.timing,
|
|
@@ -164,7 +164,7 @@ export const createUrlInfoTransformer = ({
|
|
|
164
164
|
// is a nightmare no-one could solve in years so
|
|
165
165
|
// jsenv won't emit a warning and use the following strategy:
|
|
166
166
|
// "no sourcemap is better than wrong sourcemap"
|
|
167
|
-
urlInfo.sourcemapIsWrong = sourcemapIsWrong
|
|
167
|
+
urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -172,57 +172,60 @@ export const createUrlInfoTransformer = ({
|
|
|
172
172
|
if (transformations) {
|
|
173
173
|
applyIntermediateTransformations(urlInfo, transformations)
|
|
174
174
|
}
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (sourcemapsSourcesProtocol !== "file:///") {
|
|
196
|
-
sourcemap.sources = sourcemap.sources.map((source) => {
|
|
197
|
-
if (source.startsWith("file:///")) {
|
|
198
|
-
return `${sourcemapsSourcesProtocol}${source.slice(
|
|
199
|
-
"file:///".length,
|
|
200
|
-
)}`
|
|
201
|
-
}
|
|
202
|
-
return source
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ")
|
|
206
|
-
if (!urlInfo.sourcemapIsWrong) {
|
|
207
|
-
if (sourcemaps === "inline") {
|
|
208
|
-
sourcemapReference.generatedSpecifier =
|
|
209
|
-
generateSourcemapDataUrl(sourcemap)
|
|
175
|
+
if (urlInfo.sourcemapReference) {
|
|
176
|
+
if (
|
|
177
|
+
sourcemapsEnabled &&
|
|
178
|
+
urlInfo.sourcemap &&
|
|
179
|
+
!urlInfo.generatedUrl.startsWith("data:")
|
|
180
|
+
) {
|
|
181
|
+
// during build this function can be called after the file is cooked
|
|
182
|
+
// - to update content and sourcemap after "optimize" hook
|
|
183
|
+
// - to inject versioning into the entry point content
|
|
184
|
+
// in this scenarion we don't want to call injectSourcemap
|
|
185
|
+
// just update the content and the
|
|
186
|
+
const sourcemapReference = urlInfo.sourcemapReference
|
|
187
|
+
const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url)
|
|
188
|
+
sourcemapUrlInfo.contentType = "application/json"
|
|
189
|
+
const sourcemap = urlInfo.sourcemap
|
|
190
|
+
if (sourcemapsRelativeSources) {
|
|
191
|
+
sourcemap.sources = sourcemap.sources.map((source) => {
|
|
192
|
+
const sourceRelative = urlToRelativeUrl(source, urlInfo.url)
|
|
193
|
+
return sourceRelative || "."
|
|
194
|
+
})
|
|
210
195
|
}
|
|
211
|
-
if (
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
if (sourcemapsSourcesProtocol !== "file:///") {
|
|
197
|
+
sourcemap.sources = sourcemap.sources.map((source) => {
|
|
198
|
+
if (source.startsWith("file:///")) {
|
|
199
|
+
return `${sourcemapsSourcesProtocol}${source.slice(
|
|
200
|
+
"file:///".length,
|
|
201
|
+
)}`
|
|
202
|
+
}
|
|
203
|
+
return source
|
|
219
204
|
})
|
|
220
205
|
}
|
|
206
|
+
sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ")
|
|
207
|
+
if (!urlInfo.sourcemapIsWrong) {
|
|
208
|
+
if (sourcemaps === "inline") {
|
|
209
|
+
sourcemapReference.generatedSpecifier =
|
|
210
|
+
generateSourcemapDataUrl(sourcemap)
|
|
211
|
+
}
|
|
212
|
+
if (sourcemaps === "file" || sourcemaps === "inline") {
|
|
213
|
+
urlInfo.content = SOURCEMAP.writeComment({
|
|
214
|
+
contentType: urlInfo.contentType,
|
|
215
|
+
content: urlInfo.content,
|
|
216
|
+
specifier:
|
|
217
|
+
sourcemaps === "file" && sourcemapsRelativeSources
|
|
218
|
+
? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
|
|
219
|
+
: sourcemapReference.generatedSpecifier,
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
// in the end we don't use the sourcemap placeholder
|
|
225
|
+
urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url)
|
|
221
226
|
}
|
|
222
|
-
} else if (urlInfo.sourcemapReference) {
|
|
223
|
-
// in the end we don't use the sourcemap placeholder
|
|
224
|
-
urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url)
|
|
225
227
|
}
|
|
228
|
+
|
|
226
229
|
urlInfo.contentEtag =
|
|
227
230
|
urlInfo.content === urlInfo.originalContent
|
|
228
231
|
? urlInfo.originalContentEtag
|
|
@@ -148,8 +148,9 @@ export const jsenvPluginImportmap = () => {
|
|
|
148
148
|
// We must precook the importmap to know its content and inline it into the HTML
|
|
149
149
|
// In this situation the ref to the importmap was already discovered
|
|
150
150
|
// when parsing the HTML
|
|
151
|
-
const importmapReference =
|
|
152
|
-
|
|
151
|
+
const importmapReference = context.referenceUtils.find(
|
|
152
|
+
(ref) => ref.generatedSpecifier === src,
|
|
153
|
+
)
|
|
153
154
|
const importmapUrlInfo = context.urlGraph.getUrlInfo(
|
|
154
155
|
importmapReference.url,
|
|
155
156
|
)
|