前言:7月4日,字节跳动Web开发引擎负责人杨扬(dexteryy)在 GMTC 全球大前端技术大会(北京站)2021 上又搞了一场「跨年演讲」(内容超多的意思),不但现场爆满、超时严重,而且一如既往的讲完之后只要把讲稿和幻灯片拼起来就能发出来,大家可按需取用。
亮点:为了方便大家理解,杨扬(dexteryy)同学为这次分享画了 90 张图(工具是 Keynote),其实在内部版《Modern Web Stack》里有 120 多张图…
可以看到幻灯片上的标题,跟会议日程里的标题有些不一样,「现代 Web 开发」这几个字加上了引号,做这个修改是因为,原文很容易被断句成「现代的,Web 开发实践」,「现代」看上去只是一个普通的形容词,其实「现代 Web 开发」是作为一个整体的专有名词,来代指现在全球技术社区和全行业里,越来越重要的一个「大趋势」(Megatrend)、一场正在进行中的「范式转移」。
今天这场分享的主题,就是字节跳动如何把「现代 Web 开发」转化成具体的技术栈和研发工具体系,在内部广泛落地和从中获益。
这次分享的内容可以分成三个部分。
第一部分,先整体回顾「传统 Web 开发」范式中的「前端开发」技术和工程体系,有哪些瓶颈问题。
第二部分,对于在这些问题的背后、在这些问题的驱动下,正在发生的转变,做一下归纳和比较。
第三部分,介绍字节跳动在落地和推动这种转变中,发展和建设出的技术体系。对于字节这个「App 工厂」来说,这种发展相当于一场「引擎升级」的过程。
大家都知道字节跳动在业界有一个既含贬义也含褒义的外号,叫作「App 工厂」,如果我们从软件研发的角度来看待这个外号,那其实在字节内部,各种产品、工具、软件应用的开发,比大家从外部看到的更像「App 工厂」:无论数量还是多样性,形态和场景的丰富度,都是非常高、海量的。
而这些软件项目中,基于 Web 技术、前端技术的,占了大部分(这并不是因为字节有特殊的技术选型,而是行业的大背景和必然规律,我在19年一次关于「现代 Web 开发」的分享里有介绍过)。
由于字节有这种特点,所以前端技术和工程体系中的问题和瓶颈,在字节会体现的很全面、很典型,很多时候也会体现的更明显。
- 现代 Web 开发的现状与未来:https://zhuanlan.zhihu.com/p/88616149
传统的前端技术体系,无论在字节内部,还是在全行业,都可以总结为图上这个样子。
图中从下到上,代表抽象层从底层到顶层。最右边三个方块,都从最下面延伸到了最上面,代表它们都是端到端的解决方案,跟左边的体系,以及彼此之间,都是割裂的,包含大量重复,这次分享因为时间关系,不讲这几个部分。
蓝色的方块都是代码层面的,绿色的方块都是平台层面的。
这套体系是字节曾经的主流,是从业务中自然发展出来的,但随着这种发展趋于停滞,这套技术栈正在同样自然的演变成历史遗留的「祖传技术栈」,其中每个部分都有比较大的瓶颈问题。
我们逐个看一下图里的每个问题域,首先是大家最熟悉的「前端脚手架」。
不管哪种形式的脚手架,本质都是复制粘贴一堆样板代码,组成新的项目。
虽然跟建筑行业使用的脚手架一样,都是在搭建过程中使用,用完就放到一边,只留下搭完的项目。但建筑脚手架拆掉之后留下的建筑,有一套不能动的钢筋混凝土骨架,而脚手架生成的前端项目,是混杂在一起的样板代码,虽然有文件结构,但可以随意修改,而且因为基建和示例代码混在一起,所以不仅是「可以改」,而且经常是「必须改」样板文件的内容和结构,才能完成真实项目的完整搭建。
假设一个脚手架包含 A、B、C 三块功能,用这个脚手架创建出的三个项目,最初都是一样的,也都包含 A、B、C 功能。
接下来,三个项目必然需要在脚手架的生成结果上,做各种增删改,可能是因为业务需求,也可能是因为技术沉淀和工程改进。时间长了之后,三个项目之间会差别非常大,如果要做统一的改进,或者把一个项目的沉淀和改进,应用到另一个项目里,都会很困难。有时甚至要推迟需求开发,先对这些项目做一轮统一的重构,但这也只能应付眼下,之后这些项目仍然会继续分裂和腐化。
另一方面,脚手架本身也在迭代改进,但因为脚手架是一次性的,一用即抛,这些改进不能对原先创建的项目带来好处,引入这些改进的成本,跟从其他项目里引入改进的成本差不多。
进一步看看脚手架中「项目模板」的问题。
脚手架的必然结果,是需要各种项目模板。不但脚手架建设者需要提供多种模板,覆盖不同的需求,使用者也经常需要复制原有模板,修改成新的模板,比如产品的技术形态是 SPA 还是 MPA,都会产生不同的模板。
图上每个方块,都代表一个真实存在的模板,可以看到这些模板中有大量重复、又不会完全相同的内容,升级维护模板、在模板之间同步技术沉淀,都有成本。很多模板会缺少更新,长期停滞,把成本留给搭建项目的人
如果从项目场景的角度出发来设计和维护模板,也有相同的问题。图中的方块是一些最基础、最典型的场景,和场景中的技术需求,可以看到,不同场景之间的技术需求,重合度很高。
除了场景类型,一个项目还有很多类型维度,图中的每个方块,代表一种维度,比如按照图上的第三种维度,不同项目之间仅仅因为「组件库」和「设计系统」不同,就要设计和建设不同的模板。
这些维度之间的排列组合,要么会导致模板进一步分裂和数量爆炸,每种模板的维护成本更高,应用场景更小,ROI 因此变低,更加倾向于停滞;要么会导致模板对很多维度中的需求,不做考虑,只覆盖小部分需求,对项目开发的支持,局限在比较低的水平。
「传统技术栈」的第三个问题域,来自前端工程化建设中常见的对 Webpack 的「包装」。
为了避免每个前端开发者都成为「Webpack 工程师」, 很多脚手架、工程化建设,都会对 Webpack 做图上这样的包装,在最上层,提供围绕编译构建的两个命令 dev 和 build,搞出不同「规范」的配置文件和插件机制。
这种包装的第一个问题,是抽象程度很有限,配置 API 的设计也五花八门,体现不同的个人偏好和业务经验,这种配置虽然被称作「规范」,但在真实业务项目中存在感不高,业务项目还是要直接靠 Webpack 来解决很多问题,项目中包含很多 webpack 配置,脚手架模板也包含大量相关的样板代码,避免不了前面说的问题。
图中这段话来自 Redux 作者 Dan 写的一篇文章,讲 JS 工具的配置 API 的设计,这段话就是在讲这方面的抽象和设计能带来巨大的影响,有很高的门槛,需要非常严肃专业的对待,这种工作也需要高度的集中,而不是交给「Webpack 工程师」们搞各种各样的「规范」。
- The melting pot of JavaScript: https://increment.com/development/the-melting-pot-of-javascript/
业务项目深度依赖 Webpack、包含很多 Webpack 配置,还带来另一个问题:
JS 开发工具从去年开始又出现新一轮更新换代的征兆,有人把这种趋势称作 「JS 的第三纪元」,新范式的项目涌现,开始进入到日常业务的开发实践,很多场景下已经没有 Webpack。
- The Third Age of JavaScript: https://www.swyx.io/writing/js-third-age
图中右侧的 esbuild 和 swc 这样的构建工具,把编译、构建、打包、压缩等在 Webpack 里属于不同环节的部分,合并在一起,加上非 JS 的系统编程语言的帮助,大幅提升构建速度。另一方面,也能支持 ESM 优先的、不需要打包的构建场景。
Snowpack、Vite 这样的工具,在此基础上实现了开发者体验(DX)优先的、不打包(Unbundled)的开发调试模式。
这些工具和模式跟 Webpack 的设计有一些本质矛盾,目前已经被用于公共库的构建、业务项目的开发调试等真实场景里。
基于 Webpack 包装的工程化建设,第三个问题是:对项目开发的工程支持只停留在比较低的水平,比如就像 dev 和 build 命令一样,局限于跟编译构建有关的环节。
而随着行业和业务的发展,随着前端技术的发展,一个前端工程的完整需求,就像图中一样,会包含蓝色方块代表的整个研发链路的每个环节,以及每个环节下面,绿色方块代表的工程需求。这些都超出了 Webpack 的能力范围。
刚才说的这个问题,其实也是传统前端工程化建设本身的问题。
传统的工程化建设,就像图中文字说的,只能实现「代码层面」的基础建设,在创建项目的时候,做的事情大部分都属于「代码初始化」。
现代的 web 工程和前端工程,越来越多的包含「代码层面」之外的「平台层面」。
图中绿色方块代表的,是靠「代码层面」来实现工程需求,橙色方块代表的,是要靠「平台层面」才能更好实现的需求。
第五个问题域是,很多前端开发场景,比如像字节内部的前端开发,都在统一收敛到 React 技术栈,但 React 本身也是有局限的。
在 Web Infra 部门建立之前,字节内部的业务方向,比如今日头条和抖音,就已经在推进统一到 React 技术栈,目前字节的现代 Web 研发体系建设,也有意收敛和围绕着 React 来进行。
选择 React 的原因可以归纳为图上这四个,其中,符合技术趋势,设计演进更快,走在最前面,这两点让 React 在基础建设中,在有基础建设团队支持的业务场景中,都具备很大的优势。
图上高亮的这句话,很好的表达了 React 引领业界和社区发展的特点。
刚才在选择 React 的原因里,还提到 React 庞大的生态红利或验证规模。图中可以看到,在比较贴近实际使用情况的依赖下载数据里,React 在绝对数量遥遥领先的情况下,增长势头也是更快的,React 生态下的 CRA、Next.js,单独拿出来都达到或接近其他非 React 技术的使用量。
-
https://www.npmtrends.com/@babel/preset-react-vs-@vue/cli-shared-utils-vs-next-vs-nuxt-vs-react-vs-react-scripts-vs-vue-vs-vue-loader-vs-vite
这种生态和规模上的差距,在国内环境中也回避不了,国内 JS 开发者的数量差不多是全球的十分之一,所以单靠国内开发者,影响不了整个行业和技术社区的生态和基建,导致在业务支持和工程建设中,React 目前都无法取代。 -
「全球的 JS 开发者已经上千万了」:https://zhuanlan.zhihu.com/p/111204309
但在工程体系中只靠 React 自己是远远不够的,React 本身只解决视图层的问题,距离一个 Web 框架还缺很多东西,在框架层面上,React 是无偏见的,比如没有限制路由实现、组件类型、SSR 解决方案等,也没提供默认的配置和工具体系,跟一个真正框架的必备要素,是完全相反的。
- Advancing the web framework ecosystem (Chrome Dev Summit 2019): https://youtu.be/QDljY2I1Pfw
由于 Webpack、React 都不解决全链路的问题,缺乏框架级别的解决方案,很多前端项目会把目光转向发展时间更长、已经形成框架级别基建的服务器端框架领域,但这方面的 Node.js 框架,也有瓶颈问题。
业界主流的 Node.js 框架 NestJS 的作者,在文档首页的设计理念部分,就指出 React、Vue、各种开发工具,都没有解决「应用架构」的问题,而 NestJS 就是要提供开箱即用的应用架构。
传统的前端开发局限于视图层,跟完整的软件开发、产品开发相比,最缺的就是「应用架构」。
- NestJS Philosophy: https://docs.nestjs.com/#philosophy
但是 Node.js 框架能提供的,只是「服务器端应用架构」,是以服务器端开发为中心的。
有些情况下,比如活动页面,客户端部分本来就很薄,谈不上「客户端应用架构」,但这种情况下的业务关注点仍然在客户端部分,如果基于有完整服务器端应用架构的 Node.js 框架去开发这种项目,对前端开发者来说有些偏离重点。
在另一些情况下,客户端部分比较厚,这种情况下需要的「客户端应用架构」,就像图中右边的蓝色部分,跟左边代表「服务器端应用架构」的橙色部分,是完全不同的,如果使用 Node.js 框架,蓝色部分仍然需要自己摸索和搭建。
不管什么软件架构,核心都是「分层」和「关注点分离」,完善的现代 Web 工程里,「服务器端应用架构」和「客户端应用架构」不会割裂,而是混为一体的。
- The Clean Architecture: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
除了架构,Node.js 框架也解决不了前面说的其他问题,同时还引入了图中右边的新问题:
业务逻辑既分散割裂,同时又重复,导致项目变得「低内聚高耦合」。
在「前后端分离」之后从「后端项目」里独立出来的「前端项目」,使用 Node.js 框架之后,又混入了很重的后端业务逻辑和研发需求。而 Node.js 框架随着发展,本质也越来越清楚:还是服务于专业服务器端开发的,降低不了前端开发者的服务器端开发门槛,这是一个最大的瓶颈。
未完待续
参见《 迈入现代 Web 开发 (二)》
2022.6.3日(长期有效):打个广告,苏州华为终端BG面向社会招聘人才,Java /C C++ / Python / Javascript 。有兴趣来苏州的同学们 可以加我V 15850277051 ,走内推流程,有问必答!