fixes in ContextModule

avoid generating __webpack_require__.e when no chunks are used
add optimized lazy mode when no chunks and no fake make are used
improve module id check
This commit is contained in:
Tobias Koppers 2019-02-05 17:29:27 +01:00
parent 7edcc480db
commit 7a5137d7c4
6 changed files with 80 additions and 48 deletions

View File

@ -380,13 +380,12 @@ function webpackContext(req) {
${returnModuleObject}
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
@ -414,13 +413,12 @@ function webpackContext(req) {
${returnModuleObject}
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
@ -452,13 +450,12 @@ function webpackAsyncContextResolve(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncaught exception popping up in devtools
return Promise.resolve().then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
return map[req];
});
}
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
@ -488,13 +485,12 @@ function webpackAsyncContextResolve(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncaught exception popping up in devtools
return Promise.resolve().then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
return map[req];
});
}
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
@ -527,13 +523,12 @@ function webpackAsyncContext(req) {
}
function webpackAsyncContextResolve(req) {
return ${promise}.then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
return map[req];
});
}
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
@ -546,59 +541,92 @@ module.exports = webpackAsyncContext;`;
getLazySource(blocks, id) {
let hasMultipleOrNoChunks = false;
let hasNoChunk = true;
const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0]));
const hasFakeMap = typeof fakeMap === "object";
const map = blocks
.filter(block => block.dependencies[0].module)
.map(block => ({
dependency: block.dependencies[0],
block: block,
userRequest: block.dependencies[0].userRequest
}))
.map(block => {
const chunks = block.chunkGroup ? block.chunkGroup.chunks : [];
if (chunks.length > 0) {
hasNoChunk = false;
}
if (chunks.length !== 1) {
hasMultipleOrNoChunks = true;
}
return {
dependency: block.dependencies[0],
block: block,
userRequest: block.dependencies[0].userRequest,
chunks
};
})
.sort((a, b) => {
if (a.userRequest === b.userRequest) return 0;
return a.userRequest < b.userRequest ? -1 : 1;
})
.reduce((map, item) => {
const chunks =
(item.block.chunkGroup && item.block.chunkGroup.chunks) || [];
if (chunks.length !== 1) {
hasMultipleOrNoChunks = true;
const chunks = item.chunks;
if (hasNoChunk && !hasFakeMap) {
map[item.userRequest] = item.dependency.module.id;
} else {
const arrayStart = [item.dependency.module.id];
if (typeof fakeMap === "object") {
arrayStart.push(fakeMap[item.dependency.module.id]);
}
map[item.userRequest] = arrayStart.concat(
chunks.map(chunk => chunk.id)
);
}
const arrayStart = [item.dependency.module.id];
if (typeof fakeMap === "object") {
arrayStart.push(fakeMap[item.dependency.module.id]);
}
map[item.userRequest] = arrayStart.concat(
chunks.map(chunk => chunk.id)
);
return map;
}, Object.create(null));
const chunksStartPosition = typeof fakeMap === "object" ? 2 : 1;
const requestPrefix = hasMultipleOrNoChunks
const shortMode = hasNoChunk && !hasFakeMap;
const chunksStartPosition = hasFakeMap ? 2 : 1;
const requestPrefix = hasNoChunk
? "Promise.resolve()"
: hasMultipleOrNoChunks
? `Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))`
: `__webpack_require__.e(ids[${chunksStartPosition}])`;
const returnModuleObject = this.getReturnModuleObjectSource(
fakeMap,
"ids[1]"
shortMode ? "invalid" : "ids[1]"
);
return `var map = ${JSON.stringify(map, null, "\t")};
const webpackAsyncContext =
requestPrefix === "Promise.resolve()"
? `${shortMode ? "" : ""}
function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
${shortMode ? "var id = map[req];" : "var ids = map[req], id = ids[0];"}
${returnModuleObject}
});
}`
: `function webpackAsyncContext(req) {
if(!__webpack_require__.o(map, req)) {
return Promise.resolve().then(function() {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});
}
var ids = map[req], id = ids[0];
return ${requestPrefix}.then(function() {
var id = ids[0];
${returnModuleObject}
});
}
}`;
return `var map = ${JSON.stringify(map, null, "\t")};
${webpackAsyncContext}
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
return Object.keys(map);
};

View File

@ -250,14 +250,7 @@ module.exports = class MainTemplate extends Tapable {
} else if (
chunk.hasModuleInGraph(m =>
m.blocks.some(b => b.chunkGroup && b.chunkGroup.chunks.length > 0)
) ||
chunk
.getModules()
.some(m =>
m.dependencies.some(
dep => dep.type && dep.type.startsWith("import()")
)
)
)
) {
// There async blocks in the graph, so we need to add an empty requireEnsure
// function anyway. This can happen with multiple entrypoints.

View File

@ -1079,7 +1079,7 @@ Built at: Thu Jan 01 1970 00:00:00 GMT
0.js 305 bytes 0 [emitted]
1.js 314 bytes 1 [emitted]
2.js 308 bytes 2 [emitted]
entry.js 9.03 KiB 3 [emitted] entry
entry.js 9.05 KiB 3 [emitted] entry
Entrypoint entry = entry.js
[0] ./templates/bar.js 38 bytes {0} [optional] [built]
[1] ./templates/baz.js 38 bytes {1} [optional] [built]

View File

@ -0,0 +1 @@
export default "initialModuleDefault";

View File

@ -0,0 +1 @@
exports.default = "other";

View File

@ -6,3 +6,12 @@ it("should resolve when import existed chunk (#8626)", function(done) {
done();
}).catch(done);
});
it("should resolve when import existed chunk with fake maps", function(done) {
require.context("./dir-initial-with-fake-map/");
const fileName = "initialModule";
import(`./dir-initial-with-fake-map/${fileName}`).then(({default:m}) => {
expect(m).toBe("initialModuleDefault");
done();
}).catch(done);
});