首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

迁移版本 | Migrating Versions

以下部分描述了从webpack 1到2的主要更改。

webpack 从 1 到 2 的变化,比从 2 到 3 要少很多,所以版本迁移起来难度应该不大。如果你遇到了问题,请查看 更新日志 以了解更多细节。

随着 webpack 2 版本已经发布一段时间,此章节的内容可能会在不久的将来被转移到博客文章中。最重要的是,webpack 3 版本最近发布,webpack 4 版本即将发布。如上所述,大家最好是参考 更新日志 去进行相应的版本迁移。

resolve.root, resolve.fallback, resolve.modulesDirectories

这些选项被一个单独的选项 resolve.modules 取代。更多用法请查看解析。

代码语言:javascript
复制
  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

代码语言:javascript
复制
  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 时才有效。

代码语言:javascript
复制
  module: {
-   loaders: [{
+   rules: [{
      test: /\.less$/,
-     loader: "style-loader!css-loader!less-loader"
+     use: [
+       "style-loader",
+       "css-loader",
+       "less-loader"
+     ]
    }]
  }

取消「在模块名中自动添加 -loader 后缀」

在引用 loader 时,不能再省略 -loader 后缀了:

代码语言:javascript
复制
  module: {
    rules: [
      {
        use: [
-         "style",
+         "style-loader",
-         "css",
+         "css-loader",
-         "less",
+         "less-loader",
        ]
      }
    ]
  }

你仍然可以通过配置 resolveLoader.moduleExtensions 配置选项,启用这一旧有行为,但是我们不推荐这么做。

代码语言:javascript
复制
+ resolveLoader: {
+   moduleExtensions: ["-loader"]
+ }

请参阅#2986了解更改背后的原因。

json-loader 不再需要手动添加

如果没有为 JSON 文件配置 loader,webpack 将自动尝试通过 json-loader 加载 JSON 文件。

代码语言:javascript
复制
  module: {
    rules: [
-     {
-       test: /\.json/,
-       loader: "json-loader"
-     }
    ]
  }

我们决定这么做是为了消除 webpack、 node.js 和 browserify 之间的环境差异。

配置中的 loader 默认相对于 context 进行解析

在 webpack 1 中,默认配置下 loader 解析相对于被匹配的文件。然而,在 webpack 2 中,默认配置下 loader 解析相对于 context 选项。

这解决了「在使用 npm link 或引用 context 上下文目录之外的模块时,loader 所导致的模块重复载入」的问题。

你可以删除一些 hacks 来解决这个问题:

代码语言:javascript
复制
  module: {
    rules: [
      {
        // ...
-       loader: require.resolve("my-loader")
+       loader: "my-loader"
      }
    ]
  },
  resolveLoader: {
-   root: path.resolve(__dirname, "node_modules")
  }

module.preLoadersmodule.postLoaders被删除:

代码语言:javascript
复制
  module: {
-   preLoaders: [
+   rules: [
      {
        test: /\.js$/,
+       enforce: "pre",
        loader: "eslint-loader"
      }
    ]
  }

UglifyJsPlugin sourceMap

UglifyJsPluginsourceMap 选项现在默认为 false 而不是 true。这意味着如果你在压缩代码时启用了 source map,或者想要让 uglifyjs 的警告能够对应到正确的代码行,你需要将 UglifyJsPluginsourceMap 设为 true

代码语言:javascript
复制
  devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     sourceMap: true
    })
  ]

UglifyJsPlugin 警告

UglifyJsPlugincompress.warnings 选项现在默认为 false 而不是 true。 这意味着如果你想要看到 uglifyjs 的警告信息,你需要将 compress.warnings 设为 true

代码语言:javascript
复制
  devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     compress: {
+       warnings: true
+     }
    })
  ]

UglifyJsPlugin 压缩 loaders

UglifyJsPlugin 不再压缩 loaders。在未来很长一段时间里,需要通过设置 minimize:true 来压缩 loaders。参考 loader 文档里的相关选项。

loaders 的压缩模式将在 webpack 3 或后续版本中取消。

为了兼容旧的 loaders,loaders 可以通过插件来切换到压缩模式:

代码语言:javascript
复制
  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     minimize: true
+   })
  ]

移除 DedupePlugin

不再需要 webpack.optimize.DedupePlugin。请从配置中移除。

BannerPlugin - 破坏性改动

BannerPlugin 不再接受两个参数,而是只接受单独的 options 对象。

代码语言:javascript
复制
  plugins: [
-    new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+    new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
  ]

默认加载 OccurrenceOrderPlugin

OccurrenceOrderPlugin 现在默认启用,并已重命名(在 webpack 1 中为 OccurenceOrderPlugin)。 因此,请确保从你的配置中删除该插件:

代码语言:javascript
复制
  plugins: [
    // webpack 1
-   new webpack.optimize.OccurenceOrderPlugin()
    // webpack 2
-   new webpack.optimize.OccurrenceOrderPlugin()
  ]

ExtractTextWebpackPlugin - 破坏性改动

ExtractTextPlugin 需要使用版本 2,才能在 webpack 2 下正常运行。

npm install --save-dev extract-text-webpack-plugin

这一插件的配置变化主要体现在语法上。

ExtractTextPlugin.extract

代码语言:javascript
复制
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})

代码语言:javascript
复制
plugins: [
-  new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
+  new ExtractTextPlugin({
+    filename: "bundle.css",
+    disable: false,
+    allChunks: true
+  })
]

全动态 require 现在默认会失败

只有一个表达式的依赖(例如 require(expr))将创建一个空的 context 而不是一个完整目录的 context。

这样的代码应该进行重构,因为它不能与 ES2015 模块一起使用。如果你确定不会有 ES2015 模块,你可以使用 ContextReplacementPlugin 来指示 compiler 进行正确的解析。

链接到关于动态依赖关系的文章。

在CLI和配置中使用自定义参数

如果您滥用CLI将自定义参数传递给配置,如下所示:

webpack --custom-stuff

代码语言:javascript
复制
// webpack.config.js
var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
/* ... */
module.exports = config;

你将会发现新版中不再允许这么做。CLI 现在更加严格了。

替代地,现在提供了一个接口来传递参数给配置。我们应该采用这种新方式,在未来许多工具将可能依赖于此。

webpack --env.customStuff

代码语言:javascript
复制
module.exports = function(env) {
  var customStuff = env.customStuff;
  /* ... */
  return config;
};

请参阅CLI。

require.ensure 以及 AMD require 将采用异步式调用

现在这些函数总是异步的,而不是当 chunk 已经加载完成的时候同步调用它们的回调函数(callback)。

require.ensure 现在依赖于原生的 Promise。如果在不支持 Promise 的环境里使用 require.ensure,你需要添加 polyfill。

通过 options 配置 loader

你不能再通过 webpack.config.js 的自定义属性来配置 loader。只能通过 options 来配置。下面配置的 ts 属性在 webpack 2 下不再有效:

代码语言:javascript
复制
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,但是实际上有更强大的能力

代码语言:javascript
复制
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.tsx?$/,
      loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false })
    }]
  }
}

不过它也可以分开来,写成一个单独的对象,紧跟在 loader 属性后面:

代码语言:javascript
复制
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.tsx?$/,
      loader: 'ts-loader',
      options:  { transpileOnly: false }
    }]
  }
}

LoaderOptionsPlugin 上下文

有的 loader 需要从配置中读取一些 context 信息。在未来很长一段时间里,这将需要通过 loader options 传入。详见 loader 文档的相关选项。

为了保持对旧 loaders 的兼容,这些信息可以通过插件传进来:

代码语言:javascript
复制
  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     options: {
+       context: __dirname
+     }
+   })
  ]

debug

在 webpack 1 中 debug 选项可以将 loader 切换到调试模式(debug mode)。在未来很长一段时间里,这将需要通过 loader 选项传递。详见 loader 文档的相关选项。

装载机的调试模式将在webpack 3或更高版本中删除。

为了保持与旧装载机的兼容性,装载机可以通过插件切换到调试模式:

代码语言:javascript
复制
- debug: true,
  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     debug: true
+   })
  ]

使用ES2015进行代码分割

在 webpack 1 中,可以使用 require.ensure作为实现应用程序的懒加载 chunks 的一种方法:

代码语言:javascript
复制
require.ensure([], function(require) {
  var foo = require("./module");
});

ES2015 模块加载规范定义了 import() 方法,可以在运行时(runtime)动态地加载 ES2015 模块。webpack 将 import() 作为分割点(split-point)并将所要请求的模块(requested module)放置到一个单独的 chunk 中。import() 接收模块名作为参数,并返回一个 Promise。

代码语言:javascript
复制
function onClick() {
  import("./module").then(module => {
    return module.default;
  }).catch(err => {
    console.log("Chunk loading failed");
  });
}

好消息是:如果加载 chunk 失败,我们现在可以进行处理,因为现在它基于 Promise

动态表达式

可以将部分表达式传递给import()。这与CommonJS中的表达式类似(webpack创建一个包含所有可能文件的上下文)。

import() 为每个可能的模块创建一个单独的块。

代码语言:javascript
复制
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:

代码语言:javascript
复制
// CommonJS consuming ES2015 Module
var book = require("./book");

book.currentPage;
book.readPage();
book.default === "This is a book";
代码语言:javascript
复制
// 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可以使用它们。您可以通过在您的.babelrcbabel-loader选项中设置以下内容来完成此操作。

.babelrc

代码语言:javascript
复制
{
  "presets": [
    ["es2015", { "modules": false }]
  ]
}

提示

没有必要改变一些东西,但机会

模板字符串

webpack现在支持表达式中的模板字符串。这意味着你可以开始在webpack结构中使用它们:

代码语言:javascript
复制
- require("./templates/" + name);
+ require(`./templates/${name}`);

配置承诺

webpack现在支持Promise从配置文件中返回a 。这允许在你的配置文件中进行异步处理。

webpack.config.js

代码语言:javascript
复制
module.exports = function() {
  return fetchLangs().then(lang => ({
    entry: "...",
    // ...
    plugins: [
      new DefinePlugin({ LANGUAGE: lang })
    ]
  }));
};

高级装载机匹配

webpack现在支持更多的东西来匹配装载机。

代码语言:javascript
复制
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"现在。

加载器更改

更改仅与装入器作者相关。

可缓存

现在装载器默认可以缓存。如果他们不可缓存,则装载者必须退出。

代码语言:javascript
复制
  // Cacheable loader
  module.exports = function(source) {
-   this.cacheable();
    return source;
  }
代码语言:javascript
复制
  // 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),使用复杂的选项使用所需identoptions对象,以允许从其他装载机其引用。这在2.2.1中被删除,因此当前的迁移不需要使用ident密钥。

代码语言:javascript
复制
{
  test: /\.ext/
  use: {
    loader: '...',
    options: {
-     ident: 'id',
      fn: () => require('./foo.js')
    }
  }
}

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com