webpack学习笔记
内卷, 内卷害了所有人
2021-06-06 updated: 更多配置案例可以参考官方例子
对 webpack 的配置做个笔记,后续不定期补充, 也会补充的 webpack 源码的学习
mode
mode 分为development
,production
,none
, 不配置默认为production
, 构建时抛出警告 ⚠️
performance
webpack 会抛出必要的影响性能的警告, 可以通过置为false
屏蔽警告
entry
可以是单文件入口和多文件, 有多少入口文件就会构建出多少文件
1 |
|
output
filename
中 name 为入口文件的key
, 字符串形式时 name 为 main, hash,chunkhash,contenthash 区别见hash, chunkhash, contenthash 区别
chunkFilename
针对的是那些间接引入的文件,即非 entry 指定的文件, 命名以chunkFilename
为准, [name]
为splitChunks
归类的文件名,
publicPath
html 引入 output 的 js 是的前缀路径
1 |
|
loader
webpack 默认只支持解析 js 和 json 文件, loader 用于解析不同后缀名的文件, 对于同一种文件类型使用多个 loader 时遵从从数组右向左解析原则, 写在module.rules
中, 这里看几个常用的 loader
babel
用于将 ES6+新语法转化成 ES5 语法, 需要配合@babel/preset-env
和@babel/core
使用. 对于 Promise, Map,Set 等新的 api 还需安装@babel/polyfill
, 然后在入口文件开始引入, 也可以通过 entry 数组形式引入
1 |
|
css
一般搭配这些 loader 一起使用,
sass-loader
(optional)解析 sass 成 css,相应的有(‘less-loader’, ‘stylus-loader’),postcss-loader
为 css 加上产商前缀, 增强兼容性,css-loader
解析 css,- 还有三个根据环境及框架选一个使用,
style-loader
开发环境下使用, 将 css 通过<style>
标签的方式引入 html,vue-style-loader
解析 vue 模板中的 css,MiniCssExtractPlugin.loader
生产环境下使用, 会将 css 文件单独打包,防止 html 文件过大
postcss-loader
需要配合autoprefixer
使用, 在当前项目根目录下新建postcss.config.js
引入autoprefixer
, 同时在package.json
添加browserslist
字段指定覆盖的浏览器, 新版本不支持直接内联在 webpack.config.js 中的写法
1 |
|
1 |
|
如果要使用 MinCssExtractPlugin
需要下载插件并配置
1 |
|
图片&多媒体
使用url-loader
和file-loader
, 两个 loader 区别在于url-loader
在文件大小未超过设置的阈值时会将文件转化成 base64 编码, 可以使用url-loader
, 超过阈值再使用file-loader
1 |
|
vue
vue-loader
专门用于处理 vue 文件
1 |
|
typescript
ts-loader
专门用于处理 typescript 文件
1 |
|
optimization
这个字段可以配置一个对象, 这里介绍几个重要属性(后续补充)
usedExports
开启 tree shaking, 去除未被 import 的逻辑.
对于例如.css 这类文件, 不存在具体 import 内容, webpack 默认也会把它 shake 掉, 需要配合package.json
配置的sideEffects
使用, sideEffects
维护一个数组告诉 webpack 不要对其中的文件进行 shake
在开发环境下(mode: ‘development’)下, 即使开启了 tree shaking
1 |
|
splitChunks
- type:
boolean
开启 code splitting 代码分隔, 设想以下场景, 文件中引入 lodash(假设 1MB), 业务逻辑(假设 1MB), 如果不进行代码分隔, 每回业务逻辑发生改动都会构建出 2MB 的文件, 用户每次请求都要请求 2MB, 但实际上 lodash 逻辑并没有发生改变, 这就产生了不必要的开销, 所以可以通过代码分隔将文件进行拆分为两个文件(库文件+业务逻辑文件)
tips:
魔法注释: 异步 import 是可使用, 可以设定 preload/prefetch, chunkname 等配置, 参考魔法注释
下面介绍一些重要属性(待添加)
chunks
- value: ‘all’ | ‘async’ | false
all
对同步异步的 import 都进行代码分隔,async
则只对异步 import 进行代码分隔.
但是如果cacheGroup
组中未匹配且default
为false
, 则chunks
不会对该文件进行代码分隔
minSize
- value: number
进行代码分隔的 import 包大小, 单位 Kb
maxSize
- value: number
一般不配, 是对代码分隔的包进行二次拆分的阈值(如果可以), 单位 Kb
minChunks
- value: number
最小引入次数, 即 如果 lodash 制备引入了一次则不进行代码分隔, 2 次+就会进行代码分隔
maxAsyncRequest
- value: number
一般也不配, 最多对 X 个 import 包进行代码分隔, 假设引入了 10 个包, 只会对前 5 个包进行代码分隔
automaticNameDelimiter
- value: string
当未指定cacheGroup
组中filename
时作为代码分隔生成文件名中间的连接符, 文件名命名规范为${cacheGroups匹配组的key(未匹配默认为default)}${automaticNameDelimiter连接符(默认为~)}${当前文件所在entry的key}.js
(疑惑: 如果相同的库被不同 entry 引用?)
cacheGroup
cacheGroup
的每一个属性都作为一个组, 对于每个组中test
匹配到相同正则的 import 包会打包到相同的组.
对于没有匹配到的包, 默认兜底到 default 组中, 不配置cacheGroup
时默认会存在一个匹配 node_modules 的 vendors
组.
reuseExistingChunk
则是配置是否服用之前已经缓存的相同包内容.
对于匹配到多个组的包, 会根据 priority
优先级大小分到优先级最高的组.
需要注意的是, cacheGroups 中配置的字段优先级大于外层 splitChunks 相同字段的值~
1 |
|
resolve
alias
import from 路径的别名, 例如import Cmp from '@/components/home.vue
会被解析为import Cmp from '/your/project/root/path/src/components/home.vue
.
如果项目中使用了 typescript, 要使用 alias 别名, 需要同时在webpack配置文件
和tsconfig.json
配置别名, 旨在tsconfig.json
配置是不生效的.
1 |
|
extensions
缺省后缀, import from 路径缺少后缀时, webpack 会在该目录下从左向右寻找符合的文件
1 |
|
mainFiles
缺省文件名, 这回文件都不用写了… import from 路径最后一级为目录时, webpack 会寻找目录下和 mainFiles
匹配的文件名
1 |
|
devServer
暂时用的不多, 可以参考webpack 开发服务器 devServer
Plugin
HtmlWebpackPlugin
入口文件要挂载的 html 路径, 配置new HtmlWebpackPlugin
默认会将 entry 所有入口文件都引入 html, 生成单页面, 如果要生成多页面只需配置多个new HtmlWebpackPlugin
并且配置对应的 chunk 即可
1 |
|
CleanWebpackPlugin
每次构建时先清空 output 目录上次构建的产物, 保证 output 目录构建产物都是最新的
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
1 |
|
MiniCssExtractPlugin
上面已经描述过了, 用于生产环境下剥离 css 文件, 降低耦合
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
1 |
|
VueLoaderPlugin
const {VueLoaderPlugin} = require('vue-loader')
1 |
|
HotModuleReplacementPlugin
内置插件, 热更新
1 |
|
ProvidePlugin
当在文件中使用了插件中配置的库或者库函数时, webpack 会自动引入
1 |
|
DllReferencePlugin & DllPlugin(已被 vue 和 react 废弃)
虽然被废弃了, 但还是写一下 orz, 推荐使用 HardSourceWebpackPlugin
上面说到 code splitting 可以通过splitChunks
实现, 但对于库文件, 大部分时候是 不会更改的, 而 webpack 每次打包时都会根据splitChunks
配置打包库文件, 这其实是没有必要的, 所以可以单独配置webpack.dll.js
文件, 用于打包库文件, 这样第一次打包后后续打包就不会再次打包库文件了
DllPlugin 作用于 dll 文件, 用于生成 manifest 文件作为打包前后库文件的映射, 后续打包时 webpack 检测
webpack.dll.js
其实就是一个 webpack 配置文件, 只不过针对的对象不同. 这里给出一个webpack.dll.js
的配置 demo.
1 |
|
DllReferencePlugin 作用于 webpack.config.js, 通过比对 manifest.json 映射文件不进行打包命中的库文件
1 |
|
AddAssetHtmlWebpackPlugin
将资源文件插入 html 中, 作用于HtmlWebpackPlugin
之后, 上面说的 dll 打包的库文件就可以这样引入
1 |
|
ScriptExtHtmlWebpackPlugin
不支持 webpack5, 配合html-webpack-plugin
使用, 支持异步加载 JavaScript 文件
webpack 打包 npm 包
webpack 打包库文件需要在output
额外加上library
和libraryTarget
属性, 并且将package.json
的main
入口文件修改为 webpack 输出的output
fileanem 文件
一下一个简单的 npm 包的 webpack 配置, 注意以下几点:
libraryTarget
表示使用的场景,umd
表示通用版本, 可以import(esmodule)
引入, 可以require(CommonJS)
引入, 也可以通过<script>
标签引入- 如果要直接在 html 中通过 script 引入需要指定
library
, 比如示例中指定library: 'library'
, webpack 就会将 export 内容绑定到window.library
上 - 如果 npm 包中使用了其他的库,比如 lodash, 业务场景中也使用了 lodash, 就会打包出两份 lodash, 这不合理, 可以指定
externals
不让 webpck 打包 npm 包时打包 lodash - 在 node 中导入时可能会遇到
self is not defined
报错, 需要设置globalObject
属性
1 |
|
common development production
可以新建webpack.dev.js
和webpack.prod.js
分别存储开发环境和生产环境的配置, 最后通过webpack.common.js
存储通用配置并且通过判断当前环境输出最终配置.
webpack 除了可以输出对象, 也可以输出函数, 参数为环境变量, 函数返回配置对象
env 动态配置环境
1 |
|
hash,chunkhash,contenthash
hash
表示整个构建产物的 hash 值, 多文件入口中即使只修改了一个文件, 另一个文件未作修改, hash 值也会发生改变, 多文件构建产物的 hash 值都是一样的
chunkhash
顾名思义,表示块的 hash 值,即单独入口文件构建产物 hash 值, 互相不影响, 但是如果一个 js 文件中引入了 css 文件, 当 css 文件发生变化时, 该 js 文件的 hash 值也会发生改变, 多文件构建产物的 hash 值不影响
contenthash
则是在chunkhash
的基础上忽略文件中引入 css 文件产生的变化, 仅在自身内容发生变化时改变 hash 值
详情参考segmentfault
1 |
|