@atlaspack/bundler-default 2.14.5-canary.33 → 2.14.5-canary.331
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 +555 -0
- package/dist/DefaultBundler.js +84 -0
- package/dist/MonolithicBundler.js +68 -0
- package/dist/bundleMerge.js +137 -0
- package/dist/bundlerConfig.js +223 -0
- package/dist/decorateLegacyGraph.js +189 -0
- package/dist/idealGraph.js +1471 -0
- package/dist/memoize.js +31 -0
- package/dist/stats.js +69 -0
- package/lib/DefaultBundler.js +6 -1
- package/lib/MonolithicBundler.js +11 -3
- package/lib/bundleMerge.js +106 -37
- package/lib/bundlerConfig.js +52 -6
- package/lib/decorateLegacyGraph.js +24 -3
- package/lib/idealGraph.js +410 -55
- package/lib/memoize.js +39 -0
- package/lib/stats.js +85 -0
- package/lib/types/DefaultBundler.d.ts +18 -0
- package/lib/types/MonolithicBundler.d.ts +2 -0
- package/lib/types/bundleMerge.d.ts +9 -0
- package/lib/types/bundlerConfig.d.ts +36 -0
- package/lib/types/decorateLegacyGraph.d.ts +3 -0
- package/lib/types/idealGraph.d.ts +40 -0
- package/lib/types/memoize.d.ts +2 -0
- package/lib/types/stats.d.ts +16 -0
- package/package.json +20 -12
- package/src/{DefaultBundler.js → DefaultBundler.ts} +21 -6
- package/src/{MonolithicBundler.js → MonolithicBundler.ts} +17 -5
- package/src/bundleMerge.ts +250 -0
- package/src/{bundlerConfig.js → bundlerConfig.ts} +106 -45
- package/src/{decorateLegacyGraph.js → decorateLegacyGraph.ts} +26 -7
- package/src/{idealGraph.js → idealGraph.ts} +729 -137
- package/src/memoize.ts +32 -0
- package/src/stats.ts +97 -0
- package/tsconfig.json +30 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/bundleMerge.js +0 -103
|
@@ -0,0 +1,68 @@
|
|
|
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.addJSMonolithBundle = addJSMonolithBundle;
|
|
7
|
+
const feature_flags_1 = require("@atlaspack/feature-flags");
|
|
8
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
9
|
+
function addJSMonolithBundle(bundleGraph, entryAsset, entryDep) {
|
|
10
|
+
let target = (0, nullthrows_1.default)(entryDep.target, 'Expected dependency to have a valid target');
|
|
11
|
+
// Create a single bundle to hold all JS assets
|
|
12
|
+
let bundle = bundleGraph.createBundle({
|
|
13
|
+
entryAsset,
|
|
14
|
+
target,
|
|
15
|
+
needsStableName: (0, feature_flags_1.getFeatureFlag)('singleFileOutputStableName'),
|
|
16
|
+
});
|
|
17
|
+
bundleGraph.traverse((node, _, actions) => {
|
|
18
|
+
// JS assets can be added to the bundle, but the rest are ignored
|
|
19
|
+
if (node.type === 'asset' && node.value.type === 'js') {
|
|
20
|
+
bundleGraph.addAssetToBundle(node.value, bundle);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (node.type !== 'dependency') {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let dependency = node.value;
|
|
27
|
+
if (dependency.priority === 'lazy') {
|
|
28
|
+
// Any async dependencies need to be internalized into the bundle, and will
|
|
29
|
+
// be included by the asset check above
|
|
30
|
+
bundleGraph.internalizeAsyncDependency(bundle, dependency);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let assets = bundleGraph.getDependencyAssets(dependency);
|
|
34
|
+
for (const asset of assets) {
|
|
35
|
+
if (asset.bundleBehavior === 'isolated' ||
|
|
36
|
+
asset.bundleBehavior === 'inlineIsolated') {
|
|
37
|
+
throw new Error(`${asset.bundleBehavior === 'isolated' ? 'Isolated' : 'Inline isolated'} assets are not supported for single file output builds`);
|
|
38
|
+
}
|
|
39
|
+
// For assets marked as inline, we create new bundles and let other
|
|
40
|
+
// plugins like optimizers include them in the primary bundle
|
|
41
|
+
if (asset.bundleBehavior === 'inline') {
|
|
42
|
+
// Create a new bundle to hold the isolated asset
|
|
43
|
+
let isolatedBundle = bundleGraph.createBundle({
|
|
44
|
+
entryAsset: asset,
|
|
45
|
+
target,
|
|
46
|
+
bundleBehavior: asset.bundleBehavior,
|
|
47
|
+
});
|
|
48
|
+
bundleGraph.addAssetToBundle(asset, isolatedBundle);
|
|
49
|
+
// Add the new bundle to the bundle graph, in its own bundle group
|
|
50
|
+
bundleGraph.createBundleReference(bundle, isolatedBundle);
|
|
51
|
+
bundleGraph.addBundleToBundleGroup(isolatedBundle, bundleGraph.createBundleGroup(dependency, target));
|
|
52
|
+
// Nothing below the isolated asset needs to go in the main bundle, so
|
|
53
|
+
// we can stop traversal here
|
|
54
|
+
actions.skipChildren();
|
|
55
|
+
// To be properly isolated, all of this asset's dependencies need to go
|
|
56
|
+
// in this new bundle
|
|
57
|
+
bundleGraph.traverse((subNode) => {
|
|
58
|
+
if (subNode.type === 'asset' && subNode.value.type === 'js') {
|
|
59
|
+
bundleGraph.addAssetToBundle(subNode.value, isolatedBundle);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}, asset, { skipUnusedDependencies: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, entryAsset, { skipUnusedDependencies: true });
|
|
66
|
+
let bundleGroup = bundleGraph.createBundleGroup(entryDep, target);
|
|
67
|
+
bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
|
|
68
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
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.findMergeCandidates = findMergeCandidates;
|
|
7
|
+
const assert_1 = __importDefault(require("assert"));
|
|
8
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
9
|
+
const graph_1 = require("@atlaspack/graph");
|
|
10
|
+
const utils_1 = require("@atlaspack/utils");
|
|
11
|
+
const memoize_1 = require("./memoize");
|
|
12
|
+
function getBundlesForBundleGroup(bundleGraph, bundleGroupId) {
|
|
13
|
+
let count = 0;
|
|
14
|
+
bundleGraph.traverse((nodeId) => {
|
|
15
|
+
const node = bundleGraph.getNode(nodeId);
|
|
16
|
+
if (node &&
|
|
17
|
+
(node === 'root' ||
|
|
18
|
+
(node.bundleBehavior !== 'inline' &&
|
|
19
|
+
node.bundleBehavior !== 'inlineIsolated'))) {
|
|
20
|
+
count++;
|
|
21
|
+
}
|
|
22
|
+
}, bundleGroupId);
|
|
23
|
+
return count;
|
|
24
|
+
}
|
|
25
|
+
let getBundleOverlap = (sourceBundlesA, sourceBundlesB) => {
|
|
26
|
+
let allSourceBundles = (0, utils_1.setUnion)(sourceBundlesA, sourceBundlesB);
|
|
27
|
+
let sharedSourceBundles = (0, utils_1.setIntersectStatic)(sourceBundlesA, sourceBundlesB);
|
|
28
|
+
return sharedSourceBundles.size / allSourceBundles.size;
|
|
29
|
+
};
|
|
30
|
+
// Returns a decimal showing the proportion source bundles are common to
|
|
31
|
+
// both bundles versus the total number of source bundles.
|
|
32
|
+
function checkBundleThreshold(bundleA, bundleB, threshold) {
|
|
33
|
+
return (getBundleOverlap(bundleA.bundle.sourceBundles, bundleB.bundle.sourceBundles) >= threshold);
|
|
34
|
+
}
|
|
35
|
+
let checkSharedSourceBundles = (0, memoize_1.memoize)((bundle, importantAncestorBundles) => {
|
|
36
|
+
return importantAncestorBundles.every((ancestorId) => bundle.sourceBundles.has(ancestorId));
|
|
37
|
+
});
|
|
38
|
+
let hasSuitableBundleGroup = (0, memoize_1.memoize)((bundleGraph, bundle, minBundlesInGroup) => {
|
|
39
|
+
for (let sourceBundle of bundle.sourceBundles) {
|
|
40
|
+
let bundlesInGroup = getBundlesForBundleGroup(bundleGraph, sourceBundle);
|
|
41
|
+
if (bundlesInGroup >= minBundlesInGroup) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
});
|
|
47
|
+
function validMerge(bundleGraph, config, bundleA, bundleB) {
|
|
48
|
+
if (config.maxBundleSize != null) {
|
|
49
|
+
if (bundleA.bundle.size > config.maxBundleSize ||
|
|
50
|
+
bundleB.bundle.size > config.maxBundleSize) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (config.overlapThreshold != null) {
|
|
55
|
+
if (!checkBundleThreshold(bundleA, bundleB, config.overlapThreshold)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (config.sourceBundles != null) {
|
|
60
|
+
if (!checkSharedSourceBundles(bundleA.bundle, config.sourceBundles) ||
|
|
61
|
+
!checkSharedSourceBundles(bundleB.bundle, config.sourceBundles)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (config.minBundlesInGroup != null) {
|
|
66
|
+
if (!hasSuitableBundleGroup(bundleGraph, bundleA.bundle, config.minBundlesInGroup) ||
|
|
67
|
+
!hasSuitableBundleGroup(bundleGraph, bundleB.bundle, config.minBundlesInGroup)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function getMergeClusters(graph, candidates) {
|
|
74
|
+
let clusters = [];
|
|
75
|
+
for (let [candidate, edgeType] of candidates.entries()) {
|
|
76
|
+
let cluster = [];
|
|
77
|
+
graph.traverse((nodeId) => {
|
|
78
|
+
cluster.push((0, nullthrows_1.default)(graph.getNode(nodeId)));
|
|
79
|
+
// Remove node from candidates as it has already been processed
|
|
80
|
+
candidates.delete(nodeId);
|
|
81
|
+
}, candidate, edgeType);
|
|
82
|
+
clusters.push(cluster);
|
|
83
|
+
}
|
|
84
|
+
return clusters;
|
|
85
|
+
}
|
|
86
|
+
function getPossibleMergeCandidates(bundleGraph, bundles) {
|
|
87
|
+
let mergeCandidates = bundles.map((bundleId) => {
|
|
88
|
+
let bundle = bundleGraph.getNode(bundleId);
|
|
89
|
+
(0, assert_1.default)(bundle && bundle !== 'root', 'Bundle should exist');
|
|
90
|
+
return {
|
|
91
|
+
id: bundleId,
|
|
92
|
+
bundle,
|
|
93
|
+
contentKey: bundleId.toString(),
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
const uniquePairs = [];
|
|
97
|
+
for (let i = 0; i < mergeCandidates.length; i++) {
|
|
98
|
+
for (let j = i + 1; j < mergeCandidates.length; j++) {
|
|
99
|
+
let a = mergeCandidates[i];
|
|
100
|
+
let b = mergeCandidates[j];
|
|
101
|
+
// @ts-expect-error TS18048
|
|
102
|
+
if (a.bundle.internalizedAssets.equals(b.bundle.internalizedAssets)) {
|
|
103
|
+
uniquePairs.push([a, b]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return uniquePairs;
|
|
108
|
+
}
|
|
109
|
+
function findMergeCandidates(bundleGraph, bundles, config) {
|
|
110
|
+
let graph = new graph_1.ContentGraph();
|
|
111
|
+
let candidates = new Map();
|
|
112
|
+
let allPossibleMergeCandidates = getPossibleMergeCandidates(bundleGraph, bundles);
|
|
113
|
+
// Build graph of clustered merge candidates
|
|
114
|
+
for (let i = 0; i < config.length; i++) {
|
|
115
|
+
// Ensure edge type coresponds to config index
|
|
116
|
+
let edgeType = i + 1;
|
|
117
|
+
for (let group of allPossibleMergeCandidates) {
|
|
118
|
+
let candidateA = group[0];
|
|
119
|
+
let candidateB = group[1];
|
|
120
|
+
if (!validMerge(bundleGraph, config[i], candidateA, candidateB)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
let bundleNode = graph.addNodeByContentKeyIfNeeded(candidateA.contentKey, candidateA.id);
|
|
124
|
+
let otherBundleNode = graph.addNodeByContentKeyIfNeeded(candidateB.contentKey, candidateB.id);
|
|
125
|
+
// Add edge in both directions
|
|
126
|
+
graph.addEdge(bundleNode, otherBundleNode, edgeType);
|
|
127
|
+
graph.addEdge(otherBundleNode, bundleNode, edgeType);
|
|
128
|
+
candidates.set(bundleNode, edgeType);
|
|
129
|
+
candidates.set(otherBundleNode, edgeType);
|
|
130
|
+
}
|
|
131
|
+
// Remove bundles that have been allocated to a higher priority merge
|
|
132
|
+
allPossibleMergeCandidates = allPossibleMergeCandidates.filter((group) => !graph.hasContentKey(group[0].contentKey) &&
|
|
133
|
+
!graph.hasContentKey(group[1].contentKey));
|
|
134
|
+
}
|
|
135
|
+
(0, memoize_1.clearCaches)();
|
|
136
|
+
return getMergeClusters(graph, candidates);
|
|
137
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
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.loadBundlerConfig = loadBundlerConfig;
|
|
7
|
+
const diagnostic_1 = require("@atlaspack/diagnostic");
|
|
8
|
+
const feature_flags_1 = require("@atlaspack/feature-flags");
|
|
9
|
+
const utils_1 = require("@atlaspack/utils");
|
|
10
|
+
const assert_1 = __importDefault(require("assert"));
|
|
11
|
+
function resolveModeConfig(config, mode) {
|
|
12
|
+
let generalConfig = {};
|
|
13
|
+
let modeConfig = {};
|
|
14
|
+
for (const key of Object.keys(config)) {
|
|
15
|
+
if (key === 'development' || key === 'production') {
|
|
16
|
+
if (key === mode) {
|
|
17
|
+
// @ts-expect-error TS2322
|
|
18
|
+
modeConfig = config[key];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
generalConfig[key] = config[key];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...generalConfig,
|
|
27
|
+
...modeConfig,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Default options by http version.
|
|
31
|
+
const HTTP_OPTIONS = {
|
|
32
|
+
'1': {
|
|
33
|
+
minBundles: 1,
|
|
34
|
+
manualSharedBundles: [],
|
|
35
|
+
minBundleSize: 30000,
|
|
36
|
+
maxParallelRequests: 6,
|
|
37
|
+
disableSharedBundles: false,
|
|
38
|
+
sharedBundleMerge: [],
|
|
39
|
+
},
|
|
40
|
+
'2': {
|
|
41
|
+
minBundles: 1,
|
|
42
|
+
manualSharedBundles: [],
|
|
43
|
+
minBundleSize: 20000,
|
|
44
|
+
maxParallelRequests: 25,
|
|
45
|
+
disableSharedBundles: false,
|
|
46
|
+
sharedBundleMerge: [],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const CONFIG_SCHEMA = {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
http: {
|
|
53
|
+
type: 'number',
|
|
54
|
+
enum: Object.keys(HTTP_OPTIONS).map((k) => Number(k)),
|
|
55
|
+
},
|
|
56
|
+
manualSharedBundles: {
|
|
57
|
+
type: 'array',
|
|
58
|
+
items: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {
|
|
61
|
+
name: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
},
|
|
64
|
+
assets: {
|
|
65
|
+
type: 'array',
|
|
66
|
+
items: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
types: {
|
|
71
|
+
type: 'array',
|
|
72
|
+
items: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
root: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
},
|
|
79
|
+
split: {
|
|
80
|
+
type: 'number',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ['name', 'assets'],
|
|
84
|
+
additionalProperties: false,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
sharedBundleMerge: {
|
|
88
|
+
type: 'array',
|
|
89
|
+
items: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
overlapThreshold: {
|
|
93
|
+
type: 'number',
|
|
94
|
+
},
|
|
95
|
+
maxBundleSize: {
|
|
96
|
+
type: 'number',
|
|
97
|
+
},
|
|
98
|
+
sourceBundles: {
|
|
99
|
+
type: 'array',
|
|
100
|
+
items: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
minBundlesInGroup: {
|
|
105
|
+
type: 'number',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
additionalProperties: false,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
asyncBundleMerge: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
bundleSize: {
|
|
115
|
+
type: 'number',
|
|
116
|
+
required: true,
|
|
117
|
+
},
|
|
118
|
+
maxOverfetchSize: {
|
|
119
|
+
type: 'number',
|
|
120
|
+
required: true,
|
|
121
|
+
},
|
|
122
|
+
ignore: {
|
|
123
|
+
type: 'array',
|
|
124
|
+
items: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
additionalProperties: false,
|
|
130
|
+
},
|
|
131
|
+
minBundles: {
|
|
132
|
+
type: 'number',
|
|
133
|
+
},
|
|
134
|
+
minBundleSize: {
|
|
135
|
+
type: 'number',
|
|
136
|
+
},
|
|
137
|
+
maxParallelRequests: {
|
|
138
|
+
type: 'number',
|
|
139
|
+
},
|
|
140
|
+
disableSharedBundles: {
|
|
141
|
+
type: 'boolean',
|
|
142
|
+
},
|
|
143
|
+
loadConditionalBundlesInParallel: {
|
|
144
|
+
type: 'boolean',
|
|
145
|
+
},
|
|
146
|
+
sharedBundleMergeThreshold: {
|
|
147
|
+
type: 'number',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
additionalProperties: false,
|
|
151
|
+
};
|
|
152
|
+
async function loadBundlerConfig(config, options, logger) {
|
|
153
|
+
let conf;
|
|
154
|
+
if ((0, feature_flags_1.getFeatureFlag)('resolveBundlerConfigFromCwd')) {
|
|
155
|
+
conf = await config.getConfigFrom(`${process.cwd()}/index`, [], {
|
|
156
|
+
packageKey: '@atlaspack/bundler-default',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
conf = await config.getConfig([], {
|
|
161
|
+
packageKey: '@atlaspack/bundler-default',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (!conf) {
|
|
165
|
+
const modDefault = {
|
|
166
|
+
...HTTP_OPTIONS['2'],
|
|
167
|
+
projectRoot: options.projectRoot,
|
|
168
|
+
};
|
|
169
|
+
// @ts-expect-error TS2322
|
|
170
|
+
return modDefault;
|
|
171
|
+
}
|
|
172
|
+
(0, assert_1.default)(conf?.contents != null);
|
|
173
|
+
let modeConfig = resolveModeConfig(conf.contents, options.mode);
|
|
174
|
+
// minBundles will be ignored if shared bundles are disabled
|
|
175
|
+
if (modeConfig.minBundles != null &&
|
|
176
|
+
modeConfig.disableSharedBundles === true) {
|
|
177
|
+
logger.warn({
|
|
178
|
+
origin: '@atlaspack/bundler-default',
|
|
179
|
+
message: `The value of "${modeConfig.minBundles}" set for minBundles will not be used as shared bundles have been disabled`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// minBundleSize will be ignored if shared bundles are disabled
|
|
183
|
+
if (modeConfig.minBundleSize != null &&
|
|
184
|
+
modeConfig.disableSharedBundles === true) {
|
|
185
|
+
logger.warn({
|
|
186
|
+
origin: '@atlaspack/bundler-default',
|
|
187
|
+
message: `The value of "${modeConfig.minBundleSize}" set for minBundleSize will not be used as shared bundles have been disabled`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// maxParallelRequests will be ignored if shared bundles are disabled
|
|
191
|
+
if (modeConfig.maxParallelRequests != null &&
|
|
192
|
+
modeConfig.disableSharedBundles === true) {
|
|
193
|
+
logger.warn({
|
|
194
|
+
origin: '@atlaspack/bundler-default',
|
|
195
|
+
message: `The value of "${modeConfig.maxParallelRequests}" set for maxParallelRequests will not be used as shared bundles have been disabled`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (modeConfig.manualSharedBundles) {
|
|
199
|
+
let nameArray = modeConfig.manualSharedBundles.map((a) => a.name);
|
|
200
|
+
let nameSet = new Set(nameArray);
|
|
201
|
+
(0, assert_1.default)(nameSet.size == nameArray.length, 'The name field must be unique for property manualSharedBundles');
|
|
202
|
+
}
|
|
203
|
+
utils_1.validateSchema.diagnostic(CONFIG_SCHEMA, {
|
|
204
|
+
data: modeConfig,
|
|
205
|
+
source: () => options.inputFS.readFileSync(conf.filePath, 'utf8'),
|
|
206
|
+
filePath: conf.filePath,
|
|
207
|
+
prependKey: `/${(0, diagnostic_1.encodeJSONKeyComponent)('@atlaspack/bundler-default')}`,
|
|
208
|
+
}, '@atlaspack/bundler-default', 'Invalid config for @atlaspack/bundler-default');
|
|
209
|
+
let http = modeConfig.http ?? 2;
|
|
210
|
+
// @ts-expect-error TS7053
|
|
211
|
+
let defaults = HTTP_OPTIONS[http];
|
|
212
|
+
return {
|
|
213
|
+
minBundles: modeConfig.minBundles ?? defaults.minBundles,
|
|
214
|
+
minBundleSize: modeConfig.minBundleSize ?? defaults.minBundleSize,
|
|
215
|
+
sharedBundleMerge: modeConfig.sharedBundleMerge ?? defaults.sharedBundleMerge,
|
|
216
|
+
asyncBundleMerge: modeConfig.asyncBundleMerge,
|
|
217
|
+
maxParallelRequests: modeConfig.maxParallelRequests ?? defaults.maxParallelRequests,
|
|
218
|
+
projectRoot: options.projectRoot,
|
|
219
|
+
disableSharedBundles: modeConfig.disableSharedBundles ?? defaults.disableSharedBundles,
|
|
220
|
+
manualSharedBundles: modeConfig.manualSharedBundles ?? defaults.manualSharedBundles,
|
|
221
|
+
loadConditionalBundlesInParallel: modeConfig.loadConditionalBundlesInParallel,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
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.decorateLegacyGraph = decorateLegacyGraph;
|
|
7
|
+
const graph_1 = require("@atlaspack/graph");
|
|
8
|
+
const feature_flags_1 = require("@atlaspack/feature-flags");
|
|
9
|
+
const assert_1 = __importDefault(require("assert"));
|
|
10
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
11
|
+
const idealGraph_1 = require("./idealGraph");
|
|
12
|
+
function decorateLegacyGraph(idealGraph, bundleGraph) {
|
|
13
|
+
let idealBundleToLegacyBundle = new Map();
|
|
14
|
+
let { bundleGraph: idealBundleGraph, dependencyBundleGraph, bundleGroupBundleIds, manualAssetToBundle, } = idealGraph;
|
|
15
|
+
// This line can be deleted once supportWebpackChunkName feature flag is removed.
|
|
16
|
+
let entryBundleToBundleGroup = new Map();
|
|
17
|
+
// Step Create Bundles: Create bundle groups, bundles, and shared bundles and add assets to them
|
|
18
|
+
for (let [bundleNodeId, idealBundle] of idealBundleGraph.nodes.entries()) {
|
|
19
|
+
if (!idealBundle || idealBundle === 'root')
|
|
20
|
+
continue;
|
|
21
|
+
let entryAsset = idealBundle.mainEntryAsset;
|
|
22
|
+
// This line can be deleted once supportWebpackChunkName feature flag is removed.
|
|
23
|
+
let bundleGroup;
|
|
24
|
+
let bundle;
|
|
25
|
+
if (bundleGroupBundleIds.has(bundleNodeId)) {
|
|
26
|
+
(0, assert_1.default)(idealBundle.manualSharedBundle == null, 'Processing a manualSharedBundle as a BundleGroup');
|
|
27
|
+
let dependencies = dependencyBundleGraph
|
|
28
|
+
.getNodeIdsConnectedTo(dependencyBundleGraph.getNodeIdByContentKey(String(bundleNodeId)), graph_1.ALL_EDGE_TYPES)
|
|
29
|
+
.map((nodeId) => {
|
|
30
|
+
let dependency = (0, nullthrows_1.default)(dependencyBundleGraph.getNode(nodeId));
|
|
31
|
+
(0, assert_1.default)(dependency.type === 'dependency');
|
|
32
|
+
return dependency.value;
|
|
33
|
+
});
|
|
34
|
+
(0, assert_1.default)(entryAsset != null, 'Processing a bundleGroup with no entry asset');
|
|
35
|
+
let bundleGroups = new Map();
|
|
36
|
+
for (let dependency of dependencies) {
|
|
37
|
+
bundleGroup = bundleGraph.createBundleGroup(dependency, idealBundle.target);
|
|
38
|
+
bundleGroups.set(bundleGroup.entryAssetId, bundleGroup);
|
|
39
|
+
}
|
|
40
|
+
if ((0, feature_flags_1.getFeatureFlag)('supportWebpackChunkName')) {
|
|
41
|
+
(0, assert_1.default)(bundleGroups.size > 0, 'No bundle groups created');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
(0, assert_1.default)(bundleGroup);
|
|
45
|
+
entryBundleToBundleGroup.set(bundleNodeId, bundleGroup);
|
|
46
|
+
}
|
|
47
|
+
bundle = (0, nullthrows_1.default)(bundleGraph.createBundle({
|
|
48
|
+
entryAsset: (0, nullthrows_1.default)(entryAsset),
|
|
49
|
+
bundleRoots: Array.from(idealBundle.bundleRoots),
|
|
50
|
+
needsStableName: idealBundle.needsStableName,
|
|
51
|
+
bundleBehavior: idealBundle.bundleBehavior,
|
|
52
|
+
target: idealBundle.target,
|
|
53
|
+
manualSharedBundle: idealBundle.manualSharedBundle,
|
|
54
|
+
}));
|
|
55
|
+
if ((0, feature_flags_1.getFeatureFlag)('supportWebpackChunkName')) {
|
|
56
|
+
for (let bundleGroup of bundleGroups.values()) {
|
|
57
|
+
bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
(0, assert_1.default)(bundleGroup);
|
|
62
|
+
bundleGraph.addBundleToBundleGroup(bundle, bundleGroup);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (idealBundle.sourceBundles.size > 0 &&
|
|
66
|
+
!idealBundle.mainEntryAsset) {
|
|
67
|
+
let uniqueKey = idealBundle.uniqueKey != null
|
|
68
|
+
? idealBundle.uniqueKey
|
|
69
|
+
: [...idealBundle.assets].map((asset) => asset.id).join(',');
|
|
70
|
+
bundle = (0, nullthrows_1.default)(bundleGraph.createBundle({
|
|
71
|
+
uniqueKey,
|
|
72
|
+
needsStableName: idealBundle.needsStableName,
|
|
73
|
+
bundleBehavior: idealBundle.bundleBehavior,
|
|
74
|
+
type: idealBundle.type,
|
|
75
|
+
target: idealBundle.target,
|
|
76
|
+
env: idealBundle.env,
|
|
77
|
+
manualSharedBundle: idealBundle.manualSharedBundle,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
else if (idealBundle.uniqueKey != null) {
|
|
81
|
+
bundle = (0, nullthrows_1.default)(bundleGraph.createBundle({
|
|
82
|
+
uniqueKey: idealBundle.uniqueKey,
|
|
83
|
+
needsStableName: idealBundle.needsStableName,
|
|
84
|
+
bundleBehavior: idealBundle.bundleBehavior,
|
|
85
|
+
type: idealBundle.type,
|
|
86
|
+
target: idealBundle.target,
|
|
87
|
+
env: idealBundle.env,
|
|
88
|
+
manualSharedBundle: idealBundle.manualSharedBundle,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
(0, assert_1.default)(entryAsset != null);
|
|
93
|
+
bundle = (0, nullthrows_1.default)(bundleGraph.createBundle({
|
|
94
|
+
entryAsset,
|
|
95
|
+
bundleRoots: Array.from(idealBundle.bundleRoots),
|
|
96
|
+
needsStableName: idealBundle.needsStableName,
|
|
97
|
+
bundleBehavior: idealBundle.bundleBehavior,
|
|
98
|
+
target: idealBundle.target,
|
|
99
|
+
manualSharedBundle: idealBundle.manualSharedBundle,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
idealBundleToLegacyBundle.set(idealBundle, bundle);
|
|
103
|
+
for (let asset of idealBundle.assets) {
|
|
104
|
+
bundleGraph.addAssetToBundle(asset, bundle);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Step Internalization: Internalize dependencies for bundles
|
|
108
|
+
for (let idealBundle of idealBundleGraph.nodes) {
|
|
109
|
+
if (!idealBundle || idealBundle === 'root')
|
|
110
|
+
continue;
|
|
111
|
+
let bundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(idealBundle));
|
|
112
|
+
if (idealBundle.internalizedAssets) {
|
|
113
|
+
idealBundle.internalizedAssets.forEach((internalized) => {
|
|
114
|
+
let incomingDeps = bundleGraph.getIncomingDependencies(idealGraph.assets[internalized]);
|
|
115
|
+
for (let incomingDep of incomingDeps) {
|
|
116
|
+
if (incomingDep.priority === 'lazy' &&
|
|
117
|
+
incomingDep.specifierType !== 'url' &&
|
|
118
|
+
bundle.hasDependency(incomingDep)) {
|
|
119
|
+
bundleGraph.internalizeAsyncDependency(bundle, incomingDep);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Manual Shared Bundles
|
|
126
|
+
// NOTE: This only works under the assumption that manual shared bundles would have
|
|
127
|
+
// always already been loaded before the bundle that requires internalization.
|
|
128
|
+
for (let manualSharedAsset of manualAssetToBundle.keys()) {
|
|
129
|
+
let incomingDeps = bundleGraph.getIncomingDependencies(manualSharedAsset);
|
|
130
|
+
for (let incomingDep of incomingDeps) {
|
|
131
|
+
if (incomingDep.priority === 'lazy' &&
|
|
132
|
+
incomingDep.specifierType !== 'url') {
|
|
133
|
+
let bundles = bundleGraph.getBundlesWithDependency(incomingDep);
|
|
134
|
+
for (let bundle of bundles) {
|
|
135
|
+
bundleGraph.internalizeAsyncDependency(bundle, incomingDep);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Step Add to BundleGroups: Add bundles to their bundle groups
|
|
141
|
+
idealBundleGraph.traverse((nodeId, _, actions) => {
|
|
142
|
+
let node = idealBundleGraph.getNode(nodeId);
|
|
143
|
+
if (node === 'root') {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
actions.skipChildren();
|
|
147
|
+
let outboundNodeIds = idealBundleGraph.getNodeIdsConnectedFrom(nodeId);
|
|
148
|
+
let entryBundle = (0, nullthrows_1.default)(idealBundleGraph.getNode(nodeId));
|
|
149
|
+
(0, assert_1.default)(entryBundle !== 'root');
|
|
150
|
+
let legacyEntryBundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(entryBundle));
|
|
151
|
+
for (let id of outboundNodeIds) {
|
|
152
|
+
let siblingBundle = (0, nullthrows_1.default)(idealBundleGraph.getNode(id));
|
|
153
|
+
(0, assert_1.default)(siblingBundle !== 'root');
|
|
154
|
+
let legacySiblingBundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(siblingBundle));
|
|
155
|
+
bundleGraph.createBundleReference(legacyEntryBundle, legacySiblingBundle);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
// Step References: Add references to all bundles
|
|
159
|
+
for (let [asset, references] of idealGraph.assetReference) {
|
|
160
|
+
for (let [dependency, bundle] of references) {
|
|
161
|
+
let legacyBundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(bundle));
|
|
162
|
+
bundleGraph.createAssetReference(dependency, asset, legacyBundle);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// @ts-expect-error TS2488
|
|
166
|
+
for (let { type, from, to } of idealBundleGraph.getAllEdges()) {
|
|
167
|
+
let sourceBundle = (0, nullthrows_1.default)(idealBundleGraph.getNode(from));
|
|
168
|
+
if (sourceBundle === 'root') {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// @ts-expect-error TS2367
|
|
172
|
+
(0, assert_1.default)(sourceBundle !== 'root');
|
|
173
|
+
let legacySourceBundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(sourceBundle));
|
|
174
|
+
let targetBundle = (0, nullthrows_1.default)(idealBundleGraph.getNode(to));
|
|
175
|
+
if (targetBundle === 'root') {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
// @ts-expect-error TS2367
|
|
179
|
+
(0, assert_1.default)(targetBundle !== 'root');
|
|
180
|
+
let legacyTargetBundle = (0, nullthrows_1.default)(idealBundleToLegacyBundle.get(targetBundle));
|
|
181
|
+
if ((0, feature_flags_1.getFeatureFlag)('conditionalBundlingApi') &&
|
|
182
|
+
type === idealGraph_1.idealBundleGraphEdges.conditional) {
|
|
183
|
+
bundleGraph.createBundleConditionalReference(legacySourceBundle, legacyTargetBundle);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
bundleGraph.createBundleReference(legacySourceBundle, legacyTargetBundle);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|