从零开始的中大厂前端项目落地(四)
我正在参加「掘金·启航计划」
从零开始的中大厂前端项目落地(四)
落地一个前端项目涉及非常多知识,因此从6个角度入手,化整为零,逐个击破:
- 选择合适的构建工具
- 定制团队代码规范
- 测试工具
- 封装自己的组件
- 自动部署
- 安全
深入构建工具
通过前面三章,我们的项目已具雏形。但是复盘了下前三篇,感觉对构建工具讲述的不够深入,所以在向前推进之前,打算再用一两篇文章来补充之前讲的不够深入的地方。
在前端构建工具泛滥的今天,webpack凭借统一资源构建模型以及极强的开放性稳稳地占据C位,可谓AKA构建大哥了。紧跟其后是Gulp、Vite、Rollup。
有很多同学觉得这些构建工具不必深入研究,日常工作中修改webpack配置的占比不高,想到用的时候再去看文档。其实不然,如果有空闲时间,还是有必要主动地对这些构建工具有更深的见解。
《从零开始的中大厂前端项目落地(四)》
将深入构建工具中的大哥webpack
,和webpack的亲儿子turbopack
,以及他们强劲的对手vite
。
由于篇幅有限,turbopack
与vite
留到下篇文章。
webpack构建工具
深入构建工具,本篇文章打算从两个方向向webpack入手,一是从webpack的底层工作流揭开webpack打包的流程,另一个则是从webpack的配置掌握其用法。
webpack的底层工作流
我们先来看下面这个图:
整个构建过程可以分成三个阶段,分别是:初始化阶段、构建阶段(编译阶段)、封装阶段。
简单总结起来,流程大概如下:
-
首先webpack会从shell语句中读取参数(如果有的话),再读取项目中的webpack.config.js文件,然后将所有参数结合,得出最终的参数。
-
接着将创建编译对象Compiler,以及将你的项目中webpack所需的插件实例化,在webpack事件流上挂载插件钩子。
-
然后根据配置的entry参数确定所有的入口文件,调用 compilation.addEntry 将入口文件转换为 dependence 对象。
-
确定入口文件后,初始化阶段结束。
-
开始构建阶段(编译阶段),根据入口文件进行依赖收集,对所有依赖的文件进行编译,调用 loader 将模块转译为标准 JS 内容,调用 JS 解析器将内容转换为 AST 对象,从中找出该模块依赖的模块,再 递归 处理这些依赖模块,直到所有入口依赖的文件都经过了本步骤的处理。
-
所有依赖的文件都被处理过后,构建阶段结束。
-
开始封装阶段,就是将编译后的内容重新打包,输出到配置好的output中。
需要强调的是,在构建过程中,webpack和插件都采用基于事件流的发布订阅模式,监听某些构建节点,并在这些环节中执行plugin等任务。
从上面webpack整个执行过程中可以看出,三个阶段都有各自的重点,缺一不可,但是构建阶段(编译阶段)却是重中之重,下面来细看编译过程:
webpack的配置
webpack的配置非常繁多,很多人只在项目初期使用,使用的时候还得查阅文档,但是过一阵子不用的话又会忘记。我个人记性不好,只能把配置抽出来,做成脑图,以备后续之需。
下面来看看webpack的基本配置:
-
输入输出,可以在这里配置webpack的入口起点和产物输出路径。
-
后处理配置,包括mode、optimization、target,这三个配置项都是跟产物有关:
-
其中mode负责声明环境变量,例如prod,则输出压缩后的产物
-
optimization用于webpack的代码压缩、混淆等,从webpack4开始会根据mode执行不同优化,但是所有优化还是能手动配置
-
而target用于配置编译产物的目标运行环境,支持 web、node、electron 等值,不同值最终产物会有所差异
-
-
开发类配置,常见的devServer、devtool、watch,在本地开发环境相关
- devServer用于开启HRM热替换,使得开发变得更丝滑
-
性能优化配置有performance、cache等
编译阶段相关的配置
除了以上的配置,还有与构建阶段(编译阶段)相关的配置:
这几个配置项是我们日常与webpack打交道最多的几个
- resolve配置,配置模块解析,用法如下:
// webpack.config.js
module.exports = {
//...
resolve: {
// configuration options
},
};
常用的有alias、extensions、fallback、mainFiles、modules、plugins、cachePredicate、roots
字段 | 描述 | 解析 |
---|---|---|
alias | 使用别名 | 通过resolve.alias.util:path.resolve(__dirname, 'src/util/')设置util别名 |
extensions | 指定解析顺序 | 如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀 |
fallback | 重定向模块 | - |
mainFiles | 解析的文件名 | - |
modules | 解析的模块 | - |
plugins | 额外的插件 | - |
cachePredicate | 是否缓存 | 决定请求是否应该被缓存的函数。函数传入一个带有 path 和 request 属性的对象。 必须返回一个 boolean 值 |
roots | 解析的目录 | - |
- module就是用来处理不同类型的模块,先来看看module有哪些配置项:
字段 | 描述 | 解析 |
---|---|---|
generator | 使用生成器 | 统一设置rules.generator |
parser | 使用解析器 | 统一设置rules.parser |
noParse | 忽略文件 | - |
unsafeCache | 缓存解析 | - |
rules | 解析的模块 | 配置模块的规则,使用频率最高的配置项 |
rules的配置项又可以分为三类:匹配规则(条件)、处理模块
-
匹配规则(条件)
-
test(与resource.test冲突)
-
test以字符串、正则表达式、函数、数组去匹配资源
-
字符串匹配绝对路径
-
函数返回值也为绝对路径
-
正则匹配到的资源
-
数组可以传入多个,以字符串、正则、函数组成
-
-
-
exclude(与resource.exclude冲突)
- 排除exclude以下任何条件的模块,规则和test一样
-
include(与resource.include冲突)
- 引入符合include以下任何条件的模块,规则和test一样
-
resource,更具体的筛选资源项
- resource里面也能配置test、exclude、include
-
resourceQuery,更具体的筛选资源项,与resource的区别是resourceQuery匹配Query
-
schema
-
type,匹配文件类型
- type可以设置的值:'javascript/auto' | 'javascript/dynamic' | 'javascript/esm' | 'json' | 'webassembly/sync' | 'webassembly/async' | 'asset' | 'asset/source' | 'asset/resource' | 'asset/inline'
-
-
处理模块
- use可以用字符串、函数、数组传入一个或多个loader
- resolve可以配置该模块层级的解析,而不采用全局resolve解析
- plugins,webpack的插件配置项,plugins是webpack的核心。plugins接收一个数组,用法如下
下面看看webpack的一些小技巧
最后,让我们一起加油吧!
参考资料:
webpack.js.org/ 2022.stateofjs.com/en-US/libra… juejin.cn/book/711559…
转载自:https://juejin.cn/post/7246641306893303866