Merge tag 'v4.21.0' into next

4.21.0
This commit is contained in:
Tobias Koppers 2018-10-17 20:38:00 +02:00
commit 518104b3fb
30 changed files with 180 additions and 75 deletions

View File

@ -1100,6 +1100,7 @@ export interface OutputOptions {
| "commonjs2" | "commonjs2"
| "commonjs-module" | "commonjs-module"
| "amd" | "amd"
| "amd-require"
| "umd" | "umd"
| "umd2" | "umd2"
| "jsonp"; | "jsonp";

View File

@ -78,6 +78,7 @@ export type DllReferencePluginOptionsSourceType =
| "commonjs2" | "commonjs2"
| "commonjs-module" | "commonjs-module"
| "amd" | "amd"
| "amd-require"
| "umd" | "umd"
| "umd2" | "umd2"
| "jsonp"; | "jsonp";

View File

@ -11,13 +11,24 @@ const Template = require("./Template");
/** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./Compilation")} Compilation */
/**
* @typedef {Object} AmdMainTemplatePluginOptions
* @param {string=} name the library name
* @property {boolean=} requireAsWrapper
*/
class AmdMainTemplatePlugin { class AmdMainTemplatePlugin {
/** /**
* @param {string=} name the library name * @param {AmdMainTemplatePluginOptions} options the plugin options
*/ */
constructor(name) { constructor(options) {
/** @type {string=} */ if (!options || typeof options === "string") {
this.name = name; this.name = options;
this.requireAsWrapper = false;
} else {
this.name = options.name;
this.requireAsWrapper = options.requireAsWrapper;
}
} }
/** /**
@ -50,7 +61,13 @@ class AmdMainTemplatePlugin {
) )
.join(", "); .join(", ");
if (this.name) { if (this.requireAsWrapper) {
return new ConcatSource(
`require(${externalsDepsArray}, function(${externalsArguments}) { return `,
source,
"});"
);
} else if (this.name) {
const name = mainTemplate.getAssetPath(this.name, { const name = mainTemplate.getAssetPath(this.name, {
hash, hash,
chunk chunk

View File

@ -94,6 +94,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
* @typedef {Object} AvailableModulesChunkGroupMapping * @typedef {Object} AvailableModulesChunkGroupMapping
* @property {ChunkGroup} chunkGroup * @property {ChunkGroup} chunkGroup
* @property {Set<Module>} availableModules * @property {Set<Module>} availableModules
* @property {boolean} needCopy
*/ */
/** /**
@ -1344,7 +1345,7 @@ class Compilation {
const moduleGraph = this.moduleGraph; const moduleGraph = this.moduleGraph;
/** @typedef {{block: AsyncDependenciesBlock, chunkGroup: ChunkGroup}} ChunkGroupDep */ /** @typedef {{block: AsyncDependenciesBlock, chunkGroup: ChunkGroup, couldBeFiltered: boolean}} ChunkGroupDep */
/** @type {Map<ChunkGroup, ChunkGroupDep[]>} */ /** @type {Map<ChunkGroup, ChunkGroupDep[]>} */
const chunkDependencies = new Map(); const chunkDependencies = new Map();
@ -1530,7 +1531,8 @@ class Compilation {
if (!deps) chunkDependencies.set(chunkGroup, (deps = [])); if (!deps) chunkDependencies.set(chunkGroup, (deps = []));
deps.push({ deps.push({
block: b, block: b,
chunkGroup: c chunkGroup: c,
couldBeFiltered: true
}); });
// 3. We enqueue the DependenciesBlock for traversal // 3. We enqueue the DependenciesBlock for traversal
@ -1652,12 +1654,14 @@ class Compilation {
// PART TWO // PART TWO
/** @type {Set<Module>} */ /** @type {Set<Module>} */
let availableModules; let availableModules;
/** @type {Set<Module>} */
let newAvailableModules; let newAvailableModules;
/** @type {Queue<AvailableModulesChunkGroupMapping>} */ /** @type {Queue<AvailableModulesChunkGroupMapping>} */
const queue2 = new Queue( const queue2 = new Queue(
inputChunkGroups.map(chunkGroup => ({ inputChunkGroups.map(chunkGroup => ({
chunkGroup, chunkGroup,
availableModules: new Set() availableModules: new Set(),
needCopy: true
})) }))
); );
@ -1685,8 +1689,12 @@ class Compilation {
*/ */
const filterFn = dep => { const filterFn = dep => {
const depChunkGroup = dep.chunkGroup; const depChunkGroup = dep.chunkGroup;
if (!dep.couldBeFiltered) return true;
if (blocksWithNestedBlocks.has(dep.block)) return true; if (blocksWithNestedBlocks.has(dep.block)) return true;
if (areModulesAvailable(depChunkGroup, newAvailableModules)) return false; // break all modules are already available if (areModulesAvailable(depChunkGroup, newAvailableModules)) {
return false; // break all modules are already available
}
dep.couldBeFiltered = false;
return true; return true;
}; };
@ -1705,7 +1713,10 @@ class Compilation {
// the list didn't shrink. // the list didn't shrink.
let minAvailableModules = minAvailableModulesMap.get(chunkGroup); let minAvailableModules = minAvailableModulesMap.get(chunkGroup);
if (minAvailableModules === undefined) { if (minAvailableModules === undefined) {
minAvailableModulesMap.set(chunkGroup, new Set(availableModules)); minAvailableModulesMap.set(
chunkGroup,
queueItem.needCopy ? new Set(availableModules) : availableModules
);
} else { } else {
let deletedModules = false; let deletedModules = false;
for (const m of minAvailableModules) { for (const m of minAvailableModules) {
@ -1731,30 +1742,33 @@ class Compilation {
} }
} }
// 4. Filter edges with available modules // 4. Foreach remaining edge
const filteredDeps = deps.filter(filterFn);
// 5. Foreach remaining edge
const nextChunkGroups = new Set(); const nextChunkGroups = new Set();
for (let i = 0; i < filteredDeps.length; i++) { for (let i = 0; i < deps.length; i++) {
const dep = filteredDeps[i]; const dep = deps[i];
// Filter inline, rather than creating a new array from `.filter()`
if (!filterFn(dep)) {
continue;
}
const depChunkGroup = dep.chunkGroup; const depChunkGroup = dep.chunkGroup;
const depBlock = dep.block; const depBlock = dep.block;
// 6. Connect block with chunk // 5. Connect block with chunk
chunkGraph.connectBlockAndChunkGroup(depBlock, depChunkGroup); chunkGraph.connectBlockAndChunkGroup(depBlock, depChunkGroup);
// 7. Connect chunk with parent // 6. Connect chunk with parent
connectChunkGroupParentAndChild(chunkGroup, depChunkGroup); connectChunkGroupParentAndChild(chunkGroup, depChunkGroup);
nextChunkGroups.add(depChunkGroup); nextChunkGroups.add(depChunkGroup);
} }
// 8. Enqueue further traversal // 7. Enqueue further traversal
for (const nextChunkGroup of nextChunkGroups) { for (const nextChunkGroup of nextChunkGroups) {
queue2.enqueue({ queue2.enqueue({
chunkGroup: nextChunkGroup, chunkGroup: nextChunkGroup,
availableModules: newAvailableModules availableModules: newAvailableModules,
needCopy: nextChunkGroup.size !== 1
}); });
} }
} }

View File

@ -199,13 +199,14 @@ class ExternalModule extends Module {
return getSourceForGlobalVariableExternal(request, this.externalType); return getSourceForGlobalVariableExternal(request, this.externalType);
case "global": case "global":
return getSourceForGlobalVariableExternal( return getSourceForGlobalVariableExternal(
runtimeTemplate.outputOptions.globalObject, request,
this.externalType runtimeTemplate.outputOptions.globalObject
); );
case "commonjs": case "commonjs":
case "commonjs2": case "commonjs2":
return getSourceForCommonJsExternal(request); return getSourceForCommonJsExternal(request);
case "amd": case "amd":
case "amd-require":
case "umd": case "umd":
case "umd2": case "umd2":
return getSourceForAmdOrUmdExternal( return getSourceForAmdOrUmdExternal(

View File

@ -27,7 +27,9 @@ const accessorToObjectAccess = accessor => {
*/ */
const accessorAccess = (base, accessor, umdProperty, joinWith = "; ") => { const accessorAccess = (base, accessor, umdProperty, joinWith = "; ") => {
const normalizedAccessor = const normalizedAccessor =
typeof accessor === "object" ? accessor[umdProperty] : accessor; typeof accessor === "object" && !Array.isArray(accessor)
? accessor[umdProperty]
: accessor;
const accessors = Array.isArray(normalizedAccessor) const accessors = Array.isArray(normalizedAccessor)
? normalizedAccessor ? normalizedAccessor
: [normalizedAccessor]; : [normalizedAccessor];
@ -139,15 +141,16 @@ class LibraryTemplatePlugin {
compilation compilation
); );
break; break;
case "amd": { case "amd":
case "amd-require": {
const AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin"); const AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin");
if (this.name) { if (this.name && typeof this.name !== "string") {
if (typeof this.name !== "string")
throw new Error("library name must be a string for amd target"); throw new Error("library name must be a string for amd target");
new AmdMainTemplatePlugin(this.name).apply(compilation);
} else {
new AmdMainTemplatePlugin().apply(compilation);
} }
new AmdMainTemplatePlugin({
name: this.name,
requireAsWrapper: this.target === "amd-require"
}).apply(compilation);
break; break;
} }
case "umd": case "umd":

View File

@ -249,7 +249,7 @@ module.exports = class MainTemplate {
this.hooks.requireExtensions.tap( this.hooks.requireExtensions.tap(
"MainTemplate", "MainTemplate",
(source, renderContext) => { (source, renderContext) => {
const { chunk, hash } = renderContext; const { chunk, hash, chunkGraph } = renderContext;
const buf = []; const buf = [];
const chunkMaps = chunk.getChunkMaps(); const chunkMaps = chunk.getChunkMaps();
// Check if there are non initial chunks which need to be imported using require-ensure // Check if there are non initial chunks which need to be imported using require-ensure
@ -265,6 +265,22 @@ module.exports = class MainTemplate {
); );
buf.push(Template.indent("return Promise.all(promises);")); buf.push(Template.indent("return Promise.all(promises);"));
buf.push("};"); buf.push("};");
} else if (
chunkGraph.hasModuleInGraph(chunk, m =>
m.blocks.some(b => {
const chunkGroup = chunkGraph.getBlockChunkGroup(b);
return chunkGroup && chunkGroup.chunks.length > 0;
})
)
) {
// There async blocks in the graph, so we need to add an empty requireEnsure
// function anyway. This can happen with multiple entrypoints.
buf.push("// The chunk loading function for additional chunks");
buf.push("// Since all referenced chunks are already included");
buf.push("// in this file, this function is empty here.");
buf.push(`${this.requireFn}.e = function requireEnsure() {`);
buf.push(Template.indent("return Promise.resolve();"));
buf.push("};");
} }
buf.push(""); buf.push("");
buf.push("// expose the modules object (__webpack_modules__)"); buf.push("// expose the modules object (__webpack_modules__)");

View File

@ -20,7 +20,7 @@ module.exports = function() {
var script = document.createElement("script"); var script = document.createElement("script");
script.charset = "utf-8"; script.charset = "utf-8";
script.src = $require$.p + $hotChunkFilename$; script.src = $require$.p + $hotChunkFilename$;
$crossOriginLoading$; if ($crossOriginLoading$) script.crossOrigin = $crossOriginLoading$;
head.appendChild(script); head.appendChild(script);
} }

View File

@ -585,9 +585,7 @@ class JsonpMainTemplatePlugin {
.replace(/\$require\$/g, mainTemplate.requireFn) .replace(/\$require\$/g, mainTemplate.requireFn)
.replace( .replace(
/\$crossOriginLoading\$/g, /\$crossOriginLoading\$/g,
crossOriginLoading crossOriginLoading ? JSON.stringify(crossOriginLoading) : "null"
? `script.crossOrigin = ${JSON.stringify(crossOriginLoading)}`
: ""
) )
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename) .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename)

View File

@ -53,7 +53,6 @@
"husky": "^1.0.0-rc.6", "husky": "^1.0.0-rc.6",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"jest": "^23.4.1", "jest": "^23.4.1",
"jest-silent-reporter": "^0.0.5",
"json-loader": "^0.5.7", "json-loader": "^0.5.7",
"json-schema-to-typescript": "^6.0.1", "json-schema-to-typescript": "^6.0.1",
"less": "^2.5.1", "less": "^2.5.1",

View File

@ -963,6 +963,7 @@
"commonjs2", "commonjs2",
"commonjs-module", "commonjs-module",
"amd", "amd",
"amd-require",
"umd", "umd",
"umd2", "umd2",
"jsonp" "jsonp"

View File

@ -35,7 +35,7 @@ module.exports = ajv =>
data, data,
`The provided value ${JSON.stringify( `The provided value ${JSON.stringify(
data data
)} contans exclamation mark (!) which is not allowed because it's reserved for loader syntax.` )} contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.`
) )
]; ];
passes = false; passes = false;

View File

@ -88,6 +88,7 @@
"commonjs2", "commonjs2",
"commonjs-module", "commonjs-module",
"amd", "amd",
"amd-require",
"umd", "umd",
"umd2", "umd2",
"jsonp" "jsonp"

View File

@ -239,7 +239,7 @@ describe("Validation", () => {
} }
}, },
message: [ message: [
' - configuration.output.path: The provided value "/somepath/!test" contans exclamation mark (!) which is not allowed because it\'s reserved for loader syntax.', ' - configuration.output.path: The provided value "/somepath/!test" contains exclamation mark (!) which is not allowed because it\'s reserved for loader syntax.',
" -> The output directory as **absolute path** (required)." " -> The output directory as **absolute path** (required)."
] ]
}, },

View File

@ -1163,13 +1163,13 @@ Child
`; `;
exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = ` exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = `
"Hash: 05e860caf71fe3b2d19aee833b1335bf5cefe6d3074451f01c7cf41c58065d34f2c917d77c3f99ff "Hash: 4c55553bd94205710a5fee833b1335bf5cefe6d3074451f01c7cf41c58065d34f2c917d77c3f99ff
Child 1 chunks: Child 1 chunks:
Hash: 05e860caf71fe3b2d19a Hash: 4c55553bd94205710a5f
Time: Xms Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT Built at: Thu Jan 01 1970 00:00:00 GMT
Asset Size Chunks Chunk Names Asset Size Chunks Chunk Names
bundle.js 6.39 KiB 0 [emitted] main bundle.js 6.67 KiB 0 [emitted] main
Entrypoint main = bundle.js Entrypoint main = bundle.js
chunk {0} bundle.js (main) 191 bytes <{0}> >{0}< [entry] [rendered] chunk {0} bundle.js (main) 191 bytes <{0}> >{0}< [entry] [rendered]
[0] ./index.js 73 bytes {0} [built] [0] ./index.js 73 bytes {0} [built]

View File

@ -0,0 +1,8 @@
import run from "./c";
import "./d";
it("should not crash", () => {
return run().then(result => {
expect(result.default).toBe("ok");
});
})

View File

@ -0,0 +1,3 @@
import run from "./c";
run();

View File

@ -0,0 +1,3 @@
export default function run() {
return import("./d");
}

View File

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

View File

@ -0,0 +1,9 @@
module.exports = {
entry: {
bundle0: "./a",
other: "./b"
},
output: {
filename: "[name].js"
}
};

View File

@ -0,0 +1,11 @@
afterEach(done => {
delete global.EXTERNAL_TEST_GLOBAL;
done();
});
it("should move externals in chunks into entry chunk", function() {
global.EXTERNAL_TEST_GLOBAL = 42;
// eslint-disable-next-line node/no-missing-require
const result = require("external");
expect(result).toBe(42);
});

View File

@ -0,0 +1,5 @@
module.exports = {
externals: {
external: "global EXTERNAL_TEST_GLOBAL"
}
};

View File

@ -0,0 +1,3 @@
it("should define global object with property", function() {
expect(a["b"]).toBeDefined();
});

View File

@ -0,0 +1,5 @@
module.exports = {
output: {
library: ["a", "b"]
}
};

View File

@ -0,0 +1,3 @@
it("should define property in 'window' object", function() {
expect(window["a"]["b"]).toBeDefined();
});

View File

@ -0,0 +1,7 @@
module.exports = {
target: "web",
output: {
library: ["a", "b"],
libraryTarget: "window"
}
};

View File

@ -0,0 +1,10 @@
it("should run", function() {
});
it("should name require", function() {
var fs = nodeRequire("fs");
var source = fs.readFileSync(__filename, "utf-8");
expect(source).toMatch(/require\(\[[^\]]*\], function\(/);
});

View File

@ -0,0 +1,17 @@
const webpack = require("../../../../");
module.exports = {
output: {
libraryTarget: "amd-require"
},
node: {
__dirname: false,
__filename: false
},
plugins: [
new webpack.BannerPlugin({
raw: true,
banner:
"var nodeRequire = require;\nvar require = function(deps, fn) { fn(); }\n"
})
]
};

View File

@ -6,5 +6,5 @@ it("should name define", function() {
var fs = require("fs"); var fs = require("fs");
var source = fs.readFileSync(__filename, "utf-8"); var source = fs.readFileSync(__filename, "utf-8");
expect(source).toMatch("define(function("); expect(source).toMatch(/define\(\[[^\]]*\], function\(/);
}); });

View File

@ -3842,17 +3842,6 @@ jest-matcher-utils@^23.2.0:
jest-get-type "^22.1.0" jest-get-type "^22.1.0"
pretty-format "^23.2.0" pretty-format "^23.2.0"
jest-message-util@^23.0.0:
version "23.3.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.3.0.tgz#bc07b11cec6971fb5dd9de2dfb60ebc22150c160"
integrity sha1-vAexHOxpcftd2d4t+2DrwiFQwWA=
dependencies:
"@babel/code-frame" "^7.0.0-beta.35"
chalk "^2.0.1"
micromatch "^3.1.10"
slash "^1.0.0"
stack-utils "^1.0.1"
jest-message-util@^23.4.0: jest-message-util@^23.4.0:
version "23.4.0" version "23.4.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f"
@ -3942,14 +3931,6 @@ jest-serializer@^23.0.1:
resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165"
integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=
jest-silent-reporter@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/jest-silent-reporter/-/jest-silent-reporter-0.0.5.tgz#14139b7a991b7bcca880dd8a69c33a91723a8f1f"
integrity sha512-LWNEJEeI9jbqOaNyqmnLWyEJXaNlDMCDqX6NbY89pzgerb3iExky56zD5oBvh+nvgzEND9cjL57EhifaAJBhjw==
dependencies:
chalk "^2.3.1"
jest-util "^23.0.0"
jest-snapshot@^23.4.1: jest-snapshot@^23.4.1:
version "23.4.1" version "23.4.1"
resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.4.1.tgz#090de9acae927f6a3af3005bda40d912b83e9c96" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.4.1.tgz#090de9acae927f6a3af3005bda40d912b83e9c96"
@ -3967,19 +3948,6 @@ jest-snapshot@^23.4.1:
pretty-format "^23.2.0" pretty-format "^23.2.0"
semver "^5.5.0" semver "^5.5.0"
jest-util@^23.0.0:
version "23.0.1"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.0.1.tgz#68ea5bd7edb177d3059f9797259f8e0dacce2f99"
integrity sha1-aOpb1+2xd9MFn5eXJZ+ODazOL5k=
dependencies:
callsites "^2.0.0"
chalk "^2.0.1"
graceful-fs "^4.1.11"
is-ci "^1.0.10"
jest-message-util "^23.0.0"
mkdirp "^0.5.1"
source-map "^0.6.0"
jest-util@^23.4.0: jest-util@^23.4.0:
version "23.4.0" version "23.4.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561"
@ -4652,7 +4620,7 @@ micromatch@^2.3.11:
parse-glob "^3.0.4" parse-glob "^3.0.4"
regex-cache "^0.4.2" regex-cache "^0.4.2"
micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: micromatch@^3.1.4, micromatch@^3.1.8:
version "3.1.10" version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==