从 v1 迁移到 v2 或 v3

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

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 现在是 module.rules

旧的 loader 配置已被更强大的规则系统取代,该系统允许配置 loader 及更多功能。出于兼容性原因,旧的 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: {
          // ...
        }
      }
    ]
  }

Loader 链

与 webpack 1 中一样,loader 可以被链接以将结果从一个 loader 传递到另一个 loader。使用rule.use 配置选项,use 可以设置为 loader 数组。在 webpack 1 中,loader 通常使用 ! 进行链式调用。此样式仅在使用旧版选项 module.loaders 时受支持。

  module: {
-   loaders: [{
+   rules: [{
      test: /\.less$/,
-     loader: "style-loader!css-loader!less-loader"
+     use: [
+       "style-loader",
+       "css-loader",
+       "less-loader"
+     ]
    }]
  }

自动 -loader 模块名称扩展已移除

引用 loader 时,不再可能省略 -loader 扩展名

  module: {
    rules: [
      {
        use: [
-         "style",
+         "style-loader",
-         "css",
+         "css-loader",
-         "less",
+         "less-loader",
        ]
      }
    ]
  }

您仍然可以使用 resolveLoader.moduleExtensions 配置选项选择旧行为,但不推荐这样做。

+ resolveLoader: {
+   moduleExtensions: ["-loader"]
+ }

有关此更改的原因,请参阅#2986

不再需要 json-loader

当没有为 JSON 文件配置任何 loader 时,webpack 将自动尝试使用json-loader 加载 JSON 文件。

  module: {
    rules: [
-     {
-       test: /\.json/,
-       loader: "json-loader"
-     }
    ]
  }

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

配置中的 Loader 相对上下文解析

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

这解决了在使用 npm link 或引用 context 外部模块时,loader 导致的重复模块问题。

您可以移除一些用于规避此问题的技巧

  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

UglifyJsPluginsourceMap 选项现在默认为 false 而不是 true。这意味着如果您正在使用源映射来处理最小化代码,或者想要获取 uglifyjs 警告的正确行号,则需要为 UglifyJsPlugin 设置 sourceMap: true

  devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     sourceMap: true
    })
  ]

UglifyJsPlugin warnings

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

  devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     compress: {
+       warnings: true
+     }
    })
  ]

UglifyJsPlugin 最小化 loader

UglifyJsPlugin 不再将 loader 切换到最小化模式。minimize: true 设置需要长期通过 loader 选项传递。请参阅 loader 文档以获取相关选项。

loader 的最小化模式将在 webpack 3 或更高版本中移除。

为了保持与旧 loader 的兼容性,可以通过插件将 loader 切换到最小化模式

  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     minimize: true
+   })
  ]

DedupePlugin 已移除

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

BannerPlugin - 破坏性变更

BannerPlugin 不再接受两个参数,而是接受一个单独的选项对象。

  plugins: [
-    new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+    new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
  ]

OccurrenceOrderPlugin 现在默认开启

OccurrenceOrderPlugin 现在默认启用,并且已重命名(在 webpack 1 中为 OccurenceOrderPlugin)。因此,请确保将其从您的配置中移除。

  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

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 现在默认失败

现在,仅包含表达式的依赖(即 require(expr))将创建一个空上下文,而不是完整目录的上下文。

这样的代码应该进行重构,因为它无法与 ES2015 模块一起工作。如果无法重构,您可以使用 ContextReplacementPlugin 来提示编译器进行正确的解析。

在 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 已经加载时同步调用其回调。

require.ensure 现在依赖于原生的 Promise。如果在使用 require.ensure 的环境中缺少 Promise,则需要一个 polyfill。

Loader 配置通过 options 进行

您**不能再**在 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 的名称后面。它很像查询字符串,但实际上具有更大的能力

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false }),
      },
    ],
  },
};

但它也可以是与 loader 一起提供的单独指定对象

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        options: { transpileOnly: false },
      },
    ],
  },
};

LoaderOptionsPlugin context

一些 loader 需要上下文信息并从配置中读取它们。这需要长期通过 loader 选项传递。请参阅 loader 文档以获取相关选项。

为了保持与旧 loader 的兼容性,可以通过插件传递此信息

  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     options: {
+       context: __dirname
+     }
+   })
  ]

debug

在 webpack 1 中,debug 选项将 loader 切换到调试模式。这需要长期通过 loader 选项传递。请参阅 loader 文档以获取相关选项。

loader 的调试模式将在 webpack 3 或更高版本中移除。

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

- debug: true,
  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     debug: true
+   })
  ]

使用 ES2015 进行代码分割

在 webpack 1 中,您可以使用require.ensure() 作为延迟加载应用程序 chunk 的方法

require.ensure([], function (require) {
  var foo = require('./module');
});

ES2015 Loader 规范将import() 定义为在运行时动态加载 ES2015 模块的方法。Webpack 将 import() 视为一个分割点,并将请求的模块放入一个单独的 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() 为每个可能的模块创建一个单独的 chunk。

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 可以使用它们。您可以通过在您的 .babelrcbabel-loader 选项中设置以下内容来完成此操作。

.babelrc

{
  "presets": [["es2015", { "modules": false }]]
}

提示

无需更改,但有机会

模板字符串

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

- require("./templates/" + name);
+ require(`./templates/${name}`);

配置 Promise

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

webpack.config.js

module.exports = function () {
  return fetchLangs().then((lang) => ({
    entry: '...',
    // ...
    plugins: [new DefinePlugin({ LANGUAGE: lang })],
  }));
};

高级 loader 匹配

Webpack 现在支持更多 loader 匹配项。

module.exports = {
  //...
  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"

Loader 变更

仅与 loader 作者相关的更改。

可缓存

Loader 现在默认是可缓存的。如果 loader 不可缓存,则必须选择退出。

  // 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 可选的 loader 选项。

webpack 2 现在支持任何 JS 对象作为 loader 选项。

在 webpack 2.2.1 之前(即从 2.0.0 到 2.2.0),使用复杂选项需要为 options 对象使用 ident 以允许其他 loader 引用它。**此功能在 2.2.1 中已移除**,因此当前迁移不需要使用 ident 键。

{
  test: /\.ext/
  use: {
    loader: '...',
    options: {
-     ident: 'id',
      fn: () => require('./foo.js')
    }
  }
}

14 贡献者

sokrajhnnsgrgurdomfarolinojohnnyreillyjouni-kantolafrederikprijckchrisVillanuevabebrawhowdy39selbekkndelangenEugeneHlushkobyzyk