@jsenv/core 25.0.0 → 25.2.0

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.
Files changed (60) hide show
  1. package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +2 -2
  2. package/dist/build_manifest.js +4 -4
  3. package/dist/compile_proxy/asset-manifest.json +2 -2
  4. package/dist/compile_proxy/{compile_proxy_e3b0c442_809f35f7.js.map → compile_proxy.html__inline__20_809f35f7.js.map} +0 -0
  5. package/dist/compile_proxy/{compile_proxy_7ad5faa6.html → compile_proxy_8dfaee51.html} +3 -4
  6. package/dist/redirector/asset-manifest.json +2 -2
  7. package/dist/redirector/{redirector_e3b0c442_e391410e.js.map → redirector.html__inline__15_e391410e.js.map} +0 -0
  8. package/dist/redirector/{redirector_eb92e8a7.html → redirector_3e9a97b9.html} +3 -4
  9. package/dist/toolbar/asset-manifest.json +1 -1
  10. package/dist/toolbar/{toolbar_f7b8a263.html → toolbar_361afb84.html} +2 -3
  11. package/dist/toolbar_injector/asset-manifest.json +2 -2
  12. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js → toolbar_injector_fac1e995.js} +2 -2
  13. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js.map → toolbar_injector_fac1e995.js.map} +2 -2
  14. package/package.json +8 -8
  15. package/readme.md +61 -52
  16. package/src/buildProject.js +21 -13
  17. package/src/commonJsToJavaScriptModule.js +8 -7
  18. package/src/execute.js +2 -0
  19. package/src/executeTestPlan.js +14 -0
  20. package/src/internal/building/buildUsingRollup.js +4 -2
  21. package/src/internal/building/build_stats.js +3 -0
  22. package/src/internal/building/build_url_generator.js +153 -0
  23. package/src/internal/building/css/parseCssRessource.js +32 -26
  24. package/src/internal/building/html/parseHtmlRessource.js +109 -91
  25. package/src/internal/building/js/parseJsRessource.js +5 -13
  26. package/src/internal/building/parseRessource.js +3 -0
  27. package/src/internal/building/ressource_builder.js +72 -64
  28. package/src/internal/building/ressource_builder_util.js +17 -5
  29. package/src/internal/building/rollup_plugin_jsenv.js +262 -189
  30. package/src/internal/building/url_fetcher.js +16 -7
  31. package/src/internal/building/url_loader.js +1 -5
  32. package/src/internal/building/url_versioning.js +0 -173
  33. package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
  34. package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
  35. package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
  36. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
  37. package/src/internal/compiling/compile-directory/updateMeta.js +2 -8
  38. package/src/internal/compiling/compile-directory/validateCache.js +1 -2
  39. package/src/internal/compiling/compileFile.js +22 -10
  40. package/src/internal/compiling/compileHtml.js +15 -28
  41. package/src/internal/compiling/createCompiledFileService.js +22 -24
  42. package/src/internal/compiling/html_source_file_service.js +18 -19
  43. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +14 -4
  44. package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
  45. package/src/internal/compiling/jsenvCompilerForHtml.js +534 -263
  46. package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
  47. package/src/internal/compiling/startCompileServer.js +83 -20
  48. package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
  49. package/src/internal/executing/executePlan.js +2 -0
  50. package/src/internal/fetchUrl.js +3 -2
  51. package/src/internal/integrity/integrity_algorithms.js +26 -0
  52. package/src/internal/integrity/integrity_parsing.js +50 -0
  53. package/src/internal/integrity/integrity_update.js +23 -0
  54. package/src/internal/integrity/integrity_validation.js +49 -0
  55. package/src/internal/jsenvCoreDirectoryUrl.js +2 -0
  56. package/src/internal/jsenv_remote_directory.js +156 -0
  57. package/src/internal/origin_directory_converter.js +62 -0
  58. package/src/internal/response_validation.js +11 -24
  59. package/src/internal/sourceMappingURLUtils.js +10 -0
  60. package/src/internal/url_conversion.js +1 -0
@@ -24,7 +24,7 @@ import {
24
24
  replaceHtmlNode,
25
25
  getHtmlNodeAttributeByName,
26
26
  stringifyHtmlAst,
27
- getUniqueNameForInlineHtmlNode,
27
+ getIdForInlineHtmlNode,
28
28
  removeHtmlNodeAttribute,
29
29
  setHtmlNodeText,
30
30
  getHtmlNodeTextNode,
@@ -32,6 +32,7 @@ import {
32
32
  stringifySrcset,
33
33
  getHtmlNodeLocation,
34
34
  removeHtmlNode,
35
+ addHtmlNodeAttribute,
35
36
  } from "@jsenv/core/src/internal/compiling/compileHtml.js"
36
37
  import {
37
38
  getJavaScriptSourceMappingUrl,
@@ -47,6 +48,7 @@ import { collectNodesMutations } from "../parsing.utils.js"
47
48
 
48
49
  import { collectSvgMutations } from "../svg/parseSvgRessource.js"
49
50
  import { moveCssUrls } from "../css/moveCssUrls.js"
51
+ import { applyAlgoToRepresentationData } from "../../integrity/integrity_algorithms.js"
50
52
 
51
53
  export const parseHtmlRessource = async (
52
54
  htmlRessource,
@@ -172,20 +174,21 @@ const regularScriptSrcVisitor = (
172
174
  if (!srcAttribute) {
173
175
  return null
174
176
  }
175
-
177
+ const integrityAttribute = getHtmlNodeAttributeByName(script, "integrity")
178
+ const integrity = integrityAttribute ? integrityAttribute.value : ""
176
179
  const remoteScriptReference = notifyReferenceFound({
177
180
  referenceLabel: "html script",
178
181
  contentTypeExpected: "application/javascript",
179
182
  ressourceSpecifier: srcAttribute.value,
183
+ integrity,
184
+ ...crossoriginFromHtmlNode(script),
180
185
  ...referenceLocationFromHtmlNode(script, "src"),
181
186
  })
182
187
  return ({ getUrlRelativeToImporter }) => {
183
188
  const ressource = remoteScriptReference.ressource
184
-
185
189
  if (ressource.isExternal) {
186
190
  return
187
191
  }
188
-
189
192
  if (shouldInline({ ressource, htmlNode: script })) {
190
193
  removeHtmlNodeAttribute(script, srcAttribute)
191
194
  const { bufferAfterBuild } = ressource
@@ -200,14 +203,19 @@ const regularScriptSrcVisitor = (
200
203
  const sourcemapInlineUrl = urlToRelativeUrl(sourcemapBuildUrl, htmlUrl)
201
204
  jsString = setJavaScriptSourceMappingUrl(jsString, sourcemapInlineUrl)
202
205
  }
203
-
204
206
  setHtmlNodeText(script, jsString)
205
207
  remoteScriptReference.inlinedCallback()
206
208
  return
207
209
  }
208
-
209
210
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
210
211
  srcAttribute.value = urlRelativeToImporter
212
+ if (integrityAttribute) {
213
+ const base64Value = applyAlgoToRepresentationData(
214
+ "sha256",
215
+ ressource.bufferAfterBuild,
216
+ )
217
+ integrityAttribute.value = `sha256-${base64Value}`
218
+ }
211
219
  }
212
220
  }
213
221
 
@@ -233,12 +241,10 @@ const regularScriptTextNodeVisitor = (
233
241
  if (!textNode) {
234
242
  return null
235
243
  }
236
-
237
- const ressourceSpecifier = getUniqueNameForInlineHtmlNode(
238
- script,
239
- scripts,
240
- `${urlToFilename(htmlRessource.url)}__inline__[id].js`,
241
- )
244
+ const scriptId = getIdForInlineHtmlNode(script, scripts)
245
+ const ressourceSpecifier = `${urlToFilename(
246
+ htmlRessource.url,
247
+ )}__inline__${scriptId}.js`
242
248
  const jsReference = notifyReferenceFound({
243
249
  referenceLabel: "html inline script",
244
250
  contentTypeExpected: "application/javascript",
@@ -266,25 +272,25 @@ const moduleScriptSrcVisitor = (script, { format, notifyReferenceFound }) => {
266
272
  if (!srcAttribute) {
267
273
  return null
268
274
  }
269
-
275
+ const integrityAttribute = getHtmlNodeAttributeByName(script, "integrity")
276
+ const integrity = integrityAttribute ? integrityAttribute.value : ""
270
277
  const remoteScriptReference = notifyReferenceFound({
271
278
  referenceLabel: "html module script",
272
279
  contentTypeExpected: "application/javascript",
273
280
  ressourceSpecifier: srcAttribute.value,
281
+ integrity,
282
+ ...crossoriginFromHtmlNode(script),
274
283
  ...referenceLocationFromHtmlNode(script, "src"),
275
284
  isJsModule: true,
276
285
  })
277
286
  return ({ getUrlRelativeToImporter }) => {
278
287
  const { ressource } = remoteScriptReference
279
-
280
288
  if (format === "systemjs") {
281
289
  removeHtmlNodeAttribute(script, typeAttribute)
282
290
  }
283
-
284
291
  if (ressource.isExternal) {
285
292
  return
286
293
  }
287
-
288
294
  if (shouldInline({ ressource, htmlNode: script })) {
289
295
  // here put a warning if we cannot inline importmap because it would mess
290
296
  // the remapping (note that it's feasible) but not yet supported
@@ -299,15 +305,20 @@ const moduleScriptSrcVisitor = (script, { format, notifyReferenceFound }) => {
299
305
  // with these assumptions we can force the sourcemap url
300
306
  const sourcemapUrl = `${ressource.buildRelativeUrl}.map`
301
307
  jsString = setJavaScriptSourceMappingUrl(jsString, sourcemapUrl)
302
-
303
308
  setHtmlNodeText(script, jsString)
304
309
  remoteScriptReference.inlinedCallback()
305
310
  return
306
311
  }
307
-
308
312
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
309
313
  const relativeUrlNotation = ensureRelativeUrlNotation(urlRelativeToImporter)
310
314
  srcAttribute.value = relativeUrlNotation
315
+ if (integrityAttribute) {
316
+ const base64Value = applyAlgoToRepresentationData(
317
+ "sha256",
318
+ ressource.bufferAfterBuild,
319
+ )
320
+ integrityAttribute.value = `sha256-${base64Value}`
321
+ }
311
322
  }
312
323
  }
313
324
 
@@ -332,12 +343,10 @@ const moduleScriptTextNodeVisitor = (
332
343
  if (!textNode) {
333
344
  return null
334
345
  }
335
-
336
- const ressourceSpecifier = getUniqueNameForInlineHtmlNode(
337
- script,
338
- scripts,
339
- `${urlToFilename(htmlRessource.url)}__inline__[id].js`,
340
- )
346
+ const scriptId = getIdForInlineHtmlNode(script, scripts)
347
+ const ressourceSpecifier = `${urlToFilename(
348
+ htmlRessource.url,
349
+ )}__inline__${scriptId}.js`
341
350
  const jsReference = notifyReferenceFound({
342
351
  referenceLabel: "html inline module script",
343
352
  contentTypeExpected: "application/javascript",
@@ -373,24 +382,24 @@ const importmapScriptSrcVisitor = (
373
382
  if (!srcAttribute) {
374
383
  return null
375
384
  }
376
-
385
+ const integrityAttribute = getHtmlNodeAttributeByName(script, "integrity")
386
+ const integrity = integrityAttribute ? integrityAttribute.value : ""
377
387
  const importmapReference = notifyReferenceFound({
378
388
  referenceLabel: "html importmap",
379
389
  contentTypeExpected: "application/importmap+json",
380
390
  ressourceSpecifier: srcAttribute.value,
391
+ integrity,
392
+ ...crossoriginFromHtmlNode(script),
381
393
  ...referenceLocationFromHtmlNode(script, "src"),
382
394
  })
383
395
  return ({ getUrlRelativeToImporter }) => {
384
396
  const { ressource } = importmapReference
385
-
386
397
  if (format === "systemjs") {
387
398
  typeAttribute.value = "systemjs-importmap"
388
399
  }
389
-
390
400
  if (ressource.isExternal) {
391
401
  return
392
402
  }
393
-
394
403
  if (
395
404
  // for esmodule we always inline the importmap
396
405
  // as it's the only thing supported by Chrome
@@ -404,22 +413,22 @@ const importmapScriptSrcVisitor = (
404
413
  // here put a warning if we cannot inline importmap because it would mess
405
414
  // the remapping (note that it's feasible) but not yet supported
406
415
  const { bufferAfterBuild } = ressource
407
-
408
416
  const importmapString = String(bufferAfterBuild)
409
- replaceHtmlNode(
410
- script,
411
- `<script>
412
- ${importmapString}</script>`,
413
- {
414
- attributesToIgnore: ["src"],
415
- },
416
- )
417
+ removeHtmlNodeAttribute(script, srcAttribute)
418
+ setHtmlNodeText(script, importmapString)
419
+ removeHtmlNodeAttribute(script, integrityAttribute)
417
420
  importmapReference.inlinedCallback()
418
421
  return
419
422
  }
420
-
421
423
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
422
424
  srcAttribute.value = urlRelativeToImporter
425
+ if (integrityAttribute) {
426
+ const base64Value = applyAlgoToRepresentationData(
427
+ "sha256",
428
+ ressource.bufferAfterBuild,
429
+ )
430
+ integrityAttribute.value = `sha256-${base64Value}`
431
+ }
423
432
  }
424
433
  }
425
434
 
@@ -444,17 +453,14 @@ const importmapScriptTextNodeVisitor = (
444
453
  if (!textNode) {
445
454
  return null
446
455
  }
447
-
456
+ const importmapScriptId = getIdForInlineHtmlNode(script, scripts)
448
457
  const importmapReference = notifyReferenceFound({
449
458
  referenceLabel: "html inline importmap",
450
459
  contentTypeExpected: "application/importmap+json",
451
- ressourceSpecifier: getUniqueNameForInlineHtmlNode(
452
- script,
453
- scripts,
454
- `${urlToFilename(htmlRessource.url)}__inline__[id].importmap`,
455
- ),
460
+ ressourceSpecifier: `${urlToFilename(
461
+ htmlRessource.url,
462
+ )}__inline__${importmapScriptId}.importmap`,
456
463
  ...referenceLocationFromHtmlNode(script),
457
-
458
464
  contentType: "application/importmap+json",
459
465
  bufferBeforeBuild: Buffer.from(textNode.value),
460
466
  isInline: true,
@@ -463,7 +469,6 @@ const importmapScriptTextNodeVisitor = (
463
469
  if (format === "systemjs") {
464
470
  typeAttribute.value = "systemjs-importmap"
465
471
  }
466
-
467
472
  const { bufferAfterBuild } = importmapReference.ressource
468
473
  textNode.value = bufferAfterBuild
469
474
  }
@@ -485,38 +490,34 @@ const linkStylesheetHrefVisitor = (
485
490
  if (relAttribute.value !== "stylesheet") {
486
491
  return null
487
492
  }
488
-
493
+ const integrityAttribute = getHtmlNodeAttributeByName(link, "integrity")
494
+ const integrity = integrityAttribute ? integrityAttribute.value : ""
489
495
  const cssReference = notifyReferenceFound({
490
496
  referenceLabel: "html stylesheet link",
491
497
  contentTypeExpected: "text/css",
492
498
  ressourceSpecifier: hrefAttribute.value,
499
+ integrity,
500
+ ...crossoriginFromHtmlNode(link),
493
501
  ...referenceLocationFromHtmlNode(link, "href"),
494
502
  })
495
- return async ({
496
- getUrlRelativeToImporter,
497
- precomputeBuildRelativeUrl,
498
- buildDirectoryUrl,
499
- }) => {
503
+ return async ({ getUrlRelativeToImporter, buildDirectoryUrl }) => {
500
504
  const { ressource } = cssReference
501
-
502
505
  if (ressource.isExternal) {
503
506
  return
504
507
  }
505
-
506
508
  if (shouldInline({ ressource, htmlNode: link })) {
507
509
  const { bufferAfterBuild } = ressource
508
510
  let code = String(bufferAfterBuild)
509
511
  const { buildRelativeUrl } = ressource
510
512
  const cssBuildUrl = resolveUrl(buildRelativeUrl, buildDirectoryUrl)
511
- const htmlUrl = resolveUrl(
512
- precomputeBuildRelativeUrl(htmlRessource),
513
+ const htmlBuildUrl = resolveUrl(
514
+ htmlRessource.buildRelativeUrlWithoutHash,
513
515
  buildDirectoryUrl,
514
516
  )
515
-
516
517
  const moveResult = await moveCssUrls({
517
518
  code,
518
519
  from: cssBuildUrl,
519
- to: htmlUrl,
520
+ to: htmlBuildUrl,
520
521
  // moveCssUrls will change the css source code
521
522
  // Ideally we should update the sourcemap referenced by css
522
523
  // to target the one after css urls are moved.
@@ -527,24 +528,38 @@ const linkStylesheetHrefVisitor = (
527
528
  sourcemapMethod: null,
528
529
  })
529
530
  code = moveResult.code
530
-
531
531
  const sourcemapRelativeUrl = getCssSourceMappingUrl(code)
532
532
  if (sourcemapRelativeUrl) {
533
533
  const cssBuildUrl = resolveUrl(buildRelativeUrl, buildDirectoryUrl)
534
534
  const sourcemapBuildUrl = resolveUrl(sourcemapRelativeUrl, cssBuildUrl)
535
- const sourcemapInlineUrl = urlToRelativeUrl(sourcemapBuildUrl, htmlUrl)
535
+ const sourcemapInlineUrl = urlToRelativeUrl(
536
+ sourcemapBuildUrl,
537
+ htmlBuildUrl,
538
+ )
536
539
  code = setCssSourceMappingUrl(code, sourcemapInlineUrl)
537
540
  }
538
-
539
541
  replaceHtmlNode(link, `<style>${code}</style>`, {
540
- attributesToIgnore: ["href", "rel", "as", "crossorigin", "type"],
542
+ attributesToIgnore: [
543
+ "href",
544
+ "rel",
545
+ "as",
546
+ "crossorigin",
547
+ "type",
548
+ "integrity",
549
+ ],
541
550
  })
542
551
  cssReference.inlinedCallback()
543
552
  return
544
553
  }
545
-
546
554
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
547
555
  hrefAttribute.value = urlRelativeToImporter
556
+ if (integrityAttribute) {
557
+ const base64Value = applyAlgoToRepresentationData(
558
+ "sha256",
559
+ ressource.bufferAfterBuild,
560
+ )
561
+ integrityAttribute.value = `sha256-${base64Value}`
562
+ }
548
563
  }
549
564
  }
550
565
 
@@ -556,7 +571,6 @@ const linkHrefVisitor = (
556
571
  if (!hrefAttribute) {
557
572
  return null
558
573
  }
559
-
560
574
  const href = hrefAttribute.value
561
575
  const relAttribute = getHtmlNodeAttributeByName(link, "rel")
562
576
  const rel = relAttribute ? relAttribute.value : undefined
@@ -567,7 +581,6 @@ const linkHrefVisitor = (
567
581
  "preload",
568
582
  "modulepreload",
569
583
  ].includes(rel)
570
-
571
584
  let contentTypeExpected
572
585
  const typeAttribute = getHtmlNodeAttributeByName(link, "type")
573
586
  const type = typeAttribute ? typeAttribute.value : ""
@@ -580,19 +593,21 @@ const linkHrefVisitor = (
580
593
  contentTypeExpected = "application/javascript"
581
594
  isJsModule = true
582
595
  }
583
-
596
+ const integrityAttribute = getHtmlNodeAttributeByName(link, "integrity")
597
+ const integrity = integrityAttribute ? integrityAttribute.value : ""
584
598
  const linkReference = notifyReferenceFound({
585
599
  referenceLabel: rel ? `html ${rel} link href` : `html link href`,
586
600
  isRessourceHint,
587
601
  contentTypeExpected,
588
602
  ressourceSpecifier: href,
603
+ integrity,
604
+ ...crossoriginFromHtmlNode(link),
589
605
  ...referenceLocationFromHtmlNode(link, "href"),
590
606
  urlVersioningDisabled: contentTypeExpected === "application/manifest+json",
591
607
  isJsModule,
592
608
  })
593
609
  return ({ getUrlRelativeToImporter }) => {
594
610
  const { ressource } = linkReference
595
-
596
611
  if (isRessourceHint) {
597
612
  if (isReferencedOnlyByRessourceHint(ressource)) {
598
613
  ressourceHintNeverUsedCallback({
@@ -604,36 +619,34 @@ const linkHrefVisitor = (
604
619
  // we could remove the HTML node but better keep it untouched and let user decide what to do
605
620
  return
606
621
  }
607
-
608
622
  ressource.inlinedCallbacks.push(() => {
609
623
  removeHtmlNode(link)
610
624
  })
611
625
  }
612
-
613
626
  if (ressource.isExternal) {
614
627
  return
615
628
  }
616
-
617
629
  if (format === "systemjs" && rel === "modulepreload") {
618
630
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
619
- replaceHtmlNode(
620
- link,
621
- `<link rel="preload" href="${urlRelativeToImporter}" as="script" />`,
622
- )
631
+ relAttribute.value = "preload"
632
+ hrefAttribute.value = urlRelativeToImporter
633
+ addHtmlNodeAttribute(link, { name: "as", value: "script" })
623
634
  return
624
635
  }
625
-
626
636
  if (shouldInline({ ressource, htmlNode: link })) {
627
- replaceHtmlNode(
628
- link,
629
- `<link href="${getRessourceAsBase64Url(ressource)}" />`,
630
- )
637
+ removeHtmlNode(link)
631
638
  linkReference.inlinedCallback()
632
639
  return
633
640
  }
634
-
635
641
  const urlRelativeToImporter = getUrlRelativeToImporter(ressource)
636
642
  hrefAttribute.value = urlRelativeToImporter
643
+ if (integrityAttribute) {
644
+ const base64Value = applyAlgoToRepresentationData(
645
+ "sha256",
646
+ ressource.bufferAfterBuild,
647
+ )
648
+ integrityAttribute.value = `sha256-${base64Value}`
649
+ }
637
650
  }
638
651
  }
639
652
 
@@ -647,17 +660,14 @@ const styleTextNodeVisitor = (
647
660
  if (!textNode) {
648
661
  return null
649
662
  }
650
-
663
+ const styleId = getIdForInlineHtmlNode(style, styles)
651
664
  const inlineStyleReference = notifyReferenceFound({
652
665
  referenceLabel: "html style",
653
666
  contentTypeExpected: "text/css",
654
- ressourceSpecifier: getUniqueNameForInlineHtmlNode(
655
- style,
656
- styles,
657
- `${urlToFilename(htmlRessource.url)}__inline__[id].css`,
658
- ),
667
+ ressourceSpecifier: `${urlToFilename(
668
+ htmlRessource.url,
669
+ )}__inline__${styleId}.css`,
659
670
  ...referenceLocationFromHtmlNode(style),
660
-
661
671
  contentType: "text/css",
662
672
  bufferBeforeBuild: Buffer.from(textNode.value),
663
673
  isInline: true,
@@ -673,10 +683,10 @@ const imgSrcVisitor = (img, { notifyReferenceFound }) => {
673
683
  if (!srcAttribute) {
674
684
  return null
675
685
  }
676
-
677
686
  const srcReference = notifyReferenceFound({
678
687
  referenceLabel: "html img src",
679
688
  ressourceSpecifier: srcAttribute.value,
689
+ ...crossoriginFromHtmlNode(img),
680
690
  ...referenceLocationFromHtmlNode(img, "src"),
681
691
  })
682
692
  return ({ getUrlRelativeToImporter }) => {
@@ -694,19 +704,18 @@ const srcsetVisitor = (htmlNode, { notifyReferenceFound }) => {
694
704
  if (!srcsetAttribute) {
695
705
  return null
696
706
  }
697
-
698
707
  const srcsetParts = parseSrcset(srcsetAttribute.value)
699
708
  const srcsetPartsReferences = srcsetParts.map(({ specifier }, index) =>
700
709
  notifyReferenceFound({
701
710
  referenceLabel: `html srcset ${index}`,
702
711
  ressourceSpecifier: specifier,
712
+ ...crossoriginFromHtmlNode(htmlNode),
703
713
  ...referenceLocationFromHtmlNode(htmlNode, "srcset"),
704
714
  }),
705
715
  )
706
716
  if (srcsetParts.length === 0) {
707
717
  return null
708
718
  }
709
-
710
719
  return ({ getUrlRelativeToImporter }) => {
711
720
  srcsetParts.forEach((srcsetPart, index) => {
712
721
  const reference = srcsetPartsReferences[index]
@@ -727,12 +736,12 @@ const sourceSrcVisitor = (source, { notifyReferenceFound }) => {
727
736
  if (!srcAttribute) {
728
737
  return null
729
738
  }
730
-
731
739
  const typeAttribute = getHtmlNodeAttributeByName(source, "type")
732
740
  const srcReference = notifyReferenceFound({
733
741
  referenceLabel: "html source",
734
742
  contentTypeExpected: typeAttribute ? typeAttribute.value : undefined,
735
743
  ressourceSpecifier: srcAttribute.value,
744
+ ...crossoriginFromHtmlNode(source),
736
745
  ...referenceLocationFromHtmlNode(source, "src"),
737
746
  })
738
747
  return ({ getUrlRelativeToImporter }) => {
@@ -757,6 +766,15 @@ const referenceToUrl = ({ reference, htmlNode, getUrlRelativeToImporter }) => {
757
766
  return getUrlRelativeToImporter(ressource)
758
767
  }
759
768
 
769
+ const crossoriginFromHtmlNode = (htmlNode) => {
770
+ const crossOriginAttribute = getHtmlNodeAttributeByName(
771
+ htmlNode,
772
+ "crossorigin",
773
+ )
774
+ const crossorigin = crossOriginAttribute ? crossOriginAttribute.value : ""
775
+ return { crossorigin }
776
+ }
777
+
760
778
  const referenceLocationFromHtmlNode = (htmlNode, htmlAttributeName) => {
761
779
  const locInfo = getHtmlNodeLocation(htmlNode, htmlAttributeName)
762
780
  return locInfo
@@ -1,6 +1,7 @@
1
1
  import { urlToFilename, resolveUrl, urlToRelativeUrl } from "@jsenv/filesystem"
2
2
 
3
3
  import {
4
+ generateSourcemapUrl,
4
5
  getJavaScriptSourceMappingUrl,
5
6
  setJavaScriptSourceMappingUrl,
6
7
  } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
@@ -14,8 +15,8 @@ export const parseJsRessource = async (
14
15
  const jsUrl = jsRessource.url
15
16
  const jsString = String(jsRessource.bufferBeforeBuild)
16
17
  const jsSourcemapUrl = getJavaScriptSourceMappingUrl(jsString)
17
- let sourcemapReference
18
18
 
19
+ let sourcemapReference
19
20
  if (jsSourcemapUrl) {
20
21
  sourcemapReference = notifyReferenceFound({
21
22
  referenceLabel: "js sourcemapping comment",
@@ -32,7 +33,7 @@ export const parseJsRessource = async (
32
33
  sourcemapReference = notifyReferenceFound({
33
34
  referenceLabel: "js sourcemapping comment",
34
35
  contentType: "application/octet-stream",
35
- ressourceSpecifier: `${urlToFilename(jsUrl)}.map`,
36
+ ressourceSpecifier: urlToRelativeUrl(generateSourcemapUrl(jsUrl), jsUrl),
36
37
  isPlaceholder: true,
37
38
  isSourcemap: true,
38
39
  })
@@ -40,7 +41,6 @@ export const parseJsRessource = async (
40
41
 
41
42
  return async ({ buildDirectoryUrl }) => {
42
43
  const sourcemapRessource = sourcemapReference.ressource
43
-
44
44
  let code
45
45
  let map
46
46
  if (!sourcemapRessource.isPlaceholder) {
@@ -76,13 +76,10 @@ export const parseJsRessource = async (
76
76
  code = result.code
77
77
  map = result.map
78
78
  }
79
-
80
79
  jsRessource.buildEnd(code)
81
-
82
80
  if (!map) {
83
81
  return
84
82
  }
85
-
86
83
  // In theory code should never be modified once buildEnd() is called
87
84
  // because buildRelativeUrl might be versioned based on file content
88
85
  // There is an exception for sourcemap because we want to update sourcemap.file
@@ -95,16 +92,12 @@ export const parseJsRessource = async (
95
92
  jsRessource.buildRelativeUrl,
96
93
  buildDirectoryUrl,
97
94
  )
98
- const sourcemapPrecomputedBuildUrl = resolveUrl(
99
- `${urlToFilename(jsBuildUrl)}.map`,
100
- jsBuildUrl,
101
- )
102
-
95
+ const sourcemapPrecomputedBuildUrl = generateSourcemapUrl(jsBuildUrl)
103
96
  map.file = urlToFilename(jsBuildUrl)
104
97
  if (map.sources) {
105
98
  map.sources = map.sources.map((source) => {
106
99
  const sourceUrl = resolveUrl(source, jsUrl)
107
- const sourceOriginalUrl = asOriginalUrl(sourceUrl)
100
+ const sourceOriginalUrl = asOriginalUrl(sourceUrl) || sourceUrl
108
101
  const sourceUrlRelativeToSourceMap = urlToRelativeUrl(
109
102
  sourceOriginalUrl,
110
103
  sourcemapPrecomputedBuildUrl,
@@ -114,7 +107,6 @@ export const parseJsRessource = async (
114
107
  }
115
108
  const mapAsText = JSON.stringify(map, null, " ")
116
109
  sourcemapRessource.buildEnd(mapAsText)
117
-
118
110
  const sourcemapBuildUrl = resolveUrl(
119
111
  sourcemapRessource.buildRelativeUrl,
120
112
  buildDirectoryUrl,
@@ -27,6 +27,7 @@ export const parseRessource = async (
27
27
  notifiers,
28
28
  {
29
29
  projectDirectoryUrl,
30
+ jsenvRemoteDirectory,
30
31
  format,
31
32
  systemJsUrl,
32
33
  asProjectUrl,
@@ -125,6 +126,7 @@ export const parseRessource = async (
125
126
 
126
127
  if (contentType === "text/css") {
127
128
  return parseCssRessource(ressource, notifiers, {
129
+ jsenvRemoteDirectory,
128
130
  asProjectUrl,
129
131
  asOriginalUrl,
130
132
  asOriginalServerUrl,
@@ -156,6 +158,7 @@ export const parseRessource = async (
156
158
  ) {
157
159
  return parseJsRessource(ressource, notifiers, {
158
160
  projectDirectoryUrl,
161
+ jsenvRemoteDirectory,
159
162
  asProjectUrl,
160
163
  asOriginalUrl,
161
164
  asOriginalServerUrl,