@jsenv/core 28.3.0 → 28.3.4

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 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.findByGeneratedSpecifier(src);
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
@@ -16998,28 +16998,36 @@ const jsenvPluginAutoreloadServer = ({
16998
16998
  url,
16999
16999
  event
17000
17000
  }) => {
17001
- const urlInfo = urlGraph.getUrlInfo(url); // file not part of dependency graph
17001
+ const onUrlInfo = urlInfo => {
17002
+ const relativeUrl = formatUrlForClient(url);
17003
+ const hotUpdate = propagateUpdate(urlInfo);
17002
17004
 
17003
- if (!urlInfo) {
17004
- return;
17005
- }
17005
+ if (hotUpdate.declined) {
17006
+ notifyDeclined({
17007
+ cause: `${relativeUrl} ${event}`,
17008
+ reason: hotUpdate.reason,
17009
+ declinedBy: hotUpdate.declinedBy
17010
+ });
17011
+ } else {
17012
+ notifyAccepted({
17013
+ cause: `${relativeUrl} ${event}`,
17014
+ reason: hotUpdate.reason,
17015
+ instructions: hotUpdate.instructions
17016
+ });
17017
+ }
17018
+ };
17006
17019
 
17007
- const relativeUrl = formatUrlForClient(url);
17008
- const hotUpdate = propagateUpdate(urlInfo);
17020
+ urlGraph.urlInfoMap.forEach(urlInfo => {
17021
+ if (urlInfo.url === url) {
17022
+ onUrlInfo(urlInfo);
17023
+ } else {
17024
+ const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url);
17009
17025
 
17010
- if (hotUpdate.declined) {
17011
- notifyDeclined({
17012
- cause: `${relativeUrl} ${event}`,
17013
- reason: hotUpdate.reason,
17014
- declinedBy: hotUpdate.declinedBy
17015
- });
17016
- } else {
17017
- notifyAccepted({
17018
- cause: `${relativeUrl} ${event}`,
17019
- reason: hotUpdate.reason,
17020
- instructions: hotUpdate.instructions
17021
- });
17022
- }
17026
+ if (urlWithoutSearch === url) {
17027
+ onUrlInfo(urlInfo);
17028
+ }
17029
+ }
17030
+ });
17023
17031
  });
17024
17032
  clientFilesPruneCallbackList.push((prunedUrlInfos, firstUrlInfo) => {
17025
17033
  const mainHotUpdate = propagateUpdate(firstUrlInfo);
@@ -17800,7 +17808,7 @@ const createUrlInfoTransformer = ({
17800
17808
  // jsenv won't emit a warning and use the following strategy:
17801
17809
  // "no sourcemap is better than wrong sourcemap"
17802
17810
 
17803
- urlInfo.sourcemapIsWrong = sourcemapIsWrong;
17811
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
17804
17812
  }
17805
17813
  };
17806
17814
 
@@ -17809,52 +17817,54 @@ const createUrlInfoTransformer = ({
17809
17817
  applyIntermediateTransformations(urlInfo, transformations);
17810
17818
  }
17811
17819
 
17812
- if (sourcemapsEnabled && urlInfo.sourcemap && !urlInfo.generatedUrl.startsWith("data:")) {
17813
- // during build this function can be called after the file is cooked
17814
- // - to update content and sourcemap after "optimize" hook
17815
- // - to inject versioning into the entry point content
17816
- // in this scenarion we don't want to call injectSourcemap
17817
- // just update the content and the
17818
- const sourcemapReference = urlInfo.sourcemapReference;
17819
- const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url);
17820
- sourcemapUrlInfo.contentType = "application/json";
17821
- const sourcemap = urlInfo.sourcemap;
17822
-
17823
- if (sourcemapsRelativeSources) {
17824
- sourcemap.sources = sourcemap.sources.map(source => {
17825
- const sourceRelative = urlToRelativeUrl(source, urlInfo.url);
17826
- return sourceRelative || ".";
17827
- });
17828
- }
17820
+ if (urlInfo.sourcemapReference) {
17821
+ if (sourcemapsEnabled && urlInfo.sourcemap && !urlInfo.generatedUrl.startsWith("data:")) {
17822
+ // during build this function can be called after the file is cooked
17823
+ // - to update content and sourcemap after "optimize" hook
17824
+ // - to inject versioning into the entry point content
17825
+ // in this scenarion we don't want to call injectSourcemap
17826
+ // just update the content and the
17827
+ const sourcemapReference = urlInfo.sourcemapReference;
17828
+ const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url);
17829
+ sourcemapUrlInfo.contentType = "application/json";
17830
+ const sourcemap = urlInfo.sourcemap;
17831
+
17832
+ if (sourcemapsRelativeSources) {
17833
+ sourcemap.sources = sourcemap.sources.map(source => {
17834
+ const sourceRelative = urlToRelativeUrl(source, urlInfo.url);
17835
+ return sourceRelative || ".";
17836
+ });
17837
+ }
17829
17838
 
17830
- if (sourcemapsSourcesProtocol !== "file:///") {
17831
- sourcemap.sources = sourcemap.sources.map(source => {
17832
- if (source.startsWith("file:///")) {
17833
- return `${sourcemapsSourcesProtocol}${source.slice("file:///".length)}`;
17834
- }
17839
+ if (sourcemapsSourcesProtocol !== "file:///") {
17840
+ sourcemap.sources = sourcemap.sources.map(source => {
17841
+ if (source.startsWith("file:///")) {
17842
+ return `${sourcemapsSourcesProtocol}${source.slice("file:///".length)}`;
17843
+ }
17835
17844
 
17836
- return source;
17837
- });
17838
- }
17845
+ return source;
17846
+ });
17847
+ }
17839
17848
 
17840
- sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
17849
+ sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
17841
17850
 
17842
- if (!urlInfo.sourcemapIsWrong) {
17843
- if (sourcemaps === "inline") {
17844
- sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
17845
- }
17851
+ if (!urlInfo.sourcemapIsWrong) {
17852
+ if (sourcemaps === "inline") {
17853
+ sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
17854
+ }
17846
17855
 
17847
- if (sourcemaps === "file" || sourcemaps === "inline") {
17848
- urlInfo.content = SOURCEMAP.writeComment({
17849
- contentType: urlInfo.contentType,
17850
- content: urlInfo.content,
17851
- specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
17852
- });
17856
+ if (sourcemaps === "file" || sourcemaps === "inline") {
17857
+ urlInfo.content = SOURCEMAP.writeComment({
17858
+ contentType: urlInfo.contentType,
17859
+ content: urlInfo.content,
17860
+ specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
17861
+ });
17862
+ }
17853
17863
  }
17864
+ } else {
17865
+ // in the end we don't use the sourcemap placeholder
17866
+ urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
17854
17867
  }
17855
- } else if (urlInfo.sourcemapReference) {
17856
- // in the end we don't use the sourcemap placeholder
17857
- urlGraph.deleteUrlInfo(urlInfo.sourcemapReference.url);
17858
17868
  }
17859
17869
 
17860
17870
  urlInfo.contentEtag = urlInfo.content === urlInfo.originalContent ? urlInfo.originalContentEtag : bufferToEtag$1(Buffer.from(urlInfo.content));
@@ -18632,6 +18642,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18632
18642
  const references = [];
18633
18643
  context.referenceUtils = {
18634
18644
  _references: references,
18645
+ find: predicate => references.find(predicate),
18646
+ readGeneratedSpecifier,
18635
18647
  add: props => {
18636
18648
  const [reference, referencedUrlInfo] = resolveReference(createReference({
18637
18649
  parentUrl: urlInfo.url,
@@ -18640,8 +18652,6 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18640
18652
  references.push(reference);
18641
18653
  return [reference, referencedUrlInfo];
18642
18654
  },
18643
- find: predicate => references.find(predicate),
18644
- readGeneratedSpecifier,
18645
18655
  found: ({
18646
18656
  trace,
18647
18657
  ...rest
@@ -18703,6 +18713,29 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18703
18713
 
18704
18714
  return [newReference, newUrlInfo];
18705
18715
  },
18716
+ inject: ({
18717
+ trace,
18718
+ ...rest
18719
+ }) => {
18720
+ if (trace === undefined) {
18721
+ const {
18722
+ url,
18723
+ line,
18724
+ column
18725
+ } = getCallerPosition();
18726
+ trace = traceFromUrlSite({
18727
+ url,
18728
+ line,
18729
+ column
18730
+ });
18731
+ }
18732
+
18733
+ return context.referenceUtils.add({
18734
+ trace,
18735
+ injected: true,
18736
+ ...rest
18737
+ });
18738
+ },
18706
18739
  becomesInline: (reference, {
18707
18740
  isOriginalPosition,
18708
18741
  specifier,
@@ -18729,37 +18762,8 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
18729
18762
  content
18730
18763
  });
18731
18764
  },
18732
- inject: ({
18733
- trace,
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;
18765
+ becomesExternal: () => {
18766
+ throw new Error("not implemented yet");
18763
18767
  }
18764
18768
  }; // "fetchUrlContent" hook
18765
18769
 
@@ -25305,11 +25309,17 @@ const createFileService = ({
25305
25309
  clientFileChangeCallbackList.push(({
25306
25310
  url
25307
25311
  }) => {
25308
- const urlInfo = urlGraph.getUrlInfo(url);
25312
+ urlGraph.urlInfoMap.forEach(urlInfo => {
25313
+ if (urlInfo.url === url) {
25314
+ urlGraph.considerModified(urlInfo);
25315
+ } else {
25316
+ const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url);
25309
25317
 
25310
- if (urlInfo) {
25311
- urlGraph.considerModified(urlInfo);
25312
- }
25318
+ if (urlWithoutSearch === url) {
25319
+ urlGraph.considerModified(urlInfo);
25320
+ }
25321
+ }
25322
+ });
25313
25323
  });
25314
25324
  const kitchen = createKitchen({
25315
25325
  signal,
@@ -25486,22 +25496,30 @@ const createFileService = ({
25486
25496
  const urlInfoTargetedByCache = urlGraph.getParentIfInline(urlInfo);
25487
25497
 
25488
25498
  if (ifNoneMatch) {
25489
- if (urlInfoTargetedByCache.contentEtag === ifNoneMatch && urlInfoTargetedByCache.isValid()) {
25499
+ const [clientOriginalContentEtag, clientContentEtag] = ifNoneMatch.split("_");
25500
+
25501
+ if (urlInfoTargetedByCache.originalContentEtag === clientOriginalContentEtag && urlInfoTargetedByCache.contentEtag === clientContentEtag && urlInfoTargetedByCache.isValid()) {
25502
+ const headers = {
25503
+ "cache-control": `private,max-age=0,must-revalidate`
25504
+ };
25505
+ Object.keys(urlInfo.headers).forEach(key => {
25506
+ if (key !== "content-length") {
25507
+ headers[key] = urlInfo.headers[key];
25508
+ }
25509
+ });
25490
25510
  return {
25491
25511
  status: 304,
25492
- headers: {
25493
- "cache-control": `private,max-age=0,must-revalidate`,
25494
- ...urlInfo.headers
25495
- }
25512
+ headers
25496
25513
  };
25497
25514
  }
25498
25515
  }
25499
25516
 
25500
25517
  try {
25501
25518
  // urlInfo objects are reused, they must be "reset" before cooking them again
25502
- if (urlInfo.contentEtag && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
25519
+ if ((urlInfo.error || urlInfo.contentEtag) && !urlInfo.isInline && urlInfo.type !== "sourcemap") {
25503
25520
  urlInfo.error = null;
25504
25521
  urlInfo.sourcemap = null;
25522
+ urlInfo.sourcemapIsWrong = null;
25505
25523
  urlInfo.sourcemapReference = null;
25506
25524
  urlInfo.content = null;
25507
25525
  urlInfo.originalContent = null;
@@ -25526,11 +25544,12 @@ const createFileService = ({
25526
25544
  url: reference.url,
25527
25545
  status: 200,
25528
25546
  headers: {
25529
- "content-length": Buffer.byteLength(urlInfo.content),
25530
25547
  "cache-control": `private,max-age=0,must-revalidate`,
25531
- "eTag": urlInfoTargetedByCache.contentEtag,
25548
+ // it's safe to use "_" separator because etag is encoded with base64 (see https://stackoverflow.com/a/13195197)
25549
+ "eTag": `${urlInfoTargetedByCache.originalContentEtag}_${urlInfoTargetedByCache.contentEtag}`,
25532
25550
  ...urlInfo.headers,
25533
- "content-type": urlInfo.contentType
25551
+ "content-type": urlInfo.contentType,
25552
+ "content-length": Buffer.byteLength(urlInfo.content)
25534
25553
  },
25535
25554
  body: urlInfo.content,
25536
25555
  timing: urlInfo.timing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "28.3.0",
3
+ "version": "28.3.4",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -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
- inject: ({ trace, ...rest }) => {
548
- if (trace === undefined) {
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
- const urlInfo = urlGraph.getUrlInfo(url)
99
- if (urlInfo) {
100
- urlGraph.considerModified(urlInfo)
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.contentEtag === ifNoneMatch &&
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
- "eTag": urlInfoTargetedByCache.contentEtag,
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
- sourcemapsEnabled &&
177
- urlInfo.sourcemap &&
178
- !urlInfo.generatedUrl.startsWith("data:")
179
- ) {
180
- // during build this function can be called after the file is cooked
181
- // - to update content and sourcemap after "optimize" hook
182
- // - to inject versioning into the entry point content
183
- // in this scenarion we don't want to call injectSourcemap
184
- // just update the content and the
185
- const sourcemapReference = urlInfo.sourcemapReference
186
- const sourcemapUrlInfo = urlGraph.getUrlInfo(sourcemapReference.url)
187
- sourcemapUrlInfo.contentType = "application/json"
188
- const sourcemap = urlInfo.sourcemap
189
- if (sourcemapsRelativeSources) {
190
- sourcemap.sources = sourcemap.sources.map((source) => {
191
- const sourceRelative = urlToRelativeUrl(source, urlInfo.url)
192
- return sourceRelative || "."
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 (sourcemaps === "file" || sourcemaps === "inline") {
212
- urlInfo.content = SOURCEMAP.writeComment({
213
- contentType: urlInfo.contentType,
214
- content: urlInfo.content,
215
- specifier:
216
- sourcemaps === "file" && sourcemapsRelativeSources
217
- ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
218
- : sourcemapReference.generatedSpecifier,
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
@@ -1,4 +1,8 @@
1
- import { urlIsInsideOf, urlToRelativeUrl } from "@jsenv/urls"
1
+ import {
2
+ urlIsInsideOf,
3
+ urlToRelativeUrl,
4
+ asUrlWithoutSearch,
5
+ } from "@jsenv/urls"
2
6
 
3
7
  export const jsenvPluginAutoreloadServer = ({
4
8
  clientFileChangeCallbackList,
@@ -113,26 +117,33 @@ export const jsenvPluginAutoreloadServer = ({
113
117
  return iterate(firstUrlInfo, seen)
114
118
  }
115
119
  clientFileChangeCallbackList.push(({ url, event }) => {
116
- const urlInfo = urlGraph.getUrlInfo(url)
117
- // file not part of dependency graph
118
- if (!urlInfo) {
119
- return
120
- }
121
- const relativeUrl = formatUrlForClient(url)
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
- })
120
+ const onUrlInfo = (urlInfo) => {
121
+ const relativeUrl = formatUrlForClient(url)
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
+ }
135
136
  }
137
+ urlGraph.urlInfoMap.forEach((urlInfo) => {
138
+ if (urlInfo.url === url) {
139
+ onUrlInfo(urlInfo)
140
+ } else {
141
+ const urlWithoutSearch = asUrlWithoutSearch(urlInfo.url)
142
+ if (urlWithoutSearch === url) {
143
+ onUrlInfo(urlInfo)
144
+ }
145
+ }
146
+ })
136
147
  })
137
148
  clientFilesPruneCallbackList.push((prunedUrlInfos, firstUrlInfo) => {
138
149
  const mainHotUpdate = propagateUpdate(firstUrlInfo)
@@ -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
- context.referenceUtils.findByGeneratedSpecifier(src)
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
  )