Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #9634 #9635

Merged
merged 1 commit into from Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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"
}
};