@atlaspack/bundler-default 2.14.5-canary.2 → 2.14.5-canary.200

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.
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findMergeCandidates = findMergeCandidates;
7
+ function _assert() {
8
+ const data = _interopRequireDefault(require("assert"));
9
+ _assert = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _nullthrows() {
15
+ const data = _interopRequireDefault(require("nullthrows"));
16
+ _nullthrows = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _graph() {
22
+ const data = require("@atlaspack/graph");
23
+ _graph = function () {
24
+ return data;
25
+ };
26
+ return data;
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");
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
+
53
+ // Returns a decimal showing the proportion source bundles are common to
54
+ // both bundles versus the total number of source bundles.
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;
89
+ }
90
+ }
91
+ return true;
92
+ }
93
+ function getMergeClusters(graph, candidates) {
94
+ let clusters = [];
95
+ for (let [candidate, edgeType] of candidates.entries()) {
96
+ let cluster = [];
97
+ graph.traverse(nodeId => {
98
+ cluster.push((0, _nullthrows().default)(graph.getNode(nodeId)));
99
+ // Remove node from candidates as it has already been processed
100
+ candidates.delete(nodeId);
101
+ }, candidate, edgeType);
102
+ clusters.push(cluster);
103
+ }
104
+ return clusters;
105
+ }
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) {
131
+ let graph = new (_graph().ContentGraph)();
132
+ let candidates = new Map();
133
+ let allPossibleMergeCandidates = getPossibleMergeCandidates(bundleGraph, bundles);
134
+
135
+ // Build graph of clustered merge candidates
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)) {
143
+ continue;
144
+ }
145
+ let bundleNode = graph.addNodeByContentKeyIfNeeded(candidateA.contentKey, candidateA.id);
146
+ let otherBundleNode = graph.addNodeByContentKeyIfNeeded(candidateB.contentKey, candidateB.id);
147
+
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);
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));
157
+ }
158
+ (0, _memoize.clearCaches)();
159
+ return getMergeClusters(graph, candidates);
160
+ }
@@ -11,6 +11,13 @@ function _diagnostic() {
11
11
  };
12
12
  return data;
13
13
  }
14
+ function _featureFlags() {
15
+ const data = require("@atlaspack/feature-flags");
16
+ _featureFlags = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
14
21
  function _utils() {
15
22
  const data = require("@atlaspack/utils");
16
23
  _utils = function () {
@@ -32,14 +39,13 @@ function resolveModeConfig(config, mode) {
32
39
  for (const key of Object.keys(config)) {
33
40
  if (key === 'development' || key === 'production') {
34
41
  if (key === mode) {
42
+ // @ts-expect-error TS2322
35
43
  modeConfig = config[key];
36
44
  }
37
45
  } else {
38
46
  generalConfig[key] = config[key];
39
47
  }
40
48
  }
41
-
42
- // $FlowFixMe Not sure how to convince flow here...
43
49
  return {
44
50
  ...generalConfig,
45
51
  ...modeConfig
@@ -53,14 +59,16 @@ const HTTP_OPTIONS = {
53
59
  manualSharedBundles: [],
54
60
  minBundleSize: 30000,
55
61
  maxParallelRequests: 6,
56
- disableSharedBundles: false
62
+ disableSharedBundles: false,
63
+ sharedBundleMerge: []
57
64
  },
58
65
  '2': {
59
66
  minBundles: 1,
60
67
  manualSharedBundles: [],
61
68
  minBundleSize: 20000,
62
69
  maxParallelRequests: 25,
63
- disableSharedBundles: false
70
+ disableSharedBundles: false,
71
+ sharedBundleMerge: []
64
72
  }
65
73
  };
66
74
  const CONFIG_SCHEMA = {
@@ -101,6 +109,50 @@ const CONFIG_SCHEMA = {
101
109
  additionalProperties: false
102
110
  }
103
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
+ },
104
156
  minBundles: {
105
157
  type: 'number'
106
158
  },
@@ -115,22 +167,34 @@ const CONFIG_SCHEMA = {
115
167
  },
116
168
  loadConditionalBundlesInParallel: {
117
169
  type: 'boolean'
170
+ },
171
+ sharedBundleMergeThreshold: {
172
+ type: 'number'
118
173
  }
119
174
  },
120
175
  additionalProperties: false
121
176
  };
122
177
  async function loadBundlerConfig(config, options, logger) {
123
- let conf = await config.getConfig([], {
124
- packageKey: '@atlaspack/bundler-default'
125
- });
178
+ var _conf;
179
+ let conf;
180
+ if ((0, _featureFlags().getFeatureFlag)('resolveBundlerConfigFromCwd')) {
181
+ conf = await config.getConfigFrom(`${process.cwd()}/index`, [], {
182
+ packageKey: '@atlaspack/bundler-default'
183
+ });
184
+ } else {
185
+ conf = await config.getConfig([], {
186
+ packageKey: '@atlaspack/bundler-default'
187
+ });
188
+ }
126
189
  if (!conf) {
127
190
  const modDefault = {
128
191
  ...HTTP_OPTIONS['2'],
129
192
  projectRoot: options.projectRoot
130
193
  };
194
+ // @ts-expect-error TS2322
131
195
  return modDefault;
132
196
  }
133
- (0, _assert().default)((conf === null || conf === void 0 ? void 0 : conf.contents) != null);
197
+ (0, _assert().default)(((_conf = conf) === null || _conf === void 0 ? void 0 : _conf.contents) != null);
134
198
  let modeConfig = resolveModeConfig(conf.contents, options.mode);
135
199
 
136
200
  // minBundles will be ignored if shared bundles are disabled
@@ -168,10 +232,13 @@ async function loadBundlerConfig(config, options, logger) {
168
232
  prependKey: `/${(0, _diagnostic().encodeJSONKeyComponent)('@atlaspack/bundler-default')}`
169
233
  }, '@atlaspack/bundler-default', 'Invalid config for @atlaspack/bundler-default');
170
234
  let http = modeConfig.http ?? 2;
235
+ // @ts-expect-error TS7053
171
236
  let defaults = HTTP_OPTIONS[http];
172
237
  return {
173
238
  minBundles: modeConfig.minBundles ?? defaults.minBundles,
174
239
  minBundleSize: modeConfig.minBundleSize ?? defaults.minBundleSize,
240
+ sharedBundleMerge: modeConfig.sharedBundleMerge ?? defaults.sharedBundleMerge,
241
+ asyncBundleMerge: modeConfig.asyncBundleMerge,
175
242
  maxParallelRequests: modeConfig.maxParallelRequests ?? defaults.maxParallelRequests,
176
243
  projectRoot: options.projectRoot,
177
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) {