Repository: webpack/webpack
Pull request #6416 (2018-01-30 01:15:32)

feat: add helpful error messages for removed plugins
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**What kind of change does this PR introduce?**

Gives helpful error messages when accessing removed plugins from v3.

TODO:
- [x] Tests
- [x] ~~Include links to relevant documentation~~ Will create an issue on webpack.js.org repo to track this

**Did you add tests for your changes?**

Yes

**Summary**

The current behavior will produce an error like "TypeError: webpack.optimize.UglifyJsPlugin is not a constructor". This PR gives a more appropriate message to point the user in the right direction. 

See https://github.com/webpack/webpack/issues/6409#issuecomment-361338563

**Does this PR introduce a breaking change?**

<!-- If this PR introduces a breaking change, please describe the impact and a migration path for existing applications. -->

No



Patch:
diff --git a/lib/RemovedPluginError.js b/lib/RemovedPluginError.js
new file mode 100644
index 000000000..772464fb0
--- /dev/null
+++ b/lib/RemovedPluginError.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const WebpackError = require("./WebpackError");
+
+module.exports = class RemovedPluginError extends WebpackError {
+	constructor(message) {
+		super();
+
+		this.message = message;
+
+		Error.captureStackTrace(this, this.constructor);
+	}
+};
diff --git a/lib/webpack.js b/lib/webpack.js
index edeca329b..da5d53923 100644
--- a/lib/webpack.js
+++ b/lib/webpack.js
@@ -12,6 +12,7 @@ const WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter");
 const validateSchema = require("./validateSchema");
 const WebpackOptionsValidationError = require("./WebpackOptionsValidationError");
 const webpackOptionsSchema = require("../schemas/WebpackOptions.json");
+const RemovedPluginError = require("./RemovedPluginError");
 
 const webpack = (options, callback) => {
 	const webpackOptionsValidationErrors = validateSchema(webpackOptionsSchema, options);
@@ -132,3 +133,27 @@ exportPlugins(exports.node = {}, {
 exportPlugins(exports.debug = {}, {
 	"ProfilingPlugin": () => require("./debug/ProfilingPlugin"),
 });
+
+const defineMissingPluginError = (namespace, pluginName, errorMessage) => {
+	Reflect.defineProperty(namespace, pluginName, {
+		configurable: false,
+		enumerable: true,
+		get() {
+			throw new RemovedPluginError(errorMessage);
+		}
+	});
+};
+
+// TODO remove in webpack 5
+defineMissingPluginError(
+	exports.optimize,
+	"UglifyJsPlugin",
+	"webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead."
+);
+
+// TODO remove in webpack 5
+defineMissingPluginError(
+	exports.optimize,
+	"CommonsChunkPlugin",
+	"webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead."
+);


Test patch:
diff --git a/test/RemovedPlugins.unittest.js b/test/RemovedPlugins.unittest.js
new file mode 100644
index 000000000..e1dfcd7e0
--- /dev/null
+++ b/test/RemovedPlugins.unittest.js
@@ -0,0 +1,17 @@
+const webpack = require("../lib/webpack");
+const RemovedPluginError = require("../lib/RemovedPluginError");
+require("should");
+
+describe("removed plugin errors", () => {
+	it("should error when accessing removed plugins", () => {
+		(() => webpack.optimize.UglifyJsPlugin).should.throw(
+			RemovedPluginError,
+			/webpack\.optimize\.UglifyJsPlugin has been removed, please use config\.optimization\.minimize instead\./
+		);
+
+		(() => webpack.optimize.CommonsChunkPlugin).should.throw(
+			RemovedPluginError,
+			/webpack\.optimize\.CommonsChunkPlugin has been removed, please use config\.optimization\.splitChunks instead\./
+		);
+	});
+});