Skip to content

Commit

Permalink
Merge pull request #9635 from webpack/bugfix/9634
Browse files Browse the repository at this point in the history
fixes #9634
  • Loading branch information
sokra committed Aug 27, 2019
2 parents 54519bd + 83dd295 commit 6bf1868
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 14 deletions.
63 changes: 49 additions & 14 deletions lib/buildChunkGraph.js
Expand Up @@ -28,11 +28,13 @@ const GraphHelpers = require("./GraphHelpers");

/**
* @typedef {Object} ChunkGroupInfo
* @property {ChunkGroup} chunkGroup the chunk group
* @property {Set<Module>} minAvailableModules current minimal set of modules available at this point
* @property {boolean} minAvailableModulesOwned true, if minAvailableModules is owned and can be modified
* @property {Set<Module>[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules
* @property {QueueItem[]} skippedItems queue items that were skipped because module is already available in parent chunks (need to reconsider when minAvailableModules is shrinking)
* @property {Set<Module>} resultingAvailableModules set of modules available including modules from this chunk group
* @property {Set<ChunkGroup>} children set of children chunk groups, that will be revisited when availableModules shrink
*/

/**
Expand Down Expand Up @@ -196,11 +198,13 @@ const visitModules = (
});
}
chunkGroupInfoMap.set(chunkGroup, {
chunkGroup,
minAvailableModules: new Set(),
minAvailableModulesOwned: true,
availableModulesToBeMerged: [],
skippedItems: [],
resultingAvailableModules: undefined
resultingAvailableModules: undefined,
children: undefined
});
return queue;
};
Expand Down Expand Up @@ -418,7 +422,7 @@ const visitModules = (
}
logger.timeEnd("visiting");

if (queueConnect.size > 0) {
while (queueConnect.size > 0) {
logger.time("calculating available modules");

// Figure out new parents for chunk groups
Expand All @@ -435,17 +439,26 @@ const visitModules = (
}
}
info.resultingAvailableModules = resultingAvailableModules;
if (info.children === undefined) {
info.children = targets;
} else {
for (const target of targets) {
info.children.add(target);
}
}

// 2. Update chunk group info
for (const target of targets) {
let chunkGroupInfo = chunkGroupInfoMap.get(target);
if (chunkGroupInfo === undefined) {
chunkGroupInfo = {
chunkGroup: target,
minAvailableModules: undefined,
minAvailableModulesOwned: undefined,
availableModulesToBeMerged: [],
skippedItems: [],
resultingAvailableModules: undefined
resultingAvailableModules: undefined,
children: undefined
};
chunkGroupInfoMap.set(target, chunkGroupInfo);
}
Expand All @@ -463,7 +476,7 @@ const visitModules = (
// Execute the merge
for (const info of outdatedChunkGroupInfo) {
const availableModulesToBeMerged = info.availableModulesToBeMerged;
let minAvailableModules = info.minAvailableModules;
let cachedMinAvailableModules = info.minAvailableModules;

// 1. Get minimal available modules
// It doesn't make sense to traverse a chunk again with more available modules.
Expand All @@ -474,29 +487,31 @@ const visitModules = (
}
let changed = false;
for (const availableModules of availableModulesToBeMerged) {
if (minAvailableModules === undefined) {
minAvailableModules = availableModules;
info.minAvailableModules = minAvailableModules;
if (cachedMinAvailableModules === undefined) {
cachedMinAvailableModules = availableModules;
info.minAvailableModules = cachedMinAvailableModules;
info.minAvailableModulesOwned = false;
changed = true;
} else {
if (info.minAvailableModulesOwned) {
// We own it and can modify it
for (const m of minAvailableModules) {
for (const m of cachedMinAvailableModules) {
if (!availableModules.has(m)) {
minAvailableModules.delete(m);
cachedMinAvailableModules.delete(m);
changed = true;
}
}
} else {
for (const m of minAvailableModules) {
for (const m of cachedMinAvailableModules) {
if (!availableModules.has(m)) {
// minAvailableModules need to be modified
// cachedMinAvailableModules need to be modified
// but we don't own it
// construct a new Set as intersection of minAvailableModules and availableModules
// construct a new Set as intersection of cachedMinAvailableModules and availableModules
/** @type {Set<Module>} */
const newSet = new Set();
const iterator = minAvailableModules[Symbol.iterator]();
const iterator = cachedMinAvailableModules[
Symbol.iterator
]();
/** @type {IteratorResult<Module>} */
let it;
while (!(it = iterator.next()).done) {
Expand All @@ -510,9 +525,16 @@ const visitModules = (
newSet.add(module);
}
}
minAvailableModules = newSet;
cachedMinAvailableModules = newSet;
info.minAvailableModulesOwned = true;
info.minAvailableModules = newSet;

// Update the cache from the first queue
// if the chunkGroup is currently cached
if (chunkGroup === info.chunkGroup) {
minAvailableModules = cachedMinAvailableModules;
}

changed = true;
break;
}
Expand All @@ -528,6 +550,19 @@ const visitModules = (
queue.push(queueItem);
}
info.skippedItems.length = 0;

// 3. Reconsider children chunk groups
if (info.children !== undefined) {
const chunkGroup = info.chunkGroup;
for (const c of info.children) {
let connectList = queueConnect.get(chunkGroup);
if (connectList === undefined) {
connectList = new Set();
queueConnect.set(chunkGroup, connectList);
}
connectList.add(c);
}
}
}
outdatedChunkGroupInfo.clear();
logger.timeEnd("merging available modules");
Expand Down
1 change: 1 addition & 0 deletions test/configCases/chunk-graph/issue-9634/async-b.js
@@ -0,0 +1 @@
export default import(/* webpackChunkName: "shared" */ "./shared");
1 change: 1 addition & 0 deletions test/configCases/chunk-graph/issue-9634/async-b2.js
@@ -0,0 +1 @@
export default import(/* webpackChunkName: "async-b" */ "./async-b");
13 changes: 13 additions & 0 deletions test/configCases/chunk-graph/issue-9634/entry-a.js
@@ -0,0 +1,13 @@
import leaf from "./leaf";

it("should include the leaf module", () => {
expect(leaf).toBe("ok");
});

it("should load the leaf module from a", () => {
return import(/* webpackChunkName: "shared" */ "./shared").then(shared => {
return shared.default.then(module => {
expect(module.default).toBe("ok");
});
});
});
11 changes: 11 additions & 0 deletions test/configCases/chunk-graph/issue-9634/entry-b.js
@@ -0,0 +1,11 @@
it("should load the leaf module from b", () => {
return import(/* webpackChunkName: "async-b2" */ "./async-b2").then(asy => {
return asy.default.then(asy => {
return asy.default.then(shared => {
return shared.default.then(module => {
expect(module.default).toBe("ok");
});
});
});
});
});
1 change: 1 addition & 0 deletions test/configCases/chunk-graph/issue-9634/leaf.js
@@ -0,0 +1 @@
export default "ok";
3 changes: 3 additions & 0 deletions test/configCases/chunk-graph/issue-9634/module.js
@@ -0,0 +1,3 @@
import leaf from "./leaf";

export default leaf;
1 change: 1 addition & 0 deletions test/configCases/chunk-graph/issue-9634/shared.js
@@ -0,0 +1 @@
export default import(/* webpackChunkName: "module" */ "./module");
5 changes: 5 additions & 0 deletions test/configCases/chunk-graph/issue-9634/test.config.js
@@ -0,0 +1,5 @@
module.exports = {
findBundle: function(i, options) {
return ["a.js", "b.js"];
}
};
9 changes: 9 additions & 0 deletions test/configCases/chunk-graph/issue-9634/webpack.config.js
@@ -0,0 +1,9 @@
module.exports = {
entry: {
b: "./entry-b",
a: "./entry-a"
},
output: {
filename: "[name].js"
}
};

0 comments on commit 6bf1868

Please sign in to comment.