webpack
开始,请允许我吹一波,last-order,yyds 大佬的掘金juejin.cn/user/366762…
1 编译流程
-
创建 Compiler 编译对象
-
确定编译环境
-
初始化entryOtions,解析入口文件,构建依赖树
-
初始化内部解析
-
决定以什么样的方式开始编译
-
开始对文件进行编译
-
对每个模块创建Compilation
- Compilation 会对依赖树的模块进行编译,可以在编译期间被加载、封存、 优化、分块、重新创建
-
编译结束
-
输出文件
-
编译完成
2 编译优化
-
优化分析
- 体积分析:webpack-bundle-analyzer
- 速度分析:speed-measure-webpack-plugin
- 日志分析:webpack --stats
-
优化方案
- 使用dllPlugin
- babel-loader添加cacheDirectory
- 使用thread-loader优化loader
- 使用高版本node和webpack
- 开启tree shaking和scope hoisting
- webpack5配置长缓存
- 使用css-minimizer-webpack-plugin压缩css
- 使用terser-wbpack-plugin压缩js,并去掉无用的js
- webpack5的module-federation
- split chunks 分包
3 HMR
- webpack-dev-server在启动的时候会给entry去注入webpack/hot/dev-server
- 注入wbpack-dev-server/client/index.js
- 判断是否存在webpack.HotModuleReplacementPlugin (作用:这个插件会注入一个module.hot的一个对象,该对象提供了一些方法,用于更新)
- 监听webpack hooks的compile(编译)、done(编译成功) 、invalid (编译失败)钩子
- 初始化express、webpack-dev-middleware
-
启动express、socket服务
- socket服务主要是用于监听一些特定的事件进行更新处理
- webpack-dev-middleware会以watch的形式监听文件更改,当文件发生变化的时候,会生成xxx.hot-update.js(当前的文件)和xxx.hot-update.json(下次更改的hash),调用location.reload() 刷新页面
4 tree shaking Tree Shaking | webpack 中文文档 (docschina.org)
- 基于es6的模块机制实现,主要是因为es6的模块是静态的,可以被webpack解析,而require、import是可以动态的
- 如果有些模块有副作用需要在package.json设置sideEffects: false
- 副作用:在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export
5 模块解析规则 模块解析(Module Resolution) | webpack 中文文档 (docschina.org)
- webpack 通过 enhanced-resolve 对模块进行解析,支持绝对路径、相对路径、模块路径
6 核心
-
mode
- development
- production
- none
-
entry
- 入口文件
-
output
- 输出的路径
-
loader
- webpack只支持js进行编译,而其他文件都需要通过loader进行转换,loader本质是个函数,每个loader都会拿到上一个loader所处理的结果,并在当前loader进行处理,然后并返回,传递给下一个loader。
- 可以通过loader-runner进行调试,schema-utils对loader的参数进行校验
- Loader Interface | webpack 中文文档 (docschina.org)
-
Hash
-
hash
- 每次构建都会生成新的Hash,并且所有 chunk 一样
-
chunk hash
- 每次构建如果文件发生变化则生成新的Hash,否则不生成,但是如果引用 css 文件,依然会导致 hash 重新生成
- chunk hash 根据入口的文件进行递归依赖解析,从而生成对应的 hash
-
content hash
- 每次构建生成新的Hash,如果 css 发生了变化,js则不重新生成,css 则生成 hash
- content hash 根据文件内容生成,推荐使用
-
- external 用来过滤模块
-
target
- web
- node
-
plugin
-
作用
- plugin 的作用是监听 webpack 的生命周期,在对应的生命周期进行相应的处理
-
原理
- plugin是个类,需要提供一个apply方法,apply内接受compiler对象,compiler是webpack构建期间所生成的编译对象,可以通过监听compiler.hooks.xxx.tap 或者tapAsync,来实现插件,其中还有一个重要的对象是compilation,而compilation是webpack每次产生新的构建就会生成的一个对象,其中compiler在整个构建期间只会有一个,而compilation会有多个。
- compiler和compilation都继承于tapable,而tapable其实是类似于node的eventEmitter的一个库,插件主要就是通过compiler或者compilation对webpack的构建周期进行各种处理的一个方式。
-
tapable
- 同步
- SyncHook
- SyncBailHook
- SyncWaterfallHook
- SyncLoopHook
-
异步
-
并行
- AsyncParallelHook
- AsyncParallelBailHook
-
串行
- AsyncSeriesHook
- AsyncSeriesBailHook
- AsyncSeriesWaterfallHook
-
-
类型
-
bail
- 当前函数有返回值,就停止执行
-
waterfall
- 调用时,值会传递给下一个函数
-
loop
- 当返回true表示继续循环,返回undefined结束循环
-
-
注册方式
- 同步通过tap进行注册,异步通过tapAsync、tapPromise
-
调用方式
- 同步通过call进行调用,异步通过callAsync、promise
-
-
如何检测xx插件是否存在
- 遍历插件,判断 plugin 的 constructor.name 属性即可
\