Skip to content

Commit 235b87b

Browse files
committed
make sure to generate correct chunk connection for blocks that are only connected in some runtimes
fixes #8677
1 parent 4a1f068 commit 235b87b

7 files changed

Lines changed: 89 additions & 58 deletions

File tree

lib/buildChunkGraph.js

Lines changed: 44 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ const GraphHelpers = require("./GraphHelpers");
3838
*/
3939

4040
/**
41-
* @typedef {Object} ChunkGroupDep
42-
* @property {AsyncDependenciesBlock} block referencing block
41+
* @typedef {Object} BlockChunkGroupConnection
42+
* @property {ChunkGroupInfo} originChunkGroupInfo origin chunk group
4343
* @property {ChunkGroup} chunkGroup referenced chunk group
4444
*/
4545

@@ -143,15 +143,15 @@ const extraceBlockInfoMap = compilation => {
143143
* @param {Compilation} compilation the compilation
144144
* @param {Entrypoint[]} inputChunkGroups input groups
145145
* @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules
146-
* @param {Map<ChunkGroup, ChunkGroupDep[]>} chunkDependencies dependencies for chunk groups
146+
* @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
147147
* @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
148148
* @param {Set<ChunkGroup>} allCreatedChunkGroups filled with all chunk groups that are created here
149149
*/
150150
const visitModules = (
151151
compilation,
152152
inputChunkGroups,
153153
chunkGroupInfoMap,
154-
chunkDependencies,
154+
blockConnections,
155155
blocksWithNestedBlocks,
156156
allCreatedChunkGroups
157157
) => {
@@ -229,6 +229,8 @@ const visitModules = (
229229
let chunk;
230230
/** @type {ChunkGroup} */
231231
let chunkGroup;
232+
/** @type {ChunkGroupInfo} */
233+
let chunkGroupInfo;
232234
/** @type {DependenciesBlock} */
233235
let block;
234236
/** @type {Set<Module>} */
@@ -263,17 +265,17 @@ const visitModules = (
263265
blockChunkGroups.set(b, c);
264266
allCreatedChunkGroups.add(c);
265267
}
268+
blockConnections.set(b, []);
266269
} else {
267270
// TODO webpack 5 remove addOptions check
268271
if (c.addOptions) c.addOptions(b.groupOptions);
269272
c.addOrigin(module, b.loc, b.request);
270273
}
271274

272-
// 2. We store the Block+Chunk mapping as dependency for the chunk
273-
let deps = chunkDependencies.get(chunkGroup);
274-
if (!deps) chunkDependencies.set(chunkGroup, (deps = []));
275-
deps.push({
276-
block: b,
275+
// 2. We store the connection for the block
276+
// to connect it later if needed
277+
blockConnections.get(b).push({
278+
originChunkGroupInfo: chunkGroupInfo,
277279
chunkGroup: c
278280
});
279281

@@ -306,7 +308,7 @@ const visitModules = (
306308
chunk = queueItem.chunk;
307309
if (chunkGroup !== queueItem.chunkGroup) {
308310
chunkGroup = queueItem.chunkGroup;
309-
const chunkGroupInfo = chunkGroupInfoMap.get(chunkGroup);
311+
chunkGroupInfo = chunkGroupInfoMap.get(chunkGroup);
310312
minAvailableModules = chunkGroupInfo.minAvailableModules;
311313
skippedItems = chunkGroupInfo.skippedItems;
312314
}
@@ -583,17 +585,14 @@ const visitModules = (
583585
/**
584586
*
585587
* @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks
586-
* @param {Map<ChunkGroup, ChunkGroupDep[]>} chunkDependencies dependencies for chunk groups
588+
* @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks
587589
* @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules
588590
*/
589591
const connectChunkGroups = (
590592
blocksWithNestedBlocks,
591-
chunkDependencies,
593+
blockConnections,
592594
chunkGroupInfoMap
593595
) => {
594-
/** @type {Set<Module>} */
595-
let resultingAvailableModules;
596-
597596
/**
598597
* Helper function to check if all modules of a chunk are available
599598
*
@@ -611,49 +610,38 @@ const connectChunkGroups = (
611610
};
612611

613612
// For each edge in the basic chunk graph
614-
/**
615-
* @param {ChunkGroupDep} dep the dependency used for filtering
616-
* @returns {boolean} used to filter "edges" (aka Dependencies) that were pointing
617-
* to modules that are already available. Also filters circular dependencies in the chunks graph
618-
*/
619-
const filterFn = dep => {
620-
const depChunkGroup = dep.chunkGroup;
621-
// TODO is this needed?
622-
if (blocksWithNestedBlocks.has(dep.block)) return true;
623-
if (areModulesAvailable(depChunkGroup, resultingAvailableModules)) {
624-
return false; // break all modules are already available
613+
for (const [block, connections] of blockConnections) {
614+
// 1. Check if connection is needed
615+
// When none of the dependencies need to be connected
616+
// we can skip all of them
617+
// It's not possible to filter each item so it doesn't create inconsistent
618+
// connections and modules can only create one version
619+
// TODO maybe decide this per runtime
620+
if (
621+
// TODO is this needed?
622+
!blocksWithNestedBlocks.has(block) &&
623+
connections.every(({ chunkGroup, originChunkGroupInfo }) =>
624+
areModulesAvailable(
625+
chunkGroup,
626+
originChunkGroupInfo.resultingAvailableModules
627+
)
628+
)
629+
) {
630+
continue;
625631
}
626-
return true;
627-
};
628-
629-
// For all deps, check if chunk groups need to be connected
630-
for (const [chunkGroup, deps] of chunkDependencies) {
631-
if (deps.length === 0) continue;
632-
633-
// 1. Get info from chunk group info map
634-
const info = chunkGroupInfoMap.get(chunkGroup);
635-
resultingAvailableModules = info.resultingAvailableModules;
636632

637633
// 2. Foreach edge
638-
for (let i = 0; i < deps.length; i++) {
639-
const dep = deps[i];
634+
for (let i = 0; i < connections.length; i++) {
635+
const { chunkGroup, originChunkGroupInfo } = connections[i];
640636

641-
// Filter inline, rather than creating a new array from `.filter()`
642-
// TODO check if inlining filterFn makes sense here
643-
if (!filterFn(dep)) {
644-
continue;
645-
}
646-
const depChunkGroup = dep.chunkGroup;
647-
const depBlock = dep.block;
637+
// 3. Connect block with chunk
638+
GraphHelpers.connectDependenciesBlockAndChunkGroup(block, chunkGroup);
648639

649-
// 5. Connect block with chunk
650-
GraphHelpers.connectDependenciesBlockAndChunkGroup(
651-
depBlock,
652-
depChunkGroup
640+
// 4. Connect chunk with parent
641+
GraphHelpers.connectChunkGroupParentAndChild(
642+
originChunkGroupInfo.chunkGroup,
643+
chunkGroup
653644
);
654-
655-
// 6. Connect chunk with parent
656-
GraphHelpers.connectChunkGroupParentAndChild(chunkGroup, depChunkGroup);
657645
}
658646
}
659647
};
@@ -685,8 +673,8 @@ const cleanupUnconnectedGroups = (compilation, allCreatedChunkGroups) => {
685673
const buildChunkGraph = (compilation, inputChunkGroups) => {
686674
// SHARED STATE
687675

688-
/** @type {Map<ChunkGroup, ChunkGroupDep[]>} */
689-
const chunkDependencies = new Map();
676+
/** @type {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} */
677+
const blockConnections = new Map();
690678

691679
/** @type {Set<ChunkGroup>} */
692680
const allCreatedChunkGroups = new Set();
@@ -703,7 +691,7 @@ const buildChunkGraph = (compilation, inputChunkGroups) => {
703691
compilation,
704692
inputChunkGroups,
705693
chunkGroupInfoMap,
706-
chunkDependencies,
694+
blockConnections,
707695
blocksWithNestedBlocks,
708696
allCreatedChunkGroups
709697
);
@@ -712,7 +700,7 @@ const buildChunkGraph = (compilation, inputChunkGroups) => {
712700

713701
connectChunkGroups(
714702
blocksWithNestedBlocks,
715-
chunkDependencies,
703+
blockConnections,
716704
chunkGroupInfoMap
717705
);
718706

test/__snapshots__/StatsTestCases.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,7 @@ cir2 from cir1.js 359 bytes 6, 5 [emitted] cir2 from cir1
16391639
cir2.js 299 bytes 5 [emitted] cir2
16401640
main.js 9.25 KiB 7 [emitted] main
16411641
Entrypoint main = main.js
1642-
chunk {0} cir1.js (cir1) 81 bytes <{5}> <{7}> >{6}< [rendered]
1642+
chunk {0} cir1.js (cir1) 81 bytes <{5}> <{6}> <{7}> >{6}< [rendered]
16431643
> [5] ./index.js 13:0-54
16441644
> [7] ./circular2.js 1:0-79
16451645
> [7] ./circular2.js 1:0-79
@@ -1664,7 +1664,7 @@ chunk {4} chunk.js (chunk) 0 bytes <{2}> <{3}> [rendered]
16641664
chunk {5} cir2.js (cir2) 81 bytes <{7}> >{0}< [rendered]
16651665
> [5] ./index.js 14:0-54
16661666
[7] ./circular2.js 81 bytes {5} {6} [built]
1667-
chunk {6} cir2 from cir1.js (cir2 from cir1) 81 bytes <{0}> [rendered]
1667+
chunk {6} cir2 from cir1.js (cir2 from cir1) 81 bytes <{0}> >{0}< [rendered]
16681668
> [6] ./circular1.js 1:0-79
16691669
> [6] ./circular1.js 1:0-79
16701670
[7] ./circular2.js 81 bytes {5} {6} [built]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import c1 from "./c1";
2+
3+
it("should allow to import an conditionally unneeded chunk", function(done) {
4+
c1()
5+
.then(function(c2) {
6+
return c2.default();
7+
})
8+
.then(function(c1_) {
9+
expect(c1_.value).toBe(1);
10+
done();
11+
});
12+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import c2 from "./c2";
2+
3+
it("should allow to import an conditionally unneeded chunk", function(done) {
4+
c2()
5+
.then(function(c1) {
6+
return c1.default();
7+
})
8+
.then(function(c2_) {
9+
expect(c2_.value).toBe(2);
10+
done();
11+
});
12+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default () => import("./c2");
2+
export const value = 1;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default () => import("./c1");
2+
export const value = 2;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/** @type {import("../../../../").Configuration} */
2+
module.exports = {
3+
entry: {
4+
bundle0: "./a",
5+
bundle1: "./b"
6+
},
7+
optimization: {
8+
flagIncludedChunks: false,
9+
chunkIds: "named"
10+
},
11+
output: {
12+
filename: "[name].js",
13+
chunkFilename: "[id].[chunkhash].js"
14+
}
15+
};

0 commit comments

Comments
 (0)