猫耳大型活动提效——组件低代码化

1. 引言

猫耳前端在开发活动的过程中,经历过传统的 pro code 阶段,即活动页面完全由前端开发编码实现,直到 2020 年接入公司内部的低代码活动平台,满足了大部分日常活动的需求,运营可自主配置活动并上线,释放了相当一部分的开发人力。不过,此时的方案仍然无法很好地服务大型直播活动场景,比如年度 S 级的直播活动,这类活动赛程多且持续时间长(可长达两周),页面和组件都包含多种状态,运营难以配置出大型直播活动的所有需求,故此阶段的大型活动仍然完全由开发编码实现,需要占用较多人力,但此类活动从数量上来看连 1% 都不到。鉴于我们已在日常活动中积累维护了相当多功能的低代码组件,如何复用已有的低代码组件来更快实现更多活动玩法就成了一个值得研究的问题。此外,大型活动从筹备到结束,时间长达数月,而密集开发阶段可能只占其中的一个月,密集开发结束后的长尾需求又该如何优化提效?接下来本文将介绍猫耳前端在活动场景的低代码探索经验,以及最终稳定的开发模式。

2. 场景分析与问题识别

2.1 不同场景的开发方案

把时间先拨回 2022 年,当时我们已有一定的平台使用经验,从技术角度将活动划分为两大类型,根据业务需求采取不同的方案:

2.1.1 配置类页面(Low Code + No Code)

此类活动经产运及技术负责人评估后,若无需开发参与则由产运同事自助配置并上线。若需要开发参与,则视情况修改组件或开发 JS 或 CSS 补丁代码来实现,沉淀下来的代码也可用于后续的类似活动。

图片

2.1.2 开发类页面(Pro Code)

图片

在一些玩法较为复杂、活动状态多的场景,配置页面的难度可能会呈指数级上升,当时平台也并不具备完善的预览能力,所以此类活动几乎完全由开发负责实现(部分页面可能会跳转到配置类页面)。虽然工作量较大,但简单来说就是根据设计稿、产品需求文档、接口文档这几个关键输入来实现活动页面,在流程上并没有太多可说的。

图片

2.2 问题与尝试

回到引言的问题,在讨论更具体的解决方案之前,我们先看看在经过几次大型活动的 pro code 开发后发现了哪些问题,在前期又做了哪些尝试:

2.2.1 活动规则变更效率低

由于活动页为了保证用户体验会集成较多的玩法规则,由于运营无法在活动的密集开发阶段一次性给到准确无误或完全不变的规则说明,在活动上线前,前端需要持续配合更新页面内的活动规则,有时候是换图,有时候是调整文字描述,改动的发布流程较长且影响开发测试效率。

前期尝试:比较泛的解决方法是将前端写死的切图改为从静态资源服务中获取,我们也确实在个别活动中尝试约定过资源路径,产运将资源上传到特定路径后,开发使用约定好的路径来加载资源,但此方案并没有很好地利用现有的低代码平台(如:配置间距、管理资源版本),也存在额外的上手成本和维护成本。

2.2.2 部分常见的需求处理效率低

相似需求总是需要走开发上线的流程,导致开发人力总是紧张,且效率难提高,如:

  • 每次活动都会设计新的榜单样式,这类换皮工作对开发来说耗时且枯燥,影响其他需求的开发进度

  • 直播活动结束后,开发需要按业务流程固化榜单数据,每次都需要将服务端导出的数据替换到代码中,然后再走一遍上线流程

该问题在前期并没有想到很好的处理方法,直到后续复用低代码组件才得以解决。

2.2.3 重复开发组件

前端在大型活动中存在重复开发组件的情况(如:直播榜单组件)。榜单在直播活动中是标配组件,但大型活动页面状态较为复杂,无法直接通过低代码平台配置,导致这类场景我们一直没能复用运营配置的组件,于是又额外开发维护了一套 pro code 场景的榜单组件。

前期尝试:将配置了单个 low code 组件的页面通过 iframe 的形式载入页面框架内,也确实满足了一些活动需求,但同时也发现了其局限性:

  • 组件若涉及弹窗和遮罩,由于弹窗和遮罩都是基于 iframe 页面插入的,难以直接基于宿主页面居中摆放弹窗,遮罩的处理也比较复杂

  • 页面之间可能存在跨域的情况,个别需求得花心思解决

  • iframe 页面完整加载较慢,会重复请求宿主页面加载过的资源,部分请求也并非必要

以上提到的几个痛点,不仅影响我们每次活动的交付效率,也使得前端团队整体的资源利用率较低,前端团队总是处理类似需求得不到成长,也无法推进其它业务需求。

3. 解决方案与实施

秉持着不写新代码就没有新 bugDRY 的开发原则,作者在经过几次 pro code 活动后开始思考:是否有方案可以解决以上问题,让我们可以有精力去做其它更加价值的工作?

3.1 远程组件

2022 年 10 月,首个接入B站远程组件能力(内部名:片段加载器)的猫耳直播活动上线,本次活动在 pro code 页面框架的基础上加载了运营配置的低代码榜单组件、弹窗、活动规则等内容,解决了第一部分提及的所有问题。

图片

3.1.1 原理

顾名思义,远程组件依赖于服务端的组件数据,其包含三大数据:组件 JS 资源、组件 CSS 资源、组件 JSON 参数(运营配置)。组件数据的拉取、组件的渲染等工作,则由客户端的加载器提供支持。

前端研发人员在 pro code 页面框架内集成加载器后,只需传入约定好的页面片段 ID,加载器即可完成页面片段的拉取工作,并复用 low code 页面的渲染器完成渲染工作。

图片

3.1.2 项目工作流

上述编码细节转变的背后,更深层次的转变其实是「开发类页面工作流程」的转变,以及项目人员的工作职责变化。

图片

从新的流程中不难观察到,前端能够在设计稿尚未交付的情况下就提前介入,设计一些适合低代码化的功能模块,然后转交给运营配置使用。前端不仅能够在更专注业务逻辑的情况下提前交付运营也在复杂活动中获得了调整和发布的能力(仅限于部分功能模块),一些运营侧的调整也不必再走前端的发布流程,减少各端沟通返工的情况,项目的整体效率更高。

回到第一部分的具体问题来说,技术侧从以往活动中识别出后期需求、维护需求、效率问题后,可以借助低代码平台将流程功能化,从而实现更顺滑的交付效果。

3.1.3 接入前后的代码对比

旧的代码实现

为了更好地理解效率提升的效果,让我们先看一个典型的旧代码实现示例。这段代码展示了如何编写一个直播榜单组件,一个需要定制的 pro code 榜单通常需要 100+ 行的 CSS 代码,这也意味着前端要等设计资源完全 ready 后才能进开发(给设计也带来了压力),而在活动中需要定制的榜单往往不止一个,且每次活动都需要开发。在活动 DDL 明确的情况下,很容易给前端造成任务堆积,人力不足的问题。

图片

新的代码实现

现在,通过采用远程加载低代码组件的方法,我们大大简化了这个过程。下面是一个使用远程加载低代码组件的示例代码。前端只需一行代码即可加载运营配置的 low code 榜单组件,无需编写繁琐的 CSS 代码,设计同事也可以调低榜单模块的优先级,优先完成其它高优的设计任务。

图片

以下是直播榜单组件在后台系统中的界面截图,展示了运营人员如何通过界面配置而不是编写代码来完成同样的任务。

图片

3.2 接入方案

以下是猫耳前端在接入公司内部低代码平台过程中积累的接入方案。

3.2.1 Pro Code 页面能力对齐 Low Code 页面

为确保 low code 组件能够在 pro code 页面框架内正常运行,我们将一些页面的基础能力封装到了单独的包内,使得不同环境都能够获得一致的效果。

基于 RxJS 实现组件间的数据共享与事件通信

在 low code 页面中,我们基于 RxJS 的 BehaviorSubject 实现了页面级别的数据共享方案,各组件可通过订阅 window 上挂载的 BehaviorSubject 数据流,及时获取全局数据(如:活动状态)。

而在 pro code 页面框架内,在综合考虑开发成本、性能、隔离性(不考虑沙盒环境)这几点后,所以我们直接在页面框架内复用了 low code 页面的初始化流程,确保各组件能够直接接入页面。

图片

内置 Low Code 环境组件,优化加载速度

在 low code 页面中,我们用于初始化页面环境的组件本身也是个 low code 组件,按流程来说,在 pro code 页面内使用时也需要等待加载器的拉取渲染时间,而其余组件则要等初始化完成后才能正常渲染,所以存在一定的阻塞情况。

图片

优化前的默认实现

以下是优化前的页面初始化时序图。

图片

优化后的实现

优化后的时序图已经在远程组件的 3.1.1 原理小节贴过了,可以返回查看。

简而言之,我们将 low code 页面的环境组件直接集成到了 pro code 页面框架内,跟随页面一起构建发布,并且屏蔽了加载器对于环境组件的拉取和渲染逻辑,使得页面能够更快完成初始化。

Pro Code 页面维护所有 Low Code 组件配置数据,支持「合并同类组件的请求」

对于传统的 pro code 页面来说,如果出现需要请求同一接口的同类组件(如:多个音频、多个主播的信息),我们可能只需要在请求时带上 ID 数组即可,但对于 low code 页面来说,为了保证最灵活的制作能力,我们不一定会封装固定布局的组件,更倾向于封装原子组件或者较为基础的业务组件,所以运营拖入页面的可能是一个个独立的组件(同类组件,但配置了多个),每个组件都单独配置了 ID,如果不做处理的话可能会并发出非常多的请求。

图片

图片

对于这种场景,我们以前采取的方案是:在该 low code 组件的 JS 资源被插入执行时(此时渲染器还没有渲染组件),读取页面内配置的所有同类组件,合并配置后统一发出请求,然后借助 rxjs 缓存接口响应数据。等到组件被渲染器实际渲染出来后,再订阅该 rxjs 数据源,实现合并批量请求的目的。

如果现在需要在 pro code 页面框架内实现该场景,对比 low code 页面我们缺少了直接可用的完整组件配置,需要等所有片段都加载完才能拿到完整组件数据。不过这也不难解决,基于已有的 rxjs 数据共享流程,我们只需要对这类组件稍加改造,将直接获取所有组件的配置数据改为订阅所有组件的配置数据。当页面框架逐个获取到组件信息后,逐个塞入 rxjs subject 的组件数据列表,然后组件侧结合 rxjs debounce 操作符(避免频繁请求接口),按一样的流程请求接口获取数据即可。

以下是简化后的请求远程组件并渲染的核心流程。

fetchSegment(pageId)  .then(async (res: any) => {    if (!res || !containerRef.current) {      console.error('segment load failure')      return    }    const { info, render } = res    if (!loadedPageIds.includes(pageId)) {      loadedPageIds.push(pageId)      const newComponentsMap = makeComponentsMap(info.configure?.pageData)      window.MissEvanEvents.next((prev: any) => {        const mergedComponentsMap = Object.entries(newComponentsMap).reduce((acc, [key, value]) => {          acc[key] = (acc[key] ?? []).concat(value)          return acc        }, prev.componentsMap ?? {})        return {          ...prev,          componentsMap: mergedComponentsMap,        }      })    }    render({ container: containerRef.current, needRenderEnvComponent: false })  })  .catch((e: any) => {    console.error('segment load failure', e)  })

3.2.2 规范代码块开发模式

上文在配置类页面已经提到过代码块,代码块由 JS 和 CSS 文件构成,在特定时机插入页面执行,主要执行一些 dom 操作或添加样式。在 pro code 页面框架内集成代码块时我们也做了一些优化工作。

由于代码块的效果依赖 JS 的插入执行,在按需渲染的场景会存在重复插入执行的情况,若忘记清理副作用也更容易出现问题(如:事件泄漏、定时器无法终止)。为优化该问题,我们在 JS 中临时加入了一些代码来检查逻辑是否执行过,以及定时任务是否需要执行等操作,避免出现不必要的问题,并在后续基于 document.currentScript 设计了一套代码块的生命周期函数,用于规范常用代码块的参数、执行、清理。

// 代码块被插入时的定制逻辑
function mount(dependency) {}

// 代码块被销毁时的清理逻辑
function unmount(dependency) {}

ContextManager.initLifecycle({ mount, unmount })

​​​​​​​

我们在 24 年 3 月份将该方案提交给活动中台并进行了比较密切的几次讨论,平台综合各个业务的需求在 24 年 9 月份上线了更加通用的平台级别的代码块开发工具,后续也仍在持续迭代。

4. 成果与效益

4.1 释放前端开发人力

鉴于活动玩法并非一成不变,不同开发者的能力也有区别,单纯的代码量或是工时人天数据并不能准确体现出低代码带来的提升,顶多用于内部预估未来活动的工作量,故以下统计的是各个具有代表性的活动低代码程度,以及组件和代码块的复用情况。由于部分需求比较零散,实际成果可能会比下表更多一些:

图片

从表中可以发现前端自主开发了非常多的代码块,尤其是某些乍一看随便写写也挺快而且没啥复用价值的功能模块,我们也选择将其低代码化交由运营配置。这样做的好处是:不仅大部分内容可以实现脱离设计稿提前开发,还可以摆脱许多后期需求和维护需求,对前端开发来说是一个非常有利的提效模式。

从岗位职责的角度来看,也可以认为代码块开发模式(高频)是在产品正式介入组件设计前(较低频),前端提前将功能模块进行了一部分的抽象设计,便于后续将该功能开发成低代码组件。在代码块开发模式下,运营侧的体验可能弱于组件模式(平台层面已在优化这个问题,如:降低配置难度,提高开发效率),但是仍能够保持一定的交付效率,以及用户侧一致的体验。

4.2 版本管理颗粒度进一步细化

pro code 页面接入 low code 组件后,也带来了一个副产品——页面被打散,版本管理的颗粒度更细了。我们也亲身经历过线上活动出现紧急问题,产运直接调整发布,快速缩小影响范围然后开发再排查修复的情况。远程组件让我们在应急处理线上问题时又多了一种手段。

5. 结语

以上是猫耳前端对于活动低代码场景的探索和经验总结,欢迎在评论区继续讨论,一起挖掘业务提效的方法。在此感谢猫耳前端组以及 EVA 平台组一起参与建设的同事们,特别感谢 EVA 平台组的璇儿、琥珀草、谷风长道、小白白川、V、Fryderyk 等同事对我们提供的大力支持。对 bilibili 活动中台系统设计感兴趣的小伙伴可以继续移步查看这篇新活动平台建设历程与架构演进。

   -End-

     作者丨Helson、Rui

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/984359.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ESP8266UDP透传

1. 配置 WiFi 模式 ATCWMODE3 // softAPstation mode 响应 : OK 2. PC 连⼊入 ESP8266 softAP 就是连接wifi 3.查询ESP8266设备的IP地址 ATCIFSR 响应: CIFSR: APIP, "192.168.4.1" CIFSR: APMAC, "1a: fe: 34: a5:8d: c6" CIFSR: STAIP, "192.…

【仿muduo库one thread one loop式并发服务器实现】

文章目录 一、项目介绍1-1、项目总体简介1-2、项目开发环境1-3、项目核心技术1-4、项目开发流程1-5、项目如何使用 二、框架设计2-1、功能模块划分2-1-1、SERVER模块2-1-2、协议模块 2-2、项目蓝图2-2-1、整体图2-2-2、模块关系图2-2-2-1、Connection 模块关系图2-2-2-2、Accep…

私有云基础架构与运维(二)

二.私有云基础架构 【项目概述】 经过云计算基础知识及核心技术的学习后,希望进一步了解 IT 基础架构的演变过 程,通过学习传统架构、集群架构以及私有云基础架构的相关知识,认识企业从传统 IT 基 础架构到私有云基础架构转型的必要性。…

DeepSeek R1-32B医疗大模型的完整微调实战分析(全码版)

DeepSeek R1-32B微调实战指南 ├── 1. 环境准备 │ ├── 1.1 硬件配置 │ │ ├─ 全参数微调:4*A100 80GB │ │ └─ LoRA微调:单卡24GB │ ├── 1.2 软件依赖 │ │ ├─ PyTorch 2.1.2+CUDA │ │ └─ Unsloth/ColossalAI │ └── 1.3 模…

vue3 vite项目安装eslint

npm install eslint -D 安装eslint库 npx eslint --init 初始化配置,按项目实际情况选 自动生成eslint.config.js,可以添加自定义rules 安装ESLint插件 此时打开vue文件就会标红有问题的位置 安装prettier npm install prettier eslint-config-pr…

【五.LangChain技术与应用】【10.LangChain ChatPromptTemplate(下):复杂场景下的应用】

凌晨两点的西二旗,你盯着监控大屏上跳动的错误日志,智能客服系统在流量洪峰中像纸船一样摇晃。用户骂声塞满弹窗:“等了十分钟就这?”“刚才说的怎么不认了?”“我要人工!!”——这时候你需要的不只是ChatPromptTemplate,而是给对话系统装上航天级操控台。 一、模板组…

javascrip网页设计案例,SuperSlide+bootstrap+html经典组合

概述 JavaScript作为一种强大的脚本语言,在网页设计领域发挥着举足轻重的作用,能够为网页赋予丰富的交互性与动态功能。以下通过具体案例来深入理解其应用。​ 假设要打造一个旅游网站,该网站具备诸多实用功能。在响应式设计方面&#xff0…

python量化交易——金融数据管理最佳实践——使用qteasy大批量自动拉取金融数据

文章目录 使用数据获取渠道自动填充数据QTEASY数据拉取功能数据拉取接口refill_data_source()数据拉取API的功能特性多渠道拉取数据实现下载流量控制实现错误重试日志记录其他功能 qteasy是一个功能全面且易用的量化交易策略框架, Github地址在这里。使用它&#x…

Vite 6 升级指南:CJS 和 ESM 的爱恨情仇

Vite 6 升级指南:CJS 和 ESM 的爱恨情仇 前言:老朋友 CJS,新欢 ESM 说到 JavaScript 模块化,CJS 和 ESM 这俩货简直像是两代人的思维碰撞。前者是 Node.js 的老朋友,后者是前端新时代的宠儿。Vite 6 直接把 CJS 踢出…

FreeRTOS任务状态查询

一.任务相关API vTaskList(),创建一个表格描述每个任务的详细信息 char biaoge[1000]; //定义一个缓存 vTaskList(biaoge); //将表格存到这缓存中 printf("%s /r/n",biaoge); 1.uxTaskPriorityGet(&#xf…

【3】VS Code 新建上位机项目---C#窗体与控件开发

【3】VS Code 新建上位机项目---C#窗体与控件开发 1 窗体1.1 新建窗体1.2 windows程序与窗口的关系1.3 windows程序的事件1.3.1 定义事件与处理事件1.3.2 关联事件1.3.3 Windows窗体对象创建与显示(show与ShowDialog())2 控件与容器2.1 常用容器2.1.1 Groupbox2.1.2 Pannel2.1.…

AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异

背景 字节跳动正式发布中国首个AI原生集成开发环境工具(AI IDE)——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro,支持切换满血版DeepSeek R1&V3, 可以帮助各阶段开发者与AI流畅协作,更快、更高质量地完…

ubuntu 20.04下ZEDmini安装使用

提前安装好显卡驱动和cuda,如果没有安装可以参考我的这两篇文章进行安装: ubuntu20.04配置YOLOV5(非虚拟机)_ubuntu20.04安装yolov5-CSDN博客 ubuntu20.04安装显卡驱动及问题总结_乌班图里怎么备份显卡驱动-CSDN博客 还需要提前…

2025数据存储技术风向标:解析数据湖与数据仓库的实战效能差距

一、技术演进的十字路口 当前全球数据量正以每年65%的复合增长率激增,IDC预测到2027年企业将面临日均处理500TB数据的挑战。在这样的背景下,传统数据仓库与新兴数据湖的博弈进入白热化阶段。Gartner最新报告显示,采用混合架构的企业数据运营效…

Spring(1)——mvc概念,部分常用注解

1、什么是Spring Web MVC? Spring MVC 是一种基于 Java 的实现了 MVC(Model-View-Controller,模型 - 视图 - 控制器)设计模式的 Web 应用框架,它是 Spring 框架的一个重要组成部分,用于构建 Web 应用程序。…

PY32MD320单片机 QFN32封装,内置多功能三相 NN 型预驱。

PY32MD320单片机是普冉半导体的一款电机专用MCU,芯片采用了高性能的 32 位 ARM Cortex-M0 内核,主要用于电机控制。PY32MD320嵌入高达 64 KB Flash 和 8 KB SRAM 存储器,最高工作频率 48 MHz。PY32MD320单片机的工作温度范围为 -40 ~ 105 ℃&…

《OkHttp:工作原理 拦截器链深度解析》

目录 一、OKHttp 的基本使用 1. 添加依赖 2. 发起 HTTP 请求 3. 拦截器(Interceptor) 4. 高级配置 二、OKHttp 核心原理 1. 责任链模式(Interceptor Chain) 2. 连接池(ConnectionPool) 3. 请求调度…

HeidiSQL:一款免费的数据库管理工具

HeidiSQL 是一款免费的图形化数据库管理工具,支持 MySQL、MariaDB、Microsoft SQL、PostgreSQL、SQLite、Interbase 以及 Firebird,目前只能在 Windows 平台使用。 HeidiSQL 的核心功能包括: 免费且开源,所有功能都可以直接使用。…

C/C++蓝桥杯算法真题打卡(Day3)

一、P8598 [蓝桥杯 2013 省 AB] 错误票据 - 洛谷 算法代码&#xff1a; #include<bits/stdc.h> using namespace std;int main() {int N;cin >> N; // 读取数据行数unordered_map<int, int> idCount; // 用于统计每个ID出现的次数vector<int> ids; …

【2025软考高级架构师】——软件工程(2)

摘要 本文主要介绍了软件工程中常见的多种软件过程模型&#xff0c;包括瀑布模型、原型模型、V模型、W模型、迭代与增量模型、螺旋模型、构件组装模型、基于构件的软件工程&#xff08;CBSE&#xff09;、快速应用开发&#xff08;RAD&#xff09;、统一过程/统一开发方法和敏…