@jsenv/core 27.0.0-alpha.31 → 27.0.0-alpha.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.0-alpha.31",
3
+ "version": "27.0.0-alpha.32",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -234,6 +234,7 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
234
234
  })
235
235
  }
236
236
  })
237
+ const bundleUrlRedirections = {}
237
238
  await Object.keys(bundlers).reduce(async (previous, type) => {
238
239
  await previous
239
240
  const bundler = bundlers[type]
@@ -276,6 +277,13 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
276
277
  rawUrlRedirections[url] = buildUrl
277
278
  rawUrls[buildUrl] = url
278
279
  bundleUrlInfos[buildUrl] = bundleUrlInfo
280
+ if (bundlerGeneratedUrlInfo.data.bundleRelativeUrl) {
281
+ const urlForBundler = new URL(
282
+ bundlerGeneratedUrlInfo.data.bundleRelativeUrl,
283
+ buildDirectoryUrl,
284
+ ).href
285
+ bundleUrlRedirections[urlForBundler] = buildUrl
286
+ }
279
287
  })
280
288
  } catch (e) {
281
289
  bundleTask.fail()
@@ -313,6 +321,10 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
313
321
  reference.specifier[0] === "/"
314
322
  ? new URL(reference.specifier.slice(1), buildDirectoryUrl).href
315
323
  : new URL(reference.specifier, reference.parentUrl).href
324
+ const urlRedirectedByBundle = bundleUrlRedirections[url]
325
+ if (urlRedirectedByBundle) {
326
+ return urlRedirectedByBundle
327
+ }
316
328
  const parentIsFromBundle = Boolean(
317
329
  bundleUrlInfos[reference.parentUrl],
318
330
  )
@@ -579,220 +591,22 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
579
591
  ${Object.keys(finalGraph.urlInfos).join("\n")}`,
580
592
  )
581
593
  if (versioning) {
582
- const versioningTask = createTaskLog(logger, "inject version in urls")
583
- try {
584
- const urlsSorted = sortUrlGraphByDependencies(finalGraph)
585
- urlsSorted.forEach((url) => {
586
- if (url.startsWith("data:")) {
587
- return
588
- }
589
- const urlInfo = finalGraph.getUrlInfo(url)
590
- if (urlInfo.type === "sourcemap") {
591
- return
592
- }
593
- // ignore:
594
- // - inline files:
595
- // they are already taken into account in the file where they appear
596
- // - external files
597
- // we don't know their content
598
- // - unused files without reference
599
- // File updated such as style.css -> style.css.js or file.js->file.es5.js
600
- // Are used at some point just to be discarded later because they need to be converted
601
- // There is no need to version them and we could not because the file have been ignored
602
- // so their content is unknown
603
- if (urlInfo.isInline) {
604
- return
605
- }
606
- if (urlInfo.external) {
607
- return
608
- }
609
- if (!urlInfo.data.isEntryPoint && urlInfo.dependents.size === 0) {
610
- return
611
- }
612
-
613
- const urlContent =
614
- urlInfo.type === "html"
615
- ? stringifyHtmlAst(
616
- parseHtmlString(urlInfo.content, {
617
- storeOriginalPositions: false,
618
- }),
619
- { removeOriginalPositionAttributes: true },
620
- )
621
- : urlInfo.content
622
- const versionGenerator = createVersionGenerator()
623
- versionGenerator.augmentWithContent({
624
- content: urlContent,
625
- contentType: urlInfo.contentType,
626
- lineBreakNormalization,
627
- })
628
- urlInfo.dependencies.forEach((dependencyUrl) => {
629
- // this dependency is inline (data:) or remote (http://, https://)
630
- if (!dependencyUrl.startsWith("file:")) {
631
- return
632
- }
633
- const dependencyUrlInfo = finalGraph.getUrlInfo(dependencyUrl)
634
- if (
635
- // this content is part of the file, no need to take into account twice
636
- dependencyUrlInfo.isInline ||
637
- // this dependency content is not known
638
- dependencyUrlInfo.external
639
- ) {
640
- return
641
- }
642
- if (dependencyUrlInfo.data.version) {
643
- versionGenerator.augmentWithDependencyVersion(
644
- dependencyUrlInfo.data.version,
645
- )
646
- } else {
647
- // because all dependencies are know, if the dependency has no version
648
- // it means there is a circular dependency between this file
649
- // and it's dependency
650
- // in that case we'll use the dependency content
651
- versionGenerator.augmentWithContent({
652
- content: dependencyUrlInfo.content,
653
- contentType: dependencyUrlInfo.contentType,
654
- lineBreakNormalization,
655
- })
656
- }
657
- })
658
- urlInfo.data.version = versionGenerator.generate()
659
-
660
- urlInfo.data.versionedUrl = injectVersionIntoBuildUrl({
661
- buildUrl: urlInfo.url,
662
- version: urlInfo.data.version,
663
- versioningMethod,
664
- })
665
- })
666
- const versionMappings = {}
667
- const usedVersionMappings = []
668
- const versioningKitchen = createKitchen({
669
- logger,
670
- rootDirectoryUrl: buildDirectoryUrl,
671
- urlGraph: finalGraph,
672
- scenario: "build",
673
- sourcemaps,
674
- runtimeCompat,
675
- plugins: [
676
- jsenvPluginInline({
677
- fetchInlineUrls: false,
678
- analyzeConvertedScripts: true, // to be able to version their urls
679
- allowEscapeForVersioning: true,
680
- }),
681
- {
682
- name: "jsenv:versioning",
683
- appliesDuring: { build: true },
684
- resolveUrl: (reference) => {
685
- if (reference.specifier[0] === "#") {
686
- reference.external = true
687
- }
688
- const buildUrl = buildUrls[reference.specifier]
689
- if (buildUrl) {
690
- return buildUrl
691
- }
692
- const url = new URL(reference.specifier, reference.parentUrl).href
693
- return url
694
- },
695
- formatUrl: (reference) => {
696
- if (reference.isInline) {
697
- return null
698
- }
699
- // specifier comes from "normalize" hook done a bit earlier in this file
700
- // we want to get back their build url to access their infos
701
- const referencedUrlInfo = finalGraph.getUrlInfo(reference.url)
702
- if (!canUseVersionedUrl(referencedUrlInfo)) {
703
- return reference.specifier
704
- }
705
- // data:* urls and so on
706
- if (!referencedUrlInfo.url.startsWith("file:")) {
707
- return null
708
- }
709
- const versionedUrl = referencedUrlInfo.data.versionedUrl
710
- if (!versionedUrl) {
711
- // happens for sourcemap
712
- return `${baseUrl}${urlToRelativeUrl(
713
- referencedUrlInfo.url,
714
- buildDirectoryUrl,
715
- )}`
716
- }
717
- const versionedSpecifier = `${baseUrl}${urlToRelativeUrl(
718
- versionedUrl,
719
- buildDirectoryUrl,
720
- )}`
721
- versionMappings[reference.specifier] = versionedSpecifier
722
- buildUrls[versionedSpecifier] = versionedUrl
723
-
724
- const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
725
- if (parentUrlInfo.jsQuote) {
726
- // the url is inline inside js quotes
727
- usedVersionMappings.push(reference.specifier)
728
- return () =>
729
- `${parentUrlInfo.jsQuote}+__v__(${JSON.stringify(
730
- reference.specifier,
731
- )})+${parentUrlInfo.jsQuote}`
732
- }
733
- if (
734
- reference.type === "js_url_specifier" ||
735
- reference.subtype === "import_dynamic"
736
- ) {
737
- usedVersionMappings.push(reference.specifier)
738
- return () => `__v__(${JSON.stringify(reference.specifier)})`
739
- }
740
- return versionedSpecifier
741
- },
742
- fetchUrlContent: (versionedUrlInfo) => {
743
- if (!versionedUrlInfo.url.startsWith("file:")) {
744
- return { external: true }
745
- }
746
- if (versionedUrlInfo.isInline) {
747
- const rawUrlInfo = rawGraph.getUrlInfo(
748
- rawUrls[versionedUrlInfo.url],
749
- )
750
- const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
751
- return {
752
- originalContent: rawUrlInfo
753
- ? rawUrlInfo.originalContent
754
- : undefined,
755
- sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
756
- contentType: versionedUrlInfo.contentType,
757
- content: versionedUrlInfo.content,
758
- }
759
- }
760
- return versionedUrlInfo
761
- },
762
- },
763
- ],
764
- })
765
- await loadUrlGraph({
766
- urlGraph: finalGraph,
767
- kitchen: versioningKitchen,
768
- startLoading: (cookEntryFile) => {
769
- postBuildEntryUrls.forEach((postBuildEntryUrl) => {
770
- cookEntryFile({
771
- trace: `entryPoint`,
772
- type: "entry_point",
773
- specifier: postBuildEntryUrl,
774
- })
775
- })
776
- },
777
- })
778
- if (usedVersionMappings.length) {
779
- const versionMappingsNeeded = {}
780
- usedVersionMappings.forEach((specifier) => {
781
- versionMappingsNeeded[specifier] = versionMappings[specifier]
782
- })
783
- await injectGlobalVersionMapping({
784
- finalGraphKitchen,
785
- finalGraph,
786
- versionMappings: versionMappingsNeeded,
787
- })
788
- }
789
- } catch (e) {
790
- versioningTask.fail()
791
- throw e
792
- }
793
- versioningTask.done()
594
+ await applyUrlVersioning({
595
+ logger,
596
+ buildDirectoryUrl,
597
+ rawUrls,
598
+ buildUrls,
599
+ baseUrl,
600
+ postBuildEntryUrls,
601
+ sourcemaps,
602
+ runtimeCompat,
603
+ rawGraph,
604
+ finalGraph,
605
+ finalGraphKitchen,
606
+ lineBreakNormalization,
607
+ versioningMethod,
608
+ })
794
609
  }
795
-
796
610
  GRAPH.forEach(finalGraph, (urlInfo) => {
797
611
  if (!urlInfo.url.startsWith("file:")) {
798
612
  return
@@ -818,7 +632,6 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
818
632
  urlInfo.data.buildUrlIsVersioned = useVersionedUrl
819
633
  urlInfo.data.buildUrlSpecifier = buildUrlSpecifier
820
634
  })
821
-
822
635
  await resyncRessourceHints({
823
636
  finalGraphKitchen,
824
637
  finalGraph,
@@ -846,7 +659,6 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
846
659
  finalGraph,
847
660
  lineBreakNormalization,
848
661
  })
849
-
850
662
  logger.debug(
851
663
  `graph urls post-versioning:
852
664
  ${Object.keys(finalGraph.urlInfos).join("\n")}`,
@@ -905,6 +717,235 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
905
717
  }
906
718
  }
907
719
 
720
+ const applyUrlVersioning = async ({
721
+ logger,
722
+ buildDirectoryUrl,
723
+ rawUrls,
724
+ buildUrls,
725
+ baseUrl,
726
+ postBuildEntryUrls,
727
+ sourcemaps,
728
+ runtimeCompat,
729
+ rawGraph,
730
+ finalGraph,
731
+ finalGraphKitchen,
732
+ lineBreakNormalization,
733
+ versioningMethod,
734
+ }) => {
735
+ const versioningTask = createTaskLog(logger, "inject version in urls")
736
+ try {
737
+ const urlsSorted = sortUrlGraphByDependencies(finalGraph)
738
+ urlsSorted.forEach((url) => {
739
+ if (url.startsWith("data:")) {
740
+ return
741
+ }
742
+ const urlInfo = finalGraph.getUrlInfo(url)
743
+ if (urlInfo.type === "sourcemap") {
744
+ return
745
+ }
746
+ // ignore:
747
+ // - inline files:
748
+ // they are already taken into account in the file where they appear
749
+ // - external files
750
+ // we don't know their content
751
+ // - unused files without reference
752
+ // File updated such as style.css -> style.css.js or file.js->file.es5.js
753
+ // Are used at some point just to be discarded later because they need to be converted
754
+ // There is no need to version them and we could not because the file have been ignored
755
+ // so their content is unknown
756
+ if (urlInfo.isInline) {
757
+ return
758
+ }
759
+ if (urlInfo.external) {
760
+ return
761
+ }
762
+ if (!urlInfo.data.isEntryPoint && urlInfo.dependents.size === 0) {
763
+ return
764
+ }
765
+
766
+ const urlContent =
767
+ urlInfo.type === "html"
768
+ ? stringifyHtmlAst(
769
+ parseHtmlString(urlInfo.content, {
770
+ storeOriginalPositions: false,
771
+ }),
772
+ { removeOriginalPositionAttributes: true },
773
+ )
774
+ : urlInfo.content
775
+ const versionGenerator = createVersionGenerator()
776
+ versionGenerator.augmentWithContent({
777
+ content: urlContent,
778
+ contentType: urlInfo.contentType,
779
+ lineBreakNormalization,
780
+ })
781
+ urlInfo.dependencies.forEach((dependencyUrl) => {
782
+ // this dependency is inline (data:) or remote (http://, https://)
783
+ if (!dependencyUrl.startsWith("file:")) {
784
+ return
785
+ }
786
+ const dependencyUrlInfo = finalGraph.getUrlInfo(dependencyUrl)
787
+ if (
788
+ // this content is part of the file, no need to take into account twice
789
+ dependencyUrlInfo.isInline ||
790
+ // this dependency content is not known
791
+ dependencyUrlInfo.external
792
+ ) {
793
+ return
794
+ }
795
+ if (dependencyUrlInfo.data.version) {
796
+ versionGenerator.augmentWithDependencyVersion(
797
+ dependencyUrlInfo.data.version,
798
+ )
799
+ } else {
800
+ // because all dependencies are know, if the dependency has no version
801
+ // it means there is a circular dependency between this file
802
+ // and it's dependency
803
+ // in that case we'll use the dependency content
804
+ versionGenerator.augmentWithContent({
805
+ content: dependencyUrlInfo.content,
806
+ contentType: dependencyUrlInfo.contentType,
807
+ lineBreakNormalization,
808
+ })
809
+ }
810
+ })
811
+ urlInfo.data.version = versionGenerator.generate()
812
+
813
+ urlInfo.data.versionedUrl = injectVersionIntoBuildUrl({
814
+ buildUrl: urlInfo.url,
815
+ version: urlInfo.data.version,
816
+ versioningMethod,
817
+ })
818
+ })
819
+ const versionMappings = {}
820
+ const usedVersionMappings = []
821
+ const versioningKitchen = createKitchen({
822
+ logger,
823
+ rootDirectoryUrl: buildDirectoryUrl,
824
+ urlGraph: finalGraph,
825
+ scenario: "build",
826
+ sourcemaps,
827
+ runtimeCompat,
828
+ plugins: [
829
+ jsenvPluginInline({
830
+ fetchInlineUrls: false,
831
+ analyzeConvertedScripts: true, // to be able to version their urls
832
+ allowEscapeForVersioning: true,
833
+ }),
834
+ {
835
+ name: "jsenv:versioning",
836
+ appliesDuring: { build: true },
837
+ resolveUrl: (reference) => {
838
+ if (reference.specifier[0] === "#") {
839
+ reference.external = true
840
+ }
841
+ const buildUrl = buildUrls[reference.specifier]
842
+ if (buildUrl) {
843
+ return buildUrl
844
+ }
845
+ const url = new URL(reference.specifier, reference.parentUrl).href
846
+ return url
847
+ },
848
+ formatUrl: (reference) => {
849
+ if (reference.isInline) {
850
+ return null
851
+ }
852
+ // specifier comes from "normalize" hook done a bit earlier in this file
853
+ // we want to get back their build url to access their infos
854
+ const referencedUrlInfo = finalGraph.getUrlInfo(reference.url)
855
+ if (!canUseVersionedUrl(referencedUrlInfo)) {
856
+ return reference.specifier
857
+ }
858
+ // data:* urls and so on
859
+ if (!referencedUrlInfo.url.startsWith("file:")) {
860
+ return null
861
+ }
862
+ const versionedUrl = referencedUrlInfo.data.versionedUrl
863
+ if (!versionedUrl) {
864
+ // happens for sourcemap
865
+ return `${baseUrl}${urlToRelativeUrl(
866
+ referencedUrlInfo.url,
867
+ buildDirectoryUrl,
868
+ )}`
869
+ }
870
+ const versionedSpecifier = `${baseUrl}${urlToRelativeUrl(
871
+ versionedUrl,
872
+ buildDirectoryUrl,
873
+ )}`
874
+ versionMappings[reference.specifier] = versionedSpecifier
875
+ buildUrls[versionedSpecifier] = versionedUrl
876
+
877
+ const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl)
878
+ if (parentUrlInfo.jsQuote) {
879
+ // the url is inline inside js quotes
880
+ usedVersionMappings.push(reference.specifier)
881
+ return () =>
882
+ `${parentUrlInfo.jsQuote}+__v__(${JSON.stringify(
883
+ reference.specifier,
884
+ )})+${parentUrlInfo.jsQuote}`
885
+ }
886
+ if (
887
+ reference.type === "js_url_specifier" ||
888
+ reference.subtype === "import_dynamic"
889
+ ) {
890
+ usedVersionMappings.push(reference.specifier)
891
+ return () => `__v__(${JSON.stringify(reference.specifier)})`
892
+ }
893
+ return versionedSpecifier
894
+ },
895
+ fetchUrlContent: (versionedUrlInfo) => {
896
+ if (!versionedUrlInfo.url.startsWith("file:")) {
897
+ return { external: true }
898
+ }
899
+ if (versionedUrlInfo.isInline) {
900
+ const rawUrlInfo = rawGraph.getUrlInfo(
901
+ rawUrls[versionedUrlInfo.url],
902
+ )
903
+ const finalUrlInfo = finalGraph.getUrlInfo(versionedUrlInfo.url)
904
+ return {
905
+ originalContent: rawUrlInfo
906
+ ? rawUrlInfo.originalContent
907
+ : undefined,
908
+ sourcemap: finalUrlInfo ? finalUrlInfo.sourcemap : undefined,
909
+ contentType: versionedUrlInfo.contentType,
910
+ content: versionedUrlInfo.content,
911
+ }
912
+ }
913
+ return versionedUrlInfo
914
+ },
915
+ },
916
+ ],
917
+ })
918
+ await loadUrlGraph({
919
+ urlGraph: finalGraph,
920
+ kitchen: versioningKitchen,
921
+ startLoading: (cookEntryFile) => {
922
+ postBuildEntryUrls.forEach((postBuildEntryUrl) => {
923
+ cookEntryFile({
924
+ trace: `entryPoint`,
925
+ type: "entry_point",
926
+ specifier: postBuildEntryUrl,
927
+ })
928
+ })
929
+ },
930
+ })
931
+ if (usedVersionMappings.length) {
932
+ const versionMappingsNeeded = {}
933
+ usedVersionMappings.forEach((specifier) => {
934
+ versionMappingsNeeded[specifier] = versionMappings[specifier]
935
+ })
936
+ await injectGlobalVersionMapping({
937
+ finalGraphKitchen,
938
+ finalGraph,
939
+ versionMappings: versionMappingsNeeded,
940
+ })
941
+ }
942
+ } catch (e) {
943
+ versioningTask.fail()
944
+ throw e
945
+ }
946
+ versioningTask.done()
947
+ }
948
+
908
949
  const injectVersionIntoBuildUrl = ({ buildUrl, version, versioningMethod }) => {
909
950
  if (versioningMethod === "search_param") {
910
951
  return injectQueryParams(buildUrl, {
@@ -132,9 +132,9 @@ const rollupPluginJsenv = ({
132
132
  // there is 3 types of file: "placeholder", "asset", "chunk"
133
133
  if (rollupFileInfo.type === "chunk") {
134
134
  const jsModuleBundleUrlInfo = {
135
- // buildRelativeUrl: rollupFileInfo.fileName,
136
135
  data: {
137
136
  generatedBy: "rollup",
137
+ bundleRelativeUrl: rollupFileInfo.fileName,
138
138
  usesImport:
139
139
  rollupFileInfo.imports.length > 0 ||
140
140
  rollupFileInfo.dynamicImports.length > 0,
@@ -176,7 +176,18 @@ const rollupPluginJsenv = ({
176
176
  fileUrlConverter,
177
177
  jsModuleUrlInfos,
178
178
  })
179
- return insideJs ? `js/${chunkInfo.name}.js` : `${chunkInfo.name}.js`
179
+ let nameFromUrlInfo
180
+ if (chunkInfo.facadeModuleId) {
181
+ const url = fileUrlConverter.asFileUrl(chunkInfo.facadeModuleId)
182
+ const urlInfo = jsModuleUrlInfos.find(
183
+ (jsModuleUrlInfo) => jsModuleUrlInfo.url === url,
184
+ )
185
+ if (urlInfo) {
186
+ nameFromUrlInfo = urlInfo.filename
187
+ }
188
+ }
189
+ const name = nameFromUrlInfo || `${chunkInfo.name}.js`
190
+ return insideJs ? `js/${name}` : `${name}`
180
191
  },
181
192
  // https://rollupjs.org/guide/en/#outputpaths
182
193
  // paths: (id) => {