resolve.root
,resolve.fallback
,resolve.modulesDirectories
These configuration items have all been replaced by a single configuration: resolve.modules
. See resolving for more details.
resolve: {
- root: path.join(__dirname, "src")
+ modules: [
+ path.join(__dirname, "src"),
+ "node_modules"
+ ]
}
resolve.extensions
This option no longer requires an empty string. Its behavior has been moved to resolve.enforceExtension
. See resolving for more details.
resolve.*
Many changes have been made here. Since they are not widely used, they will not be listed individually. See resolving for more details.
module.loaders
is now module.rules
The old loader configuration has been replaced by a more powerful rules system, which allows configuring loaders and more. For consistency, the old module.loaders
syntax is still valid and usable. The new naming convention is easier to understand, making it a good reason to upgrade your configuration using module.rules
.
module: {
- loaders: [
+ rules: [
{
test: /\.css$/,
- loaders: [
+ use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
- query: {
+ options: {
modules: true
}
]
},
{
test: /\.jsx$/,
loader: "babel-loader", // Do not use "use" here
options: {
// ...
}
}
]
}
Chaining loaders
Just like in webpack 1, loaders can be chained, passing the result of one loader to the next. Using rule.use, use
can be set to a list of loaders. In webpack 1, loaders were chained together using !
. This style is now only supported within module.loaders
.
module: {
- loaders: {
+ rules: {
test: /\.less$/,
- loader: "style-loader!css-loader!less-loader"
+ use: [
+ "style-loader",
+ "css-loader",
+ "less-loader"
+ ]
}
}
The feature of automatically adding the -loader
suffix has been removed
The -loader
suffix can no longer be omitted when importing loaders.
module: {
rules: [
{
use: [
-"style",
+"style-loader",
-"css",
+"css-loader",
-"less",
+"less-loader",
],
},
];
}
However, you can still achieve the previous behavior using the resolveLoader.moduleExtensions
configuration, but we do not recommend it.
+ resolveLoader: {
+ moduleExtensions: ["-loader"]
+ }
json-loader
is no longer needed
When no corresponding loader is configured for JSON files, webpack will automatically use json-loader
to load them.
module: {
rules: [
- {
- test: /\.json/,
- loader: "json-loader"
- }
]
}
Webpack chose to do this to smooth out the differences between webpack, Node.js, and Browserify environments.
Loaders in configuration resolve relative to context
In webpack 1, configured loaders resolved relative to the matched file. However, in webpack 2, configured loaders resolve based on the context
setting.
This resolves issues of duplicate module imports caused by using npm link
or referencing modules outside the context
.
You might have solved this problem with a hack like this:
module: {
rules: [
{
// ...
- loader: require.resolve("my-loader")
+ loader: "my-loader"
}
]
},
resolveLoader: {
- root: path.resolve(__dirname, "node_modules")
}
module.preLoaders
and module.postLoaders
have been removed.
module: {
- preLoaders: [
+ rules: [
{
test: /\.js$/,
+ enforce: "pre",
loader: "eslint-loader"
}
]
}
UglifyJsPlugin
sourceMap
The default sourceMap
option in UglifyJsPlugin
has changed from true
to false
. This means if you need source map functionality in your minified code, you must manually configure sourceMap: true
.
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ sourceMap: true
})
]
UglifyJsPlugin
warnings
Similar to the previous point, the default compress.warnings
option in UglifyJsPlugin
has changed from true
to false
. If you need to see UglifyJS warnings, you must set compress.warnings
to true
.
devtool: "source-map",
plugins: [
new UglifyJsPlugin({
+ compress: {
+ warnings: true
+ }
})
]
UglifyJsPlugin
minimize loaders
UglifyJsPlugin
no longer switches loaders in minimize mode. minimize: true
must now always be set in the configuration passed to the loader. See the documentation for more details.
In webpack 3 or later versions, the loader minimization mode feature will be removed.
BannerPlugin
- breaking change
BannerPlugin
no longer supports passing two arguments; instead, it expects a single object.
plugins: [
- new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+ new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
]
OccurrenceOrderPlugin
is now a default setting
No longer needs to be configured manually.
plugins: [
- new webpack.optimize.OccurrenceOrderPlugin()
]
ExtractTextWebpackPlugin
- breaking change
ExtractTextWebpackPlugin 1.0.0
does not work correctly in webpack 2; you need to install ExtractTextPlugin V2
.
npm install --save-dev extract-text-webpack-plugin@beta
The configuration differences are mainly syntactic.
ExtractTextPlugin.extract
module: {
rules: [
test: /.css$/,
- loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" })
+ loader: ExtractTextPlugin.extract({
+ fallbackLoader: "style-loader",
+ loader: "css-loader",
+ publicPath: "/dist"
+ })
]
}
new ExtractTextPlugin({options})
plugins: [
- new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
+ new ExtractTextPlugin({
+ filename: "bundle.css",
+ disable: false,
+ allChunks: true
+ })
]
Full dynamic requires now fail by default
A dependency determined by an expression will now create an empty context instead of the previous context that included the entire folder.
It’s best to refactor this code, as it won’t work with ES2015 modules. If that’s not possible for you, you can use ContextReplacementPlugin
to specify the correct path for the compiler.
Using custom parameters in CLI and configuration files
If you’ve been misusing CLI arguments to pass custom parameters into your configuration, like this:
webapck --custom-stuff
// webpack.config.js
var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
/* ... */
module.exports = config;
You’ll find this is no longer allowed, as the CLI is now stricter than before.
Instead, there is now an interface for passing arguments to the configuration. Future tools will be based on this.
webpack --env.customStuff
module.exports = function (env) {
var customStuff = env.customStuff;
/* ... */
return config;
};
See CLI
require.ensure
and AMD require
are now asynchronous
These functions have become asynchronous, replacing the previous behavior where their callbacks would execute synchronously if the code block had already been loaded.
require.ensure
now relies on native Promise
. If you use require.ensure
in an environment that does not support Promise
, you will need a polyfill.
Loader configuration must use options
You can no longer configure loaders via a custom property in webpack.config.js
. It must be done through options
. The ts
property configuration below is no longer valid in webpack 2.
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader'
}]
},
// does not work with webpack 2
ts: { transpileOnly: false }
}
What are options
?
Good question. Strictly speaking, it can be two things; both are ways to configure a loader. A typical options
is called query
, which is a string that can be appended after the loader name. It’s more like a query string, but actually has greater powers.
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false })
}]
}
}
It can also be a specified object, provided alongside the loader:
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader'
options: { transpileOnly: false }
}]
}
}
LoaderOptionsPlugin
context
Some loaders need to read context information from the configuration file. This needs to be set in the loader’s options for the long term.
For compatibility with older loaders, you can pass it to the loader via this plugin:
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ options: {
+ context: __dirname
+ }
+ })
]
debug
In webpack 1, the debug
option was used to switch loaders into debug mode.
In webpack 3 or later versions, this mode will be removed.
For compatibility with older loaders, you can pass arguments to the loader via this plugin:
- debug: true,
plugins: [
+ new webpack.LoaderOptionsPlugin({
+ debug: true
+ })
]
ES2015 Code Splitting
In webpack 1, you could lazy-load code chunks using require.ensure
:
require.ensure([], function (require) {
var foo = require("./module");
});
In ES2015, we use import()
as a method to dynamically load ES2015 modules at runtime.
Webpack treats import()
as a split point and separates the loaded code into a distinct chunk.
import()
takes a module name as an argument and returns a Promise object.
function onClick() {
import("./module")
.then((module) => {
return module.default;
})
.catch((err) => {
console.log("Chunk loading failed");
});
}
Good news: chunk loading failures can now be handled because they are Promise-based.
Caveat: require.ensure
allows conveniently specifying a chunk name via its third argument, but the import
API does not yet support this feature. If you still rely on this functionality, you can continue to use require.ensure
.
require.ensure(
[],
function (require) {
var foo = require("./module");
},
"custom-chunk-name",
);
If you want to use import
with Babel, you need to install the dynamic-import syntax plugin, which is still in Stage 3, to bypass parsing errors. Once this proposal is added to the standard, this will no longer be necessary.
Dynamic expressions
It’s very likely you’ll need to pass an expression to import()
. The handling pattern here is very similar to CommonJS.
import()
creates a separate chunk for each possible module.
function route(path, query) {
return import(`./routes/${path}/route`).then(
(route) => new route.Route(query),
);
}
// This creates a separate chunk for each possible route
Mixing ES2015, AMD, and CommonJS
If it’s AMD and CommonJS, they can be freely mixed. In this case, Webpack’s behavior is similar to Babel or node-eps.
// CommonJS consuming ES2015 Module
var book = require("./book");
book.currentPage;
book.readPage();
book.default === "This is a book";
// ES2015 Module consuming CommonJS
// module.exports map to default
import fs, { readFileSync } from "fs";
// named exports are read from returned object+
typeof fs.readFileSync === "function";
typeof readFileSync === "function";
It’s important to note that you need to tell Babel not to parse these module symbols so that webpack can use them. You can configure this in .babelrc
as follows:
babelrc
{
"presets": [
["es2015", { "modules": false }]
]
}
Tips
No changes are required, but these features are very convenient.
String Templates
Webpack now supports using string templates in expressions. This means you can use them in webpack constructs:
- require("./templates/" + name);
+ require(`./templates/${name}`);
Configuration Promise
Webpack now supports returning a Promise
from the configuration file. This means you can perform asynchronous operations within your configuration.
webpack.config.js
module.exports = function () {
return fetchLangs().then((lang) => ({
entry: "...",
// ...
plugins: [new DefinePlugin({ LANGUAGE: lang })],
}));
};
Advanced Loader Matching
Webpack now supports more ways for loaders to match files.
module: {
rules: [
{
resource: /filename/, // matches "/path/filename.js"
resourceQuery: /querystring/, // matches "/filename.js?querystring"
issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
},
];
}
More Command-Line Options
Some new command-line options have been added:
--define process.env.NODE_ENV="production"
, see DefinePlugin
.
--display-depth
shows the distance of each module from the entry point
--display-used-exports
shows which exports of a module are used
--display-max-modules
sets the maximum number of modules displayed in the output
-p
also sets process.env.NODE_ENV
to “production”
Loader Changes
Relevant only to loader authors.
Cacheable
Loaders are now cacheable by default. Loaders must opt-out by returning if they are not cacheable.
// Cacheable loader
module.exports = function(source) {
- this.cacheable();
return source;
}
// Not cacheable loader
module.exports = function(source) {
+ this.cacheable(false);
return source;
}
Complex Options
Webpack 1 only supported loaders with options that could be JSON.stringify
-ed. Webpack 2 supports all plugins receiving a JavaScript object as an argument.
Using complex options introduces a limitation. The options object needs an ident
so it can be referenced by other loaders.
Having an ident
on the options object means it can be referenced by other inline loaders.
require('some-loader??by-iden!resource')
{
test: /.../,
loader: "...",
options: {
ident: "by-ident",
magic: () => return Math.random()
}
}
This inline syntax should not be used frequently, but it can be used by loader-generated code. Example: style-loader
generates a module that require
s the remaining request (e.g., to expose CSS).
// style-loader generated code (simplified)
var addStyle = require("./add-style");
var css = require("-!css-loader?{"modules":true}!postcss-loader??postcss-ident");
addStyle(css);
So if you’re using complex options, inform your users about ident
.
This article was published on January 20, 2017 and last updated on January 20, 2017, 3181 days ago. The content may be outdated.