写点什么

深度解读字节跳动 Web Infra 发起的 Modern.js 开源项⽬

  • 2021-10-28
  • 本文字数:13287 字

    阅读完需:约 44 分钟

深度解读字节跳动Web Infra发起的 Modern.js 开源项⽬

7⽉,字节跳动 Web Infra 做过⼀次主题为 《迈⼊现代 Web 开发(字节跳动的现代 Web 开发实践)》 的分享,在分享中他们梳理了「传统前端技术栈」的典型组成部分,展示了其中每个部分都存在的瓶颈问题。也介绍了在这些问题的驱动下,业界正在发⽣从「传统 Web 开发范式」到「现代 Web 开发范式」的「范式转移」。在这个分享的最后预告了 Modern.js 开源项⽬。


10 ⽉ 27-28 ⽇举办的 稀⼟开发者⼤会 上,字节跳动 Web Infra 正式发起 Modern.js 开源项⽬。在专场分享《介绍 Modern.js——现代 Web ⼯程体系》中,⾸先介绍了业界和字节内部的前端开发、 Web 开发在发⽣哪些影响深远的变⾰,从这些变⾰的⻆度,展示了基于 Modern.js 的现代 Web 开发。


这些变⾰包括:

  • 更多「前端开发者」成为「应⽤开发者 / 产品开发者」

先讨论了什么根本因素在驱动这种转变,"Frontend Focused" 的意义,指出服务器端开发⻔槛不断降低的⻓期趋势、原有基建的缺陷,⽤ Modern.js 演示了「⼀体化、⽆服务器化的全栈开发」、「以客⼾端为中⼼的 Web 开发」

  • 从「前后端分离」到「前后端⼀体化」

分析了「前后端分离」产⽣的两种前端项⽬,为什么其中⼀种是「假分离」,另⼀种「不完整」,⽤ Modern.js 演示了「前后端⼀体化」在哪些地⽅带来改变

  • Meta Framework 取代传统「前端三剑客」

分析了四代「前端三剑客」,以及每⼀代都被下⼀代的成员「吞并」的规律,结合字节内部的 真实案例,讲解了 Meta Framework 的⻆⾊

  • 形成基于「前端技术」的成熟 GUI 软件研发体系

先明确了「前端技术」的定义, 结合 Modern.js 的功能和设计,讨论了如何实现「充分抽象」,才能 解决 DX 和 UX 的⽭盾

  • 智能化、平台化、低码化


接下来系统介绍了 Modern.js 的六⼤要素,包括:

  • 普及:现代 Web 开发范式

回顾了这种范式的 9 ⼤主要特征

  • 核⼼:现代 Web 应⽤(MWA)

从 Universal App、⼀体化、应⽤架构、Runtime API 这四个⻆度来了解 MWA。

在应⽤架构部分介绍了 Modern.js 中 Model 的设计和背景

  • 内置:前端⼯程最佳实践◦ 列举了⼏个典型的最佳实践,包括 Post-Webpack Era 的新⼯具趋势、Modern.js 的 Unbundled 开发,Modern.js 推荐的「CSS 三剑客」,Modern.js 微前端项⽬跟直接使⽤ Garfish 的微前端项⽬对⽐、模块⼯程⽅案和 Monorepo ⼯程⽅案中的最佳实践。

  • 包含:Web 开发全流程

演示了 Modern.js 在「编码」环节的微⽣成器功能、在「调试环节」的微前端调试

  • 提供:⼯程标准体系

  • ⿎励:定制⼯程⽅案


末尾介绍了除已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。介绍了 Modern.js 当前⾼优的社区计划。

分享实录

⼤家好,我是来⾃字节跳动 Web Infra 的宋振伟,在字节跳动,我们部⻔负责打造和发展「Web 技术中台」和「前端研发体系」。

今年 7⽉,我们做过⼀次主题是 《字节跳动的现代 Web 开发实践》 的分享,在分享中我们梳理了 「传统前端技术栈」的典型组成部分,展示了其中每个部分都存在的瓶颈问题。

也介绍了在这些问题的驱动下,业界正在发⽣从「传统 Web 开发范式」到「现代 Web 开发范式」的 「范式转移」。


在这个分享的最后也预告了 Modern.js 开源项⽬。

昨天上午的主题演讲中,字节跳动正式发布了 Modern.js。今天的专场分享,我想结合字节内部的变⾰和实践,介绍基于 Modern.js 的现代 Web 开发,和所带来的实际效果。

议程

今天的分享可以分成三个部分。


昨天的主题演讲有说到,整个业界和字节内部的前端开发、Web 开发,都在发⽣着影响深远的变⾰,我们⾸先从这些变⾰的⻆度,看下基于 Modern.js 的现代 Web 开发是什么样⼦,有什么区别。


然后,我们整体看下 Modern.js 有哪些要素和收益。


最后再看下除了已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。

我们先来看第⼀部分「现代 Web 开发」

⼀、基于 Modern.js 的现代 Web 开发

1. 更多「前端开发者」成为「应⽤开发者 / 产品开发者」

可以从这五个⽅⾯的变⾰,来展示「现代 Web 开发」是什么样⼦。


这五个变⾰之间是承前启后的关系。⾸先最根本的推动⼒,不是来⾃技术侧,不是前端开发者⼀厢情愿的发展⾃⼰主观的技术偏好,⽽是在互联⽹和 IT ⾏业、市场需求、⽤⼾产品这⼀侧的⼤趋势,需要更多「前端开发者」成为「应⽤开发者」或「产品开发者」,⿎励和倒逼着技术领域,不断产⽣更有利于这种需求的技术形态和基础设施。


当传统技术范式遇到瓶颈,不再能进⼀步适应需求,就会发⽣「范式转移」,出现从⼀开始就针对这种需求重新设计的、新⼀代的技术范式。


这种转变推动前端技术领域出现了「从分离到⼀体化」、新⼀代「前端三剑客」的变⾰。


这种变⾰带来的新⼀代技术标准和基础设施,开始形成完全基于「前端技术」的成熟 GUI 软件研发体系,并且进⼀步朝着平台化、低码化的⽅向发展。

"Frontend Focused" 的意义


我们刚才⼀直在说「前端」,「前端」这个概念似乎⼀直是只有开发者才关⼼的技术细节,但最近⼏年,却变成了商业领域、投资机构也都很关⼼的事情,全球市场上涌现出越来越多的新⼀代云平台和研发⼯具产品,多数都涉及前端研发特有的需求和模式,其中还有很多像 Vercel 这样明确「专注于前端」的产品。


就像幻灯⽚上这张图,云计算和研发产品最初是从最接近机器的底层开始发展,从虚拟化,到容器编排,到基于容器技术的各种平台化、服务化的研发⼯具形态,这个阶段是后端技术主导的,整个趋势 是越来越向上层发展,越来越接近市场和商业价值最终所在的地⽅——也就是⾯向⽤⼾的产品,因此 必然会发展到前端技术主导的抽象层,让应⽤开发和产品开发能更专注于⽤⼾需求,⽽越来越不需要关⼼服务器端的复杂性和专业技术细节。

所以市场需求会趋向于推动应⽤开发⽅式往「专注于前端」的⽅向的发展,专注于前端就是专注于用户,⽽专注于⽤⼾是多数企业、产品的根本利益所在。

最⼤的开发者群体


另⼀⽅⾯,从进⼊移动互联⽹时代开始就不断⼤幅增加的应⽤开发需求,现在不但没减弱,反⽽还在加强,⽐如幻灯⽚上 IDC 的预测,要满⾜这么庞⼤的应⽤开发需求,传统开发⽅式和⼈才储备是很不够的,需要让尽可能多的开发者能独⽴、完整的开发这些应⽤,⽽前端技术栈的开发者,正是最⼤的开发者群体和技术社区。


所以在用户、产品、市场这⼀侧,⼀直有趋势和压⼒,需要更多「前端开发者」成为「应⽤开发者」 或「产品开发者」,⿎励和倒逼着技术领域,不断产⽣更有利于这种需求的技术形态和基础设施。

服务器端开发⻔槛不断降低


在这种客观趋势的推动下,基于 Web 技术的应⽤开发中,服务器端的占⽐和⻔槛⼀直在不断下降, 国内⼤⼚的中台建设,提供了⼤量不跟特定客⼾端捆绑、专注于数据需求和底层业务逻辑的 API,让 产品开发更聚焦在上层的客⼾端业务逻辑。还有 BaaS 和基于云函数的后端云 Serverless,也进⼀步降低服务器端的⻔槛,让前端开发者能更独⽴的、端到端的完成产品开发。


但要进⼀步降低⻔槛,提⾼效率,这些基础设施的⼀个缺陷就暴露出来,就是他们都把应⽤依赖的 API,放在应⽤项⽬之外维护,跟前端研发是割裂的。


还有⼀个缺陷是它们不解决 API 之外的服务器端需求,⽐如路由、SSR 等。


有⼀个字节内部的典型例⼦,前端开发者在⾃⼰实现的 SSR 项⽬中,始终⽤ HTTP ⽅式请求外⽹域 名的 API 来获取数据,导致 SSR 频繁超时,HTML 响应慢严重影响⽤⼾体验。可以给前端开发者做培训,让他们具备⾜够的服务器端开发思维和知识,知道要在 SSR 环节切换成内⽹的请求⽅式,还要考虑缓存机制等,但更根本的解决⽅法是屏蔽这种服务器端问题和实现细节,⾃动处理这些问题。

⼀体化、⽆服务器化的全栈开发


因此服务器端⻔槛不断降低的趋势,⾃然会发展到「⼀体化、⽆服务器化的做全栈开发」的阶段,让前端开发者直接开发 「接近纯前端的项⽬」⽽不是 「Node.js 框架项⽬」,感觉就像没有服务器⼀样。


幻灯⽚上是这次分享中第⼀个 Modern.js 的 demo, 左侧是⼀个 Modern.js 应⽤项⽬的完整⽬录结构,src/ ⽬录下的应⽤主体,可以像调⽤普通函数⽂件⼀样访问 api/ ⽬录下的 BFF 函数,不需要了解网络细节,Modern.js 会⾃动基于 BFF 函数的路径、参数等⾃动⽣成 REST API,在 CSR 过程中⾃动请求。

接下来我们在 package.json 的 modernConfig 配置⾥启⽤ SSR、「差异分发」和「⾃动 Polyfill」,可以看到这些功能不用增加代码逻辑,只需要静态开关配置。

构建后,幻灯⽚左侧可以看到产物⾥的 HTML 和 JS 都有 es6 和 es5 两个版本,⽤⼾访问时应⽤的时候,Modern.js 的 Web Server 会根据浏览器 UA 选择分发 es6 版本还是 es5 版本,也就是「差异化分发」。


右边上⾯的图是现代浏览器的访问结果,不会返回任何 polyfill 代码, 下⾯的图是低版本浏览器的访问结果, Web Server 会⾃动提供这个 UA 需要的 polyfill 代码。


可以看到 Modern.js 不但⽀持⼀体化的开发 BFF,也满⾜ BFF 之外的服务器端需求,尽可能⾃动利⽤⾃带的 web server 去做性能优化和提供产品级的兼容性,同时开发体验仍然是⽆服务器化的。

之前我们启⽤了 SSR, 左侧图上⾼亮的 HTML ⽚段,已经包含了通过 BFF 请求到的数据,会根据应⽤运⾏的⽅式⾃动选择最⾼效的请求⽅式。


这种⾃动优化不会阻碍开发者对技术细节的掌控,右边这张图展示了 BFF 函数也会⽣成标准的 REST API,可以⼿动调⽤。

以客⼾端为中⼼的 Web 开发


这种⼀体化、⽆服务器化的全栈开发进⼀步发展,⾃然会得到⼀种客⼾端为中⼼的 Web 开发⽅式。


⽐如在传统 Web 开发中,要实现常⻅的权限识别和重定向,除了前端⻚⾯的逻辑,还需要在服务器端的路由中,添加实现跳转的业务逻辑。⽐如图上,在访问 home ⻚⾯的时候根据 cookie 的值决定 要不要重定向到登陆⻚⾯。

同样的需求,在以客⼾端为中⼼的 Web 开发⽅式中,可以⼀体化的在客⼾端代码⾥实现,⽐如前⾯已经启⽤ SSR 的 Modern.js 项⽬,只需要添加 Redirect 组件,就可以实现和刚才完全相同的权限识别和重定向效果,访问⻚⾯时会根据 cookie 决定要不要返回 302 状态码。整个实现过程是客⼾端思维的。

以客⼾端为中⼼,不代表不能掌控服务器端,不能直接写服务器端业务逻辑。


如果已经习惯 Node.js 框架的开发⽅式,可以 server ⽬录的钩⼦⽂件⾥,对框架⾃带的 Web Server 添加⾃定义逻辑,⽐如⾃由添加中间件,可以在这个局部,⽤⾃⼰熟悉的传统 Web 开发⽅式实现权限识别和重定向。

2. 从「前后端分离」到「前后端⼀体化」

Web 项⽬的技术栈也在转变,相当于是先发展出「前后端分离」,然后⼜⽤新⽅式回归了 「前后端⼀体化」。

「前后端分离」


以前的 Web 开发就像图上这个 Ruby on Rails 项⽬,图中粉⾊的前端代码,「寄居」在 绿⾊的 后端 Web 框架项⽬中的,前端和后端会互相⼲扰互相拖累,做⼯程建设也⽐较⿇烦。

之后 Web 开发普遍转变到「前后端分离」的模式,分离后的前端项⽬和后端项⽬,都倾向特定的类型。

后端项⽬不倾向包含 Web 的功能,⽽这时的前端项⽬可以归纳为两种类型。

MERN 这种项⽬类型相当于⼜回到了分离前的状态,整个项⽬是基于 Node.js 框架的,前端被嵌在⾥ ⾯。这种结果其实反映出「前后端分离」实现的更多是分⼯上的分离,⽽不是技术架构上的分离,在技术架构上仍然没有摆脱以服务器端框架为中⼼的 Web 开发。

从 MERN 项⽬的结构可以看到,它不但是假分离,⽽且也不算⼀体化,React 代表的前端部分和 Node.js 框架代表的后端部分,在项⽬⾥是泾渭分明的,没有真正融合到⼀起去。


使⽤ Node.js 框架的项⽬,多数属于这个类型。

「前后端分离」模式中另⼀种前端项⽬类型,我们称作「⽼⼀代 JAMstack」,这种类型没有假分离问题,就是纯粹的前端项⽬。可以实现 SPA 和 MPA,也能基于编译⼯具实现 SSG(静态⽹站⽣成)。靠静态托管来运⾏,⿎励在 CSR 中调⽤ API 满⾜动态的应⽤需求。

「⽼⼀代 JAMstack」最⼤的问题是,虽然分离成了独⽴的项⽬,却不⾜以承担完整的应⽤开发,只能产出静态⽂件,依靠外部的 Web 服务器去运⾏,⽆法实现 SSR,三⼤组成部分⾥的 API,也需要 在项⽬之外,⽤云函数、独⽴后端项⽬等⽅式来实现,不能跟着项⽬⼀起迭代。


⽤ CRA 或直接⽤ webpack 搭建的项⽬,多数属于这个类型。

「前后端⼀体化」


在前⾯说的需要更多「前端开发者」成为「应⽤开发者」的背景下,新⼀代的 JAMstack 项⽬⽤「客⼾端为中⼼」的「前后端⼀体化」⽅式,解决了上⾯说的问题。


新⼀代 JAMstack 的三⼤组成部分虽然没变,对应的内容却有很⼤变化,JS 部分更加函数化和组件化、以 JS 为中⼼,HTML 可以完全不在项⽬中出现,⾃动⽣成。BFF API 变成项⽬⾃包含。和之前简单的静态托管相⽐,基于前端 Serverless 平台可以实现 SSR、SPR 等动态能⼒,即使是静态⻚⾯,也可以获得很多好处,⽐如前⾯展示的 「差异化分发」。

图上是⽤ Modern.js 的 demo 来展示新⼀代 JAMstack 项⽬。在开发中只需要聚焦在 JS 代码上,不 论是 SPA 还是 MPA,HTML 都是⾃动⽣成的。不论是 SSR 渲染的代码,还是 API 逻辑,构建之后按照规范输出到 dist 下的不同⽬录,构建产物规范是 Serverless 友好的,⽀持把 Web、SSR、BFF 等 拆分成不同服务器。

前⾯提到 Modern.js 倾向于 JS 为中⼼、⾃动⽣成 HTML。但不阻碍开发者⾃⼰掌控 HTML。图上是 Modern.js 渲染 HTML 的默认模板。

⼀体化 BFF 的调⽤,在前⾯的例⼦演示过,这⾥可以看到 BFF 函数的⽂件路径是有约定的,可以实 现任意设计的 REST API。

构建产物会针对 BFF、Web、SSR 分别⽣成独⽴可运⾏的 Server,这是对前端 Serverless 平台更友好的,Serverless 平台可以⾃主选择让 BFF、Web、SSR ⽤不同⽅式在独⽴进程中运⾏,不会互相⼲扰。⽐如在 SSR 环节遇到 app 代码的的内存泄露导致 SSR 超时,Web Server 不受影响,可以⾃动降级到 CSR 模式,返回静态的 HTML 给⽤⼾作为兜底,⽤⼾的 HTML 请求始终不会超时或挂掉。

对于 SSR,同样可以前后端⼀体化的开发,图⾥⾼亮的 useLoader 函数中的代码,同时适⽤于 SSR 和 CSR,如果这个 Loader 在 SSR 中已经预加载,CSR 就会⾃动跳过,否则会执⾏。

SPR 相当于有缓存机制的 SSR,在 Modern.js ⾥也可以⼀体化的开发,只要使⽤这个预渲染组件。

SSG 实际上就是在编译时运⾏的 SSR,在 Modern.js ⾥只要配置 SSG 路由,就会⾃动启⽤这种编译逻辑,给路由⽣成静态 HTML。CSR、SSR、SSG 都是⽤同⼀份代码。

3. 新⼀代「前端三剑客」和 Meta Framework

除了在技术栈层⾯向「前后端⼀体化」转变,在⼯程层⾯,传统的「前端三剑客」也在转变成元框架这种新的⼯程基建。

传统「前端三剑客」


先来回顾下传统的「前端三剑客」,第 1 代和第 2 代如图上所示,也被⼤家熟知。⽽第 3 代「前端 三剑客」由视图框架、Node.js 命令⾏、Node.js 框架三个⽅向组成。

其中 Node.js 命令⾏代表了⼯程化,其中最典型的是像 Webpack 这样的打包⼯具,以及 Babel、 PostCSS 这样的编译⼯具。


视图框架和 Node.js 框架很好理解,就是之前讨论的 MERN 项⽬中的前端和后端部分。

第 4 代「前端三剑客」


随着现代 Web 开发范式的发展,第 4 代「前端三剑客」的轮廓已经越来越明显,由元框架、前端 PaaS、低代码三个⽅向组成。其中低代码⽅向在昨天晚上稀⼟⼤会的低码专场已经介绍过,⽽ Modern.js 就属于元框架这个⽅向。

从这张图可以清楚的看到,每⼀代前端三剑客中,都有⼀个⽅向,把上⼀代前端三剑客完整包含在⾃⼰⾥⾯,变成不需要太关⼼的底层,让⾃⼰取代他们成为前端开发的新地基。


第 3 代中的视图框架,就扮演这样的⻆⾊,把第⼆代的 HTML、CSS、JS 封装在⾃⼰⾥⾯,⽽第 4 代中的元框架,⼜对视图框架、Node.js 框架、Node.js 命令⾏做了整合和抽象,成为前端开发和⼯程建设性起点,元框架扮演了过去 Webpack、React 扮演的⻆⾊。

这张 JS 框架的 S 曲线图,也能体现这种转变。在左边这个时期,发展的前沿、开发的起点,都是 React、Vue、Svelte 这样的视图框架,新的视图框架项⽬也层出不穷。现在已进⼊右边这个时期, 前沿收敛到基于 React 发展更上层的元框架。

Modern.js 作为现代 Web ⼯程体系,是由元框架组成的,提供三⼤⼯程类型,⿎励开发者基于⼯程类型建设⾃⼰的业务⼯程⽅案。


以字节内部的「⽕⼭引擎⼦应⽤⼯程⽅案」为例,初始化的⽬录结构没有什么变化,只在配置中默认加载了⾃⼰的框架插件,插件中通过 server 提供的 hook 修改渲染后的 HTML ,在原来的 HTML 上套了层壳,也就是右下⻆截图中⽕⼭引擎统⼀的顶栏和左侧导航栏。


这样建设出来的⼯程⽅案,既能满⾜垂直场景的需求或⾃⼰的偏好,⼜能保持跟三⼤⼯程类型的兼容,⾃动获得 Modern.js 的能⼒和收益

4. 基于「前端技术」的成熟 GUI 软件研发体系

在「前端开发者」成为「应⽤开发者」的⼤背景下,技术栈、⼯程基建的发展,开始形成基于「前端技术」的成熟 GUI 软件研发体系。

什么是「前端技术」


先明确⼀下我们⼀直说的前端技术,不是指做 UI 的技术,⽽是由 Web 原⽣语⾔、Web Runtime、 Web 技术⽣态组成的技术栈,不是只在浏览器⾥才有前端技术,⽽是有 Web Runtime、有 Web 语⾔的地⽅,就有前端技术。

DX 和 UX 同样重要


传统前端开发不是成熟的软件研发体系,缺乏⾜够的抽象和基建,导致 DX 和 UX 始终存在⽭盾,此消彼涨。以往的产品开发中,习惯更重视 UX,这有两⽅⾯的原因,⼀来是因为产品是由产品主导,因此更重视 UX,不会过多关注开发者体验,再就是缺乏⾜够的抽象和基建,导致 DX 和 UX 之间必须牺牲⼀个。


在新⼀代更成熟的研发体系的⽀持下,已经可以实现 DX 和 UX 的同时最⼤化了,也从「更重视 UX」 转变为「DX 优先」的⽅式。

要实现 DX 和 UX 的同时最⼤化,需要充分的抽象。⽐如前⾯提到的 Modern.js 的这个例⼦,项⽬⾥只有三个⽂件,就具备全⾯的能⼒,包括⾃动 Polyfill、差异化分发、SSR 等,既具备产品级的 UX,有保持了 DX 的简单、开箱即⽤等。

充分抽象


要实现充分抽象,需要让项⽬从基于「库、⼯具」发展成基于「框架」,这两者的区别在图上表现的 ⽐较好。蓝底⽩边部分是项⽬开发者⾃⼰写的代码。左边是传统前端项⽬,由开发者⼿写整个应⽤, 把库和⼯具当做积⽊来组装,填补项⽬⾥的空⽩。⽽右边是 Modern.js 项⽬,整个应⽤是框架本⾝,开发者⼿写的代码,是按照框架的要求填充到框架预留的位置上。

要实现充分抽象,也需要在尽可能多的环节实现最⼤化的抽象,图上体现了 Modern.js 除了像常规 的框架⼀样,在运⾏时和编译时做抽象,也会在 IDE 编写代码的环节,和部署产物的环节,引⼊最⼤化的抽象。

要实现充分抽象,也需要解决前端模板的问题,Modern.js 把各种研发场景、项⽬类型,收敛和标准 化成了始终固定的三个⼯程类型,其中「应⽤」⼯程⽅案,也就是 MWA,⽀持所有需要部署和运⾏的项⽬,「模块」⼯程⽅案⽀持所有需要实现代码复⽤的项⽬。

5. 智能化、平台化、低码化

Modern.js 代表的现代 Web 开发,也在继续朝着智能化、平台化、低码化的⽅向发展。

智能化⽅⾯,当前可⽤的功能,是⽤ Modern.js 的初始化⼯具创建的项⽬,会开箱即⽤的在 VSCode ⾥做好配置,启⽤⼏千条规则组成的 ESLint 全量规则集,加上按最佳实践内置在 ESLint ⾥的 Prettier,期望尽可能多⾃动修正问题,⽽不是仅仅提示问题。也追求尽可能多的让 IDE 负责⽣成真正的源码,让开发者⼿写的代码变成跟 IDE 沟通的语⾔。

在平台化⽅⾯,Modern.js 的⽬标之⼀就是形成「⼯程标准」,让各种前端 PaaS 平台可以围绕标准实现⾼级能⼒,⽐如图上粉⾊部分列出的产品级 Web Server、差异化分发、SSR 兜底、ESR、微前 端等,都需要结合代码层⾯的⼯程标准。

除了部署运⾏环节⽅⾯的平台,有了⼯程标准之后,研发环节也可以引⼊更多低码提效。


⽬前我们内部使⽤的研发平台,可以直接在图形界⾯上简单操作完成项⽬的创建、开发、部署。图上右侧可以看到图形界⾯上展示了当前项⽬的的状态: ⼊⼝数量、项⽬配置等,蓝⾊框内添加应⽤的⼊⼝,⼀键从 「单⼊⼝」 转变为 「多⼊⼝」 。右侧在 Web IDE 中也能看到 src ⽬录结构下的变化。

低码化有两个⽅向,⼀个是刚才说的跟研发⼯具结合,另⼀个就是研发从某些⼯作中解脱出来的低码搭建,昨天的低代码专题中有介绍。

总结


到⽬前为⽌,我们从这些变⾰的⻆度,展⽰了很多 Modern.js 的 demo 和效果。

⼆、Modern.js 的六⼤要素

接下来我们系统的看⼀下 Modern.js 是什么,Modern.js 提供了什么。

1. 普及:现代 Web 开发范式

可以⽤这六⼤要素来说明 Modern.js 。


⾸先这个项⽬是希望能推动现代 Web 开发范式的普及,发展完整的现代 Web ⼯程体系,突破应⽤开发效率的瓶颈。

前⾯讨论「现代 Web 开发」的时候,已经展示过这种范式的 9 ⼤主要特征。


其中 Serverless 范式、平台化、低码化这三个特征,在当前版本的 Modern.js ⾥还没什么体现,需要后续会跟⼀些平台配合提供。

2. 核⼼:现代 Web 应⽤(MWA)

继续看第⼆个要素。Modern.js 三⼤⼯程类型中最核⼼的就是 「现代 Web 应⽤」,简称 MWA,或 直接叫「应⽤」。

从 Universal JS 到 Universal App

前⾯提到过,「应⽤」⼯程⽅案⽀持所有需要部署和运⾏的项⽬,把这些项⽬收敛成⽤同⼀套框架、 同⼀套约定、同⼀套模板、同⼀套架构、⼀套 API 来开发。


反过来,我们也可以从 Universal App、⼀体化、应⽤架构、Runtime API 这四个⻆度来了解 MWA。

Universal JS 指同⼀份 JS 代码,既能在浏览器端运⾏,也能在服务器端运⾏,Universal App 是它 的进⼀步发展,同⼀份 App 代码可以在不同环节运⾏,也可以⽤不同的模式来运⾏。

⾸先是常⻅的 MPA 和 SPA 的需求,本质上是「服务器端路由」和「客⼾端路由」的需求。


在 Modern.js ⾥它们可以随意组合。


我们之前的例⼦都是单⼊⼝应⽤,只需要把 App.tsx 组件、pages ⽬录这样的⼊⼝标识放到 src 的⼦ ⽬录⾥,就能变成多⼊⼝的 MPA,会⽤⼊⼝名⾃动⽣成服务器端路由,⽐如图上的 admin-app 和 landing-page 两个⼊⼝。


这两个⼊⼝也分别都是 SPA,根据⼊⼝标识不同,⼀个使⽤基于组件的客⼾端路由,⼀个使⽤基于⽂件系统的客⼾端路由。

然后是⽀持「动静⼀体」。


前⾯展示过⼀个静态的、CSR 的项⽬如何直接开启 SSR、SPR、SSG 功能。


Modern.js 也⽀持 CSR 和 SSR/SSG 混⽤,⽐如图上右侧红⾊⾼亮部分会在服务端渲染到 html 中, 蓝⾊区域的⽇期时间,在 CSR 阶段动态展示在⻚⾯上。也就是整体 SSR + 局部 CSR。


整体 CSR + 局部 SSR 的能⼒后续会加⼊。

在 BFF ⽀持⽅⾯,Modern.js 中还提供了类型友好的⽅式,可以通过 Type Schema 实现运⾏时⾃动 校验接⼝的参数和返回值。⽐如右下⻆请求时,参数 text 类型为 number 时,response 中会⾃动提示相应的错误。

最后 Modern.js 还⽀持不同类型的应⽤开发,上图就是之前例⼦中介绍 Web 开发模式。

最后是不同的运⾏模式。


微前端在 Modern.js 中是原⽣⽀持的,底层解决⽅案是 Web Infra 之前开源的 Garfish 微前端解决⽅案。⼀个 MWA 可以随时变成微前端主应⽤,在配置中指定⼦应⽤列表的加载地址,Modern.js 就会 ⾃动在 Web Server 中预加载⼦应⽤数据,注⼊到运⾏时,在 Runtime API 的帮助下,可以像普通 React 组件⼀样使⽤⼦应⽤。


MWA 也可以分别作为独⽴的 Web 和微前端⼦应⽤的运⾏和部署。

MWA 在启用 Electron 支持之后,能作为桌⾯应⽤来运⾏,项目里会新增 electron ⽬录用于写主进程相关代码。除了开箱即⽤的 Electron 构建等能力,也提供运⾏时 API ⽀持 Electron 的常⻅需求和最佳实践,进⼀步提升开发效率。

前后端⼀体化


第⼆个看待 MWA 的⻆度是 「前后端⼀体化」。

之前的已经演示过 BFF 函数,api/ ⽬录下每个⽂件就是 BFF 路由,当服务器端逻辑更重的时候,可以加入 Node.js 框架元素,⽬前⽀持了 4 种不同的框架,还可以⾃⼰开发 Modern.js 插件⽀持更多框架。

以客⼾端为中⼼,不代表不能掌控服务器端,不能直接写服务器端业务逻辑。


⽐如之前演示过的⽕⼭引擎子应用,除了通过框架插件来实现,我们也可以在项⽬⾥创建 server ⽬录和钩 ⼦⽂件,添加修改 HTML 渲染结果的逻辑。

在只有 src ⽬录,或有 api ⽬录的情况下,MWA 类似 JAMstack 项⽬。


如果增加了 server 等钩⼦⽂件,MWA 就能像传统 Node.js App ⼀样直接写服务器端业务逻 辑,使⽤ Node.js 框架插件、中间件等。


如果删掉 src ⽬录,MWA 就是⼀个纯 REST API 的项⽬。


我们把这三种模式之间随意迁移的能力,称作「三位⼀体」。

应⽤架构


接下来,我们从应⽤架构的⻆度看看。

传统 Web 开发中的应⽤架构,等同于服务器端应⽤架构,前端部分的架构要么缺失,要么需要项开发者⾃⼰摸索、搭建,缺乏 API ⽀持和⼀致的抽象,难以跨项⽬复⽤业务逻辑。

如上图,MWA 提供的开箱即⽤的、客⼾端为中⼼的应⽤架构。类似图上那样,可以通过标准化的 Runtime API,轻易实现 React 开发中缺少的 Model 层和 Controller 层。Model 作为封装 UI ⽆关业务逻辑的积⽊,跟 UI 组件⼀样可以复⽤和组装。

之前 Web Infra 举办的 React 核⼼开发者在线访谈⾥,Redux 作者 Dan 提到,状态管理最重要的是理解状态的类型,根据需要处理的状态是什么种类,来选择对应的⽅案。

常⻅的状态管理⽅案,都有适合的状态类型和场景,很多时候需要混合使⽤,⽽不是⼀把锤⼦锤所有钉⼦,要么所有状态都放到全局应⽤状态⾥,要么所有状态都在局部状态⾥。

很多开发者不⽤ Redux,是因为 Redux 本⾝只能算底层 API,需要手动创建和维护 store,业务逻辑被 reducer,action 等分散在不同的地方,提高了维护成本。其实 Redux 社区⼀直有解决⽅案,比如 Ducks Modular 设计模式会把业务逻辑聚集在⼀起,Redux 官方支持的主流库 RTK 也为解决这样的问题而生。


Modern.js 的 Model 基于 Redux 进⼀步提⾼抽象程度,保留了 Redux 在不可变数据、数据流等⽅⾯ 的收益,对整个 Redux ⽣态兼容,让使⽤和不使⽤ Redux 的开发者都能受益。⽀持多种状态类型,也⽀持不同的 Model 写法。

Runtime API 标准库


最后看下 MWA 的 Runtime API 标准库。

相当于「应⽤」层级的基础 API,不⽌能在 MWA ⾥使⽤,在 Modern.js 的模块⼯程⽅案⾥,同样可以使⽤这些 API,开发可复⽤的业务组件,⽀持独⽴调试和测试。


图中最上⾯蓝⾊⽅块是业务开发中常⽤的 API ,⽐如 useLoader,useModel 等 API。中间绿⾊部分就是前⾯提到的定制 web server、BFF 函数需要⽤到的 API, 最底层的插件 API。整个框架的基础,框架里所有的包都是用插件 API 来实现的,也可以用插件 API 来扩展框架,定制工程方案。一些粉色部分包括很多重要的工具 API ,比如 useLocalModel。

当应⽤中的组件需要拆分成独⽴的模块复⽤时,实现中用到的 Runtime API ,还能正常调试、测试吗?答案是肯定的。这套 API 相当于「应⽤」领域的 API 标准库,不⽌能在 MWA ⾥使⽤,在 Modern.js 的「模块」⼯程⽅案⾥,同样可以使⽤这些 API,开发可复⽤的业务组件,⽀持独⽴调试和测试。上图右侧是模块⼯程的⽬录结构。左侧 TableList 组件中使⽤了 useLoader API,调试时只需要 提供对应的 story ⽂件,模块⼯程⽅案⽀持我们在 Storybook 可视化测试以及单元测试中测试使用了 Runtime API 的组件。

3. 内置:前端⼯程最佳实践

对于第三个要素,简单列举⼏个 Modernjs 内置的前端⼯程最佳实践。

Post-Webpack Era


传统前端⼯程建设都是基于 Webpack 的配置封装, Webpack 配置复杂和编译缓慢的问题,⼤家应该都有⽐较深的感受, 但是从去年开始业界涌现很多新的⼯具,完全不涉及 Webpack,⽐如 Snowpack、 Vite、wmr 等,有⼈把它称为 JS 第三纪元。

从第三纪元开始, esbuild 、swc 这种编译打包⼯具使⽤⾮ JS 的系统编程语⾔开发,显著提⾼构建速度。编译时间的缩减也意味着不打包,按需编译的 ESM 场景可以实现, Snowpack、Vite 这样的⼯具就是在 esbuild 的基础上实现的开发者体验优先的不打包开发调试模式。在 Modern.js 中不打包的模式⽬前已经被⽤于公共库的构建、业务项⽬的开发调试等真实场景。

Modern.js 中也内置类似 Snowpack、Vite 的不打包开发调试模式,左侧启⽤该功能之后,运⾏效果就像图上右侧那样,开发服务器在秒级启动。

为什么可以做到速度这么快?主要是因为业务代码只有在请求时使⽤ esbuild 按需编译,第三⽅依赖⾃动从 Goofy PDN 加载已经预编译好的产物。

CSS 最佳实践


在 CSS 开发⽅⾯,Modern.js 默认推荐图上「CSS 三剑客」搭配使⽤,有需要也可以开启 LESS/SASS 等预处理器和 CSS Modules ⽀持。

默认零配置、样板⽂件最⼩化


和以前把功能作为样板⽂件塞到项⽬⾥相⽐, 现代 Web 开发范式下的最佳实践是默认零配置的,同时样板⽂件尽可能简洁最⼩化。之前我们也通过例⼦看到 Modern.js 项⽬⼿动创建⾮常简单,只需要应⽤根组件和 package.json。


跟直接使⽤ Garfish 开发微前端⼦主应⽤的项⽬做对⽐,上图可以看到直接使⽤ Garfish 的项⽬,需要⼿动运⾏ Garfish 框架、处理公⽤模块、路由等逻辑。除了运⾏时,还需要编译环节⾃定义⼀⼤堆配置。直接使⽤还是有⼀定的成本。

之前的例⼦已经说过,在 Modern.js 中使⽤微前端,只需要在 web 应⽤的基础上启⽤微前端功能, 提供⼦应⽤列表即可,每个⼦应⽤加载后就是组件、路由可以⾃⼰灵活组织。

构建产物规范


Modern.js 的模块⼯程⽅案,会并⾏编译出多种符合社区主流规范的构建产物。模块的编译也是不打包的,更容易引⼊速度更快的⼯具⽐如 esbuild、swc 等。

Monorepo ⼯程⽅案


应⽤和库如果分散在不同项⽬开发的话,通过 npm link 调试也⽐较⿇烦,业界的主流⽅案是通过 Monorepo 管理多个子文档, Modern.js 本⾝就是基于 pnpm monorepo 开发的,同时也将这部分最佳实践收敛到 monorepo ⼯程⽅案。默认使⽤ pnpm 进行包管理,左侧是它的⽬录结构,apps 对应的是 MWA 应⽤ 、features/packages 对应是可复⽤的模块。


右侧内部模块指的是不会发布到 npm、仅在当前仓库下复⽤的库。它本⾝不需要构建,同仓库下的应⽤直接使⽤它的源码即可。monorepo 我们也提供了 new 命令,可以选择创建应⽤或者模块。

更多


除了上⾯提到的⼀些最佳实践,Modernjs 还提供了单元测试、集成测试、Visual Testing 等、ESlint 全量规则集等最佳实践。这⾥不⼀⼀展开介绍。可以查阅 Modernjs 文档进一步了解。

4. 包含:Web 开发全流程

Modernjs 不只是在上述运行、构建、调试等方面提供了支持,它本身就覆盖了 Web 开发的全流程。

在编码环节,可以通过微⽣成器启⽤某个功能或者添加⼊⼝,从 SPA 迁移到 MPA, 和前⾯提到的通过研发平台「低码提效」类似,还可以像图上那样在项⽬⽬录下执⾏ new 命令选择要启⽤的功能。这个命令会⾃动重构我们的代码。


通过微⽣成器按需⾃动启⽤的⽅式,可以放⼼的将⼀些功能作为插件提供,也可以控制 Modern.js 初始化项⽬的体积。

在微前端⼦应⽤开发时,通常情况下主应⽤已经部署上线了,这时候开发⼦应⽤就需要结合线上的主 应⽤⼀起调试,之前的⽅式通常是通过全局代理⼦应⽤ js 到本地,⽐较⿇烦。


Modern.js 中只需要主应⽤像右下⻆那样启⽤ DEBUG 模式,之后打开主应⽤线上链接,在 header 中设置需要开发的⼦应⽤信息,server 会⾃动替换注⼊到 html 中的⼦应⽤列表数据。这样也就可以让线上主应⽤加载本地⼦应⽤。

在运⾏环节,传统的 Web 开发模式,通常是没有提供⽣产环境运⾏项⽬的⽅式,MWA 项⽬本⾝⾃ 带产品级的 Server,⾃⼰就能产品级的运⾏⾃⼰,⽐如图上的⾃动 Polyfill 服务。之前也提过,结 合 serverless 平台,可以⾃动做⼀些优化。也可以在本地运⾏模拟⽣产环境的效果。

5. 提供:⼯程标准体系

Modern.js 不只是⼀个现代 Web 应⽤开发框架,⽽提供了整套现代 Web ⼯程体系。

前⾯已经介绍过,我们将前端开发中涉及的场景收敛到 3 种,就是图上应⽤、模块和 monorepo。

不仅解决了业务模板数量爆炸的问题。融合后的⼯程类型,⽐如 MWA 不是多个场景简单叠加,导致 ⼯程变的⼤⽽全,通过抽象可以做到很轻量,也能更容易交付⼀些之前不好实现的功能。

6. ⿎励:定制⼯程⽅案

Modern.js ⿎励业务结合⾃⾝场景定制垂直的⼯程⽅案。

就像前⾯提到的⽕⼭引擎例⼦⼀样,封装插件、微⽣成器、定制出⾃⼰的业务⼯程⽅案。

关于 Modern.js 六⼤要素的更多解释和例⼦,可以在官⽹上看到。

三、Modern.js 社区和现代 Web 研发体系

最后我们⼀起看下除了已经发布的开源项⽬,还有哪些对现代 Web 开发者有帮助的事情在发起和推进中。

Modern.js 开源项⽬现在是刚起步的状态,昨天上线的官⽹,以及最新发的 1.0 版,都是公测状态, 还需要更多意⻅、测试和实践,希望⼤家多参与社区建设。


Modern.js 的起点是字节内部的现代 Web ⼯程体系项⽬,现在⼤部分代码已经完全转到 Github 上开发,⼯作流还在建设中。


双⽉计划、每周计划、缺陷管理等,也都会全⾯转到 Github 上公开推进。


当前版本还没有包含 Roadmap 上⼀些重要功能,希望尽量以每周发版的节奏,把这些功能补上。

昨天的分享介绍了 「现代 Web 研发体系」中的其他部分,这些部分⼏乎也都算的上是 Modern.js 的 重要功能,后续会陆续对外开放,欢迎⼤家关注。

最后,屏幕上右下⻆⼆维码是 Modern.js 官⽹的地址,可以在官⽹上通过快速上⼿和实战教程了解 更多 Modernjs 的细节使⽤部分。


谢谢⼤家。


官⽹:https://modernjs.dev/

Github:https://github.com/modern-js-dev/modern.js

2021-10-28 23:576301

评论 1 条评论

发布
用户头像
BSN区块链服务网络是全球性基础设施网络,有各类官方指定应用可以满足你的不同需求哦~
2021-11-03 17:40
回复
没有更多了
发现更多内容

CSS10 - 盒子模型&常用无序列表样式

Mr.Cactus

html/css

架构师训练营大作业(二)

曾彪彪

「架构师训练营第 1 期」

架构师训练营第 1 期 - 第 12 周 - 命题作业

wgl

架构师训练营第 1 期

写在再次学习python之前-why篇

赵开忠

Python 28天写作

区块链挖矿系统APP软件开发

系统开发

生产环境全链路压测建设历程 24:FAQ 5、6负载均衡、如何不影响正常业务?

数列科技杨德华

28天写作

三只猫

架构师训练营第 1 期 - 大作业1

Anyou Liu

架构师训练营第 1 期

SafePoint 与 Stop The World 全解(基于OpenJDK 11版本)

AI乔治

Java 架构 jdk JVM

记一次JVM OOM 实战优化

AI乔治

Java 架构 JVM OOM

我能加入写作训练营,一切都因为...

李忠良

个人成长 驱动力量 28天写作

小心!你可能搞了个假的头脑风暴!

Justin

团队协作 28天写作 头脑风暴 群体迷思 创造性思维

第2周课后练习-OOD的五大原则

潘涛

架构师训练营 4 期

28天带你玩转Kubernetes--第一天(课程介绍)

Java全栈封神

Kubernetes 云原生 k8s入门 28天写作 k8s教程

我们为什么要学习Springboot?

武哥聊编程

Java springboot SpringBoot 2 28天写作

架构师训练营大作业(一)

曾彪彪

「架构师训练营第 1 期」

Flink 自定义Avro序列化(Source/Sink)到kafka中

大数据老哥

大数据 flink hadoop

第2周总结-架构中的设计模式

潘涛

架构师训练营 4 期

HDFS SHELL详解(1)

罗小龙

hadoop 28天写作 hdfs shell

28天瞎写的第二百一二天:一次删库没跑路的故事

树上

28天写作 删库

解读《Java开发手册(泰山版)》- 会当凌绝顶,一览众山小

xcbeyond

Java Java开发手册 28天写作

职业成长就是一个逐渐“变帅”的过程

俊毅

【计算机内功修炼】三:一文彻底理解IO多路复用

码农的荒岛求生

epoll

序言 基层管理者技能修炼的九把刀

一笑

管理 28天写作

视频号发展简史&第一天数据 | 视频号28天(02)

赵新龙

28天写作

【Node.js】静态页面和简单的路由

德育处主任

大前端 Node 28天写作

自下而上的问题清单

将军-技术演讲力教练

28天写作

学创业,读毛选 Jan 9, 2021

王泰

28天写作 读毛选,学创业

关系中的密码:麻烦

熊斌

个人成长 28天写作 亲密关系

区块链的前世今生(1)

抗哥

kill -9 导致 kafka 重启失败的惨痛经历!

AI乔治

Java kafka 架构

深度解读字节跳动Web Infra发起的 Modern.js 开源项⽬_云计算_Modern.js团队_InfoQ精选文章