三石的webpack.config.js(进阶篇)

635 阅读8分钟

三石的webpack.config.js(基础篇)
其他专栏篇也有汇总

Externals

一般来说,会将第三方库打包到bundle中;如果不想这么做,就可以配置 externals参数。配置后,这些 import 的包会在运行时从外部获取,例如,从 CDN 获取
library 开发人员经常会使用到这个,因为library本身对大小就有要求,所以如果打包进三方库,那就太不划算了

具有外部依赖(external dependency)的 bundle 可以在各种模块上下文(module context)中使用,例如 CommonJS, AMD, 全局变量和 ES2015 模块。外部 library 可能是以下任何一种形式:

  • root:可以通过一个全局变量访问 library(例如,通过 script 标签)。
  • commonjs:可以将 library 作为一个 CommonJS 模块访问。
  • commonjs2:和上面的类似,但导出的是 module.exports.default.
  • amd:类似于 commonjs,但使用 AMD 模块系统

externals

  1. 字符串 例如,若想将 fs-extra 从输出的 bundle 中剔除并在运行时中引入它,你可以如下定义:
module.exports = {
  // ...
  externals: {
    'fs-extra': 'commonjs2 fs-extra',
  },
};

这样的做法会让任何依赖的模块都不变,正如以下所示的代码:

import fs from 'fs-extra';

会将代码编译成:

const fs = require('fs-extra');
  1. 字符串数组
module.exports = {
  //...
  externals: {
    subtract: ['./math', 'subtract'],
  },
};

subtract: ['./math', 'subtract'] 转换为层级结构,其中 ./math 是父模块,而 bundle 只引用 subtract 变量下的子集。该例子会编译成 require('./math').subtract;

  1. 对象
module.exports = {
  //...
  externals: {
    lodash: {
      commonjs: 'lodash',
      amd: 'lodash',
      root: '_', // 指向全局变量
    },
  },
};

这里 lodash 这个外部 library 可以在 AMD 和 CommonJS 模块系统中通过 lodash 访问,但在全局变量形式下用 _ 访问

  1. 正则 匹配给定正则表达式的每个依赖,都将从输出 bundle 中排除
module.exports = {
  //...
  externals: /^(jquery|$)$/i,
};
  1. 函数

externalsType

指定 externals 的默认类型。当 external 被设置为 amdumdsystem 以及 jsonp 时,library.type 的值也应相同

resolveLoader

用法与 resolve 一样,只不过 resolve 配置是针对模块的解析规则,而 resolveLoader 则是针对Loader的解析规则

devtool

配置 source map 的生成方式及是否生成

可以直接使用 SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin 来替代使用 devtool 选项,因为它有更多的选项。不能同时使用 devtool 选项和 SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin 插件。devtool 选项在内部添加过这些插件,所以你最终将应用两次插件。 常用devtool配置选项:

  • eval 会将每一个module模块,执行eval,执行后不会生成 source-map 文件,打包速度很快。仅仅在每个模块后,增加 sourceURL 来关联模块处理前后对应的关系
    缺点: 由于会映射到转换后的代码,而不是映射到原始代码,所以不能正确的显示行数
  • source-map 会为每一个打包后的模块生成独立的sourcemap文件,且在每个模块后增加sourceMappingURL来关联 map 文件,功能最完全
    缺点: 减慢打包速度
  • eval-source-map 使用eval打包源文件模块,直接在源文件中写入干净完整的source-map
    不影响构建速度,但影响执行速度和安全,建议开发环境中使用,生产阶段不要使用
  • cheap-module-source-map 会产生一个不带映射到列的单独的map文件
    缺点: 开发者工具就只能看到行,但无法对应到具体的列(符号),对调试不便
  • cheap-module-eval-source-map 不会产生单独的map文件,(与eval-source-map类似)
    缺点: 开发者工具就只能看到行,但无法对应到具体的列(符号),对调试不便
  • inline-source-map 不会生成独立的 .map文件,而是将 .map文件以dataURL的形式插入 缺点: 会使bundle.js文件变得非常大,因为它需要把 sourceMappingURL 以dataurl的形式插入到bundle.js里面去

如何选择?

  1. 源代码中的列信息是没有任何作用,因此我们打包后的文件不希望包含列相关信息,只有行信息能建立打包前后的依赖关系。因此不管**是开发环境或生产环境,我们都希望添加cheap的基本类型来忽略打包前后的列信息。****

  2. 不管是开发环境还是正式环境,我们都希望能定位到bug的源代码具体的位置,比如说某个vue文件报错了,我们希望能定位到具体的vue文件,因此我们也需要module配置。**

  3. 我们需要生成map文件的形式,因此我们需要增加 source-map属性。**

  4. 我们介绍了eval打包代码的时候,知道eval打包后的速度非常快,因为它不生成map文件,但是可以对eval组合使用 eval-source-map使用会将map文件以DataURL的形式存在打包后的js文件中

参考理解

Watch

Webpack 可以监听文件变化,当它们修改后会重新编译。这个选项可以配置相关参数

如何开启监听模式

有两种开启模式:

  • 启动 webpack 命令时,带上 --watch 参数
  • 在配置 webpack.config.js 中设置 watch:true

缺点:每次需要手动刷新浏览器

原理

根据 watchOptions.poll 配置轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout 后再重新编译。

webpack.config.js 配置

watch

启动/关闭 Watch 模式

webpack-dev-server 和 webpack-dev-middleware 里 Watch 模式默认开启

watchOptions.aggregateTimeout

单位为毫秒。当第一个文件更改,会在重新构建前增加延迟。这个选项允许 webpack 将这段时间内进行的任何其他更改都聚合到一次重新构建里

watchOptions.ingored

不监听哪些文件的修改,默认为空。
对于某些系统,监听大量文件会导致大量的 CPU 或内存占用。可以使用正则排除像 node_modules 如此庞大的文件夹

module.exports = {
  //...
  watchOptions: {
    ignored: /node_modules/,
    // 或者
    // ignored: [path.posix.resolve(__dirname, './ignored-dir')]  等

  },
};

watchOptions.poll

判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的。
通过传递 true 开启轮询,或者指定毫秒为单位进行轮询

module.exports = {
  //...
  watchOptions: {
    poll: 1000, // 每秒检查一次变动
  }
};

watchOptions.followSymlinks

据软链接查找文件,通常是不需要的

watchOptions.stdin

是否在 stdin 流结束时停止监听。

故障排除

  1. 发现修改,但并未做处理 在运行 webpack 时,通过使用 --progress 标志,来验证文件修改后,是否没有通知 webpack。如果进度显示保存,但没有输出文件,则可能是配置问题,而不是文件监视问题

  2. macOS Bug 在 macOS 中,某些情况下文件夹可能会损坏

  3. Windows Paths 为 webpack 期望获得多个配置选项的绝对路径(如 __dirname + '/app/folder'),所以 Windows 的路径分隔符 \ 可能会破坏某些功能。

使用正确的分隔符。即 path.resolve(__dirname, 'app/folder') 或 path.join(__dirname, 'app', 'folder')

  1. Vim 在某些机器上,Vim 预先将 backupcopy 设置为 auto。这可能会导致系统的文件监视机制出现问题。将此选项设置为 yes 可以确保创建文件的副本,并在保存时覆盖原始文件。

:set backupcopy=yes

  1. 在 WebStorm 中保存 使用 JetBrains WebStorm IDE 时,你可能会发现保存修改过的文件,并不会按照预期触发观察者。尝试在设置中禁用 Back up files before saving 选项,该选项确定在原文件被覆盖之前,文件是否先保存到临时位置:取消选中 File > {Settings|Preferences} > Appearance & Behavior > System Settings > Back up files before saving。在一些 webstorm 版本中,该配置项可能会被称为 "safe write"(首先将更改保存到临时文件)

Cache

缓存生成的 webpack 模块和 chunk,来改善 构建速度
webpack5新特性

type

'memory' | 'filesystem': 将 cache 类型设置为内存或者文件系统。memory 选项很简单,它告诉 webpack 在内存中存储缓存,不允许额外的配置. 'filesystem' 会有更多的可配置项,如 cache.cacheDirectory

cache 会在开发模式被设置成 type: 'memory' ,在 生产 模式中被禁用。 
cache: true 与 cache: { type: 'memory' } 配置作用一致

version

type 为 'filesystem' 有效
缓存数据的版本。不同版本不会允许重用缓存和重载当前的内容。当配置以一种无法重用缓存的方式改变时,要更新缓存的版本。这会让缓存失效。

store

type 为 'filesystem' 有效
告诉 webpack 什么时候将数据存放在文件系统中,目前只支持pack
store: 'pack': 当编译器闲置时候,将缓存数据都存放在一个文件中

maxAge

type 为 'filesystem' 有效
允许未使用的缓存留在文件系统缓存中的时间(以毫秒为单位);默认为一个月

performance

当资源(webpack 生成的任何文件)和入口起点超过指定文件限制,配置如何展示性能提示

assetFilter

允许 webpack 控制用于计算性能提示的文件
如下配置后,将只给出 js 文件的性能提示

module.exports = {
  //...
  performance: {
    assetFilter: function (assetFilename) {
      return assetFilename.endsWith('.js');
    },
  },
};

hints

'warning': 'error' | 'warning' boolean: false 配置是否提示以及用什么级别的提示

maxAssetSize

单位为bytes,当资源大小超过这个值时,将生成提示

maxEntrypointSize

单位为bytes,当entry文件大小超过这个值时,将生成提示

Other

  1. Stats 精确地控制 bundle 信息该怎么显示

  2. Experiments 允许用户去开启并试用一些实验的特性,如 asset