UNPKG

3.2 kBJavaScriptView Raw
1/**
2 * Find an ancestor of a chunk. Return the distance from the target or -1 if not found.
3 *
4 * @param {ChunkGroup} initialSrc
5 * @param {ChunkGroup} target
6 * @param {number} initialDistance
7 * @return {number} distance from target of parent or -1 when not found
8 */
9function findAncestorDistance(initialSrc, target, initialDistance) {
10 const distances = [];
11 const parentChunkQueue = [
12 {
13 src: initialSrc,
14 currentDistance: initialDistance,
15 },
16 ];
17 const visitedChunks = new Set([initialSrc]);
18 while (parentChunkQueue.length > 0) {
19 const { src, currentDistance } = parentChunkQueue.pop();
20 if (target === src) {
21 if (currentDistance >= 0) {
22 distances.push(currentDistance);
23 }
24 } else {
25 const parentChunkGroups = src.getParents();
26 for (let i = parentChunkGroups.length - 1; i >= 0; i--) {
27 if (!visitedChunks.has(parentChunkGroups[i])) {
28 visitedChunks.add(parentChunkGroups[i]);
29 parentChunkQueue.push({
30 src: parentChunkGroups[i],
31 currentDistance: currentDistance + 1,
32 });
33 }
34 }
35 }
36 }
37 if (distances.length === 0) {
38 return -1;
39 }
40 return Math.min(...distances);
41}
42
43/**
44 * Find the closest common parent chunk from a list.
45 * Since closure-compiler requires a chunk tree to have a single root,
46 * there will always be a common parent.
47 *
48 * @param {!Array<string>} chunkGroups
49 * @param {number} currentDistance
50 * @return {{chunkGroup: (!ChunkGroup|undefined), distance: number}}
51 */
52function findNearestCommonParentChunk(chunkGroups, currentDistance = 0) {
53 // Map of chunk name to distance from target
54 const distances = new Map();
55 for (let i = 1; i < chunkGroups.length; i++) {
56 const distance = findAncestorDistance(
57 chunkGroups[i],
58 chunkGroups[0],
59 currentDistance
60 );
61 if (distance < 0) {
62 distances.delete(chunkGroups[0]);
63 } else if (
64 !distances.has(chunkGroups[0]) ||
65 distance < distances.get(chunkGroups[0])
66 ) {
67 distances.set(chunkGroups[0], distance);
68 }
69 }
70 if (distances.size === 0) {
71 // chunkGroup[0] was not a parent for the other chunk groups.
72 // So move up the graph one level and check again.
73 chunkGroups[0].getParents().forEach((chunkGroupParent) => {
74 const distanceRecord = findNearestCommonParentChunk(
75 [chunkGroupParent].concat(chunkGroups.slice(1)),
76 currentDistance + 1
77 );
78 if (
79 distanceRecord.distance >= 0 &&
80 (!distances.has(distanceRecord.chunkGroup) ||
81 distances.get(distanceRecord.chunkGroup) < distanceRecord.distance)
82 ) {
83 distances.set(distanceRecord.chunkGroup, distanceRecord.distance);
84 }
85 });
86 }
87
88 const nearestCommonParent = {
89 chunkGroup: undefined, // eslint-disable-line no-undefined
90 distance: -1,
91 };
92 distances.forEach((distance, chunkGroup) => {
93 if (
94 nearestCommonParent.distance < 0 ||
95 distance < nearestCommonParent.distance
96 ) {
97 nearestCommonParent.chunkGroup = chunkGroup;
98 nearestCommonParent.distance = distance;
99 }
100 });
101 return nearestCommonParent;
102}
103
104module.exports = findNearestCommonParentChunk;