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归类的文件名,
publicPathhtml 引入 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 输出的outputfileanem 文件
一下一个简单的 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 | |