@atlaspack/bundler-default 2.14.5-canary.20 → 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.
- package/CHANGELOG.md +411 -0
- package/lib/DefaultBundler.js +6 -1
- package/lib/MonolithicBundler.js +11 -3
- package/lib/bundleMerge.js +106 -37
- package/lib/bundlerConfig.js +51 -5
- package/lib/decorateLegacyGraph.js +24 -3
- package/lib/idealGraph.js +426 -50
- 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 +21 -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} +105 -44
- package/src/{decorateLegacyGraph.js → decorateLegacyGraph.ts} +26 -7
- package/src/{idealGraph.js → idealGraph.ts} +669 -102
- package/src/memoize.ts +32 -0
- package/src/stats.ts +97 -0
- package/tsconfig.json +4 -0
- package/src/bundleMerge.js +0 -103
package/src/memoize.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ManyKeysMap from 'many-keys-map';
|
|
2
|
+
|
|
3
|
+
let caches: Array<any> = [];
|
|
4
|
+
|
|
5
|
+
export function clearCaches() {
|
|
6
|
+
for (let cache of caches) {
|
|
7
|
+
cache.clear();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function memoize<Args extends Array<unknown>, Return>(
|
|
12
|
+
fn: (...args: Args) => Return,
|
|
13
|
+
): (...args: Args) => Return {
|
|
14
|
+
let cache = new ManyKeysMap();
|
|
15
|
+
caches.push(cache);
|
|
16
|
+
|
|
17
|
+
return function (...args: Args): Return {
|
|
18
|
+
// Navigate through the cache hierarchy
|
|
19
|
+
let cached = cache.get(args);
|
|
20
|
+
if (cached !== undefined) {
|
|
21
|
+
// If the result is cached, return it
|
|
22
|
+
return cached;
|
|
23
|
+
}
|
|
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
|
+
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
}
|
package/src/stats.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {relative} from 'path';
|
|
2
|
+
import {NodeId} from '@atlaspack/graph';
|
|
3
|
+
import {DefaultMap, debugTools} from '@atlaspack/utils';
|
|
4
|
+
|
|
5
|
+
import {Bundle} from './idealGraph';
|
|
6
|
+
|
|
7
|
+
interface MergedBundle {
|
|
8
|
+
id: NodeId;
|
|
9
|
+
reason: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Stats {
|
|
13
|
+
projectRoot: string;
|
|
14
|
+
merges: DefaultMap<NodeId, MergedBundle[]> = new DefaultMap(() => []);
|
|
15
|
+
|
|
16
|
+
constructor(projectRoot: string) {
|
|
17
|
+
this.projectRoot = projectRoot;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
trackMerge(bundleToKeep: NodeId, bundleToRemove: NodeId, reason: string) {
|
|
21
|
+
if (!debugTools['bundle-stats']) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.merges
|
|
26
|
+
.get(bundleToKeep)
|
|
27
|
+
.push(...this.merges.get(bundleToRemove), {id: bundleToRemove, reason});
|
|
28
|
+
this.merges.delete(bundleToRemove);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getBundleLabel(bundle: Bundle): string {
|
|
32
|
+
if (bundle.manualSharedBundle) {
|
|
33
|
+
return bundle.manualSharedBundle;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (bundle.mainEntryAsset) {
|
|
37
|
+
let relativePath = relative(
|
|
38
|
+
this.projectRoot,
|
|
39
|
+
bundle.mainEntryAsset.filePath,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (relativePath.length > 100) {
|
|
43
|
+
relativePath =
|
|
44
|
+
relativePath.slice(0, 50) + '...' + relativePath.slice(-50);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return relativePath;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return `shared`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
report(getBundle: (bundleId: NodeId) => Bundle | null | undefined): void {
|
|
54
|
+
if (!debugTools['bundle-stats']) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type MergeResult = Record<string, string | number>;
|
|
59
|
+
let mergeResults: Array<MergeResult> = [];
|
|
60
|
+
|
|
61
|
+
let totals: Record<string, string | number> = {
|
|
62
|
+
label: 'Totals',
|
|
63
|
+
merges: 0,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
for (let [bundleId, mergedBundles] of this.merges) {
|
|
67
|
+
let bundle = getBundle(bundleId);
|
|
68
|
+
if (!bundle) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let result: MergeResult = {
|
|
73
|
+
label: this.getBundleLabel(bundle),
|
|
74
|
+
size: bundle.size,
|
|
75
|
+
merges: mergedBundles.length,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
for (let merged of mergedBundles) {
|
|
79
|
+
result[merged.reason] = ((result[merged.reason] as number) || 0) + 1;
|
|
80
|
+
totals[merged.reason] = ((totals[merged.reason] as number) || 0) + 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
(totals.merges as number) += mergedBundles.length;
|
|
84
|
+
mergeResults.push(result);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
mergeResults.sort((a, b) => {
|
|
88
|
+
// Sort by bundle size descending
|
|
89
|
+
return (b.size as number) - (a.size as number);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
mergeResults.push(totals);
|
|
93
|
+
|
|
94
|
+
// eslint-disable-next-line no-console
|
|
95
|
+
console.table(mergeResults);
|
|
96
|
+
}
|
|
97
|
+
}
|
package/tsconfig.json
ADDED
package/src/bundleMerge.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// @flow strict-local
|
|
2
|
-
|
|
3
|
-
import invariant from 'assert';
|
|
4
|
-
import nullthrows from 'nullthrows';
|
|
5
|
-
import type {NodeId} from '@atlaspack/graph';
|
|
6
|
-
import type {Bundle, IdealBundleGraph} from './idealGraph';
|
|
7
|
-
import {ContentGraph} from '@atlaspack/graph';
|
|
8
|
-
|
|
9
|
-
// Returns a decimal showing the proportion source bundles are common to
|
|
10
|
-
// both bundles versus the total number of source bundles.
|
|
11
|
-
function scoreBundleMerge(bundleA: Bundle, bundleB: Bundle): number {
|
|
12
|
-
let sharedSourceBundles = 0;
|
|
13
|
-
let allSourceBundles = new Set([
|
|
14
|
-
...bundleA.sourceBundles,
|
|
15
|
-
...bundleB.sourceBundles,
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
for (let bundle of bundleB.sourceBundles) {
|
|
19
|
-
if (bundleA.sourceBundles.has(bundle)) {
|
|
20
|
-
sharedSourceBundles++;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return sharedSourceBundles / allSourceBundles.size;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function getMergeClusters(
|
|
28
|
-
graph: ContentGraph<NodeId>,
|
|
29
|
-
candidates: Set<NodeId>,
|
|
30
|
-
): Array<Array<NodeId>> {
|
|
31
|
-
let clusters = [];
|
|
32
|
-
|
|
33
|
-
for (let candidate of candidates) {
|
|
34
|
-
let cluster: Array<NodeId> = [];
|
|
35
|
-
|
|
36
|
-
graph.traverse((nodeId) => {
|
|
37
|
-
cluster.push(nullthrows(graph.getNode(nodeId)));
|
|
38
|
-
// Remove node from candidates as it has already been processed
|
|
39
|
-
candidates.delete(nodeId);
|
|
40
|
-
}, candidate);
|
|
41
|
-
|
|
42
|
-
clusters.push(cluster);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return clusters;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function findMergeCandidates(
|
|
49
|
-
bundleGraph: IdealBundleGraph,
|
|
50
|
-
bundles: Array<NodeId>,
|
|
51
|
-
threshold: number,
|
|
52
|
-
): Array<Array<NodeId>> {
|
|
53
|
-
let graph = new ContentGraph<NodeId>();
|
|
54
|
-
let seen = new Set<string>();
|
|
55
|
-
let candidates = new Set<NodeId>();
|
|
56
|
-
|
|
57
|
-
// Build graph of clustered merge candidates
|
|
58
|
-
for (let bundleId of bundles) {
|
|
59
|
-
let bundle = bundleGraph.getNode(bundleId);
|
|
60
|
-
invariant(bundle && bundle !== 'root');
|
|
61
|
-
if (bundle.type !== 'js') {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
for (let otherBundleId of bundles) {
|
|
66
|
-
if (bundleId === otherBundleId) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let key = [bundleId, otherBundleId].sort().join(':');
|
|
71
|
-
|
|
72
|
-
if (seen.has(key)) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
seen.add(key);
|
|
76
|
-
|
|
77
|
-
let otherBundle = bundleGraph.getNode(otherBundleId);
|
|
78
|
-
invariant(otherBundle && otherBundle !== 'root');
|
|
79
|
-
|
|
80
|
-
let score = scoreBundleMerge(bundle, otherBundle);
|
|
81
|
-
|
|
82
|
-
if (score >= threshold) {
|
|
83
|
-
let bundleNode = graph.addNodeByContentKeyIfNeeded(
|
|
84
|
-
bundleId.toString(),
|
|
85
|
-
bundleId,
|
|
86
|
-
);
|
|
87
|
-
let otherBundleNode = graph.addNodeByContentKeyIfNeeded(
|
|
88
|
-
otherBundleId.toString(),
|
|
89
|
-
otherBundleId,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
// Add edge in both directions
|
|
93
|
-
graph.addEdge(bundleNode, otherBundleNode);
|
|
94
|
-
graph.addEdge(otherBundleNode, bundleNode);
|
|
95
|
-
|
|
96
|
-
candidates.add(bundleNode);
|
|
97
|
-
candidates.add(otherBundleNode);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return getMergeClusters(graph, candidates);
|
|
103
|
-
}
|