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"
| "commonjs-module"
| "amd"
| "amd-require"
| "umd"
| "umd2"
| "jsonp";

View File

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

View File

@ -11,13 +11,24 @@ const Template = require("./Template");
/** @typedef {import("./Compilation")} Compilation */
/**
* @typedef {Object} AmdMainTemplatePluginOptions
* @param {string=} name the library name
* @property {boolean=} requireAsWrapper
*/
class AmdMainTemplatePlugin {
/**
* @param {string=} name the library name
* @param {AmdMainTemplatePluginOptions} options the plugin options
*/
constructor(name) {
/** @type {string=} */
this.name = name;
constructor(options) {
if (!options || typeof options === "string") {
this.name = options;
this.requireAsWrapper = false;
} else {
this.name = options.name;
this.requireAsWrapper = options.requireAsWrapper;
}
}
/**
@ -50,7 +61,13 @@ class AmdMainTemplatePlugin {
)
.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, {
hash,
chunk

View File

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

View File

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

View File

@ -249,7 +249,7 @@ module.exports = class MainTemplate {
this.hooks.requireExtensions.tap(
"MainTemplate",
(source, renderContext) => {
const { chunk, hash } = renderContext;
const { chunk, hash, chunkGraph } = renderContext;
const buf = [];
const chunkMaps = chunk.getChunkMaps();
// 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("};");
} 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("// expose the modules object (__webpack_modules__)");

View File

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

View File

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@ module.exports = ajv =>
data,
`The provided value ${JSON.stringify(
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;

View File

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

View File

@ -239,7 +239,7 @@ describe("Validation", () => {
}
},
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)."
]
},

View File

@ -1163,13 +1163,13 @@ Child
`;
exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = `
"Hash: 05e860caf71fe3b2d19aee833b1335bf5cefe6d3074451f01c7cf41c58065d34f2c917d77c3f99ff
"Hash: 4c55553bd94205710a5fee833b1335bf5cefe6d3074451f01c7cf41c58065d34f2c917d77c3f99ff
Child 1 chunks:
Hash: 05e860caf71fe3b2d19a
Hash: 4c55553bd94205710a5f
Time: Xms
Built at: Thu Jan 01 1970 00:00:00 GMT
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
chunk {0} bundle.js (main) 191 bytes <{0}> >{0}< [entry] [rendered]
[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 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"
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:
version "23.4.0"
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"
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:
version "23.4.1"
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"
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:
version "23.4.0"
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"
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"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==