星夜搭建平台结合微前端在火山引擎官网上的实践

语言: CN / TW / HK

小编语:本文来自字节跳动「星夜」搭建平台在掘金公开课上的一次分享(点击原文跳转),内容以支持火山引擎官网建设成果,阐述了「星夜」搭建平台与当前主流搭建平台的不同设计思路。同时,还介绍了搭建平台与微前端如何结合,以解决复杂场景下的多种解决方案融合思路。

本文首发于公众号「ByteDance Web Infra」,欢迎关注。

为什么需要搭建平台

数字化转型和应用的爆发,带动对 IT 人才需求的增长,但是 IT 人才一直面临供需不平衡的难题。根据 Garter 预测,未来市场对应用的开发需要将会数倍高于 IT 公司的产能,而搭建平台不仅满足了企业对迅速增长应用开发需求,而且还能帮助企业降低开发成本。

核心问题

传统产研的协作模式是类似下面流水线的工作模式,环环相扣,不难看出能和真实「产品」接触的只有研发。这就导致一个非常严重的问题,但凡真实产品上的修改就必须经过研发,研发资源跟不上就导致整条业务流水线不能很好的工作。

在工程项目更加复杂、参与人员更加庞大的游戏开发领域,则没有使用上面这种流水线似的工作模式。所有和游戏开发相关的人员,都围绕着真实「产品」进行工作,直接或间接在修改代码。例如游戏研发通过游戏引擎;美术通过动画、精灵、网格编辑器;策划则通过关卡、行为、策略等编辑器;所有分工都围着这张桌子,用各种适合自己的工具,产出的都是最终游戏中真实的组成部分。

「圆桌」模式使得没有一方完全被另一方阻塞,整个事情变得更加有效率。

打破研发壁垒

Gartner 提出过“全面开发者”概念,借助于一些组件化、可视化平台,一些不具备编程技能、不懂代码和开发的“小白”,也能自主组织或参与开发,从而把代码开发由一项程序员专属技能扩展到更广泛的人群。

如何把圆桌模式也复刻到 「Web 开发」领域呢?问题的关键在于能否像游戏领域一样给 Web 开发中的各个角色提供类似的工具打破研发壁垒,搭建平台的出现就是为了解决这个问题。

为什么选择星夜

火山引擎官网团队在选择星夜之前也调研过一些其他类似的产品,经过产品功能和实现方案分析对比后,发现其中不少的弊端,但星夜能很好的解决它们,这也是选择星夜的主要原因。

两个例子

在介绍星夜之前,先来看两个典型的例子,分析它们的优劣。

CMS

内容管理系统是一种位于 WEB 前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。WordPress 是全球最大、最受欢迎的内容管理系统,它包含丰富的物料、模版、以及插件功能。

用户经过简单的拖拽、配置就能完成一个页面搭建的工作。它的优点是非常简单,即使没有任何经验的小白也能简单学习后实现功能需求。

❓:能使用 CMS 去解决火山引擎官网项目遇到的问题吗?

🙋: 不能,原因有以下两点: - 页面模板中可变内容是和模板绑定的,灵活性低,难以支持灵活多变的业务需求。 - CMS 更适合配置内容,物料开发不是很灵活,而且火山引擎官网项目组件的提供方来源多个,第三方想要上火山引擎官网就必须按照规范重新开发一套物料。

基于 DSL 的可视化搭建

这里并不是要介绍具体的产品形态,而是技术领域常见的概念。

如上图所示是基于 DSL 的可视化搭建的工作流程图。

基于 DSL 的可视化搭建的本质是将前端开发工作转变成「做配置」,这种方式的优势在于实现是非常简单的。所有物料生态、物料开发方式、产物的预览方式、运行方式、发布方式等,都是围绕这种「配置」方式。

上面两张图片分别展示了我之前工作过平台的 DSL 片段截图。第一张图片描述了 View 的相关信息,另一张图片则描述了 Data 的相关信息。

❓:基于 DSL 的可视化搭建实现方式上有什么问题呢? 🙋:核心问题有三点:

  • 物料平台锁定。由于 DSL 一般是内部定义,这就导致解析、渲染DSL的组件必然会和它绑定起来。
  • 倾向于垂直领域。比如你现在能推测出第二张图片里面描述的相关信息吗?DSL 的定义一般会结合业务场景,图片二描述一道有关互动题目的相关信息,比如互动题目类型是拖拽,作答方式是多选等。不同业务场景差异性是非常大的,所以很难去定义一套比较通用的 DSL 定义。
  • 历史包袱严重。例如由于业务需求变化,“answerArea”字段变成对象数组,那么新的渲染器逻辑就必须要兼容两种逻辑了。

总结两点

  1. 解决灵活的组件开发以及业务定制化需求
  2. 解决暴露 DSL 所带来的问题

星夜(Starry)

星夜是以 Code In & Code Out 模式为核心,输入封装良好的物料,输出专业的前端工程源码,不对外生产 DSL 的全码可视化搭建平台。

星夜行为逻辑

星夜通过 Code In(自定义开发物料)解决了灵活的组件开发以及业务定制化需求,Code Out 解决了因 DSL 暴露所带来的问题。

Code In

物料作为搭建平台的原料,其地位不言而喻,而满足业务定制化需求的自定义物料开发则是物料开发中最重要的一环。特别是对于接入星夜的业务方研发来说,开发方式越贴近原生、开发概念越少、现有组件迁移物料成本越低会更有利于物料开发。下面会举两个例子展示星夜物料的开发过程。

基础功能

星夜的物料是本质就是一个 React 的组件,只不过我们约定了一些运行时协议,用于将普通的 React 组件变成物料。首先来看左侧的物料代码,它定义了一个简单的 React 组件。该组件接受三个参数 title、children 、onClick 分别表示渲染的文本标题、子节点以及点击事件的回调函数,整个组件最后被 createBlock 的 HOC 包裹后返回。右侧则展示通过 createEditor 和 addPropertyControls 去定义物料在星夜编辑器中的配置项,通过 props 名称去做映射关系。完成以上两个步骤就基本完成一个星夜物料的开发。

将开发好的物料拖入左侧结构树中后就可以进行配置,配置主要分为属性配置和逻辑配置。

  • 属性配置:在右侧属性配置面板配置 title 为 "Hello Starry",并在结构树中内容插槽部分拖入图片物料

  • 逻辑配置:在逻辑面板中点击事件后添加简单提示逻辑

中间画布实时显示了配置的实际效果,可以看到“Hello Starry”和图片以及成功的显示出来,当物料被点击时则会执行逻辑面板配置逻辑出现简单提示。

状态 & 方法暴露

在平时业务需求开发过程中,经常需要暴露组件内部状态&方法进行数据之间的联动,那么在星夜物料中是如何做到这一点呢?

借助运行时提供的 useGlobalState 和 ref 能轻松做到这一点,下面我们来看一下代码。

如上图所示,通过 useGlobalState 轻松定义了一个名为 data 的状态,紧接着通过 ref 向外暴露了 setData 方法用于修改 data 状态。下面 useEffect 的代码表示当 title 发生变化时修改内部状态 data,这样就完成了向外暴露 props 的功能了。右侧代码和上面类似,只不过这里不再使用 addPropertyControls 而是 addRefSchema 去定义在编辑器中的配置项。

为了验证其功能,在星夜编辑器中拖入一个新的文本组件,将文本组件的内容的绑定为组件的「暴露值」,文本组件也成功显示出“Hello Starry”。

通过上面两个真实星夜物料开发的例子,我们可以做一个小结。星夜物料开发主要分为两个部分,组件本身开发和属性、逻辑面板定义。因为星夜物料是基于 React 开发的,所以在开发上和平时的组件开发差异不大,只是为了在星夜编辑器上实现功能,加入了一些运行时相关的代码。而属性、逻辑面板定义则是通过星夜提供的插件去描述定义的,这块是比较简单。

越贴近原生开发越好”和“开发概念越少越好”这两个是基本符合的,那么还剩一个“现有组件迁移物料成本越低越好”怎么理解呢?这里就需要介绍星夜的另一个特点-平台解耦。

平台解偶

如下图所示还是上面开发的物料,只不过这一次是通过 Pro Code 的方式引入,可以看到也是能正常渲染的。这也就是意味着,之前业务方开发过的 Pro Code 组件经过改造、封装(主要是星夜运行时代码引入),以及属性、逻辑的配置定义就能变成星夜的物料。平台解耦的特性极大的提升了将业务接入到星夜平台的效率。

到这里我们回答了第一个问题“解决灵活的组件开发以及业务定制化需求”。下图是星夜物料的结构图, React 组件通过 createBlock 导出后,由运行时提供包括包括状态、插槽以及插件的功能。

Code Out

星夜的产出是一个完整的前端工程项目,并没有向外暴露 DSL,也就没有因为暴露 DSL 带来的问题,下面我们简单看一下代码生成相关的内容。

最左侧是星夜编辑器的主要三个配置,包括结构树、属性面板的配置以及逻辑面板的配置。中间则是编辑器内部维护存储其信息的数据结构,data 存储属性面板配置,以物料的 id 为 key,属性则以 key-value 的形式保存;slots 是存储结构树信息的,以物料 id 为 key,在 children 中储存其子节点相关信息;logic 储存逻辑面板信息,同样是以物料 id 为 key,value 以事件名称为映射保存,比如 type 是 serialize 表示其 content 是以串行执行的,与此相对还有 parallel,type 是 action 则表示具体事件了。

右侧是根据此数据结构生成的可执行代码,slots 用于生成 jsx 的嵌套关系,data 用于生成相应组件上的 props, logic 用于生成其绑定的事件,其它生成代码则是组件运行时需要的代码。整个 React Page 组件最后会被插入到一个完整的 Modern.js 工程当中。

实际效果

这张图片是火山引擎官网搭建的一张实际效果图片,左侧是业务方开发的业务物料,中间是搭建效果的实时预览,右侧是相应物料的属性配置表单。火山引擎官网在星夜平台搭建了超过150+的页面,沉淀了超过70+的物料组件,原先1-2人天的需求,最后可以独自由 PM、运营独立20min搭建配置出来,提升效果明显。

产物适配改造

不过不要高兴的太早,业务问题往往没有那么容易解决,正是因为接入星夜导致引入了新的问题。其一是火山引擎官网的开发已经进行了很长一段时间了,整个项目工程已经非常庞大,业务方希望保留原工程项目,并且想继续迭代。其二是火山引擎官网页面需要 SSR 。

总的来说,我们面临又了一个新的问题,是如何将搭建平台搭建的页面整合到火山引擎官网原项目当中,并且实现 SSR 。为了解决上面的问题,就用到微前端技术。

方案设计

Garfish 是字节开源的一款微前端框架,包括许多功能(动态加载子应用、路由劫持、数据通信、沙箱等),但是很可惜的是目前 Garfish 没有支持 SSR。因为火山引擎官网是需要支持 SSR,所以不能直接使用 Garfish。

Garfish 技术方案

这里简单解释一下为什么不支持 SSR,主要是因为微前端框架对主子应用的技术栈是没有要求的,比如说 React 子应用在服务端 renderToString 产生的字符串插入到 Vue 主应用的项目当中,在浏览器再次渲染时会出现不兼容的问题。除此之外,还得考虑服务端主子应用的数据通信、路由等,所以实现起来是非常麻烦的。不过庆幸的是火山引擎官网的原项目和星夜的产物都是 React 代码,这样我们就可以借鉴微前端思路将星夜的产物接入到火山引擎官网原项目当中,并且实现 SSR。

整体微前端接入方案如图所示,最下层当然就是星夜以及由它搭建出来的应用,然后经过打包、编译,通过原工程的部署服务关联资源后,就能在原工程中拿到星夜代码的产物了。最后就可以在原工程中实现星夜产物渲染、路由、SSR相关的逻辑。

方案落地

渲染

渲染主要包括三个部分下载代码、new Function 挂载组件、以及缓存、渲染组件。

左图是渲染功能的三步伪代码,右图是星夜的产物截图。其中第一步和第三步不做过多赘述了,主要来介绍一下第二步挂载组件。首先看一下打包后的产物,组件产物被包裹到 products 函数内部,然后根据环境分别将 products 挂载到 module 或者 window 上面。 第一步就需要拿到产物函数,我们通过 new Function 执行将 products 函数挂载到 module 对象上,紧接着通过执行 products 函数拿到挂载到 exports 对象上面的组件,获取到组件后,就可以正常渲染了。

路由

由于火山引擎原项目和星夜产出均使用 React 技术栈,所以路由控制这块只需要我们将上面拿到的组件使用 Route 组件包裹然后插入到原工程即可。

为了方便业务方使用,我们使用 React Context 将包裹好的组件暴露出来,然后通过 Route 组件插入到原工程即可。

SSR

由于火山引擎官网原项目本身已经支持 SSR,其次使用星夜搭建的火山引擎官网页面并没有使用外部数据,所以 SSR 本身的渲染逻辑和数据脱水、注水并不需要我们关心。不过由于 SSR 除了在服务端渲染外,还需要在浏览器上再渲染一遍,所以子应用模块列表还需要注入到 window 上面,在浏览器端渲染时从 window 上获取。除此之外还需要将打包过的 CSS 通过 style 标签插入进来。

到这里,为了接入火山引擎官网,对星夜产物的适配改造已经全部介绍完成了。

未来规划

火山引擎官网团队在接入星夜之后,产研团队协同模式发生了变化,研发由原来开发组件变成开发封装良好,屏蔽业务逻辑的物料;产品和运营同学能借助星夜平台的能力独立完成页面的搭建工作。随着业务需求不断的迭代,相应的业务物料也会越来越完善,整个团队运转会越来越高效。

因为篇幅的原因,还有很多关于星夜其他能力并未向大家展示出来。例如星夜还支持函数、变量、模板、代码编辑器、流程引擎等,同时也支持业务方以低码中台方式实现自己的搭建平台,全链路定制业务流程。业务方可以在星夜提供编辑器 SDK 和 OpenAPI 的基础上,结合业务定制能力(如权限、后端搭建、模板等),打通业务全链路流程,实现业务自己的搭建平台。

当然如果企业内部希望直接复用星夜的搭建能力,我们支持以私有化部署的方式部署到企业内部环境。(已和多家知名企业合作中)

我们是字节跳动基础架构研发效能团队,如果您也对搭建平台感兴趣,不妨加入我们,一起打造一款先进的搭建产品吧!🚀🚀🚀

内推地址:https://job.toutiao.com/s/FvJ55u8

如果你对我们做的事情比较感兴趣,或者对岗位什么疑惑,欢迎加群讨论。加群方式:添加扫码微信「wxid_yxpo65himowi22」,备注「星夜平台」。

origin_img_v2_438ef353-9ac4-41a5-b220-4d061dbfd96g.jpg