@jsenv/core 22.4.0 → 23.0.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 (106) hide show
  1. package/dist/jsenv_browser_system.js +331 -256
  2. package/dist/jsenv_browser_system.js.map +55 -33
  3. package/dist/jsenv_compile_proxy.js +186 -108
  4. package/dist/jsenv_compile_proxy.js.map +48 -42
  5. package/dist/jsenv_exploring_redirector.js +148 -71
  6. package/dist/jsenv_exploring_redirector.js.map +26 -20
  7. package/dist/jsenv_toolbar.js +215 -104
  8. package/dist/jsenv_toolbar.js.map +39 -26
  9. package/helpers/new_stylesheet/new_stylesheet.js +411 -0
  10. package/{LICENSE → license} +0 -0
  11. package/main.js +8 -7
  12. package/package.json +23 -19
  13. package/readme.md +9 -6
  14. package/src/buildProject.js +3 -7
  15. package/src/execute.js +23 -10
  16. package/src/executeTestPlan.js +0 -4
  17. package/src/importUsingChildProcess.js +36 -32
  18. package/src/internal/{babel-plugin-replace-expressions.js → babel_plugin_replace_expressions.js} +0 -0
  19. package/src/internal/{babel-plugin-transform-import-meta.js → babel_plugin_transform_import_meta.js} +0 -0
  20. package/src/internal/browser-launcher/executeHtmlFile.js +6 -8
  21. package/src/internal/browser-launcher/jsenv-browser-system.js +3 -0
  22. package/src/internal/building/asset_url_versioning.js +5 -9
  23. package/src/internal/building/buildServiceWorker.js +6 -13
  24. package/src/internal/building/buildUsingRollup.js +41 -4
  25. package/src/internal/building/build_logs.js +11 -0
  26. package/src/internal/building/build_stats.js +7 -1
  27. package/src/internal/building/createJsenvRollupPlugin.js +402 -297
  28. package/src/internal/building/css/parseCssRessource.js +67 -71
  29. package/src/internal/building/css/parseCssUrls.js +2 -2
  30. package/src/internal/building/css/{postcss-urlhash-plugin.js → postcss_plugin_url_visitor.js} +43 -21
  31. package/src/internal/building/css/replaceCssUrls.js +17 -14
  32. package/src/internal/building/css_module.js +47 -0
  33. package/src/internal/building/html/parseHtmlRessource.js +44 -43
  34. package/src/internal/building/import_references.js +81 -0
  35. package/src/internal/building/importmap/parseImportmapRessource.js +5 -2
  36. package/src/internal/building/js/minifyJs.js +30 -3
  37. package/src/internal/building/js/parseJsRessource.js +70 -77
  38. package/src/internal/building/json/parseJsonRessource.js +3 -2
  39. package/src/internal/building/parseRessource.js +11 -8
  40. package/src/internal/building/parsing.utils.js +4 -15
  41. package/src/internal/building/ressource_builder.js +142 -114
  42. package/src/internal/building/ressource_builder_util.js +31 -18
  43. package/src/internal/building/{fetchSourcemap.js → sourcemap_loader.js} +29 -27
  44. package/src/internal/building/svg/parseSvgRessource.js +7 -3
  45. package/src/internal/building/url-versioning.js +2 -1
  46. package/src/internal/building/url_fetcher.js +79 -0
  47. package/src/internal/building/url_loader.js +267 -0
  48. package/src/internal/building/url_trace.js +1 -1
  49. package/src/internal/building/webmanifest/parseWebmanifestRessource.js +9 -4
  50. package/src/internal/compiling/{js-compilation-service/ensureGlobalThisImportBabelPlugin.js → babel_plugin_global_this_as_jsenv_import.js} +4 -2
  51. package/src/internal/compiling/babel_plugin_import_assertions.js +100 -0
  52. package/src/internal/compiling/babel_plugin_new_stylesheet_as_jsenv_import.js +109 -0
  53. package/src/internal/compiling/babel_plugin_transform_import_specifier.js +86 -0
  54. package/src/internal/compiling/babel_plugins.js +2 -0
  55. package/src/internal/compiling/createCompiledFileService.js +46 -15
  56. package/src/internal/compiling/html_source_file_service.js +2 -2
  57. package/src/internal/compiling/js-compilation-service/{transformBabelHelperToImportBabelPlugin.js → babel_plugin_babel_helpers_as_jsenv_imports.js} +1 -1
  58. package/src/internal/compiling/js-compilation-service/{ensureRegeneratorRuntimeImportBabelPlugin.js → babel_plugin_regenerator_runtime_as_jsenv_import.js} +1 -1
  59. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +7 -16
  60. package/src/internal/compiling/js-compilation-service/transformJs.js +0 -2
  61. package/src/internal/compiling/jsenvCompilerForHtml.js +2 -7
  62. package/src/internal/compiling/rollup_plugin_commonjs_named_exports.js +2 -2
  63. package/src/internal/compiling/startCompileServer.js +11 -4
  64. package/src/internal/escapeTemplateStringSpecialCharacters.js +20 -0
  65. package/src/internal/executing/coverage/{babel-plugin-instrument.js → babel_plugin_instrument.js} +17 -6
  66. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +1 -1
  67. package/src/internal/executing/executeConcurrently.js +5 -3
  68. package/src/internal/executing/executePlan.js +16 -2
  69. package/src/internal/executing/generateFileExecutionSteps.js +2 -1
  70. package/src/internal/executing/launchAndExecute.js +43 -69
  71. package/src/internal/executing/writeLog.js +25 -18
  72. package/src/internal/exploring/exploring.css +2 -1
  73. package/src/internal/exploring/exploring.redirector.js +0 -1
  74. package/src/internal/generateGroupMap/generateGroupMap.js +14 -10
  75. package/src/internal/generateGroupMap/jsenvBabelPluginCompatMap.js +30 -0
  76. package/src/internal/generateGroupMap/jsenvPluginCompatMap.js +0 -6
  77. package/src/internal/generateGroupMap/one_runtime_compat.js +9 -38
  78. package/src/internal/generateGroupMap/runtime_compat.js +9 -24
  79. package/src/internal/generateGroupMap/runtime_compat_composition.js +2 -12
  80. package/src/internal/generateGroupMap/runtime_support.js +53 -0
  81. package/src/internal/jsenvInternalFiles.js +0 -1
  82. package/src/internal/node-launcher/createControllableNodeProcess.js +2 -3
  83. package/src/internal/response_validation.js +143 -0
  84. package/src/internal/runtime/createBrowserRuntime/createBrowserRuntime.js +8 -3
  85. package/src/internal/runtime/createBrowserRuntime/createBrowserSystem.js +165 -25
  86. package/src/internal/runtime/createBrowserRuntime/displayErrorInDocument.js +7 -6
  87. package/src/internal/runtime/createBrowserRuntime/scanBrowserRuntimeFeatures.js +124 -68
  88. package/src/internal/runtime/createNodeRuntime/createNodeRuntime.js +8 -86
  89. package/src/internal/runtime/createNodeRuntime/createNodeSystem.js +53 -9
  90. package/src/internal/runtime/createNodeRuntime/scanNodeRuntimeFeatures.js +115 -0
  91. package/src/internal/runtime/module-registration.js +86 -136
  92. package/src/internal/runtime/resolveGroup.js +2 -3
  93. package/src/internal/toolbar/compilation/toolbar.compilation.js +15 -17
  94. package/src/internal/toolbar/eventsource/toolbar.eventsource.js +35 -8
  95. package/src/internal/toolbar/toolbar.main.js +7 -4
  96. package/src/internal/url_utils.js +33 -0
  97. package/src/internal/url_utils.test.js +39 -0
  98. package/src/jsonToJavaScriptModule.js +12 -0
  99. package/src/launchBrowser.js +50 -34
  100. package/src/launchNode.js +6 -3
  101. package/src/requireUsingChildProcess.js +36 -32
  102. package/src/startExploring.js +25 -11
  103. package/src/internal/building/transformImportMetaUrlReferences.js +0 -71
  104. package/src/internal/runtime/resolveBrowserGroup.js +0 -5
  105. package/src/internal/runtime/resolveNodeGroup.js +0 -5
  106. package/src/internal/validateResponseStatusIsOk.js +0 -91
@@ -4,9 +4,11 @@ import {
4
4
  urlIsInsideOf,
5
5
  urlToParentUrl,
6
6
  urlToBasename,
7
+ urlToFilename,
7
8
  } from "@jsenv/filesystem"
8
9
  import { createLogger } from "@jsenv/logger"
9
10
 
11
+ import { setJavaScriptSourceMappingUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
10
12
  import { promiseTrackRace } from "../promise_track_race.js"
11
13
  import { parseDataUrl } from "../dataUrl.utils.js"
12
14
 
@@ -22,17 +24,16 @@ import { computeBuildRelativeUrlForRessource } from "./asset_url_versioning.js"
22
24
  import { stringifyUrlSite } from "./url_trace.js"
23
25
 
24
26
  export const createRessourceBuilder = (
25
- { fetch, parse },
27
+ { urlFetcher, urlLoader, parseRessource },
26
28
  {
27
29
  logLevel,
28
30
  format,
29
- baseUrl,
30
- buildDirectoryRelativeUrl,
31
+ compileServerOrigin,
32
+ buildDirectoryUrl,
31
33
 
32
34
  asOriginalServerUrl,
33
35
  urlToHumanUrl,
34
36
 
35
- loadUrl = () => null,
36
37
  emitChunk,
37
38
  emitAsset,
38
39
  setAssetSource,
@@ -43,8 +44,6 @@ export const createRessourceBuilder = (
43
44
  ) => {
44
45
  const logger = createLogger({ logLevel })
45
46
 
46
- const buildDirectoryUrl = resolveUrl(buildDirectoryRelativeUrl, baseUrl)
47
-
48
47
  const createReferenceForEntryPoint = async ({
49
48
  entryContentType,
50
49
  entryUrl,
@@ -58,7 +57,7 @@ export const createRessourceBuilder = (
58
57
  const callerLocation = getCallerLocation()
59
58
  const entryReference = createReference({
60
59
  ressourceSpecifier: entryUrl,
61
- ressourceContentTypeExpected: entryContentType,
60
+ contentTypeExpected: entryContentType,
62
61
  referenceUrl: callerLocation.url,
63
62
  referenceLine: callerLocation.line,
64
63
  referenceColumn: callerLocation.column,
@@ -79,10 +78,7 @@ export const createRessourceBuilder = (
79
78
  // on await que les assets, pour le js rollup s'en occupe
80
79
  await Promise.all(
81
80
  entryReference.ressource.dependencies.map(async (dependency) => {
82
- if (
83
- dependency.ressourceContentTypeExpected ===
84
- "application/importmap+json"
85
- ) {
81
+ if (dependency.contentTypeExpected === "application/importmap+json") {
86
82
  // don't await for importmap right away, it must be handled as the very last asset
87
83
  // to be aware of build mappings.
88
84
  // getReadyPromise() for that importmap will be called during getAllAssetEntryEmittedPromise
@@ -105,6 +101,9 @@ export const createRessourceBuilder = (
105
101
  // for asset builder which is waiting for rollup
106
102
  return
107
103
  }
104
+ if (ressource.isPlaceholder) {
105
+ return
106
+ }
108
107
  await readyPromise
109
108
  }),
110
109
  )
@@ -121,14 +120,17 @@ export const createRessourceBuilder = (
121
120
  jsUrl,
122
121
  jsLine,
123
122
  jsColumn,
123
+ isImportAssertion,
124
124
 
125
+ contentTypeExpected,
125
126
  ressourceSpecifier,
126
127
  contentType,
127
128
  bufferBeforeBuild,
128
129
  }) => {
129
130
  const reference = createReference({
131
+ isImportAssertion,
130
132
  ressourceSpecifier,
131
- ressourceContentTypeExpected: contentType,
133
+ contentTypeExpected,
132
134
  referenceUrl: jsUrl,
133
135
  referenceLine: jsLine,
134
136
  referenceColumn: jsColumn,
@@ -158,7 +160,8 @@ export const createRessourceBuilder = (
158
160
  const createReference = ({
159
161
  referenceShouldNotEmitChunk,
160
162
  isRessourceHint,
161
- ressourceContentTypeExpected,
163
+ isImportAssertion,
164
+ contentTypeExpected,
162
165
  ressourceSpecifier,
163
166
  referenceUrl,
164
167
  referenceColumn,
@@ -168,7 +171,9 @@ export const createRessourceBuilder = (
168
171
  bufferBeforeBuild,
169
172
  isEntryPoint,
170
173
  isJsModule,
174
+ isSourcemap,
171
175
  isInline,
176
+ isPlaceholder,
172
177
  fileNamePattern,
173
178
  urlVersioningDisabled,
174
179
 
@@ -231,7 +236,7 @@ export const createRessourceBuilder = (
231
236
  isExternal = false
232
237
  isInline = true
233
238
  const { mediaType, base64Flag, data } = parseDataUrl(ressourceUrl)
234
- ressourceContentTypeExpected = mediaType
239
+ contentTypeExpected = mediaType
235
240
  contentType = mediaType
236
241
  bufferBeforeBuild = base64Flag
237
242
  ? Buffer.from(data, "base64")
@@ -277,8 +282,10 @@ export const createRessourceBuilder = (
277
282
 
278
283
  isEntryPoint,
279
284
  isJsModule,
285
+ isSourcemap,
280
286
  isExternal,
281
287
  isInline,
288
+ isPlaceholder,
282
289
  fileNamePattern,
283
290
  urlVersioningDisabled,
284
291
  })
@@ -288,7 +295,8 @@ export const createRessourceBuilder = (
288
295
  const reference = {
289
296
  referenceShouldNotEmitChunk,
290
297
  isRessourceHint,
291
- ressourceContentTypeExpected,
298
+ isImportAssertion,
299
+ contentTypeExpected,
292
300
  referenceUrl,
293
301
  referenceColumn,
294
302
  referenceLine,
@@ -328,8 +336,10 @@ export const createRessourceBuilder = (
328
336
 
329
337
  isEntryPoint = false,
330
338
  isJsModule = false,
339
+ isSourcemap = false,
331
340
  isExternal = false,
332
341
  isInline = false,
342
+ isPlaceholder = false,
333
343
 
334
344
  fileNamePattern,
335
345
  urlVersioningDisabled = false,
@@ -343,13 +353,15 @@ export const createRessourceBuilder = (
343
353
 
344
354
  isEntryPoint,
345
355
  isJsModule,
356
+ isSourcemap,
346
357
  isInline,
347
358
  isExternal,
359
+ isPlaceholder,
348
360
 
349
361
  urlVersioningDisabled,
350
362
  fileNamePattern,
351
363
 
352
- relativeUrl: urlToRelativeUrl(ressourceUrl, baseUrl),
364
+ relativeUrl: urlToRelativeUrl(ressourceUrl, compileServerOrigin),
353
365
  bufferAfterBuild: undefined,
354
366
  }
355
367
 
@@ -357,54 +369,9 @@ export const createRessourceBuilder = (
357
369
  ressource.usedCallback = resolve
358
370
  })
359
371
  ressource.inlinedCallbacks = []
360
- ressource.buildDonePromise = new Promise((resolve, reject) => {
361
- ressource.buildDoneCallback = ({ buildFileInfo, buildManifest }) => {
362
- if (!ressource.isJsModule) {
363
- // nothing special to do for asset targets
364
- resolve()
365
- return
366
- }
367
-
368
- // If the module is not in the rollup build, that's an error except when
369
- // rollup chunk was not emitted, which happens when:
370
- // - js was only preloaded/prefetched and never referenced afterwards
371
- // - js was only referenced by other js
372
- if (!buildFileInfo) {
373
- const referencedOnlyByRessourceHint = !ressource.firstStrongReference
374
- if (referencedOnlyByRessourceHint) {
375
- resolve()
376
- return
377
- }
378
-
379
- const referencedOnlyByOtherJs = ressource.references.every(
380
- (ref) => ref.referenceShouldNotEmitChunk,
381
- )
382
- if (referencedOnlyByOtherJs) {
383
- resolve()
384
- return
385
- }
386
-
387
- reject(
388
- new Error(
389
- `${shortenUrl(ressource.url)} cannot be found in the build info`,
390
- ),
391
- )
392
- return
393
- }
394
-
395
- const bufferAfterBuild = Buffer.from(buildFileInfo.code)
396
- const fileName = buildFileInfo.fileName
397
- const buildRelativeUrl = buildManifest[fileName] || fileName
398
- // const fileName = targetFileNameFromBuildManifest(buildManifest, buildRelativeUrl) || buildRelativeUrl
399
- ressource.bufferAfterBuild = bufferAfterBuild
400
- ressource.buildRelativeUrl = buildRelativeUrl
401
- ressource.fileName = fileName
402
- if (buildFileInfo.type === "chunk") {
403
- ressource.contentType = "application/javascript"
404
- }
405
- // logger.debug(`resolve rollup chunk ${shortenUrl(ressourceUrl)}`)
406
- resolve()
407
- }
372
+ ressource.buildDoneCallbacks = []
373
+ ressource.buildDonePromise = new Promise((resolve) => {
374
+ ressource.buildDoneCallbacks.push(resolve)
408
375
  })
409
376
 
410
377
  const getBufferAvailablePromise = memoize(async () => {
@@ -413,6 +380,12 @@ export const createRessourceBuilder = (
413
380
  return
414
381
  }
415
382
 
383
+ // sourcemap placeholder buffer is ready only once the build is done
384
+ if (ressource.isPlaceholder) {
385
+ await ressource.buildDonePromise
386
+ return
387
+ }
388
+
416
389
  if (!ressource.firstStrongReference) {
417
390
  // for preload/prefetch links, we don't want to start the prefetching right away.
418
391
  // Instead we wait for something else to reference the same ressource
@@ -432,13 +405,15 @@ export const createRessourceBuilder = (
432
405
  }
433
406
  }
434
407
 
435
- const response = await fetch(ressource.url, () =>
436
- createRessourceTrace({
437
- ressource,
438
- createUrlSiteFromReference,
439
- findRessourceByUrl,
440
- }),
441
- )
408
+ const response = await urlFetcher.fetchUrl(ressource.url, {
409
+ contentTypeExpected: ressource.firstStrongReference.contentTypeExpected,
410
+ urlTrace: () =>
411
+ createRessourceTrace({
412
+ ressource,
413
+ createUrlSiteFromReference,
414
+ findRessourceByUrl,
415
+ }),
416
+ })
442
417
  if (response.url !== ressource.url) {
443
418
  const urlBeforeRedirection = ressource.url
444
419
  const urlAfterRedirection = response.url
@@ -469,7 +444,7 @@ export const createRessourceBuilder = (
469
444
  let parsingDone = false
470
445
  const notifyReferenceFound = ({
471
446
  isRessourceHint,
472
- ressourceContentTypeExpected,
447
+ contentTypeExpected,
473
448
  ressourceSpecifier,
474
449
  referenceLine,
475
450
  referenceColumn,
@@ -478,6 +453,8 @@ export const createRessourceBuilder = (
478
453
  bufferBeforeBuild,
479
454
  isJsModule = false,
480
455
  isInline = false,
456
+ isSourcemap = false,
457
+ isPlaceholder = false,
481
458
  urlVersioningDisabled,
482
459
  fileNamePattern,
483
460
  }) => {
@@ -493,12 +470,14 @@ export const createRessourceBuilder = (
493
470
  referenceLine,
494
471
  referenceColumn,
495
472
  isRessourceHint,
496
- ressourceContentTypeExpected,
473
+ contentTypeExpected,
497
474
 
498
475
  contentType,
499
476
  bufferBeforeBuild,
500
477
  isJsModule,
501
478
  isInline,
479
+ isSourcemap,
480
+ isPlaceholder,
502
481
 
503
482
  urlVersioningDisabled,
504
483
  fileNamePattern,
@@ -514,7 +493,7 @@ export const createRessourceBuilder = (
514
493
  logger.debug(`parse ${urlToHumanUrl(ressource.url)}`)
515
494
  }
516
495
 
517
- const parseReturnValue = await parse(ressource, {
496
+ const parseReturnValue = await parseRessource(ressource, {
518
497
  format,
519
498
  notifyReferenceFound,
520
499
  })
@@ -545,12 +524,24 @@ export const createRessourceBuilder = (
545
524
  const dependencies = ressource.dependencies
546
525
  await Promise.all(
547
526
  dependencies.map(async (dependencyReference) => {
548
- await dependencyReference.ressource.getReadyPromise()
527
+ const dependencyRessource = dependencyReference.ressource
528
+ if (dependencyRessource.isPlaceholder) {
529
+ return
530
+ }
531
+ await dependencyRessource.getReadyPromise()
549
532
  }),
550
533
  )
551
534
 
552
535
  const transform = ressourceTransformMap[ressource.url]
553
536
  if (typeof transform !== "function") {
537
+ if (ressource.isPlaceholder) {
538
+ return
539
+ }
540
+ // sourcemap content depends on their source file
541
+ // sourcemap.buildEnd() will be called by the source file
542
+ if (ressource.isSourcemap) {
543
+ return
544
+ }
554
545
  ressource.buildEnd(
555
546
  ressource.bufferAfterBuild || ressource.bufferBeforeBuild,
556
547
  ressource.buildRelativeUrl,
@@ -567,23 +558,14 @@ export const createRessourceBuilder = (
567
558
  // }
568
559
  // we don't yet know the exact importerBuildRelativeUrl but we can generate a fake one
569
560
  // to ensure we resolve dependency against where the importer file will be
570
-
571
561
  const importerBuildRelativeUrl = precomputeBuildRelativeUrlForRessource(
572
562
  ressource,
573
563
  {
574
564
  lineBreakNormalization,
575
565
  },
576
566
  )
577
- const assetEmitters = []
578
- const transformReturnValue = await transform({
579
- precomputeBuildRelativeUrl: (bufferAfterBuild) =>
580
- precomputeBuildRelativeUrlForRessource(ressource, {
581
- bufferAfterBuild,
582
- lineBreakNormalization,
583
- }),
584
- registerAssetEmitter: (callback) => {
585
- assetEmitters.push(callback)
586
- },
567
+ await transform({
568
+ buildDirectoryUrl,
587
569
  getUrlRelativeToImporter: (referencedRessource) => {
588
570
  const ressourceImporter = ressource
589
571
 
@@ -615,28 +597,11 @@ export const createRessourceBuilder = (
615
597
  return ressourceMap[originalServerUrl]
616
598
  },
617
599
  })
618
- if (transformReturnValue === null || transformReturnValue === undefined) {
619
- throw new Error(`transform must return an object {code, map}`)
620
- }
621
-
622
- let bufferAfterBuild
623
- let buildRelativeUrl
624
- if (typeof transformReturnValue === "string") {
625
- bufferAfterBuild = transformReturnValue
626
- } else {
627
- bufferAfterBuild = transformReturnValue.bufferAfterBuild
628
- if (transformReturnValue.buildRelativeUrl) {
629
- buildRelativeUrl = transformReturnValue.buildRelativeUrl
630
- }
600
+ if (typeof ressource.bufferAfterBuild === "undefined") {
601
+ throw new Error(
602
+ `transform must call ressource.buildEnd() for ${ressource.url}`,
603
+ )
631
604
  }
632
-
633
- ressource.buildEnd(bufferAfterBuild, buildRelativeUrl)
634
- assetEmitters.forEach((callback) => {
635
- callback({
636
- emitAsset,
637
- buildDirectoryUrl,
638
- })
639
- })
640
605
  })
641
606
 
642
607
  // was used to remove sourcemap files that are renamed after they are emitted
@@ -738,6 +703,8 @@ export const createRessourceBuilder = (
738
703
  jsModuleUrl,
739
704
  jsModuleIsInline: ressource.isInline,
740
705
  jsModuleSource: String(bufferBeforeBuild),
706
+ line: reference.referenceLine,
707
+ column: reference.referenceColumn,
741
708
  })
742
709
 
743
710
  const name = urlToBasename(jsModuleUrl)
@@ -793,7 +760,6 @@ export const createRessourceBuilder = (
793
760
  const rollupBuildEnd = ({ jsModuleBuild, buildManifest }) => {
794
761
  Object.keys(ressourceMap).forEach((ressourceUrl) => {
795
762
  const ressource = ressourceMap[ressourceUrl]
796
- const { buildDoneCallback } = ressource
797
763
 
798
764
  const buildRelativeUrl = Object.keys(jsModuleBuild).find(
799
765
  (buildRelativeUrlCandidate) => {
@@ -802,14 +768,74 @@ export const createRessourceBuilder = (
802
768
  },
803
769
  )
804
770
  const buildFileInfo = jsModuleBuild[buildRelativeUrl]
805
-
806
- buildDoneCallback({
807
- buildFileInfo,
808
- buildManifest,
771
+ applyBuildEndEffects(ressource, { buildFileInfo, buildManifest })
772
+ const { buildDoneCallbacks } = ressource
773
+ buildDoneCallbacks.forEach((buildDoneCallback) => {
774
+ buildDoneCallback()
809
775
  })
810
776
  })
811
777
  }
812
778
 
779
+ const applyBuildEndEffects = (
780
+ ressource,
781
+ {
782
+ buildFileInfo,
783
+ // buildManifest
784
+ },
785
+ ) => {
786
+ if (!ressource.isJsModule) {
787
+ // nothing special to do for non-js ressources
788
+ return
789
+ }
790
+
791
+ // If the module is not in the rollup build, that's an error except when
792
+ // rollup chunk was not emitted, which happens when:
793
+ // - js was only preloaded/prefetched and never referenced afterwards
794
+ // - js was only referenced by other js
795
+ if (!buildFileInfo) {
796
+ const referencedOnlyByRessourceHint = !ressource.firstStrongReference
797
+ if (referencedOnlyByRessourceHint) {
798
+ return
799
+ }
800
+
801
+ const referencedOnlyByOtherJs = ressource.references.every(
802
+ (ref) => ref.referenceShouldNotEmitChunk,
803
+ )
804
+ if (referencedOnlyByOtherJs) {
805
+ return
806
+ }
807
+
808
+ throw new Error(
809
+ `${shortenUrl(ressource.url)} cannot be found in the build info`,
810
+ )
811
+ }
812
+
813
+ const fileName = buildFileInfo.fileName
814
+ // const buildRelativeUrl = buildManifest[fileName] || fileName
815
+ let code = buildFileInfo.code
816
+
817
+ if (buildFileInfo.type === "chunk") {
818
+ ressource.contentType = "application/javascript"
819
+ }
820
+ ressource.fileName = fileName
821
+ ressource.buildEnd(
822
+ code,
823
+ // buildRelativeUrl
824
+ )
825
+
826
+ const map = buildFileInfo.map
827
+ if (map) {
828
+ const jsBuildUrl = resolveUrl(
829
+ ressource.buildRelativeUrl,
830
+ buildDirectoryUrl,
831
+ )
832
+ const sourcemapUrlForJs = `${urlToFilename(jsBuildUrl)}.map`
833
+ code = setJavaScriptSourceMappingUrl(code, sourcemapUrlForJs)
834
+ buildFileInfo.code = code
835
+ ressource.bufferAfterBuild = code
836
+ }
837
+ }
838
+
813
839
  const findRessourceByUrl = (url) => {
814
840
  if (url in ressourceMap) {
815
841
  return ressourceMap[url]
@@ -834,7 +860,9 @@ export const createRessourceBuilder = (
834
860
  }
835
861
 
836
862
  const shortenUrl = (url) => {
837
- return urlIsInsideOf(url, baseUrl) ? urlToRelativeUrl(url, baseUrl) : url
863
+ return urlIsInsideOf(url, compileServerOrigin)
864
+ ? urlToRelativeUrl(url, compileServerOrigin)
865
+ : url
838
866
  }
839
867
 
840
868
  const createUrlSiteFromReference = (reference) => {
@@ -842,7 +870,7 @@ export const createRessourceBuilder = (
842
870
  const referenceRessource = findRessourceByUrl(referenceUrl)
843
871
  const referenceSource = referenceRessource
844
872
  ? referenceRessource.bufferBeforeBuild
845
- : loadUrl(referenceUrl)
873
+ : urlLoader.getUrlResponseTextFromMemory(referenceUrl)
846
874
  const referenceSourceAsString = referenceSource
847
875
  ? String(referenceSource)
848
876
  : ""
@@ -53,7 +53,7 @@ export const getCallerLocation = () => {
53
53
  }
54
54
  }
55
55
 
56
- export const compareContentType = (leftContentType, rightContentType) => {
56
+ const compareContentType = (leftContentType, rightContentType) => {
57
57
  if (leftContentType === rightContentType) {
58
58
  return true
59
59
  }
@@ -76,24 +76,20 @@ export const checkContentType = (
76
76
  reference,
77
77
  { logger, showReferenceSourceLocation },
78
78
  ) => {
79
- const { ressourceContentTypeExpected } = reference
79
+ const { contentTypeExpected } = reference
80
80
  const { contentType } = reference.ressource
81
81
 
82
- if (!ressourceContentTypeExpected) {
82
+ if (!contentTypeExpected) {
83
83
  return
84
84
  }
85
85
 
86
- if (compareContentType(ressourceContentTypeExpected, contentType)) {
87
- return
88
- }
86
+ const contentTypeIsOk = Array.isArray(contentTypeExpected)
87
+ ? contentTypeExpected.some((allowedContentType) => {
88
+ return compareContentType(allowedContentType, contentType)
89
+ })
90
+ : compareContentType(contentTypeExpected, contentType)
89
91
 
90
- // sourcemap content type is fine if we got octet-stream too
91
- const { ressource } = reference
92
- if (
93
- ressourceContentTypeExpected === "application/json" &&
94
- contentType === "application/octet-stream" &&
95
- ressource.url.endsWith(".map")
96
- ) {
92
+ if (contentTypeIsOk) {
97
93
  return
98
94
  }
99
95
 
@@ -108,11 +104,11 @@ const formatContentTypeMismatchLog = (
108
104
  reference,
109
105
  { showReferenceSourceLocation },
110
106
  ) => {
111
- const { ressourceContentTypeExpected, ressource } = reference
107
+ const { contentTypeExpected, ressource } = reference
112
108
  const { contentType, url } = ressource
113
109
 
114
110
  return createDetailedMessage(
115
- `A reference was expecting ${ressourceContentTypeExpected} but found ${contentType} instead.`,
111
+ `A reference was expecting ${contentTypeExpected} but found ${contentType} instead.`,
116
112
  {
117
113
  ["reference"]: showReferenceSourceLocation(reference),
118
114
  ["ressource url"]: url,
@@ -126,7 +122,6 @@ export const formatFoundReference = ({
126
122
  referenceEffects,
127
123
  }) => {
128
124
  const { isRessourceHint } = reference
129
-
130
125
  if (isRessourceHint) {
131
126
  return formatFoundRessourceHint({
132
127
  reference,
@@ -137,7 +132,6 @@ export const formatFoundReference = ({
137
132
 
138
133
  const { ressource } = reference
139
134
  const { isEntryPoint } = ressource
140
-
141
135
  if (isEntryPoint) {
142
136
  return formatCreateReferenceForEntry({
143
137
  reference,
@@ -147,7 +141,6 @@ export const formatFoundReference = ({
147
141
  }
148
142
 
149
143
  const { isExternal } = ressource
150
-
151
144
  if (isExternal) {
152
145
  return formatFoundReferenceToExternalRessource({
153
146
  reference,
@@ -156,6 +149,15 @@ export const formatFoundReference = ({
156
149
  })
157
150
  }
158
151
 
152
+ const { isPlaceholder } = ressource
153
+ if (isPlaceholder) {
154
+ return formatCreateRessourcePlaceholder({
155
+ reference,
156
+ showReferenceSourceLocation,
157
+ referenceEffects,
158
+ })
159
+ }
160
+
159
161
  const { isInline, isJsModule } = ressource
160
162
  if (isInline && !isJsModule) {
161
163
  return formatFoundReferenceToInlineRessource({
@@ -217,6 +219,17 @@ Found external url in ${showReferenceSourceLocation(reference)}${appendEffects(
217
219
  )}`
218
220
  }
219
221
 
222
+ const formatCreateRessourcePlaceholder = ({
223
+ reference,
224
+ showReferenceSourceLocation,
225
+ referenceEffects,
226
+ }) => {
227
+ return `
228
+ Create placeholder for ressource in ${showReferenceSourceLocation(
229
+ reference,
230
+ )}${appendEffects(referenceEffects)}`
231
+ }
232
+
220
233
  const formatFoundReferenceToInlineRessource = ({
221
234
  reference,
222
235
  showReferenceSourceLocation,
@@ -1,56 +1,58 @@
1
1
  import { createCancellationToken } from "@jsenv/cancellation"
2
2
  import { resolveUrl } from "@jsenv/filesystem"
3
3
  import { createLogger, createDetailedMessage } from "@jsenv/logger"
4
+
4
5
  import {
5
6
  dataUrlToRawData,
6
7
  parseDataUrl,
7
8
  } from "@jsenv/core/src/internal/dataUrl.utils.js"
8
- import { getJavaScriptSourceMappingUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
9
9
  import { fetchUrl } from "@jsenv/core/src/internal/fetchUrl.js"
10
- import { validateResponseStatusIsOk } from "@jsenv/core/src/internal/validateResponseStatusIsOk.js"
10
+ import { validateResponse } from "@jsenv/core/src/internal/response_validation.js"
11
11
 
12
- export const fetchSourcemap = async (
13
- jsUrl,
14
- jsString,
15
- {
16
- cancellationToken = createCancellationToken(),
17
- logger = createLogger(),
18
- } = {},
19
- ) => {
20
- const jsSourcemapUrl = getJavaScriptSourceMappingUrl(jsString)
12
+ export const loadSourcemap = async ({
13
+ cancellationToken = createCancellationToken(),
14
+ logger = createLogger(),
21
15
 
22
- if (!jsSourcemapUrl) {
16
+ code,
17
+ url,
18
+ getSourceMappingUrl,
19
+ } = {}) => {
20
+ const sourcemapSpecifier = getSourceMappingUrl(code)
21
+ if (!sourcemapSpecifier) {
23
22
  return null
24
23
  }
25
24
 
26
- if (jsSourcemapUrl.startsWith("data:")) {
27
- const jsSourcemapString = dataUrlToRawData(parseDataUrl(jsSourcemapUrl))
25
+ const sourcemapUrl = resolveUrl(sourcemapSpecifier, url)
26
+ if (sourcemapUrl.startsWith("data:")) {
27
+ const sourcemapString = dataUrlToRawData(parseDataUrl(sourcemapUrl))
28
28
  return parseSourcemapString(
29
- jsSourcemapString,
30
- jsSourcemapUrl,
31
- `inline comment in ${jsUrl}`,
29
+ sourcemapString,
30
+ sourcemapUrl,
31
+ `inline comment in ${url}`,
32
32
  )
33
33
  }
34
34
 
35
- const sourcemapUrl = resolveUrl(jsSourcemapUrl, jsUrl)
36
35
  const sourcemapResponse = await fetchUrl(sourcemapUrl, {
37
36
  cancellationToken,
38
37
  ignoreHttpsError: true,
39
38
  })
40
- const okValidation = await validateResponseStatusIsOk(sourcemapResponse, {
41
- traceImport: () => [jsUrl],
39
+ const { isValid, details } = await validateResponse(sourcemapResponse, {
40
+ // we could have a better trace
41
+ // by appending the reference found in code
42
+ // to an existing urlTrace array
43
+ // good enough for now
44
+ urlTrace: url,
45
+ contentTypeExpected: ["application/json", "application/octet-stream"],
42
46
  })
43
-
44
- if (!okValidation.valid) {
45
- logger.warn(`unexpected response for sourcemap file:
46
- ${okValidation.message}`)
47
+ if (!isValid) {
48
+ logger.warn(
49
+ createDetailedMessage(`unexpected response for sourcemap`, details),
50
+ )
47
51
  return null
48
52
  }
49
53
 
50
- // in theory we should also check sourcemapResponse content-type is correctly set
51
- // but not really important.
52
54
  const sourcemapBodyAsText = await sourcemapResponse.text()
53
- return parseSourcemapString(sourcemapBodyAsText, sourcemapUrl, jsUrl)
55
+ return parseSourcemapString(sourcemapBodyAsText, sourcemapUrl, url)
54
56
  }
55
57
 
56
58
  const parseSourcemapString = (sourcemapString, sourcemapUrl, importer) => {