@atlaspack/core 2.16.2-canary.281 → 2.16.2-canary.283

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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @atlaspack/core
2
2
 
3
+ ## 2.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#869](https://github.com/atlassian-labs/atlaspack/pull/869) [`cfb4707`](https://github.com/atlassian-labs/atlaspack/commit/cfb4707087498e4fa4dcf10753fe984a248d196b) Thanks [@benjervis](https://github.com/benjervis)! - Adds a feature to the V3 devloop that will minimise the amount of work done if the change is only a content change.
8
+
9
+ ### Patch Changes
10
+
11
+ - [#873](https://github.com/atlassian-labs/atlaspack/pull/873) [`ec3abe4`](https://github.com/atlassian-labs/atlaspack/commit/ec3abe4dffc98560a850fd2f71fb566577e6c99c) Thanks [@vykimnguyen](https://github.com/vykimnguyen)! - cleanup deduplicateReporters flag
12
+
13
+ - [#870](https://github.com/atlassian-labs/atlaspack/pull/870) [`33d4c26`](https://github.com/atlassian-labs/atlaspack/commit/33d4c261ceb8d585d56b0a446ed6e28cf7f1126d) Thanks [@matt-koko](https://github.com/matt-koko)! - Support Loading TypeScript Plugin Files in v3
14
+
15
+ - [#856](https://github.com/atlassian-labs/atlaspack/pull/856) [`f31b041`](https://github.com/atlassian-labs/atlaspack/commit/f31b04107e9077c9946aadb99f6f91bb69703bb7) Thanks [@matt-koko](https://github.com/matt-koko)! - Handle Directory Entry Points in v3
16
+
17
+ - [#859](https://github.com/atlassian-labs/atlaspack/pull/859) [`8180981`](https://github.com/atlassian-labs/atlaspack/commit/8180981be14c00f9570adb70d3f350bd91d6ec0a) Thanks [@benjervis](https://github.com/benjervis)! - Re-use asset graphs when building in Native, if we have one left over from a previous incremental build
18
+
19
+ - [#883](https://github.com/atlassian-labs/atlaspack/pull/883) [`119210b`](https://github.com/atlassian-labs/atlaspack/commit/119210b597eb993c50445df87a36b70bd49cd414) Thanks [@matt-koko](https://github.com/matt-koko)! - Fix bitflags rust/js interop
20
+
21
+ - Updated dependencies [[`ec3abe4`](https://github.com/atlassian-labs/atlaspack/commit/ec3abe4dffc98560a850fd2f71fb566577e6c99c), [`c7fe3f7`](https://github.com/atlassian-labs/atlaspack/commit/c7fe3f76f247e9e20299e205e2df0a16c418eaf2), [`cfb4707`](https://github.com/atlassian-labs/atlaspack/commit/cfb4707087498e4fa4dcf10753fe984a248d196b), [`1468695`](https://github.com/atlassian-labs/atlaspack/commit/1468695fc0c9d06f060a6da9e9b0e154f11dff34), [`f31b041`](https://github.com/atlassian-labs/atlaspack/commit/f31b04107e9077c9946aadb99f6f91bb69703bb7), [`8180981`](https://github.com/atlassian-labs/atlaspack/commit/8180981be14c00f9570adb70d3f350bd91d6ec0a), [`ae77e74`](https://github.com/atlassian-labs/atlaspack/commit/ae77e7452a466b43b3fa5bed24d4ba26345ed765), [`f0a496f`](https://github.com/atlassian-labs/atlaspack/commit/f0a496f70fc8652e090cf1b3f6260e8cfbb796e2), [`7d7a55d`](https://github.com/atlassian-labs/atlaspack/commit/7d7a55dd6395ec391a2e4c33b3dec0d1ea477d4c), [`540f253`](https://github.com/atlassian-labs/atlaspack/commit/540f253dfdcd1a5caebbdc0b197319d439404aae)]:
22
+ - @atlaspack/feature-flags@2.26.2
23
+ - @atlaspack/rust@3.10.0
24
+ - @atlaspack/graph@3.6.0
25
+ - @atlaspack/utils@3.1.2
26
+ - @atlaspack/cache@3.2.33
27
+ - @atlaspack/fs@2.15.33
28
+ - @atlaspack/logger@2.14.30
29
+ - @atlaspack/package-manager@2.14.38
30
+ - @atlaspack/workers@2.14.38
31
+ - @atlaspack/plugin@2.14.38
32
+ - @atlaspack/profiler@2.14.35
33
+ - @atlaspack/types@2.15.28
34
+
3
35
  ## 2.26.2
4
36
 
5
37
  ### Patch Changes
@@ -920,6 +920,111 @@ class BundleGraph {
920
920
  return isReferenced;
921
921
  });
922
922
  }
923
+ // New method: Fast checks only (no caching of results)
924
+ isAssetReferencedFastCheck(bundle, asset) {
925
+ // Fast Check #1: If asset is in multiple bundles in same target, it's referenced
926
+ let bundlesWithAsset = this.getBundlesWithAsset(asset).filter((b) => b.target.name === bundle.target.name &&
927
+ b.target.distDir === bundle.target.distDir);
928
+ if (bundlesWithAsset.length > 1) {
929
+ return true;
930
+ }
931
+ // Fast Check #2: If asset is referenced by any async/conditional dependency, it's referenced
932
+ let assetNodeId = (0, nullthrows_1.default)(this._graph.getNodeIdByContentKey(asset.id));
933
+ if (this._graph
934
+ .getNodeIdsConnectedTo(assetNodeId, exports.bundleGraphEdgeTypes.references)
935
+ .map((id) => this._graph.getNode(id))
936
+ .some((node) => node?.type === 'dependency' &&
937
+ (node.value.priority === types_1.Priority.lazy ||
938
+ node.value.priority === types_1.Priority.conditional) &&
939
+ node.value.specifierType !== types_1.SpecifierType.url)) {
940
+ return true;
941
+ }
942
+ // Fast checks failed - return null to indicate expensive computation needed
943
+ return null;
944
+ }
945
+ getReferencedAssets(bundle) {
946
+ let referencedAssets = new Set();
947
+ // Build a map of all assets in this bundle with their dependencies
948
+ // This allows us to check all assets in a single traversal
949
+ let assetDependenciesMap = new Map();
950
+ this.traverseAssets(bundle, (asset) => {
951
+ // Always do fast checks (no caching)
952
+ let fastCheckResult = this.isAssetReferencedFastCheck(bundle, asset);
953
+ if (fastCheckResult === true) {
954
+ referencedAssets.add(asset);
955
+ return;
956
+ }
957
+ // Fast checks failed (fastCheckResult === null), need expensive computation
958
+ // Check if it's actually referenced via traversal
959
+ // Store dependencies for later batch checking
960
+ let dependencies = this._graph
961
+ .getNodeIdsConnectedTo((0, nullthrows_1.default)(this._graph.getNodeIdByContentKey(asset.id)))
962
+ .map((id) => (0, nullthrows_1.default)(this._graph.getNode(id)))
963
+ .filter((node) => node.type === 'dependency')
964
+ .map((node) => {
965
+ (0, assert_2.default)(node.type === 'dependency');
966
+ return node.value;
967
+ });
968
+ if (dependencies.length > 0) {
969
+ assetDependenciesMap.set(asset, dependencies);
970
+ }
971
+ });
972
+ // If no assets need the expensive check, return early
973
+ if (assetDependenciesMap.size === 0) {
974
+ return referencedAssets;
975
+ }
976
+ // Get the assets we need to check once
977
+ let assetsToCheck = Array.from(assetDependenciesMap.keys());
978
+ // Helper function to check if all assets from assetDependenciesMap are in referencedAssets
979
+ const allAssetsReferenced = () => assetsToCheck.length <= referencedAssets.size &&
980
+ assetsToCheck.every((asset) => referencedAssets.has(asset));
981
+ // Do ONE traversal to check all remaining assets
982
+ // We can share visitedBundles across all assets because we check every asset
983
+ // against every visited bundle, which matches the original per-asset behavior
984
+ let siblingBundles = new Set(this.getBundleGroupsContainingBundle(bundle).flatMap((bundleGroup) => this.getBundlesInBundleGroup(bundleGroup, { includeInline: true })));
985
+ let visitedBundles = new Set();
986
+ // Single traversal from all referencers
987
+ for (let referencer of siblingBundles) {
988
+ this.traverseBundles((descendant, _, actions) => {
989
+ if (descendant.id === bundle.id) {
990
+ return;
991
+ }
992
+ if (visitedBundles.has(descendant)) {
993
+ actions.skipChildren();
994
+ return;
995
+ }
996
+ visitedBundles.add(descendant);
997
+ if (descendant.type !== bundle.type ||
998
+ (0, EnvironmentManager_1.fromEnvironmentId)(descendant.env).context !==
999
+ (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env).context) {
1000
+ // Don't skip children - they might be the right type!
1001
+ return;
1002
+ }
1003
+ // Check ALL assets at once in this descendant bundle
1004
+ for (let [asset, dependencies] of assetDependenciesMap) {
1005
+ // Skip if already marked as referenced
1006
+ if (referencedAssets.has(asset)) {
1007
+ continue;
1008
+ }
1009
+ // Check if this descendant bundle references the asset
1010
+ if (!this.bundleHasAsset(descendant, asset) &&
1011
+ dependencies.some((dependency) => this.bundleHasDependency(descendant, dependency))) {
1012
+ referencedAssets.add(asset);
1013
+ }
1014
+ }
1015
+ // If all assets from assetDependenciesMap are now marked as referenced, we can stop early
1016
+ if (allAssetsReferenced()) {
1017
+ actions.stop();
1018
+ return;
1019
+ }
1020
+ }, referencer);
1021
+ // If all assets from assetDependenciesMap are referenced, no need to check more sibling bundles
1022
+ if (allAssetsReferenced()) {
1023
+ break;
1024
+ }
1025
+ }
1026
+ return referencedAssets;
1027
+ }
923
1028
  hasParentBundleOfType(bundle, type) {
924
1029
  let parents = this.getParentBundles(bundle);
925
1030
  return (parents.length > 0 && parents.every((parent) => parent.type === type));
@@ -148,6 +148,18 @@ class BundleGraph {
148
148
  isAssetReferenced(bundle, asset) {
149
149
  return __classPrivateFieldGet(this, _BundleGraph_graph, "f").isAssetReferenced((0, Bundle_1.bundleToInternalBundle)(bundle), (0, Asset_1.assetToAssetValue)(asset));
150
150
  }
151
+ isAssetReferencedFastCheck(bundle, asset) {
152
+ return __classPrivateFieldGet(this, _BundleGraph_graph, "f").isAssetReferencedFastCheck((0, Bundle_1.bundleToInternalBundle)(bundle), (0, Asset_1.assetToAssetValue)(asset));
153
+ }
154
+ getReferencedAssets(bundle) {
155
+ let internalReferencedAssets = __classPrivateFieldGet(this, _BundleGraph_graph, "f").getReferencedAssets((0, Bundle_1.bundleToInternalBundle)(bundle));
156
+ // Convert internal assets to public assets
157
+ let publicReferencedAssets = new Set();
158
+ for (let internalAsset of internalReferencedAssets) {
159
+ publicReferencedAssets.add((0, Asset_1.assetFromValue)(internalAsset, __classPrivateFieldGet(this, _BundleGraph_options, "f")));
160
+ }
161
+ return publicReferencedAssets;
162
+ }
151
163
  hasParentBundleOfType(bundle, type) {
152
164
  return __classPrivateFieldGet(this, _BundleGraph_graph, "f").hasParentBundleOfType((0, Bundle_1.bundleToInternalBundle)(bundle), type);
153
165
  }
@@ -914,6 +914,113 @@ class BundleGraph {
914
914
  return isReferenced;
915
915
  });
916
916
  }
917
+
918
+ // New method: Fast checks only (no caching of results)
919
+ isAssetReferencedFastCheck(bundle, asset) {
920
+ // Fast Check #1: If asset is in multiple bundles in same target, it's referenced
921
+ let bundlesWithAsset = this.getBundlesWithAsset(asset).filter(b => b.target.name === bundle.target.name && b.target.distDir === bundle.target.distDir);
922
+ if (bundlesWithAsset.length > 1) {
923
+ return true;
924
+ }
925
+
926
+ // Fast Check #2: If asset is referenced by any async/conditional dependency, it's referenced
927
+ let assetNodeId = (0, _nullthrows().default)(this._graph.getNodeIdByContentKey(asset.id));
928
+ if (this._graph.getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references).map(id => this._graph.getNode(id)).some(node => (node === null || node === void 0 ? void 0 : node.type) === 'dependency' && (node.value.priority === _types.Priority.lazy || node.value.priority === _types.Priority.conditional) && node.value.specifierType !== _types.SpecifierType.url)) {
929
+ return true;
930
+ }
931
+
932
+ // Fast checks failed - return null to indicate expensive computation needed
933
+ return null;
934
+ }
935
+ getReferencedAssets(bundle) {
936
+ let referencedAssets = new Set();
937
+
938
+ // Build a map of all assets in this bundle with their dependencies
939
+ // This allows us to check all assets in a single traversal
940
+ let assetDependenciesMap = new Map();
941
+ this.traverseAssets(bundle, asset => {
942
+ // Always do fast checks (no caching)
943
+ let fastCheckResult = this.isAssetReferencedFastCheck(bundle, asset);
944
+ if (fastCheckResult === true) {
945
+ referencedAssets.add(asset);
946
+ return;
947
+ }
948
+
949
+ // Fast checks failed (fastCheckResult === null), need expensive computation
950
+ // Check if it's actually referenced via traversal
951
+
952
+ // Store dependencies for later batch checking
953
+ let dependencies = this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey(asset.id))).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'dependency').map(node => {
954
+ (0, _assert().default)(node.type === 'dependency');
955
+ return node.value;
956
+ });
957
+ if (dependencies.length > 0) {
958
+ assetDependenciesMap.set(asset, dependencies);
959
+ }
960
+ });
961
+
962
+ // If no assets need the expensive check, return early
963
+ if (assetDependenciesMap.size === 0) {
964
+ return referencedAssets;
965
+ }
966
+
967
+ // Get the assets we need to check once
968
+ let assetsToCheck = Array.from(assetDependenciesMap.keys());
969
+
970
+ // Helper function to check if all assets from assetDependenciesMap are in referencedAssets
971
+ const allAssetsReferenced = () => assetsToCheck.length <= referencedAssets.size && assetsToCheck.every(asset => referencedAssets.has(asset));
972
+
973
+ // Do ONE traversal to check all remaining assets
974
+ // We can share visitedBundles across all assets because we check every asset
975
+ // against every visited bundle, which matches the original per-asset behavior
976
+ let siblingBundles = new Set(this.getBundleGroupsContainingBundle(bundle).flatMap(bundleGroup => this.getBundlesInBundleGroup(bundleGroup, {
977
+ includeInline: true
978
+ })));
979
+ let visitedBundles = new Set();
980
+
981
+ // Single traversal from all referencers
982
+ for (let referencer of siblingBundles) {
983
+ this.traverseBundles((descendant, _, actions) => {
984
+ if (descendant.id === bundle.id) {
985
+ return;
986
+ }
987
+ if (visitedBundles.has(descendant)) {
988
+ actions.skipChildren();
989
+ return;
990
+ }
991
+ visitedBundles.add(descendant);
992
+ if (descendant.type !== bundle.type || (0, _EnvironmentManager.fromEnvironmentId)(descendant.env).context !== (0, _EnvironmentManager.fromEnvironmentId)(bundle.env).context) {
993
+ // Don't skip children - they might be the right type!
994
+ return;
995
+ }
996
+
997
+ // Check ALL assets at once in this descendant bundle
998
+ for (let [asset, dependencies] of assetDependenciesMap) {
999
+ // Skip if already marked as referenced
1000
+ if (referencedAssets.has(asset)) {
1001
+ continue;
1002
+ }
1003
+
1004
+ // Check if this descendant bundle references the asset
1005
+ if (!this.bundleHasAsset(descendant, asset) && dependencies.some(dependency => this.bundleHasDependency(descendant, dependency))) {
1006
+ referencedAssets.add(asset);
1007
+ }
1008
+ }
1009
+
1010
+ // If all assets from assetDependenciesMap are now marked as referenced, we can stop early
1011
+ if (allAssetsReferenced()) {
1012
+ actions.stop();
1013
+ return;
1014
+ }
1015
+ }, referencer);
1016
+
1017
+ // If all assets from assetDependenciesMap are referenced, no need to check more sibling bundles
1018
+ if (allAssetsReferenced()) {
1019
+ break;
1020
+ }
1021
+ }
1022
+ return referencedAssets;
1023
+ }
917
1024
  hasParentBundleOfType(bundle, type) {
918
1025
  let parents = this.getParentBundles(bundle);
919
1026
  return parents.length > 0 && parents.every(parent => parent.type === type);
@@ -114,6 +114,19 @@ class BundleGraph {
114
114
  isAssetReferenced(bundle, asset) {
115
115
  return this.#graph.isAssetReferenced((0, _Bundle.bundleToInternalBundle)(bundle), (0, _Asset.assetToAssetValue)(asset));
116
116
  }
117
+ isAssetReferencedFastCheck(bundle, asset) {
118
+ return this.#graph.isAssetReferencedFastCheck((0, _Bundle.bundleToInternalBundle)(bundle), (0, _Asset.assetToAssetValue)(asset));
119
+ }
120
+ getReferencedAssets(bundle) {
121
+ let internalReferencedAssets = this.#graph.getReferencedAssets((0, _Bundle.bundleToInternalBundle)(bundle));
122
+
123
+ // Convert internal assets to public assets
124
+ let publicReferencedAssets = new Set();
125
+ for (let internalAsset of internalReferencedAssets) {
126
+ publicReferencedAssets.add((0, _Asset.assetFromValue)(internalAsset, this.#options));
127
+ }
128
+ return publicReferencedAssets;
129
+ }
117
130
  hasParentBundleOfType(bundle, type) {
118
131
  return this.#graph.hasParentBundleOfType((0, _Bundle.bundleToInternalBundle)(bundle), type);
119
132
  }
@@ -129,6 +129,8 @@ export default class BundleGraph {
129
129
  getDependencies(asset: Asset): Array<Dependency>;
130
130
  traverseAssets<TContext>(bundle: Bundle, visit: GraphVisitor<Asset, TContext>, startAsset?: Asset): TContext | null | undefined;
131
131
  isAssetReferenced(bundle: Bundle, asset: Asset): boolean;
132
+ isAssetReferencedFastCheck(bundle: Bundle, asset: Asset): boolean | null;
133
+ getReferencedAssets(bundle: Bundle): Set<Asset>;
132
134
  hasParentBundleOfType(bundle: Bundle, type: string): boolean;
133
135
  getParentBundles(bundle: Bundle): Array<Bundle>;
134
136
  isAssetReachableFromBundle(asset: Asset, bundle: Bundle): boolean;
@@ -30,6 +30,8 @@ export default class BundleGraph<TBundle extends IBundle> implements IBundleGrap
30
30
  getDependencies(asset: IAsset): Array<IDependency>;
31
31
  isAssetReachableFromBundle(asset: IAsset, bundle: IBundle): boolean;
32
32
  isAssetReferenced(bundle: IBundle, asset: IAsset): boolean;
33
+ isAssetReferencedFastCheck(bundle: IBundle, asset: IAsset): boolean | null;
34
+ getReferencedAssets(bundle: IBundle): Set<IAsset>;
33
35
  hasParentBundleOfType(bundle: IBundle, type: string): boolean;
34
36
  getBundlesInBundleGroup(bundleGroup: IBundleGroup, opts?: {
35
37
  includeInline: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/core",
3
- "version": "2.16.2-canary.281+119210b59",
3
+ "version": "2.16.2-canary.283+8eb84ee61",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -22,21 +22,21 @@
22
22
  "build:lib": "gulp build --gulpfile ../../../gulpfile.js --cwd ."
23
23
  },
24
24
  "dependencies": {
25
- "@atlaspack/build-cache": "2.13.3-canary.349+119210b59",
26
- "@atlaspack/cache": "3.1.1-canary.281+119210b59",
27
- "@atlaspack/diagnostic": "2.14.1-canary.349+119210b59",
28
- "@atlaspack/events": "2.14.1-canary.349+119210b59",
29
- "@atlaspack/feature-flags": "2.14.1-canary.349+119210b59",
30
- "@atlaspack/fs": "2.14.5-canary.281+119210b59",
31
- "@atlaspack/graph": "3.4.1-canary.349+119210b59",
32
- "@atlaspack/logger": "2.14.5-canary.281+119210b59",
33
- "@atlaspack/package-manager": "2.14.5-canary.281+119210b59",
34
- "@atlaspack/plugin": "2.14.5-canary.281+119210b59",
35
- "@atlaspack/profiler": "2.14.1-canary.349+119210b59",
36
- "@atlaspack/rust": "3.2.1-canary.281+119210b59",
37
- "@atlaspack/types": "2.14.5-canary.281+119210b59",
38
- "@atlaspack/utils": "2.14.5-canary.281+119210b59",
39
- "@atlaspack/workers": "2.14.5-canary.281+119210b59",
25
+ "@atlaspack/build-cache": "2.13.3-canary.351+8eb84ee61",
26
+ "@atlaspack/cache": "3.1.1-canary.283+8eb84ee61",
27
+ "@atlaspack/diagnostic": "2.14.1-canary.351+8eb84ee61",
28
+ "@atlaspack/events": "2.14.1-canary.351+8eb84ee61",
29
+ "@atlaspack/feature-flags": "2.14.1-canary.351+8eb84ee61",
30
+ "@atlaspack/fs": "2.14.5-canary.283+8eb84ee61",
31
+ "@atlaspack/graph": "3.4.1-canary.351+8eb84ee61",
32
+ "@atlaspack/logger": "2.14.5-canary.283+8eb84ee61",
33
+ "@atlaspack/package-manager": "2.14.5-canary.283+8eb84ee61",
34
+ "@atlaspack/plugin": "2.14.5-canary.283+8eb84ee61",
35
+ "@atlaspack/profiler": "2.14.1-canary.351+8eb84ee61",
36
+ "@atlaspack/rust": "3.2.1-canary.283+8eb84ee61",
37
+ "@atlaspack/types": "2.14.5-canary.283+8eb84ee61",
38
+ "@atlaspack/utils": "2.14.5-canary.283+8eb84ee61",
39
+ "@atlaspack/workers": "2.14.5-canary.283+8eb84ee61",
40
40
  "@mischnic/json-sourcemap": "^0.1.0",
41
41
  "@parcel/source-map": "^2.1.1",
42
42
  "base-x": "^3.0.8",
@@ -61,5 +61,5 @@
61
61
  "./src/serializerCore.js": "./src/serializerCore.browser.js"
62
62
  },
63
63
  "type": "commonjs",
64
- "gitHead": "119210b597eb993c50445df87a36b70bd49cd414"
64
+ "gitHead": "8eb84ee61a42bfe87c58079b610802b07a6a13e4"
65
65
  }
@@ -1435,6 +1435,158 @@ export default class BundleGraph {
1435
1435
  });
1436
1436
  }
1437
1437
 
1438
+ // New method: Fast checks only (no caching of results)
1439
+ isAssetReferencedFastCheck(bundle: Bundle, asset: Asset): boolean | null {
1440
+ // Fast Check #1: If asset is in multiple bundles in same target, it's referenced
1441
+ let bundlesWithAsset = this.getBundlesWithAsset(asset).filter(
1442
+ (b) =>
1443
+ b.target.name === bundle.target.name &&
1444
+ b.target.distDir === bundle.target.distDir,
1445
+ );
1446
+
1447
+ if (bundlesWithAsset.length > 1) {
1448
+ return true;
1449
+ }
1450
+
1451
+ // Fast Check #2: If asset is referenced by any async/conditional dependency, it's referenced
1452
+ let assetNodeId = nullthrows(this._graph.getNodeIdByContentKey(asset.id));
1453
+
1454
+ if (
1455
+ this._graph
1456
+ .getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references)
1457
+ .map((id) => this._graph.getNode(id))
1458
+ .some(
1459
+ (node) =>
1460
+ node?.type === 'dependency' &&
1461
+ (node.value.priority === Priority.lazy ||
1462
+ node.value.priority === Priority.conditional) &&
1463
+ node.value.specifierType !== SpecifierType.url,
1464
+ )
1465
+ ) {
1466
+ return true;
1467
+ }
1468
+
1469
+ // Fast checks failed - return null to indicate expensive computation needed
1470
+ return null;
1471
+ }
1472
+
1473
+ getReferencedAssets(bundle: Bundle): Set<Asset> {
1474
+ let referencedAssets = new Set<Asset>();
1475
+
1476
+ // Build a map of all assets in this bundle with their dependencies
1477
+ // This allows us to check all assets in a single traversal
1478
+ let assetDependenciesMap = new Map<Asset, Array<Dependency>>();
1479
+
1480
+ this.traverseAssets(bundle, (asset) => {
1481
+ // Always do fast checks (no caching)
1482
+ let fastCheckResult = this.isAssetReferencedFastCheck(bundle, asset);
1483
+
1484
+ if (fastCheckResult === true) {
1485
+ referencedAssets.add(asset);
1486
+ return;
1487
+ }
1488
+
1489
+ // Fast checks failed (fastCheckResult === null), need expensive computation
1490
+ // Check if it's actually referenced via traversal
1491
+
1492
+ // Store dependencies for later batch checking
1493
+ let dependencies = this._graph
1494
+ .getNodeIdsConnectedTo(
1495
+ nullthrows(this._graph.getNodeIdByContentKey(asset.id)),
1496
+ )
1497
+ .map((id) => nullthrows(this._graph.getNode(id)))
1498
+ .filter((node) => node.type === 'dependency')
1499
+ .map((node) => {
1500
+ invariant(node.type === 'dependency');
1501
+ return node.value;
1502
+ });
1503
+
1504
+ if (dependencies.length > 0) {
1505
+ assetDependenciesMap.set(asset, dependencies);
1506
+ }
1507
+ });
1508
+
1509
+ // If no assets need the expensive check, return early
1510
+ if (assetDependenciesMap.size === 0) {
1511
+ return referencedAssets;
1512
+ }
1513
+
1514
+ // Get the assets we need to check once
1515
+ let assetsToCheck = Array.from(assetDependenciesMap.keys());
1516
+
1517
+ // Helper function to check if all assets from assetDependenciesMap are in referencedAssets
1518
+ const allAssetsReferenced = (): boolean =>
1519
+ assetsToCheck.length <= referencedAssets.size &&
1520
+ assetsToCheck.every((asset) => referencedAssets.has(asset));
1521
+
1522
+ // Do ONE traversal to check all remaining assets
1523
+ // We can share visitedBundles across all assets because we check every asset
1524
+ // against every visited bundle, which matches the original per-asset behavior
1525
+ let siblingBundles = new Set(
1526
+ this.getBundleGroupsContainingBundle(bundle).flatMap((bundleGroup) =>
1527
+ this.getBundlesInBundleGroup(bundleGroup, {includeInline: true}),
1528
+ ),
1529
+ );
1530
+
1531
+ let visitedBundles: Set<Bundle> = new Set();
1532
+
1533
+ // Single traversal from all referencers
1534
+ for (let referencer of siblingBundles) {
1535
+ this.traverseBundles((descendant, _, actions) => {
1536
+ if (descendant.id === bundle.id) {
1537
+ return;
1538
+ }
1539
+
1540
+ if (visitedBundles.has(descendant)) {
1541
+ actions.skipChildren();
1542
+ return;
1543
+ }
1544
+
1545
+ visitedBundles.add(descendant);
1546
+
1547
+ if (
1548
+ descendant.type !== bundle.type ||
1549
+ fromEnvironmentId(descendant.env).context !==
1550
+ fromEnvironmentId(bundle.env).context
1551
+ ) {
1552
+ // Don't skip children - they might be the right type!
1553
+ return;
1554
+ }
1555
+
1556
+ // Check ALL assets at once in this descendant bundle
1557
+ for (let [asset, dependencies] of assetDependenciesMap) {
1558
+ // Skip if already marked as referenced
1559
+ if (referencedAssets.has(asset)) {
1560
+ continue;
1561
+ }
1562
+
1563
+ // Check if this descendant bundle references the asset
1564
+ if (
1565
+ !this.bundleHasAsset(descendant, asset) &&
1566
+ dependencies.some((dependency) =>
1567
+ this.bundleHasDependency(descendant, dependency),
1568
+ )
1569
+ ) {
1570
+ referencedAssets.add(asset);
1571
+ }
1572
+ }
1573
+
1574
+ // If all assets from assetDependenciesMap are now marked as referenced, we can stop early
1575
+ if (allAssetsReferenced()) {
1576
+ actions.stop();
1577
+ return;
1578
+ }
1579
+ }, referencer);
1580
+
1581
+ // If all assets from assetDependenciesMap are referenced, no need to check more sibling bundles
1582
+ if (allAssetsReferenced()) {
1583
+ break;
1584
+ }
1585
+ }
1586
+
1587
+ return referencedAssets;
1588
+ }
1589
+
1438
1590
  hasParentBundleOfType(bundle: Bundle, type: string): boolean {
1439
1591
  let parents = this.getParentBundles(bundle);
1440
1592
  return (
@@ -198,6 +198,27 @@ export default class BundleGraph<TBundle extends IBundle>
198
198
  );
199
199
  }
200
200
 
201
+ isAssetReferencedFastCheck(bundle: IBundle, asset: IAsset): boolean | null {
202
+ return this.#graph.isAssetReferencedFastCheck(
203
+ bundleToInternalBundle(bundle),
204
+ assetToAssetValue(asset),
205
+ );
206
+ }
207
+
208
+ getReferencedAssets(bundle: IBundle): Set<IAsset> {
209
+ let internalReferencedAssets = this.#graph.getReferencedAssets(
210
+ bundleToInternalBundle(bundle),
211
+ );
212
+
213
+ // Convert internal assets to public assets
214
+ let publicReferencedAssets = new Set<IAsset>();
215
+ for (let internalAsset of internalReferencedAssets) {
216
+ publicReferencedAssets.add(assetFromValue(internalAsset, this.#options));
217
+ }
218
+
219
+ return publicReferencedAssets;
220
+ }
221
+
201
222
  hasParentBundleOfType(bundle: IBundle, type: string): boolean {
202
223
  return this.#graph.hasParentBundleOfType(
203
224
  bundleToInternalBundle(bundle),