From 7edcc480dbe2c387701acd321dfa56a7d105069a Mon Sep 17 00:00:00 2001 From: mc-zone Date: Sun, 20 Jan 2019 19:39:51 +0800 Subject: [PATCH 1/2] fix: add missed __webpack_require__.e runtime while importing exist module with context --- lib/MainTemplate.js | 9 ++++++++- .../dir-initial/initialModule.js | 1 + test/cases/chunks/import-context-exist-chunk/index.js | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/cases/chunks/import-context-exist-chunk/dir-initial/initialModule.js create mode 100644 test/cases/chunks/import-context-exist-chunk/index.js diff --git a/lib/MainTemplate.js b/lib/MainTemplate.js index db42205e7de..3ea918de934 100644 --- a/lib/MainTemplate.js +++ b/lib/MainTemplate.js @@ -250,7 +250,14 @@ 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. diff --git a/test/cases/chunks/import-context-exist-chunk/dir-initial/initialModule.js b/test/cases/chunks/import-context-exist-chunk/dir-initial/initialModule.js new file mode 100644 index 00000000000..341b43e9dfa --- /dev/null +++ b/test/cases/chunks/import-context-exist-chunk/dir-initial/initialModule.js @@ -0,0 +1 @@ +export default "initialModuleDefault"; diff --git a/test/cases/chunks/import-context-exist-chunk/index.js b/test/cases/chunks/import-context-exist-chunk/index.js new file mode 100644 index 00000000000..2b4f135e586 --- /dev/null +++ b/test/cases/chunks/import-context-exist-chunk/index.js @@ -0,0 +1,8 @@ +it("should resolve when import existed chunk (#8626)", function(done) { + require.context("./dir-initial/"); + const fileName = "initialModule"; + import(`./dir-initial/${fileName}`).then(({default:m}) => { + expect(m).toBe("initialModuleDefault"); + done(); + }).catch(done); +}); From 7a5137d7c4cf3e6b8b83468ca26af5b7e7084d3c Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 5 Feb 2019 17:29:27 +0100 Subject: [PATCH 2/2] 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 --- lib/ContextModule.js | 106 +++++++++++------- lib/MainTemplate.js | 9 +- .../__snapshots__/StatsTestCases.test.js.snap | 2 +- .../initialModule.js | 1 + .../initialModule2.js | 1 + .../import-context-exist-chunk/index.js | 9 ++ 6 files changed, 80 insertions(+), 48 deletions(-) create mode 100644 test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js create mode 100644 test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js diff --git a/lib/ContextModule.js b/lib/ContextModule.js index 78e0e47aa73..f7fae1355ce 100644 --- a/lib/ContextModule.js +++ b/lib/ContextModule.js @@ -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 arrayStart = [item.dependency.module.id]; - if (typeof fakeMap === "object") { - arrayStart.push(fakeMap[item.dependency.module.id]); + 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) + ); } - 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); }; diff --git a/lib/MainTemplate.js b/lib/MainTemplate.js index 3ea918de934..db42205e7de 100644 --- a/lib/MainTemplate.js +++ b/lib/MainTemplate.js @@ -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. diff --git a/test/__snapshots__/StatsTestCases.test.js.snap b/test/__snapshots__/StatsTestCases.test.js.snap index 68d8b665f32..d441f4fb19f 100644 --- a/test/__snapshots__/StatsTestCases.test.js.snap +++ b/test/__snapshots__/StatsTestCases.test.js.snap @@ -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] diff --git a/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js b/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js new file mode 100644 index 00000000000..341b43e9dfa --- /dev/null +++ b/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule.js @@ -0,0 +1 @@ +export default "initialModuleDefault"; diff --git a/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js b/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js new file mode 100644 index 00000000000..4c27d0e9f9a --- /dev/null +++ b/test/cases/chunks/import-context-exist-chunk/dir-initial-with-fake-map/initialModule2.js @@ -0,0 +1 @@ +exports.default = "other"; diff --git a/test/cases/chunks/import-context-exist-chunk/index.js b/test/cases/chunks/import-context-exist-chunk/index.js index 2b4f135e586..8bdb5c77d2b 100644 --- a/test/cases/chunks/import-context-exist-chunk/index.js +++ b/test/cases/chunks/import-context-exist-chunk/index.js @@ -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); +});