那些简单而又复杂的工具链
小麦2024年08月23日2229 字
前几期我们介绍了现代前端开发必知的,计算机网络和前端编程语言相关的内容,
本期我们进入前端工具链的话题。
在以前,制作一张网页可能只需要一个文本编辑器,
而在现代,完成一个非常简单的前端应用,就要用到十几种工具,为什么事情变得越来越复杂了,前端真的是差生文具多吗?
工具链(Toolchain)通常指的是一组用于软件开发的工具和技术,
帮助开发者管理好从源代码到最终软件的整个开发过程。
对于前端来讲,这些工具通常包括集成开发环境、包管理工具、构建工具、调试工具、持续集成与部署(CI/CD)工具等。
现代前端通常使用 VSCode 作为集成开发环境,这不仅仅是因为它具备良好的开发体验,
还得益于它强大的插件生态,让一些比较新的语言或开发工具也能很方便地集成进来。
前端开发中的很多任务都可以在 VSCode 中的一站式完成,比如使用版本控制系统 Git、管理 NPM 包和脚本、调试 Node.js 程序等等。
另外,还有和本地 VSCode 非常相似的云 IDE,比如腾讯的 Cloud Studio、华为的 CodeArts 和阿里云的 Cloud IDE 等等,它们核心解决了本地环境和集成环境的一致性、三方代开发数据安全、协作和共享等问题。
包管理是现代软件开发绕不开的话题,
自从前端开始采用模块化开发后,
以 NPM 为代表的包管理器也应运而生。包管理的核心是代码组织与复用,这也是开发中大型项目所必须的要求。
现代前端的包管理工具有几个代表:npm、yarn 和 pnpm,它们各有特点。
npm 是最早出现的包管理器,也是 Node.js 默认自带的包管理器,被广泛采用,兼容性最强,但速度比较慢。
yarn 通过并行安装和缓存,解决了 npm 速度慢的问题,但资源消耗较大。
pnpm 后来居上,采用共享依赖模型,同时解决了 npm 和 yarn 的问题,但兼容性问题较多。
可以看到每一代包管理器都会解决上一代的问题,又快又省是包管理器的核心演进方向。
我们应该知道,前端有一个数量相当庞大的软件生态,大到一个工具、小到一个函数都可以做成一个包。
许多包又直接或间接依赖另一些包,再加上版本不同,因此包管理其实是一件相当复杂的事。
虽然开源包管理工具,已经很好地解决了安装速度和资源消耗问题,
但企业级的包管理还可以做更多事情。
比较典型的场景是应对供应链污染,前端项目的直接供应商是 NPM 仓库。一个带有 bug 的包发布后,会导致本地或持续集成环境产生问题,轻则构建失败,严重时还有安全问题。
因此企业级包管理器会在开源包管理器的基础上,增加对 bug 包的黑名单控制。
例如 cnpm 的 bug-versions 就是维护了一套黑名单,每次 cnpm 安装时都会检查和避免安装问题包,而不需要开发者改动项目代码。
另一个案例是,企业级包管理器可以通过网络 IO 优化、FUSE、OverlayFS 文件系统、文件 IO 优化等跨领域技能,进一步加速依赖安装,这也是目前开源方案没有做到的。
包管理有两个主要模式,单包管理和多包管理,我们最常用的是单包管理。
多包管理适用于在一个代码仓库里管理多个包,相比单包管理,可以很方便地共享依赖、跨包复用代码、进行联合调试和发布等等。
现代前端通常采用 Monorepo 的方式管理多包,比如 npm 自带的 workspace 模式、开源方案 Lerna 和 Rush 等等。
说完包管理,我们接着说说构建工具。前端构建工具的出现时间其实比较晚,首先是基于 Task Runner 的 Grunt(2010)和 Gulp(2013),以及模块化打包工具 Browserify(2011)、Webpack(2012)和 Rollup(2015),然后是现代的 Parcel(2017)、Vite(2020)、Turbopack(2022)和 Rspack(2023) 等。
现代前端构建工具通常包含代码转译器、优化器、打包器、开发服务器和插件系统。
转译器,有的也叫代码转换器(Transformer)或者直接叫编译器(Compiler),它们都是将源代码转换为目标平台能够直接运行代码,同时让一些比较新的语言特性能兼容旧的环境。比如箭头函数到普通函数的转换、JSX 到 JS 的转换、Less 到 CSS 的转换等等。
优化器是将转译完成的代码进一步优化,比如压缩、混淆和分割,以提升传输效率和安全性。
打包器是将转译好的代码合并到一块,它通常会内置转译器以及优化器,从源代码到最终产物,一站式完成。
开发服务器提供一个本地的 HTTP 服务器,通过 HMR、传输原生 ES 模块、接口代理等功能来提升开发体验。
插件系统是功能扩展的主要方式,可以灵活地改变整个构建工具的行为,来实现定制化需求。
近些年,前端构建工具的大趋势是极致整合以及使用 Rust 重写核心模块。
极致整合是为了减少学习负担,如果你是 webpack 时代的开发者,一定体会过一遍遍配置 babel 插件、webpack 插件的痛苦,而现代工具全部帮你搞定了。
使用 Rust 重写是为了显著提升构建和打包效率,你可能还体会不到改一行代码,持续集成要等十分钟,内存 OOM,业务方还拼命催上线的痛苦。
而基于 Rust 的构建工具能很大程度上缓解集成压力,提升工程师的幸福感。
现代构建工具是简单而又复杂的,
简单是因为它对开发者屏蔽了许多内部细节,比如基本都内置了诸如 HMR、转译工具、CSS 预处理器等工具,配合脚手架用起来很简单,你得庆幸刚入门就用上了它们。
复杂是因为它们有的选择兼容 Rollup 生态(Vite),有的选择兼容 Webpack 生态(Rspack),有的则另辟蹊径(Turbopack),这导致它们的底层架构大不相同,如果开发者要深度定制,则会面临许多取舍和困难。
现代前端针对不同场景,会用到不同的调试工具:
浏览器开发者工具,用于普通 HTML 页面的 UI、网络、性能调试,比如 Chrome DevTools、Safari Web Inspector 等。
小程序开发者工具,用于小程序模拟和真机调试。
接口调试工具,比如 Postman、Charles 等等。
框架自带的调试工具,比如 React Developer Tools、Vue Devtools 等,它们可以展示更为直观的虚拟 DOM 结构和组件状态。
一个健壮和可靠的软件研发流程,离不开持续集成(CI)和持续部署(CD),CI/CD 在现代前端也是必不可少的。
它并不复杂,相比以前蛮荒时代,现在我们可以借助 Github Action、Travis CI、Jenkins 等免费的工具或平台来轻松完成这些事情。
更多内容,后续会在单独一期视频中展开,可以关注我们的网站 front-talk.com 获取更新计划。
本期我们介绍了现代前端工具链的主要成员,下一期我们来聊聊各式各样的用户界面(UI),点关注不迷路,我们下期再见。