@jsenv/core 25.0.1 → 25.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) 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 +9 -10
  15. package/readme.md +60 -51
  16. package/src/buildProject.js +21 -13
  17. package/src/commonJsToJavaScriptModule.js +8 -7
  18. package/src/dev_server.js +2 -0
  19. package/src/execute.js +2 -0
  20. package/src/executeTestPlan.js +14 -0
  21. package/src/internal/building/buildUsingRollup.js +4 -2
  22. package/src/internal/building/build_stats.js +3 -0
  23. package/src/internal/building/build_url_generator.js +153 -0
  24. package/src/internal/building/css/parseCssRessource.js +32 -26
  25. package/src/internal/building/html/parseHtmlRessource.js +109 -91
  26. package/src/internal/building/js/parseJsRessource.js +5 -13
  27. package/src/internal/building/parseRessource.js +3 -0
  28. package/src/internal/building/ressource_builder.js +72 -64
  29. package/src/internal/building/ressource_builder_util.js +17 -5
  30. package/src/internal/building/rollup_plugin_jsenv.js +262 -189
  31. package/src/internal/building/url_fetcher.js +16 -7
  32. package/src/internal/building/url_loader.js +1 -5
  33. package/src/internal/building/url_versioning.js +0 -173
  34. package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
  35. package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
  36. package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
  37. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
  38. package/src/internal/compiling/compile-directory/updateMeta.js +4 -8
  39. package/src/internal/compiling/compile-directory/validateCache.js +1 -2
  40. package/src/internal/compiling/compileFile.js +22 -10
  41. package/src/internal/compiling/compileHtml.js +15 -28
  42. package/src/internal/compiling/createCompiledFileService.js +22 -24
  43. package/src/internal/compiling/html_source_file_service.js +18 -19
  44. package/src/internal/compiling/js-compilation-service/babelHelper.js +10 -13
  45. package/src/internal/compiling/js-compilation-service/babel_plugin_babel_helpers_as_jsenv_imports.js +4 -2
  46. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +16 -7
  47. package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
  48. package/src/internal/compiling/jsenvCompilerForHtml.js +536 -262
  49. package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
  50. package/src/internal/compiling/startCompileServer.js +83 -20
  51. package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
  52. package/src/internal/executing/executePlan.js +2 -0
  53. package/src/internal/fetchUrl.js +3 -2
  54. package/src/internal/integrity/integrity_algorithms.js +26 -0
  55. package/src/internal/integrity/integrity_parsing.js +50 -0
  56. package/src/internal/integrity/integrity_update.js +23 -0
  57. package/src/internal/integrity/integrity_validation.js +49 -0
  58. package/src/internal/jsenvCoreDirectoryUrl.js +2 -0
  59. package/src/internal/jsenv_remote_directory.js +156 -0
  60. package/src/internal/origin_directory_converter.js +62 -0
  61. package/src/internal/response_validation.js +11 -24
  62. package/src/internal/sourceMappingURLUtils.js +10 -0
  63. package/src/internal/url_conversion.js +1 -0
@@ -1,4 +1,4 @@
1
- import { resolveUrl, urlToRelativeUrl, urlIsInsideOf } from "@jsenv/filesystem"
1
+ import { resolveUrl, urlToRelativeUrl } from "@jsenv/filesystem"
2
2
  import { createLogger, loggerToLevels } from "@jsenv/logger"
3
3
 
4
4
  import { setJavaScriptSourceMappingUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
@@ -30,7 +30,7 @@ export const createRessourceBuilder = (
30
30
  onAssetSourceUpdated,
31
31
  onJsModule,
32
32
  resolveRessourceUrl,
33
- urlVersioner,
33
+ buildUrlGenerator,
34
34
  },
35
35
  ) => {
36
36
  const logger = createLogger({ logLevel })
@@ -78,7 +78,6 @@ export const createRessourceBuilder = (
78
78
  // (but that means updating html hash and importmap hash)
79
79
  return
80
80
  }
81
-
82
81
  const { ressource } = dependency
83
82
  const readyPromise = ressource.getReadyPromise()
84
83
  if (ressource.isJsModule) {
@@ -101,7 +100,7 @@ export const createRessourceBuilder = (
101
100
  )
102
101
  }
103
102
 
104
- const createReferenceFoundByRollup = async (params) => {
103
+ const createReferenceFoundByRollup = (params) => {
105
104
  return createReference({
106
105
  fromRollup: true,
107
106
  ...params,
@@ -152,7 +151,11 @@ export const createRessourceBuilder = (
152
151
  // compute all asset fileName
153
152
  Object.keys(ressourceMap).forEach((key) => {
154
153
  const ressource = ressourceMap[key]
155
- if (ressource.isExternal || ressource.isJsModule || ressource.fileName) {
154
+ if (
155
+ ressource.isExternal ||
156
+ ressource.isJsModule ||
157
+ ressource.buildFileNameWithoutHash
158
+ ) {
156
159
  return
157
160
  }
158
161
  if (ressource.isPlaceholder && !ressource.buildRelativeUrl) {
@@ -168,7 +171,9 @@ export const createRessourceBuilder = (
168
171
  return
169
172
  }
170
173
  }
171
- ressource.fileName = asFileNameWithoutHash(ressource.buildRelativeUrl)
174
+ ressource.buildFileNameWithoutHash = asFileNameWithoutHash(
175
+ ressource.buildRelativeUrl,
176
+ )
172
177
  })
173
178
  }
174
179
 
@@ -177,12 +182,14 @@ export const createRessourceBuilder = (
177
182
  const createReference = ({
178
183
  isRessourceHint,
179
184
  isImportAssertion,
180
- contentTypeExpected,
181
185
  ressourceSpecifier,
182
186
  referenceLabel,
183
187
  referenceUrl,
184
188
  referenceColumn,
185
189
  referenceLine,
190
+ contentTypeExpected,
191
+ crossorigin,
192
+ integrity,
186
193
 
187
194
  contentType,
188
195
  bufferBeforeBuild,
@@ -244,7 +251,12 @@ export const createRessourceBuilder = (
244
251
  let isExternal = false
245
252
  let isWorker = false
246
253
  let isServiceWorker = false
254
+ let isCrossOrigin = false
247
255
  if (typeof ressourceUrlResolution === "object") {
256
+ ressourceUrl = ressourceUrlResolution.url
257
+ if (ressourceUrlResolution.isCrossOrigin) {
258
+ isCrossOrigin = true
259
+ }
248
260
  if (ressourceUrlResolution.isExternal) {
249
261
  isExternal = true
250
262
  }
@@ -257,7 +269,6 @@ export const createRessourceBuilder = (
257
269
  if (ressourceUrlResolution.isJsModule) {
258
270
  isJsModule = true
259
271
  }
260
- ressourceUrl = ressourceUrlResolution.url
261
272
  } else {
262
273
  ressourceUrl = ressourceUrlResolution
263
274
  }
@@ -297,6 +308,7 @@ export const createRessourceBuilder = (
297
308
  isEntryPoint,
298
309
  isJsModule,
299
310
  isSourcemap,
311
+ isCrossOrigin,
300
312
  isExternal,
301
313
  isInline,
302
314
  isPlaceholder,
@@ -312,11 +324,13 @@ export const createRessourceBuilder = (
312
324
  fromRollup,
313
325
  isRessourceHint,
314
326
  isImportAssertion,
315
- contentTypeExpected,
316
327
  referenceLabel,
317
328
  referenceUrl,
318
329
  referenceColumn,
319
330
  referenceLine,
331
+ contentTypeExpected,
332
+ crossorigin,
333
+ integrity,
320
334
 
321
335
  isInline,
322
336
  inlinedCallback: () => {
@@ -355,7 +369,7 @@ export const createRessourceBuilder = (
355
369
  reference,
356
370
  referenceEffects: effects,
357
371
  showReferenceSourceLocation,
358
- shortenUrl,
372
+ urlToHumanUrl,
359
373
  }),
360
374
  )
361
375
  }
@@ -373,6 +387,7 @@ export const createRessourceBuilder = (
373
387
  isEntryPoint = false,
374
388
  isJsModule = false,
375
389
  isSourcemap = false,
390
+ isCrossOrigin = false,
376
391
  isExternal = false,
377
392
  isInline = false,
378
393
  isPlaceholder = false,
@@ -394,6 +409,7 @@ export const createRessourceBuilder = (
394
409
  isJsModule,
395
410
  isSourcemap,
396
411
  isInline,
412
+ isCrossOrigin,
397
413
  isExternal,
398
414
  isPlaceholder,
399
415
  isWorker,
@@ -406,6 +422,11 @@ export const createRessourceBuilder = (
406
422
  : urlToRelativeUrl(ressourceUrl, buildDirectoryUrl),
407
423
  }
408
424
 
425
+ const { buildRelativeUrlPattern, buildRelativeUrlWithoutHash } =
426
+ buildUrlGenerator.prepareBuildUrlForRessource(ressource)
427
+ ressource.buildRelativeUrlWithoutHash = buildRelativeUrlWithoutHash
428
+ ressource.buildRelativeUrlPattern = buildRelativeUrlPattern
429
+
409
430
  ressource.usedPromise = new Promise((resolve) => {
410
431
  ressource.usedCallback = resolve
411
432
  })
@@ -424,13 +445,11 @@ export const createRessourceBuilder = (
424
445
  await ressource.rollupBuildDonePromise
425
446
  return
426
447
  }
427
-
428
448
  // sourcemap placeholder buffer is ready once buildEnd is called on it
429
449
  if (ressource.isPlaceholder) {
430
450
  await ressource.buildEndCalledPromise
431
451
  return
432
452
  }
433
-
434
453
  if (!ressource.firstStrongReference) {
435
454
  // for preload/prefetch links, we don't want to start the prefetching right away.
436
455
  // Instead we wait for something else to reference the same ressource
@@ -446,9 +465,11 @@ export const createRessourceBuilder = (
446
465
  return
447
466
  }
448
467
  }
449
-
450
- const response = await urlFetcher.fetchUrl(ressource.url, {
468
+ const ressourceUrl = ressource.url
469
+ const response = await urlFetcher.fetchUrl(ressourceUrl, {
451
470
  contentTypeExpected: ressource.firstStrongReference.contentTypeExpected,
471
+ crossorigin: ressource.firstStrongReference.crossorigin,
472
+ integrity: ressource.firstStrongReference.integrity,
452
473
  urlTrace: () => {
453
474
  return createRessourceTrace({
454
475
  ressource,
@@ -457,20 +478,21 @@ export const createRessourceBuilder = (
457
478
  })
458
479
  },
459
480
  })
460
- if (response.url !== ressource.url) {
461
- const urlBeforeRedirection = ressource.url
481
+ if (response.url !== ressourceUrl) {
482
+ const urlBeforeRedirection = ressourceUrl
462
483
  const urlAfterRedirection = response.url
463
484
  ressourceRedirectionMap[urlBeforeRedirection] = urlAfterRedirection
464
485
  ressource.url = urlAfterRedirection
465
486
  }
466
-
467
487
  const responseContentTypeHeader = response.headers["content-type"]
468
488
  ressource.contentType = responseContentTypeHeader
469
-
470
489
  const responseBodyAsArrayBuffer = await response.arrayBuffer()
471
490
  ressource.bufferBeforeBuild = Buffer.from(responseBodyAsArrayBuffer)
491
+ // TODO here: integrity check
472
492
  })
473
- if (bufferBeforeBuild !== undefined) {
493
+
494
+ const setBufferBeforeBuild = (bufferBeforeBuild) => {
495
+ ressource.bufferBeforeBuild = bufferBeforeBuild
474
496
  getBufferAvailablePromise.forceMemoization(Promise.resolve())
475
497
  }
476
498
 
@@ -488,6 +510,8 @@ export const createRessourceBuilder = (
488
510
  const notifyReferenceFound = ({
489
511
  isRessourceHint,
490
512
  contentTypeExpected,
513
+ crossorigin,
514
+ integrity,
491
515
  ressourceSpecifier,
492
516
  referenceLabel,
493
517
  referenceLine,
@@ -515,6 +539,8 @@ export const createRessourceBuilder = (
515
539
  referenceColumn,
516
540
  isRessourceHint,
517
541
  contentTypeExpected,
542
+ crossorigin,
543
+ integrity,
518
544
 
519
545
  contentType,
520
546
  bufferBeforeBuild,
@@ -605,34 +631,22 @@ export const createRessourceBuilder = (
605
631
  // }
606
632
  // we don't yet know the exact importerBuildRelativeUrl but we can generate a fake one
607
633
  // to ensure we resolve dependency against where the importer file will be
608
- const importerBuildRelativeUrl =
609
- urlVersioner.precomputeBuildRelativeUrl(ressource)
634
+ const importer = ressource
610
635
  await transform({
611
636
  buildDirectoryUrl,
612
- precomputeBuildRelativeUrl: (ressource) =>
613
- urlVersioner.precomputeBuildRelativeUrl(ressource),
614
637
  getUrlRelativeToImporter: (referencedRessource) => {
615
- const ressourceImporter = ressource
616
-
617
- let referenceBuildRelativeUrl
618
-
619
- if (ressourceImporter.isJsModule) {
620
- // js can reference an url without versionning
621
- // and actually fetch the versioned url thanks to importmap
622
- referenceBuildRelativeUrl =
623
- referencedRessource.fileName ||
638
+ const referenceBuildRelativeUrl = importer.isJsModule
639
+ ? // js can reference an url without versionning
640
+ // and actually fetch the versioned url thanks to importmap
641
+ referencedRessource.buildRelativeUrlWithoutHash
642
+ : // other ressource must use the exact url
624
643
  referencedRessource.buildRelativeUrl
625
- } else {
626
- // other ressource must use the exact url
627
- referenceBuildRelativeUrl = referencedRessource.buildRelativeUrl
628
- }
629
-
630
644
  const referenceBuildUrl = resolveUrl(
631
645
  referenceBuildRelativeUrl,
632
646
  "file:///",
633
647
  )
634
648
  const importerBuildUrl = resolveUrl(
635
- importerBuildRelativeUrl,
649
+ importer.buildRelativeUrlWithoutHash,
636
650
  "file:///",
637
651
  )
638
652
  return urlToRelativeUrl(referenceBuildUrl, importerBuildUrl)
@@ -660,7 +674,7 @@ export const createRessourceBuilder = (
660
674
  ressource.bufferAfterBuild = bufferAfterBuild
661
675
  if (buildRelativeUrl === undefined) {
662
676
  ressource.buildRelativeUrl =
663
- urlVersioner.computeBuildRelativeUrl(ressource)
677
+ buildUrlGenerator.computeBuildRelativeUrl(ressource)
664
678
  }
665
679
  }
666
680
 
@@ -681,19 +695,20 @@ export const createRessourceBuilder = (
681
695
 
682
696
  const applyReferenceEffects = (reference, infoFromReference) => {
683
697
  const effects = []
698
+ if (reference.fromRollup && ressource.isJsModule && ressource.isInline) {
699
+ return effects
700
+ }
684
701
  if (ressource.isEntryPoint) {
685
702
  if (ressource.contentType === "text/html") {
686
703
  effects.push(`parse html to find references`)
687
704
  }
688
705
  }
689
-
690
706
  if (reference.isRessourceHint) {
691
707
  // do not try to load or fetch this file
692
708
  // we'll wait for something to reference it
693
709
  // if nothing references it a warning will be logged
694
710
  return effects
695
711
  }
696
-
697
712
  ressource.getBufferAvailablePromise().then(
698
713
  () => {
699
714
  if (ressource.firstStrongReference) {
@@ -702,13 +717,11 @@ export const createRessourceBuilder = (
702
717
  },
703
718
  () => {},
704
719
  )
705
-
706
720
  if (ressource.firstStrongReference) {
707
721
  // this ressource was already strongly referenced by something
708
722
  // don't try to load it twice
709
723
  return effects
710
724
  }
711
-
712
725
  ressource.firstStrongReference = reference
713
726
  // the first strong reference is allowed to transform a reference where we did not know if it was
714
727
  // a js module to a js module
@@ -719,14 +732,11 @@ export const createRessourceBuilder = (
719
732
  effects.push(`mark ${urlToHumanUrl(ressource.url)} as js module`)
720
733
  ressource.isJsModule = infoFromReference.isJsModule
721
734
  }
722
-
723
735
  ressource.usedCallback()
724
-
725
736
  if (ressource.isExternal) {
726
737
  // nothing to do
727
738
  return effects
728
739
  }
729
-
730
740
  if (ressource.isJsModule) {
731
741
  const jsModuleUrl = ressource.url
732
742
  const rollupChunk = onJsModule({
@@ -745,12 +755,10 @@ export const createRessourceBuilder = (
745
755
  }
746
756
  return effects
747
757
  }
748
-
749
758
  if (ressource.isInline) {
750
759
  // nothing to do
751
760
  return effects
752
761
  }
753
-
754
762
  const rollupAsset = onAsset({
755
763
  ressource,
756
764
  })
@@ -761,15 +769,18 @@ export const createRessourceBuilder = (
761
769
  return effects
762
770
  }
763
771
 
772
+ if (bufferBeforeBuild !== undefined) {
773
+ setBufferBeforeBuild(bufferBeforeBuild)
774
+ }
764
775
  Object.assign(ressource, {
765
776
  applyReferenceEffects,
766
777
  getBufferAvailablePromise,
767
778
  getDependenciesAvailablePromise,
768
779
  getReadyPromise,
769
780
  remove,
781
+ setBufferBeforeBuild,
770
782
  buildEnd,
771
783
  })
772
-
773
784
  return ressource
774
785
  }
775
786
 
@@ -778,7 +789,6 @@ export const createRessourceBuilder = (
778
789
  useImportMapToMaximizeCacheReuse,
779
790
  }) => {
780
791
  const jsRessources = {}
781
-
782
792
  Object.keys(ressourceMap).forEach((ressourceUrl) => {
783
793
  const ressource = ressourceMap[ressourceUrl]
784
794
  const rollupFileName = Object.keys(rollupResult).find((key) => {
@@ -786,14 +796,14 @@ export const createRessourceBuilder = (
786
796
  return (
787
797
  rollupFileInfo.url === ressourceUrl ||
788
798
  // asset
789
- ressource.fileName === key ||
799
+ ressource.buildFileNameWithoutHash === key ||
790
800
  ressource.relativeUrl === key
791
801
  )
792
802
  })
793
803
  if (rollupFileName) {
794
804
  const rollupFileInfo = rollupResult[rollupFileName]
795
805
  if (rollupFileInfo.type === "asset") {
796
- ressource.fileName = rollupFileName
806
+ ressource.buildFileNameWithoutHash = rollupFileName
797
807
  return
798
808
  }
799
809
  if (rollupFileInfo.type === "chunk") {
@@ -823,15 +833,13 @@ export const createRessourceBuilder = (
823
833
  const fileName = rollupFileInfo.fileName
824
834
  let code = rollupFileInfo.code
825
835
  ressource.contentType = "application/javascript"
826
-
827
836
  if (useImportMapToMaximizeCacheReuse) {
828
- ressource.fileName = fileName
837
+ ressource.buildFileNameWithoutHash = fileName
829
838
  ressource.buildEnd(code)
830
839
  } else {
831
- ressource.fileName = asFileNameWithoutHash(fileName)
840
+ ressource.buildFileNameWithoutHash = asFileNameWithoutHash(fileName)
832
841
  ressource.buildEnd(code, fileName)
833
842
  }
834
-
835
843
  const map = rollupFileInfo.map
836
844
  if (map) {
837
845
  const sourcemapBuildRelativeUrl = `${ressource.buildRelativeUrl}.map`
@@ -898,12 +906,6 @@ export const createRessourceBuilder = (
898
906
  return ressourceFound
899
907
  }
900
908
 
901
- const shortenUrl = (url) => {
902
- return urlIsInsideOf(url, compileServerOrigin)
903
- ? urlToRelativeUrl(url, compileServerOrigin)
904
- : url
905
- }
906
-
907
909
  const createUrlSiteFromReference = (reference) => {
908
910
  const { referenceUrl, referenceLine, referenceColumn } = reference
909
911
  const referenceRessource = findRessourceByUrl(referenceUrl)
@@ -948,8 +950,14 @@ export const createRessourceBuilder = (
948
950
  }
949
951
  return {
950
952
  ...htmlUrlSite,
951
- line: htmlUrlSite.line + urlSite.line,
952
- column: htmlUrlSite.column + urlSite.column,
953
+ line:
954
+ typeof urlSite.line === "number"
955
+ ? htmlUrlSite.line + urlSite.line
956
+ : htmlUrlSite.line,
957
+ column:
958
+ typeof urlSite.column === "number"
959
+ ? htmlUrlSite.column + urlSite.column
960
+ : htmlUrlSite.column,
953
961
  }
954
962
  }
955
963
 
@@ -120,7 +120,7 @@ export const formatFoundReference = ({
120
120
  reference,
121
121
  showReferenceSourceLocation,
122
122
  referenceEffects,
123
- shortenUrl,
123
+ urlToHumanUrl,
124
124
  }) => {
125
125
  const { ressource } = reference
126
126
  const { isEntryPoint } = ressource
@@ -140,8 +140,14 @@ Create placeholder for ${showReferenceSourceLocation(reference)}${appendEffects(
140
140
  }
141
141
 
142
142
  const { referenceLabel = "unlabelled reference" } = reference
143
+ const message = reference.ressource.isInline
144
+ ? `Found "${referenceLabel}"`
145
+ : `Found ${referenceLabel} referencing "${urlToHumanUrl(
146
+ reference.ressource.url,
147
+ { showCompiledHint: true, preferRelativeUrls: true },
148
+ )}"`
143
149
  return `
144
- Found "${referenceLabel}" referencing "${shortenUrl(reference.ressource.url)}"
150
+ ${message}
145
151
  in ${showReferenceSourceLocation(reference)}${appendEffects(
146
152
  referenceEffects,
147
153
  )}`
@@ -157,14 +163,20 @@ const appendEffects = (effects) => {
157
163
 
158
164
  export const formatDependenciesCollectedMessage = ({
159
165
  ressource,
160
- shortenUrl,
166
+ urlToHumanUrl,
161
167
  }) => {
162
168
  return createDetailedMessage(
163
169
  `
164
- Dependencies collected for ${shortenUrl(ressource.url)}`,
170
+ Dependencies collected for ${urlToHumanUrl(ressource.url, {
171
+ showCompiledHint: true,
172
+ preferRelativeUrls: true,
173
+ })}`,
165
174
  {
166
175
  dependencies: ressource.dependencies.map((dependencyReference) =>
167
- shortenUrl(dependencyReference.ressource.url),
176
+ urlToHumanUrl(dependencyReference.ressource.url, {
177
+ showCompiledHint: true,
178
+ preferRelativeUrls: true,
179
+ }),
168
180
  ),
169
181
  },
170
182
  )