迁移版本 | Migrating Versions
Migrating Versions
以下部分描述了从webpack 1到2的主要更改。
webpack 从 1 到 2 的变化,比从 2 到 3 要少很多,所以版本迁移起来难度应该不大。如果你遇到了问题,请查看 更新日志 以了解更多细节。
resolve.root, resolve.fallback, resolve.modulesDirectories
这些选项被一个单独的选项 resolve.modules 取代。更多用法请查看解析。
resolve: {
- root: path.join(__dirname, "src")
+ modules: [
+ path.join(__dirname, "src"),
+ "node_modules"
+ ]
}
resolve.extensions
该选项不再需要传递空字符串。此行为已移至resolve.enforceExtension
。请参阅解决更多用法。
resolve.*
这里更改了几个API。没有详细列出,因为它不常用。详情请参阅解决方法。
module.loaders is now module.rules
旧的加载程序配置被更强大的规则系统取代,该系统允许配置加载程序等。出于兼容性的原因,旧的module.loaders
语法仍然有效,旧的名称将被解析。新的命名约定更容易理解,并且是将配置升级为使用的一个很好的理由module.rules
。
module: {
- loaders: [
+ rules: [
{
test: /\.css$/,
- loaders: [
- "style-loader",
- "css-loader?modules=true"
+ use: [
+ {
+ loader: "style-loader"
+ },
+ {
+ loader: "css-loader",
+ options: {
+ modules: true
+ }
+ }
]
},
{
test: /\.jsx$/,
loader: "babel-loader", // Do not use "use" here
options: {
// ...
}
}
]
}
链式装载机
就像在 webpack 1 中,loader 可以链式调用,上一个 loader 的输出被作为输入传给下一个 loader。 使用 rule.use
配置选项,use
可以设置为一个 loader 数组。 在 webpack 1 中,loader 通常被用 !
连写。这一写法在 webpack 2 中只在使用旧的选项 module.loaders
时才有效。
module: {
- loaders: [{
+ rules: [{
test: /\.less$/,
- loader: "style-loader!css-loader!less-loader"
+ use: [
+ "style-loader",
+ "css-loader",
+ "less-loader"
+ ]
}]
}
在引用 loader 时,不能再省略 -loader
后缀了:
module: {
rules: [
{
use: [
- "style",
+ "style-loader",
- "css",
+ "css-loader",
- "less",
+ "less-loader",
]
}
]
}
你仍然可以通过配置 resolveLoader.moduleExtensions
配置选项,启用这一旧有行为,但是我们不推荐这么做。
+ resolveLoader: {
+ moduleExtensions: ["-loader"]
+ }
请参阅#2986了解更改背后的原因。
如果没有为 JSON 文件配置 loader,webpack 将自动尝试通过 json-loader
加载 JSON 文件。
module: {
rules: [
- {
- test: /\.json/,
- loader: "json-loader"
- }
]
}
我们决定这么做是为了消除 webpack、 node.js 和 browserify 之间的环境差异。
在 webpack 1 中,默认配置下 loader 解析相对于被匹配的文件。然而,在 webpack 2 中,默认配置下 loader 解析相对于 context 选项。
这解决了「在使用 npm link
或引用 context
上下文目录之外的模块时,loader 所导致的模块重复载入」的问题。
你可以删除一些 hacks 来解决这个问题:
module: {
rules: [
{
// ...
- loader: require.resolve("my-loader")
+ loader: "my-loader"
}
]
},
resolveLoader: {
- root: path.resolve(__dirname, "node_modules")
}
module.preLoaders和module.postLoaders被删除:
module: {
- preLoaders: [
+ rules: [
{
test: /\.js$/,
+ enforce: "pre",
loader: "eslint-loader"
}
]
}
UglifyJsPlugin sourceMap
UglifyJsPlugin
的 sourceMap
选项现在默认为 false
而不是 true
。这意味着如果你在压缩代码时启用了 source map,或者想要让 uglifyjs 的警告能够对应到正确的代码行,你需要将 UglifyJsPlugin
的 sourceMap
设为 true
。
devtool: "source-map",
plugins: [
new UglifyJsPlugin{
+ sourceMap: true
})
]
UglifyJsPlugin 警告
UglifyJsPlugin
的 compress.warnings
选项现在默认为 false
而不是 true
。 这意味着如果你想要看到 uglifyjs 的警告信息,你需要将 compress.warnings
设为 true
。
devtool: "source-map",
plugins: [
new UglifyJsPlugin{
+ compress: {
+ warnings: true
+ }
})
]
UglifyJsPlugin
不再压缩 loaders。在未来很长一段时间里,需要通过设置 minimize:true
来压缩 loaders。参考 loader 文档里的相关选项。
为了兼容旧的 loaders,loaders 可以通过插件来切换到压缩模式:
plugins: [
+ new webpack.LoaderOptionsPlugin{
+ minimize: true
+ })
]
移除 DedupePlugin
不再需要 webpack.optimize.DedupePlugin
。请从配置中移除。
plugins: [
- new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true}
+ new webpack.BannerPlugin{banner: 'Banner', raw: true, entryOnly: true}
]
OccurrenceOrderPlugin
现在默认启用,并已重命名(在 webpack 1 中为 OccurenceOrderPlugin
)。 因此,请确保从你的配置中删除该插件:
plugins: [
// webpack 1
- new webpack.optimize.OccurenceOrderPlugin()
// webpack 2
- new webpack.optimize.OccurrenceOrderPlugin()
]
ExtractTextPlugin 需要使用版本 2,才能在 webpack 2 下正常运行。
npm install --save-dev extract-text-webpack-plugin
ExtractTextPlugin.extract
module: {
rules: [
{
test: /.css$/,
- loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" })
+ use: ExtractTextPlugin.extract{
+ fallback: "style-loader",
+ use: "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
+ })
]
只有一个表达式的依赖(例如 require(expr)
)将创建一个空的 context 而不是一个完整目录的 context。
这样的代码应该进行重构,因为它不能与 ES2015 模块一起使用。如果你确定不会有 ES2015 模块,你可以使用 ContextReplacementPlugin
来指示 compiler 进行正确的解析。
链接到关于动态依赖关系的文章。
在CLI和配置中使用自定义参数
如果您滥用CLI将自定义参数传递给配置,如下所示:
webpack --custom-stuff
// webpack.config.js
var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
/* ... */
module.exports = config;
你将会发现新版中不再允许这么做。CLI 现在更加严格了。
替代地,现在提供了一个接口来传递参数给配置。我们应该采用这种新方式,在未来许多工具将可能依赖于此。
webpack --env.customStuff
module.exports = function(env) {
var customStuff = env.customStuff;
/* ... */
return config;
};
请参阅CLI。
require.ensure
以及 AMD require
将采用异步式调用
现在这些函数总是异步的,而不是当 chunk 已经加载完成的时候同步调用它们的回调函数(callback)。
require.ensure 现在依赖于原生的 Promise。如果在不支持 Promise 的环境里使用 require.ensure,你需要添加 polyfill。
你不能再通过 webpack.config.js
的自定义属性来配置 loader。只能通过 options
来配置。下面配置的 ts
属性在 webpack 2 下不再有效:
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader'
}]
},
// does not work with webpack 2
ts: { transpileOnly: false }
}
什么options?
好问题。严格来说,有两种办法,都可以用来配置 webpack 的 loader。典型的 options
被称为 query
,是一个可以被添加到 loader 名之后的字符串。它比较像一个 query
string,但是实际上有更强大的能力:
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader?' + JSON.stringify{ transpileOnly: false })
}]
}
}
module.exports = {
...
module: {
rules: [{
test: /\.tsx?$/,
loader: 'ts-loader',
options: { transpileOnly: false }
}]
}
}
LoaderOptionsPlugin 上下文
为了保持对旧 loaders 的兼容,这些信息可以通过插件传进来:
plugins: [
+ new webpack.LoaderOptionsPlugin{
+ options: {
+ context: __dirname
+ }
+ })
]
debug
在 webpack 1 中 debug
选项可以将 loader 切换到调试模式(debug
mode)。在未来很长一段时间里,这将需要通过 loader 选项传递。详见 loader 文档的相关选项。
装载机的调试模式将在webpack 3或更高版本中删除。
为了保持与旧装载机的兼容性,装载机可以通过插件切换到调试模式:
- debug: true,
plugins: [
+ new webpack.LoaderOptionsPlugin{
+ debug: true
+ })
]
使用ES2015进行代码分割
require.ensure([], function(require) {
var foo = require("./module"
}
ES2015 模块加载规范定义了 import()
方法,可以在运行时(runtime)动态地加载 ES2015 模块。webpack 将 import()
作为分割点(split-point)并将所要请求的模块(requested module)放置到一个单独的 chunk 中。import()
接收模块名作为参数,并返回一个 Promise。
function onClick() {
import("./module").then(module => {
return module.default;
}).catch(err => {
console.log("Chunk loading failed"
}
}
好消息是:如果加载 chunk 失败,我们现在可以进行处理,因为现在它基于 Promise
。
动态表达式
可以将部分表达式传递给import()
。这与CommonJS中的表达式类似(webpack创建一个包含所有可能文件的上下文)。
import()
为每个可能的模块创建一个单独的块。
function route(path, query) {
return import(`./routes/${path}/route`)
.then(route => new route.Route(query)
}
// This creates a separate chunk for each possible route
将ES2015与AMD和CommonJS混合使用
至于AMD和CommonJS,您可以自由混合所有三种模块类型(即使在同一个文件中)。在这种情况下,webpack的行为类似于babel和node-eps:
// CommonJS consuming ES2015 Module
var book = require("./book"
book.currentPage;
book.readPage(
book.default === "This is a book";
// ES2015 Module consuming CommonJS
import fs from "fs"; // module.exports map to default
import { readFileSync } from "fs"; // named exports are read from returned object+
typeof fs.readFileSync === "function";
typeof readFileSync === "function";
请注意,您需要告诉Babel不要分析这些模块符号,以便webpack可以使用它们。您可以通过在您的.babelrc
或babel-loader
选项中设置以下内容来完成此操作。
.babelrc
{
"presets": [
["es2015", { "modules": false }]
]
}
提示
没有必要改变一些东西,但机会
模板字符串
webpack现在支持表达式中的模板字符串。这意味着你可以开始在webpack结构中使用它们:
- require("./templates/" + name
+ require(`./templates/${name}`
配置承诺
webpack现在支持Promise
从配置文件中返回a 。这允许在你的配置文件中进行异步处理。
webpack.config.js
module.exports = function() {
return fetchLangs().then(lang => {
entry: "...",
// ...
plugins: [
new DefinePlugin{ LANGUAGE: lang })
]
})
};
高级装载机匹配
webpack现在支持更多的东西来匹配装载机。
module: {
rules: [
{
resource: /filename/, // matches "/path/filename.js"
resourceQuery: /^\?querystring$/, // matches "?querystring"
issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
}
]
}
更多CLI选项
您可以使用一些新的CLI选项:
--define process.env.NODE_ENV="production"
参阅DefinePlugin
。
--display-depth
显示每个模块到入口点的距离。
--display-used-exports
显示有关在模块中使用哪些导出的信息。
--display-max-modules
设置输出中显示的模块的编号(默认为15)。
-p
也定义process.env.NODE_ENV
到"production"
现在。
加载器更改
更改仅与装入器作者相关。
可缓存
现在装载器默认可以缓存。如果他们不可缓存,则装载者必须退出。
// Cacheable loader
module.exports = function(source) {
- this.cacheable(
return source;
}
// Not cacheable loader
module.exports = function(source) {
+ this.cacheable(false
return source;
}
复杂的选项
webpack 1
仅支持JSON.stringify
装载器的可选选项。
webpack 2
现在支持任何JS对象作为加载器选项。
的WebPack之前2.2.1(即,从通过2.0.0 2.2.0),使用复杂的选项使用所需ident
的options
对象,以允许从其他装载机其引用。这在2.2.1中被删除,
因此当前的迁移不需要使用ident
密钥。
{
test: /\.ext/
use: {
loader: '...',
options: {
- ident: 'id',
fn: () => require('./foo.js')
}
}
}