Skip to content

Commit 2201b86

Browse files
committed
Add mode option and choose defaults depending on mode
add optimization options use development mode for watch/hot/config tests use production mode for integration/stats tests create output directory if not existing move __esModule to runtime fix dependency behavior for cases without usedExports
1 parent d249016 commit 2201b86

File tree

160 files changed

+1188
-776
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

160 files changed

+1188
-776
lines changed

bin/config-yargs.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ module.exports = function(yargs) {
3030
describe: "Environment passed to the config, when it is a function",
3131
group: CONFIG_GROUP
3232
},
33+
"mode": {
34+
type: "string",
35+
describe: "Mode to use (production or development)",
36+
group: CONFIG_GROUP,
37+
requiresArg: true
38+
},
3339
"context": {
3440
type: "string",
3541
describe: "The root directory for resolving entry point and stats",

bin/convert-argv.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ module.exports = function(yargs, argv, convertOptions) {
1515
if(!argv.devtool) {
1616
argv.devtool = "eval-cheap-module-source-map";
1717
}
18+
if(!argv.mode) {
19+
argv.mode = "development";
20+
}
1821
}
1922
if(argv.p) {
2023
argv["optimize-minimize"] = true;
2124
argv["define"] = [].concat(argv["define"] || []).concat("process.env.NODE_ENV=\"production\"");
25+
if(!argv.mode) {
26+
argv.mode = "production";
27+
}
2228
}
2329

2430
var configFileLoaded = false;
@@ -288,6 +294,10 @@ module.exports = function(yargs, argv, convertOptions) {
288294
options.plugins.unshift(plugin);
289295
}
290296

297+
ifArg("mode", function(value) {
298+
options.mode = value;
299+
});
300+
291301
ifArgPair("entry", function(name, entry) {
292302
if(typeof options.entry[name] !== "undefined" && options.entry[name] !== null) {
293303
options.entry[name] = [].concat(options.entry[name]).concat(entry);

lib/MainTemplate.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const Template = require("./Template");
1818
// __webpack_require__.e = the chunk ensure function
1919
// __webpack_require__.d = the exported propery define getter function
2020
// __webpack_require__.o = Object.prototype.hasOwnProperty.call
21+
// __webpack_require__.r = define compatibility on export
2122
// __webpack_require__.n = compatibility get default export
2223
// __webpack_require__.h = the webpack hash
2324
// __webpack_require__.w = an object containing all installed WebAssembly.Modules keys by module id
@@ -135,6 +136,14 @@ module.exports = class MainTemplate extends Template {
135136
]));
136137
buf.push("};");
137138

139+
buf.push("");
140+
buf.push("// define __esModule on exports");
141+
buf.push(`${this.requireFn}.r = function(exports) {`);
142+
buf.push(this.indent([
143+
"Object.defineProperty(exports, '__esModule', { value: true });"
144+
]));
145+
buf.push("};");
146+
138147
buf.push("");
139148
buf.push("// getDefaultExport function for compatibility with non-harmony modules");
140149
buf.push(this.requireFn + ".n = function(module) {");

lib/Module.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ class Module extends DependenciesBlock {
214214
}
215215

216216
isUsed(exportName) {
217-
if(this.used === null) return exportName;
218-
if(!exportName) return !!this.used;
217+
if(!exportName) return this.used !== false;
218+
if(this.used === null || this.usedExports === null) return exportName;
219219
if(!this.used) return false;
220220
if(!this.usedExports) return false;
221221
if(this.usedExports === true) return exportName;

lib/NoModeWarning.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
"use strict";
6+
7+
const WebpackError = require("./WebpackError");
8+
9+
module.exports = class NoModeWarning extends WebpackError {
10+
constructor(modules) {
11+
super();
12+
13+
this.name = "NoModeWarning";
14+
this.message = "configuration\n" +
15+
"The 'mode' option has not been set. " +
16+
"Set 'mode' option to 'development' or 'production' to enable defaults for this enviroment. ";
17+
18+
Error.captureStackTrace(this, this.constructor);
19+
}
20+
};

lib/WarnNoModeSetPlugin.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
"use strict";
6+
7+
const NoModeWarning = require("./NoModeWarning");
8+
9+
class WarnNoModeSetPlugin {
10+
apply(compiler) {
11+
compiler.plugin("this-compilation", compilation => {
12+
compilation.warnings.push(new NoModeWarning());
13+
});
14+
}
15+
}
16+
17+
module.exports = WarnNoModeSetPlugin;

lib/WebpackOptionsApply.js

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const RequireContextPlugin = require("./dependencies/RequireContextPlugin");
3939
const RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
4040
const RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");
4141

42+
const WarnNoModeSetPlugin = require("./WarnNoModeSetPlugin");
43+
4244
const EnsureChunkConditionsPlugin = require("./optimize/EnsureChunkConditionsPlugin");
4345
const RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
4446
const RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
@@ -48,6 +50,11 @@ const OccurrenceOrderPlugin = require("./optimize/OccurrenceOrderPlugin");
4850
const SideEffectsFlagPlugin = require("./optimize/SideEffectsFlagPlugin");
4951
const FlagDependencyUsagePlugin = require("./FlagDependencyUsagePlugin");
5052
const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin");
53+
const ModuleConcatenationPlugin = require("./optimize/ModuleConcatenationPlugin");
54+
const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");
55+
const NamedModulesPlugin = require("./NamedModulesPlugin");
56+
const NamedChunksPlugin = require("./NamedChunksPlugin");
57+
const DefinePlugin = require("./DefinePlugin");
5158
const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
5259

5360
class WebpackOptionsApply extends OptionsApply {
@@ -274,17 +281,39 @@ class WebpackOptionsApply extends OptionsApply {
274281
new SystemPlugin(options.module)
275282
);
276283

277-
compiler.apply(
278-
new EnsureChunkConditionsPlugin(),
279-
new RemoveParentModulesPlugin(),
280-
new RemoveEmptyChunksPlugin(),
281-
new MergeDuplicateChunksPlugin(),
282-
new FlagIncludedChunksPlugin(),
283-
new OccurrenceOrderPlugin(true),
284-
new SideEffectsFlagPlugin(),
285-
new FlagDependencyExportsPlugin(),
286-
new FlagDependencyUsagePlugin()
287-
);
284+
if(typeof options.mode !== "string")
285+
compiler.apply(new WarnNoModeSetPlugin());
286+
287+
compiler.apply(new EnsureChunkConditionsPlugin());
288+
if(options.optimization.removeAvailableModules)
289+
compiler.apply(new RemoveParentModulesPlugin());
290+
if(options.optimization.removeEmptyChunks)
291+
compiler.apply(new RemoveEmptyChunksPlugin());
292+
if(options.optimization.mergedDuplicateChunks)
293+
compiler.apply(new MergeDuplicateChunksPlugin());
294+
if(options.optimization.flagIncludedChunks)
295+
compiler.apply(new FlagIncludedChunksPlugin());
296+
if(options.optimization.occurrenceOrder)
297+
compiler.apply(new OccurrenceOrderPlugin(true));
298+
if(options.optimization.sideEffects)
299+
compiler.apply(new SideEffectsFlagPlugin());
300+
if(options.optimization.providedExports)
301+
compiler.apply(new FlagDependencyExportsPlugin());
302+
if(options.optimization.usedExports)
303+
compiler.apply(new FlagDependencyUsagePlugin());
304+
if(options.optimization.concatenateModules)
305+
compiler.apply(new ModuleConcatenationPlugin());
306+
if(options.optimization.noEmitOnErrors)
307+
compiler.apply(new NoEmitOnErrorsPlugin());
308+
if(options.optimization.namedModules)
309+
compiler.apply(new NamedModulesPlugin());
310+
if(options.optimization.namedChunks)
311+
compiler.apply(new NamedChunksPlugin());
312+
if(options.optimization.nodeEnv) {
313+
compiler.apply(new DefinePlugin({
314+
"process.env.NODE_ENV": JSON.stringify(options.optimization.nodeEnv)
315+
}));
316+
}
288317

289318
if(options.performance) {
290319
compiler.apply(new SizeLimitsPlugin(options.performance));

lib/WebpackOptionsDefaulter.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const Template = require("./Template");
1010
class WebpackOptionsDefaulter extends OptionsDefaulter {
1111
constructor() {
1212
super();
13-
this.set("devtool", false);
14-
this.set("cache", true);
13+
this.set("devtool", "make", options => options.mode === "development" ? "eval" : false);
14+
this.set("cache", "make", options => options.mode === "development");
1515

1616
this.set("context", process.cwd());
1717
this.set("target", "web");
@@ -30,7 +30,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
3030
this.set("module.wrappedContextCritical", false);
3131
this.set("module.strictExportPresence", false);
3232
this.set("module.strictThisContextOnImports", false);
33-
this.set("module.unsafeCache", true);
33+
this.set("module.unsafeCache", "make", options => !!options.cache);
3434
this.set("module.rules", []);
3535
this.set("module.defaultRules", [{
3636
type: "javascript/auto",
@@ -64,21 +64,29 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
6464
this.set("output.filename", "[name].js");
6565
this.set("output.chunkFilename", "make", (options) => {
6666
const filename = options.output.filename;
67-
return filename.indexOf("[name]") >= 0 ? filename.replace("[name]", "[id]") : "[id]." + filename;
67+
const hasName = filename.indexOf("[name]") >= 0;
68+
const hasChunkHash = filename.indexOf("[chunkhash]") >= 0;
69+
// Anything with [chunkhash] is already fine
70+
if(hasChunkHash) return filename;
71+
// Replace [name] with [id] because it doesn't require a name map
72+
if(hasName) return filename.replace("[name]", "[id]");
73+
// Prefix "[id]." in front of the basename
74+
return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
6875
});
6976
this.set("output.webassemblyModuleFilename", "[modulehash].module.wasm");
7077
this.set("output.library", "");
7178
this.set("output.hotUpdateFunction", "make", (options) => {
7279
return Template.toIdentifier("webpackHotUpdate" + options.output.library);
7380
});
7481
this.set("output.jsonpFunction", "make", (options) => {
75-
return Template.toIdentifier("webpackJsonp" + options.output.library);
82+
return Template.toIdentifier("webpackJsonp" + Template.toIdentifier(options.output.library));
7683
});
7784
this.set("output.devtoolNamespace", "make", (options) => {
7885
return options.output.library || "";
7986
});
8087
this.set("output.libraryTarget", "var");
8188
this.set("output.path", process.cwd());
89+
this.set("output.pathinfo", "make", options => options.mode === "development");
8290
this.set("output.sourceMapFilename", "[file].map[query]");
8391
this.set("output.hotUpdateChunkFilename", "[id].[hash].hot-update.js");
8492
this.set("output.hotUpdateMainFilename", "[hash].hot-update.json");
@@ -114,7 +122,21 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
114122
});
115123
this.set("performance.maxAssetSize", 250000);
116124
this.set("performance.maxEntrypointSize", 250000);
117-
this.set("performance.hints", false);
125+
this.set("performance.hints", "make", options => options.mode === "production" ? "warning" : false);
126+
127+
this.set("optimization.removeAvailableModules", true);
128+
this.set("optimization.removeEmptyChunks", true);
129+
this.set("optimization.mergedDuplicateChunks", true);
130+
this.set("optimization.flagIncludedChunks", "make", options => options.mode === "production");
131+
this.set("optimization.occurrenceOrder", "make", options => options.mode === "production");
132+
this.set("optimization.sideEffects", "make", options => options.mode === "production");
133+
this.set("optimization.providedExports", true);
134+
this.set("optimization.usedExports", "make", options => options.mode === "production");
135+
this.set("optimization.concatenateModules", "make", options => options.mode === "production");
136+
this.set("optimization.noEmitOnErrors", "make", options => options.mode === "production");
137+
this.set("optimization.namedModules", "make", options => options.mode === "development");
138+
this.set("optimization.namedChunks", "make", options => options.mode === "development");
139+
this.set("optimization.nodeEnv", "make", options => options.mode);
118140

119141
this.set("resolve", "call", value => Object.assign({}, value));
120142
this.set("resolve.unsafeCache", true);

lib/dependencies/HarmonyCompatibilityDependency.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ class HarmonyCompatibilityDependency extends NullDependency {
1919
HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate {
2020
apply(dep, source) {
2121
const usedExports = dep.originModule.usedExports;
22-
if(usedExports && !Array.isArray(usedExports)) {
22+
if(usedExports !== false && !Array.isArray(usedExports)) {
2323
const exportName = dep.originModule.exportsArgument;
24-
const content = `Object.defineProperty(${exportName}, "__esModule", { value: true });\n`;
24+
const content = `__webpack_require__.r(${exportName});\n`;
2525
source.insert(-10, content);
2626
}
2727
}

lib/dependencies/HarmonyExportImportedSpecifierDependency.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,10 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
345345
}
346346

347347
getHarmonyInitOrder(dep) {
348-
const used = dep.originModule.isUsed(dep.name);
349-
if(!used) return NaN;
350-
if(!dep.name) {
348+
if(dep.name) {
349+
const used = dep.originModule.isUsed(dep.name);
350+
if(!used) return NaN;
351+
} else {
351352
const importedModule = dep.module;
352353

353354
const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
@@ -422,7 +423,7 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
422423

423424
case "dynamic-reexport":
424425
{
425-
const activeExports = Array.from(dep.activeExports).concat(dep._discoverActiveExportsFromOtherStartExports());
426+
const activeExports = new Set([...dep.activeExports, ...dep._discoverActiveExportsFromOtherStartExports()]);
426427
let content = "/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " + importVar + ") ";
427428

428429
// Filter out exports which are defined by other exports

0 commit comments

Comments
 (0)