Webpack 属于在项目中配置一次就很少改动的那种工具,但这样就导致新项目再配置 Webpack 时会有些生疏,所以将 Webpack 核心概念及常用配置记录如下。
1)核心概念
Webpack 4.x 之前的核心概念有四个:entry,output,loaders,plugins,4.x 之后增加了 mode。含义如下:
- Entry:指定 webpack 从哪个 file 开始构建他的依赖关系图,可以有一个和多个,推荐对象表示法;
- Output:webpack 构建完成后的 bundles 输出位置及 name,其中 name 一般根据 entry 的 file name 动态生成;
- Loaders:webpack 可以将非 js 文件(css、图像等)通过 loaders 处理成可供我们的应用使用的 modules。也因此在配置文件中,loaders 写在
module
对象下面,因为 loaders 处理后返回的是有效 modules。 - Plugins:如果需要额外的功能,比如压缩代码、提取 css、分析打包性能,可使用插件完成;
Loaders 将特定文件转换为有效 module,而 plugin 扩展性更强
- Mode:接受
development
、production
、none
三个值,一般指定为前两个值的一种,webpack 内部针对不同环境做优化。
2)配置
下面介绍的配置都是module.exports
的直接属性,比如:
module.exports = {
|
同时,文件头引入相应依赖的过程省略了,实际开发中请自行引入。
2.1 Entry
Entry 指定哪些文件作为 webpack 打包入口,可以有一个或者多个:
entry: {
|
2.2 Output
Output 指明 Webpack 处理完成后的 bundles 输入位置及文件 name:
output: {
|
Output 配置相对复杂:
2.2.1 output.path
即输出文件目录,推荐使用绝对路径,其中__dirname
在 Node 的 path 模块中表示当前目录(即 webpack.config.js 的目录)的绝对路径,resolve
方法可以拼接两个目录;
后一个目录可以加
/
也可以不加,此处无差别
2.2.2 output.filename
表示输出文件名称,这里注意,[]
中是变量,其中name
由在 entry 中定义的文件名决定,并且,有多少个输入文件,对应有多少个输出文件,后面的contenthash:8
表示 chunk 的 hash 值,后文介绍;
实际输出文件一般多于输入文件,因为提取公共代码、设置 sourcemap 都会单独生成输出文件
2.2.3 output.publickPath
这个配置想最为复杂,它的作用是配合 loaders 或 plugins 中设置的资源路径,指定静态文件(css、js、img)插入 html 中的引用路径,简单讲,就是 对输出的静态资源进行目录管理。这里直接使用 详解 Webpack2 的那些路径的描述,只稍作说明。
静态资源最终引用路径计算公式:
html 静态资源路径 = output.publicPath + loaders/plugins 中设置的资源路径
比如:
// publicPath 设置
|
我们上述指定publicPath
为绝对路径,实际上,也支持相对路径,相对于index.html
,用的比较少。
publicPath
默认为空字符串,但为了使输出目录更加条理,推荐使用publicPath
对静态资源进行目录管理。
2.3 Loaders
Loaders 的配置写在module
对象中,如前所述,因为 loaders 最终返回的是有效 modules,故使用了module
命名,注意是单数。这节介绍 loaders 配置及常用 loaders 两部分内容。
2.3.1 loaders 配置
loaders 规则写在 module.rules
里面(不知道为什么不直接写在 module
中),其中 rules
是个数组,可接受一个或多个 loader 配置。两点需要注意:
1)如果某类型需要多个 loader 进行处理,在 use
中按 从右往左 的顺序流式处理;
2)每个 loader 可以进行额外配置。
module: {
|
2.3.2 常用 loader
- babel-loader:es6+语法转换;
- html-loader:解析 html 文件;
- css-loader:解析 css 文件;
- sass-loader:解析 scss/sass 文件;
- style-loader:将解析后的 css 嵌入 js;
- file-loader:解析图片文件;
- url-loader:具有 file-loader 的全部功能,同时可以提取小图片为 base64(如果开启 HTTP2 这样增大 静态资源体积反而不好?);
- postcss-loader:完成 css 自动化处理,比如添加前缀、压缩 css、自动生成雪碧图等
postcss 本身支持插件扩展,常用的有 autoprefixer、cssnano、postcss-sprites,更多参考官网介绍
要在 css-loader 之前处理 css:use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
Vue 相关
- vue-loader:解析 vue 文件;
- vue-style-loader:解析 vue 中的样式文件。
2.4 Plugins
同 loaders 一样,分配置和常用 plugins 两部分
2.4.1 plugins 配置
Plugins 使用相对简单,配置项写在plugins
(复数)数组中,元素为插件的实例(通过new
调用),生成实例的时候可接收参数,具体看相应插件文档。见下面代码及注释:
plugins: [
|
2.4.2 常用 plugins
- html-webpack-plugin:将构建后的静态文件动态插入 html 中;
- webpack-merge:实际项目中,一般将 webpack 配置文件拆分为 base、dev、pro,这个插件用户合并配置文件;
- webpack.HotModuleReplacementPlugin:热更新插件,webpack 内置;
- clean-webpack-plugin:清除指定文件夹,一般是构建的目录(大型项目慎用,更新需要时间);
- mini-css-extract-plugin:提取 css 文件,减小增量更新成本(需要在
module
代理 style-loader 处理 css);style-loader 先把 css 嵌入 js 使其变成有效 module,这个插件将 css 从 js 中分离出来。这个过程不矛盾,因为最开始 webpack 无法处理 css 文件,所以需要 css-loader, style-loader 处理,嵌入到 js 中的 css mini-css-extract-plugin 可以识别并提出。这个插件是 webpack 4.x 新引入,代替 extract-text-webpack-plugin。
- optimize-css-assets-webpack-plugin:将提取出的 css 做进一步优化;
- uglifyjs-webpack-plugin:不仅仅是压缩代码,还进行了 tree shaking 工作;
- webpack-bundle-analyzer:打包后文件图形化展示工具,一目了然各文件体积;
- ProvidePlugin:webpack 内置,提取第三方库的 api,比如通过
$
符号调用 jq如果不是通过 npm 安装,而是直接在项目中引入,需要配合
resolve
的别名使用,不然找不到
2.5 Mode
接受development
、production
、none
三个值,一般取前两个值之一,指定构建环境,webpack 本身会做相应优化(配合optimization使用,下文会有更多介绍),同时省去在命令行中指定构建环境的过程。
// 相当于 webpack --mode=production
|
2.6 其他
上述配置对应 Webpack 核心概念,除此之外,还有下面配置项很常用。
2.6.1 optimization
这个选项是在 Webpack 4.x 中引入的,最常用的配置是代替CommonsChunkPlugin提取公共代码。下面直介绍提取公共 JS 代码的配置:
optimization: {
|
2.6.2 devtool
devtool
最常用功能是配置 sourcemap,生产和开发环境一般使用不同的 sourcemap,配置如下:
// 生产环境
|
关于各配置项的含义可参考Devtool和这片文章Webpack 的 devtool 和 source maps。
sourcemap 是构建后的代码 map 到源代码的映射表,便于定位 bug,具体的映射关系存储在构建后的
.map
文件中。
NOTE: 这里我们在生产环境使用的是 source-map
选项而不是其他,是因为目前 webpack 在开启 uglifyjs-webpack-plugin 优化代码后,其他模式下的 sourcemap 选项无效,官网对此也有说明。虽然使用source-map
选项生成的映射表比较大,但只有开启开发者工具的时候.map
文件才会加载,这意味着 映射表文件的大小不影响正常用户的访问体验,但是否压缩 js 文件对正常用户有直接影响,故,现阶段,生产环境 devtool 使用 source-map
选项。
2.6.3 devServer
开发环境为了更好的开发体验,可以开启热更新等功能,在devServer
中配置:
devServer: {
|
需要在插件中进行下面配置:
plugins: [
|
NOTE:如果传统多页面项目,在入口文件后面添加下面代码,配合热更新:
// 配合 webpack 配置实现热更新
|
多页面目前只有在 JS 或者 CSS 文件改变的时候实现了热更新,如果是模版(html)文件改变,没有实现热更新(可以实现自动刷新页面,但感觉很鸡肋,如果改动了模版文件,手动刷新)。
devServer 还可以设置反向代理,后续填坑。
2.6.4 resolve
resolve
选项可以指定如何解析 modules,更多是通过设置 alias 告诉 webpack 去哪找文件解析。比如,如果在项目中通过文件的形式引入的 jq,那在使用 ProvidePlugin
对 jq 进行解析的时候,就需要通过设置别名的形式告诉 webpack 去哪找 jq 源文件。
resolve: {
|
3)常见需求详细配置
下面记录针对具体需求的完整代码描述。
3.1 引入第三方库
比如,jq,zepto 等,如果通过 CDN 可以在项目中直接使用 $
符号,但如果是通过 npm 安装到本地,甚至直接将第三方库源文件写在项目中,那是无法直接使用 $
符号这种调用方式的,需要使用上文介绍的 ProvidePlugin
插件。当然,还有细节需要注意,见下面详细代码。
3.1.1 使用 npm 引入
相对于直接引入,使用 npm 可以省去我们手动指定 module 路径的麻烦,已 zepto 为例:
使用 zepto 时,直接使用 ProvidePlugin 会报错,具体参考这片文章如何在 webpack 中引入未模块化的库,如 Zepto
// 处理 zepto 模块化问题,需要安装 exports-loader 和 script-loader
|
3.1.2 直接在项目中引入源文件
同 npm 不同之处在于我们需要手动指定 zepto 的路径,如下
// 设置别名
|
3.2 提取 css
为了能将 css 从 js 中提取出来,需要在 module
中将 style-loader 替换为 MiniCssExtractPlugin.loader,见下面代码:
module: {
|
3.3 缓存控制
主要一下几个方面:
- 提取 css,添加
contenthash
(使用mini-css-extract-plugin
); - 提取公共代码(工具函数等,更改频率相比业务代码要小),添加
contenthash
,使用 webpack 自带 splitChunks 提取; - 提取第三方库代码(比如 jquery,更改频率相比公共代码还要小),添加
contenthash
,使用 webpack 自带 splitChunks 提取; - 图片可以直接打
hash
(图片文件添加 hash 并不一样,也不会随每次构建改变,还不知原理,反正可以工作,待填坑)。