@atlaspack/bundler-default 2.14.5-canary.35 → 2.14.5-canary.351

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 (37) hide show
  1. package/CHANGELOG.md +589 -0
  2. package/dist/DefaultBundler.js +84 -0
  3. package/dist/MonolithicBundler.js +68 -0
  4. package/dist/bundleMerge.js +137 -0
  5. package/dist/bundlerConfig.js +223 -0
  6. package/dist/decorateLegacyGraph.js +189 -0
  7. package/dist/idealGraph.js +1471 -0
  8. package/dist/memoize.js +31 -0
  9. package/dist/stats.js +69 -0
  10. package/lib/DefaultBundler.js +6 -1
  11. package/lib/MonolithicBundler.js +11 -3
  12. package/lib/bundleMerge.js +106 -37
  13. package/lib/bundlerConfig.js +52 -6
  14. package/lib/decorateLegacyGraph.js +24 -3
  15. package/lib/idealGraph.js +410 -55
  16. package/lib/memoize.js +39 -0
  17. package/lib/stats.js +85 -0
  18. package/lib/types/DefaultBundler.d.ts +18 -0
  19. package/lib/types/MonolithicBundler.d.ts +2 -0
  20. package/lib/types/bundleMerge.d.ts +9 -0
  21. package/lib/types/bundlerConfig.d.ts +36 -0
  22. package/lib/types/decorateLegacyGraph.d.ts +3 -0
  23. package/lib/types/idealGraph.d.ts +40 -0
  24. package/lib/types/memoize.d.ts +2 -0
  25. package/lib/types/stats.d.ts +16 -0
  26. package/package.json +20 -12
  27. package/src/{DefaultBundler.js → DefaultBundler.ts} +21 -6
  28. package/src/{MonolithicBundler.js → MonolithicBundler.ts} +17 -5
  29. package/src/bundleMerge.ts +250 -0
  30. package/src/{bundlerConfig.js → bundlerConfig.ts} +106 -45
  31. package/src/{decorateLegacyGraph.js → decorateLegacyGraph.ts} +26 -7
  32. package/src/{idealGraph.js → idealGraph.ts} +729 -137
  33. package/src/memoize.ts +32 -0
  34. package/src/stats.ts +97 -0
  35. package/tsconfig.json +30 -0
  36. package/tsconfig.tsbuildinfo +1 -0
  37. package/src/bundleMerge.js +0 -103
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.clearCaches = clearCaches;
7
+ exports.memoize = memoize;
8
+ const many_keys_map_1 = __importDefault(require("many-keys-map"));
9
+ let caches = [];
10
+ function clearCaches() {
11
+ for (let cache of caches) {
12
+ cache.clear();
13
+ }
14
+ }
15
+ function memoize(fn) {
16
+ let cache = new many_keys_map_1.default();
17
+ caches.push(cache);
18
+ return function (...args) {
19
+ // Navigate through the cache hierarchy
20
+ let cached = cache.get(args);
21
+ if (cached !== undefined) {
22
+ // If the result is cached, return it
23
+ return cached;
24
+ }
25
+ // Calculate the result and cache it
26
+ // @ts-expect-error TS2683
27
+ const result = fn.apply(this, args);
28
+ cache.set(args, result);
29
+ return result;
30
+ };
31
+ }
package/dist/stats.js ADDED
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Stats = void 0;
4
+ const path_1 = require("path");
5
+ const utils_1 = require("@atlaspack/utils");
6
+ class Stats {
7
+ constructor(projectRoot) {
8
+ this.merges = new utils_1.DefaultMap(() => []);
9
+ this.projectRoot = projectRoot;
10
+ }
11
+ trackMerge(bundleToKeep, bundleToRemove, reason) {
12
+ if (!utils_1.debugTools['bundle-stats']) {
13
+ return;
14
+ }
15
+ this.merges
16
+ .get(bundleToKeep)
17
+ .push(...this.merges.get(bundleToRemove), { id: bundleToRemove, reason });
18
+ this.merges.delete(bundleToRemove);
19
+ }
20
+ getBundleLabel(bundle) {
21
+ if (bundle.manualSharedBundle) {
22
+ return bundle.manualSharedBundle;
23
+ }
24
+ if (bundle.mainEntryAsset) {
25
+ let relativePath = (0, path_1.relative)(this.projectRoot, bundle.mainEntryAsset.filePath);
26
+ if (relativePath.length > 100) {
27
+ relativePath =
28
+ relativePath.slice(0, 50) + '...' + relativePath.slice(-50);
29
+ }
30
+ return relativePath;
31
+ }
32
+ return `shared`;
33
+ }
34
+ report(getBundle) {
35
+ if (!utils_1.debugTools['bundle-stats']) {
36
+ return;
37
+ }
38
+ let mergeResults = [];
39
+ let totals = {
40
+ label: 'Totals',
41
+ merges: 0,
42
+ };
43
+ for (let [bundleId, mergedBundles] of this.merges) {
44
+ let bundle = getBundle(bundleId);
45
+ if (!bundle) {
46
+ continue;
47
+ }
48
+ let result = {
49
+ label: this.getBundleLabel(bundle),
50
+ size: bundle.size,
51
+ merges: mergedBundles.length,
52
+ };
53
+ for (let merged of mergedBundles) {
54
+ result[merged.reason] = (result[merged.reason] || 0) + 1;
55
+ totals[merged.reason] = (totals[merged.reason] || 0) + 1;
56
+ }
57
+ totals.merges += mergedBundles.length;
58
+ mergeResults.push(result);
59
+ }
60
+ mergeResults.sort((a, b) => {
61
+ // Sort by bundle size descending
62
+ return b.size - a.size;
63
+ });
64
+ mergeResults.push(totals);
65
+ // eslint-disable-next-line no-console
66
+ console.table(mergeResults);
67
+ }
68
+ }
69
+ exports.Stats = Stats;
@@ -59,6 +59,7 @@ var _default = exports.default = new (_plugin().Bundler)({
59
59
  logger
60
60
  }) {
61
61
  let targetMap = getEntryByTarget(bundleGraph); // Organize entries by target output folder/ distDir
62
+ // @ts-expect-error TS2304
62
63
  let graphs = [];
63
64
  for (let entries of targetMap.values()) {
64
65
  let singleFileEntries = new Map();
@@ -94,7 +95,11 @@ function getEntryByTarget(bundleGraph) {
94
95
  // Find entries from assetGraph per target
95
96
  let targets = new (_utils().DefaultMap)(() => new Map());
96
97
  bundleGraph.traverse({
97
- enter(node, context, actions) {
98
+ enter(
99
+ // @ts-expect-error TS2304
100
+ node, context,
101
+ // @ts-expect-error TS2304
102
+ actions) {
98
103
  if (node.type !== 'asset') {
99
104
  return node;
100
105
  }
@@ -4,6 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.addJSMonolithBundle = addJSMonolithBundle;
7
+ function _featureFlags() {
8
+ const data = require("@atlaspack/feature-flags");
9
+ _featureFlags = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
7
14
  function _nullthrows() {
8
15
  const data = _interopRequireDefault(require("nullthrows"));
9
16
  _nullthrows = function () {
@@ -18,7 +25,8 @@ function addJSMonolithBundle(bundleGraph, entryAsset, entryDep) {
18
25
  // Create a single bundle to hold all JS assets
19
26
  let bundle = bundleGraph.createBundle({
20
27
  entryAsset,
21
- target
28
+ target,
29
+ needsStableName: (0, _featureFlags().getFeatureFlag)('singleFileOutputStableName')
22
30
  });
23
31
  bundleGraph.traverse((node, _, actions) => {
24
32
  // JS assets can be added to the bundle, but the rest are ignored
@@ -38,8 +46,8 @@ function addJSMonolithBundle(bundleGraph, entryAsset, entryDep) {
38
46
  }
39
47
  let assets = bundleGraph.getDependencyAssets(dependency);
40
48
  for (const asset of assets) {
41
- if (asset.bundleBehavior === 'isolated') {
42
- throw new Error('Isolated assets are not supported for single file output builds');
49
+ if (asset.bundleBehavior === 'isolated' || asset.bundleBehavior === 'inlineIsolated') {
50
+ throw new Error(`${asset.bundleBehavior === 'isolated' ? 'Isolated' : 'Inline isolated'} assets are not supported for single file output builds`);
43
51
  }
44
52
 
45
53
  // For assets marked as inline, we create new bundles and let other
@@ -25,67 +25,136 @@ function _graph() {
25
25
  };
26
26
  return data;
27
27
  }
28
+ function _utils() {
29
+ const data = require("@atlaspack/utils");
30
+ _utils = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ var _memoize = require("./memoize");
28
36
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
+ function getBundlesForBundleGroup(bundleGraph, bundleGroupId) {
38
+ let count = 0;
39
+ bundleGraph.traverse(nodeId => {
40
+ const node = bundleGraph.getNode(nodeId);
41
+ if (node && (node === 'root' || node.bundleBehavior !== 'inline' && node.bundleBehavior !== 'inlineIsolated')) {
42
+ count++;
43
+ }
44
+ }, bundleGroupId);
45
+ return count;
46
+ }
47
+ let getBundleOverlap = (sourceBundlesA, sourceBundlesB) => {
48
+ let allSourceBundles = (0, _utils().setUnion)(sourceBundlesA, sourceBundlesB);
49
+ let sharedSourceBundles = (0, _utils().setIntersectStatic)(sourceBundlesA, sourceBundlesB);
50
+ return sharedSourceBundles.size / allSourceBundles.size;
51
+ };
52
+
29
53
  // Returns a decimal showing the proportion source bundles are common to
30
54
  // both bundles versus the total number of source bundles.
31
- function scoreBundleMerge(bundleA, bundleB) {
32
- let sharedSourceBundles = 0;
33
- let allSourceBundles = new Set([...bundleA.sourceBundles, ...bundleB.sourceBundles]);
34
- for (let bundle of bundleB.sourceBundles) {
35
- if (bundleA.sourceBundles.has(bundle)) {
36
- sharedSourceBundles++;
55
+ function checkBundleThreshold(bundleA, bundleB, threshold) {
56
+ return getBundleOverlap(bundleA.bundle.sourceBundles, bundleB.bundle.sourceBundles) >= threshold;
57
+ }
58
+ let checkSharedSourceBundles = (0, _memoize.memoize)((bundle, importantAncestorBundles) => {
59
+ return importantAncestorBundles.every(ancestorId => bundle.sourceBundles.has(ancestorId));
60
+ });
61
+ let hasSuitableBundleGroup = (0, _memoize.memoize)((bundleGraph, bundle, minBundlesInGroup) => {
62
+ for (let sourceBundle of bundle.sourceBundles) {
63
+ let bundlesInGroup = getBundlesForBundleGroup(bundleGraph, sourceBundle);
64
+ if (bundlesInGroup >= minBundlesInGroup) {
65
+ return true;
66
+ }
67
+ }
68
+ return false;
69
+ });
70
+ function validMerge(bundleGraph, config, bundleA, bundleB) {
71
+ if (config.maxBundleSize != null) {
72
+ if (bundleA.bundle.size > config.maxBundleSize || bundleB.bundle.size > config.maxBundleSize) {
73
+ return false;
74
+ }
75
+ }
76
+ if (config.overlapThreshold != null) {
77
+ if (!checkBundleThreshold(bundleA, bundleB, config.overlapThreshold)) {
78
+ return false;
79
+ }
80
+ }
81
+ if (config.sourceBundles != null) {
82
+ if (!checkSharedSourceBundles(bundleA.bundle, config.sourceBundles) || !checkSharedSourceBundles(bundleB.bundle, config.sourceBundles)) {
83
+ return false;
84
+ }
85
+ }
86
+ if (config.minBundlesInGroup != null) {
87
+ if (!hasSuitableBundleGroup(bundleGraph, bundleA.bundle, config.minBundlesInGroup) || !hasSuitableBundleGroup(bundleGraph, bundleB.bundle, config.minBundlesInGroup)) {
88
+ return false;
37
89
  }
38
90
  }
39
- return sharedSourceBundles / allSourceBundles.size;
91
+ return true;
40
92
  }
41
93
  function getMergeClusters(graph, candidates) {
42
94
  let clusters = [];
43
- for (let candidate of candidates) {
95
+ for (let [candidate, edgeType] of candidates.entries()) {
44
96
  let cluster = [];
45
97
  graph.traverse(nodeId => {
46
98
  cluster.push((0, _nullthrows().default)(graph.getNode(nodeId)));
47
99
  // Remove node from candidates as it has already been processed
48
100
  candidates.delete(nodeId);
49
- }, candidate);
101
+ }, candidate, edgeType);
50
102
  clusters.push(cluster);
51
103
  }
52
104
  return clusters;
53
105
  }
54
- function findMergeCandidates(bundleGraph, bundles, threshold) {
106
+ function getPossibleMergeCandidates(bundleGraph, bundles) {
107
+ let mergeCandidates = bundles.map(bundleId => {
108
+ let bundle = bundleGraph.getNode(bundleId);
109
+ (0, _assert().default)(bundle && bundle !== 'root', 'Bundle should exist');
110
+ return {
111
+ id: bundleId,
112
+ bundle,
113
+ contentKey: bundleId.toString()
114
+ };
115
+ });
116
+ const uniquePairs = [];
117
+ for (let i = 0; i < mergeCandidates.length; i++) {
118
+ for (let j = i + 1; j < mergeCandidates.length; j++) {
119
+ let a = mergeCandidates[i];
120
+ let b = mergeCandidates[j];
121
+
122
+ // @ts-expect-error TS18048
123
+ if (a.bundle.internalizedAssets.equals(b.bundle.internalizedAssets)) {
124
+ uniquePairs.push([a, b]);
125
+ }
126
+ }
127
+ }
128
+ return uniquePairs;
129
+ }
130
+ function findMergeCandidates(bundleGraph, bundles, config) {
55
131
  let graph = new (_graph().ContentGraph)();
56
- let seen = new Set();
57
- let candidates = new Set();
132
+ let candidates = new Map();
133
+ let allPossibleMergeCandidates = getPossibleMergeCandidates(bundleGraph, bundles);
58
134
 
59
135
  // Build graph of clustered merge candidates
60
- for (let bundleId of bundles) {
61
- let bundle = bundleGraph.getNode(bundleId);
62
- (0, _assert().default)(bundle && bundle !== 'root');
63
- if (bundle.type !== 'js') {
64
- continue;
65
- }
66
- for (let otherBundleId of bundles) {
67
- if (bundleId === otherBundleId) {
136
+ for (let i = 0; i < config.length; i++) {
137
+ // Ensure edge type coresponds to config index
138
+ let edgeType = i + 1;
139
+ for (let group of allPossibleMergeCandidates) {
140
+ let candidateA = group[0];
141
+ let candidateB = group[1];
142
+ if (!validMerge(bundleGraph, config[i], candidateA, candidateB)) {
68
143
  continue;
69
144
  }
70
- let key = [bundleId, otherBundleId].sort().join(':');
71
- if (seen.has(key)) {
72
- continue;
73
- }
74
- seen.add(key);
75
- let otherBundle = bundleGraph.getNode(otherBundleId);
76
- (0, _assert().default)(otherBundle && otherBundle !== 'root');
77
- let score = scoreBundleMerge(bundle, otherBundle);
78
- if (score >= threshold) {
79
- let bundleNode = graph.addNodeByContentKeyIfNeeded(bundleId.toString(), bundleId);
80
- let otherBundleNode = graph.addNodeByContentKeyIfNeeded(otherBundleId.toString(), otherBundleId);
145
+ let bundleNode = graph.addNodeByContentKeyIfNeeded(candidateA.contentKey, candidateA.id);
146
+ let otherBundleNode = graph.addNodeByContentKeyIfNeeded(candidateB.contentKey, candidateB.id);
81
147
 
82
- // Add edge in both directions
83
- graph.addEdge(bundleNode, otherBundleNode);
84
- graph.addEdge(otherBundleNode, bundleNode);
85
- candidates.add(bundleNode);
86
- candidates.add(otherBundleNode);
87
- }
148
+ // Add edge in both directions
149
+ graph.addEdge(bundleNode, otherBundleNode, edgeType);
150
+ graph.addEdge(otherBundleNode, bundleNode, edgeType);
151
+ candidates.set(bundleNode, edgeType);
152
+ candidates.set(otherBundleNode, edgeType);
88
153
  }
154
+
155
+ // Remove bundles that have been allocated to a higher priority merge
156
+ allPossibleMergeCandidates = allPossibleMergeCandidates.filter(group => !graph.hasContentKey(group[0].contentKey) && !graph.hasContentKey(group[1].contentKey));
89
157
  }
158
+ (0, _memoize.clearCaches)();
90
159
  return getMergeClusters(graph, candidates);
91
160
  }
@@ -39,14 +39,13 @@ function resolveModeConfig(config, mode) {
39
39
  for (const key of Object.keys(config)) {
40
40
  if (key === 'development' || key === 'production') {
41
41
  if (key === mode) {
42
+ // @ts-expect-error TS2322
42
43
  modeConfig = config[key];
43
44
  }
44
45
  } else {
45
46
  generalConfig[key] = config[key];
46
47
  }
47
48
  }
48
-
49
- // $FlowFixMe Not sure how to convince flow here...
50
49
  return {
51
50
  ...generalConfig,
52
51
  ...modeConfig
@@ -61,7 +60,7 @@ const HTTP_OPTIONS = {
61
60
  minBundleSize: 30000,
62
61
  maxParallelRequests: 6,
63
62
  disableSharedBundles: false,
64
- sharedBundleMergeThreshold: 1
63
+ sharedBundleMerge: []
65
64
  },
66
65
  '2': {
67
66
  minBundles: 1,
@@ -69,7 +68,7 @@ const HTTP_OPTIONS = {
69
68
  minBundleSize: 20000,
70
69
  maxParallelRequests: 25,
71
70
  disableSharedBundles: false,
72
- sharedBundleMergeThreshold: 1
71
+ sharedBundleMerge: []
73
72
  }
74
73
  };
75
74
  const CONFIG_SCHEMA = {
@@ -110,6 +109,50 @@ const CONFIG_SCHEMA = {
110
109
  additionalProperties: false
111
110
  }
112
111
  },
112
+ sharedBundleMerge: {
113
+ type: 'array',
114
+ items: {
115
+ type: 'object',
116
+ properties: {
117
+ overlapThreshold: {
118
+ type: 'number'
119
+ },
120
+ maxBundleSize: {
121
+ type: 'number'
122
+ },
123
+ sourceBundles: {
124
+ type: 'array',
125
+ items: {
126
+ type: 'string'
127
+ }
128
+ },
129
+ minBundlesInGroup: {
130
+ type: 'number'
131
+ }
132
+ },
133
+ additionalProperties: false
134
+ }
135
+ },
136
+ asyncBundleMerge: {
137
+ type: 'object',
138
+ properties: {
139
+ bundleSize: {
140
+ type: 'number',
141
+ required: true
142
+ },
143
+ maxOverfetchSize: {
144
+ type: 'number',
145
+ required: true
146
+ },
147
+ ignore: {
148
+ type: 'array',
149
+ items: {
150
+ type: 'string'
151
+ }
152
+ }
153
+ },
154
+ additionalProperties: false
155
+ },
113
156
  minBundles: {
114
157
  type: 'number'
115
158
  },
@@ -148,6 +191,7 @@ async function loadBundlerConfig(config, options, logger) {
148
191
  ...HTTP_OPTIONS['2'],
149
192
  projectRoot: options.projectRoot
150
193
  };
194
+ // @ts-expect-error TS2322
151
195
  return modDefault;
152
196
  }
153
197
  (0, _assert().default)(((_conf = conf) === null || _conf === void 0 ? void 0 : _conf.contents) != null);
@@ -183,16 +227,18 @@ async function loadBundlerConfig(config, options, logger) {
183
227
  }
184
228
  _utils().validateSchema.diagnostic(CONFIG_SCHEMA, {
185
229
  data: modeConfig,
186
- source: await options.inputFS.readFile(conf.filePath, 'utf8'),
230
+ source: () => options.inputFS.readFileSync(conf.filePath, 'utf8'),
187
231
  filePath: conf.filePath,
188
232
  prependKey: `/${(0, _diagnostic().encodeJSONKeyComponent)('@atlaspack/bundler-default')}`
189
233
  }, '@atlaspack/bundler-default', 'Invalid config for @atlaspack/bundler-default');
190
234
  let http = modeConfig.http ?? 2;
235
+ // @ts-expect-error TS7053
191
236
  let defaults = HTTP_OPTIONS[http];
192
237
  return {
193
238
  minBundles: modeConfig.minBundles ?? defaults.minBundles,
194
239
  minBundleSize: modeConfig.minBundleSize ?? defaults.minBundleSize,
195
- sharedBundleMergeThreshold: modeConfig.sharedBundleMergeThreshold ?? defaults.sharedBundleMergeThreshold,
240
+ sharedBundleMerge: modeConfig.sharedBundleMerge ?? defaults.sharedBundleMerge,
241
+ asyncBundleMerge: modeConfig.asyncBundleMerge,
196
242
  maxParallelRequests: modeConfig.maxParallelRequests ?? defaults.maxParallelRequests,
197
243
  projectRoot: options.projectRoot,
198
244
  disableSharedBundles: modeConfig.disableSharedBundles ?? defaults.disableSharedBundles,
@@ -42,11 +42,13 @@ function decorateLegacyGraph(idealGraph, bundleGraph) {
42
42
  bundleGroupBundleIds,
43
43
  manualAssetToBundle
44
44
  } = idealGraph;
45
+ // This line can be deleted once supportWebpackChunkName feature flag is removed.
45
46
  let entryBundleToBundleGroup = new Map();
46
47
  // Step Create Bundles: Create bundle groups, bundles, and shared bundles and add assets to them
47
48
  for (let [bundleNodeId, idealBundle] of idealBundleGraph.nodes.entries()) {
48
49
  if (!idealBundle || idealBundle === 'root') continue;
49
50
  let entryAsset = idealBundle.mainEntryAsset;
51
+ // This line can be deleted once supportWebpackChunkName feature flag is removed.
50
52
  let bundleGroup;
51
53
  let bundle;
52
54
  if (bundleGroupBundleIds.has(bundleNodeId)) {
@@ -57,19 +59,33 @@ function decorateLegacyGraph(idealGraph, bundleGraph) {
57
59
  return dependency.value;
58
60
  });
59
61
  (0, _assert().default)(entryAsset != null, 'Processing a bundleGroup with no entry asset');
62
+ let bundleGroups = new Map();
60
63
  for (let dependency of dependencies) {
61
64
  bundleGroup = bundleGraph.createBundleGroup(dependency, idealBundle.target);
65
+ bundleGroups.set(bundleGroup.entryAssetId, bundleGroup);
66
+ }
67
+ if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
68
+ (0, _assert().default)(bundleGroups.size > 0, 'No bundle groups created');
69
+ } else {
70
+ (0, _assert().default)(bundleGroup);
71
+ entryBundleToBundleGroup.set(bundleNodeId, bundleGroup);
62
72
  }
63
- (0, _assert().default)(bundleGroup);
64
- entryBundleToBundleGroup.set(bundleNodeId, bundleGroup);
65
73
  bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
66
74
  entryAsset: (0, _nullthrows().default)(entryAsset),
75
+ bundleRoots: Array.from(idealBundle.bundleRoots),
67
76
  needsStableName: idealBundle.needsStableName,
68
77
  bundleBehavior: idealBundle.bundleBehavior,
69
78
  target: idealBundle.target,
70
79
  manualSharedBundle: idealBundle.manualSharedBundle
71
80
  }));
72
- bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
81
+ if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
82
+ for (let bundleGroup of bundleGroups.values()) {
83
+ bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
84
+ }
85
+ } else {
86
+ (0, _assert().default)(bundleGroup);
87
+ bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
88
+ }
73
89
  } else if (idealBundle.sourceBundles.size > 0 && !idealBundle.mainEntryAsset) {
74
90
  let uniqueKey = idealBundle.uniqueKey != null ? idealBundle.uniqueKey : [...idealBundle.assets].map(asset => asset.id).join(',');
75
91
  bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
@@ -95,6 +111,7 @@ function decorateLegacyGraph(idealGraph, bundleGraph) {
95
111
  (0, _assert().default)(entryAsset != null);
96
112
  bundle = (0, _nullthrows().default)(bundleGraph.createBundle({
97
113
  entryAsset,
114
+ bundleRoots: Array.from(idealBundle.bundleRoots),
98
115
  needsStableName: idealBundle.needsStableName,
99
116
  bundleBehavior: idealBundle.bundleBehavior,
100
117
  target: idealBundle.target,
@@ -162,6 +179,8 @@ function decorateLegacyGraph(idealGraph, bundleGraph) {
162
179
  bundleGraph.createAssetReference(dependency, asset, legacyBundle);
163
180
  }
164
181
  }
182
+
183
+ // @ts-expect-error TS2488
165
184
  for (let {
166
185
  type,
167
186
  from,
@@ -171,12 +190,14 @@ function decorateLegacyGraph(idealGraph, bundleGraph) {
171
190
  if (sourceBundle === 'root') {
172
191
  continue;
173
192
  }
193
+ // @ts-expect-error TS2367
174
194
  (0, _assert().default)(sourceBundle !== 'root');
175
195
  let legacySourceBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(sourceBundle));
176
196
  let targetBundle = (0, _nullthrows().default)(idealBundleGraph.getNode(to));
177
197
  if (targetBundle === 'root') {
178
198
  continue;
179
199
  }
200
+ // @ts-expect-error TS2367
180
201
  (0, _assert().default)(targetBundle !== 'root');
181
202
  let legacyTargetBundle = (0, _nullthrows().default)(idealBundleToLegacyBundle.get(targetBundle));
182
203
  if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && type === _idealGraph.idealBundleGraphEdges.conditional) {