前端新思路:组件即函数和Serverless SSR实践

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 在今天,对于Node.js运维和高并发依然是很有挑战的,为了提效,将架构演进为页面即服务,可是粒度还不够,借着云原生和Serverless大潮,无运维,轻松扩展,对前端是极大的诱惑。那么,基于FaaS之上,前端有哪些可能性呢?

image.png

在今天,对于Node.js运维和高并发依然是很有挑战的,为了提效,将架构演进为页面即服务,可是粒度还不够,借着云原生和Serverless大潮,无运维,轻松扩展,对前端是极大的诱惑。那么,基于FaaS之上,前端有哪些可能性呢?

2019年上半年,我在阿里巴巴经济体前端委员会推进的Serverless研发体系共建项目中负责Serverless SSR的研究,将CSR,SSR,边缘渲染进行整合和尝试,提出组件即服务的概念(Component as Service),试图结合FaaS,做出更简单的开发方式。本次分享主要围绕Serverless SSR和它的演进过程、背后思考为主。

本文是狼叔在D2大会的分享《前端新思路:组件即服务和Serverless SSR实践》的内容,阅读需要10分钟,你将了解如下内容。

  1. 可以了解Serverless时代端侧渲染面临的具体问题
  2. 可以了解Serverless SSR规范以及渲染体系的完整工作链路和原理
  3. 为业内提供解决Serverless SSR渲染问题的新思路

image.png

狼叔(网名i5ting)现为阿里巴巴前端技术专家,Node.js 技术布道者,Node全栈公众号运营者,曾就职于去哪儿、新浪、网秦,做过前端、后端、数据分析,是一名全栈技术的实践者。目前负责BU的Node.js和基础框架开发,已出版《狼书(卷1) 更了不起的Node.js》。

Wolfred Sang (a.k.a. i5ting) is a full-stack developer and Node.js evangelist. He works for Alibaba Group as a Principal Front-End Developer and runs a self-media on the topic of Full-stack Node.js. He worked for well-known dot-com companies in the past, such as Qunar, Sina and NQ Mobile. His expertise and experiences cover not only front-end development but also back-end engineering and data insight extracting. He is currently leading the Node.js development and maintaining the core codebase in his business unit. His book “The Marvelous Node.js” (Part I) was published in July 2019.

技术趋势分析

image.png

今年的技术趋势,我的判断是技术混乱期已过,提效才是今日的挑战。

image.png

在Node.js领域,今年新东西也不多,最新已经发布到13,lts是12,Egg.js的生态持续完善,进度也不如前2年,成熟之后创新就少了。在很多框架上加入ts似乎已经政治正确了。比如自身是基于ts的nest框架,比如阿里也开源了基于Egg生态的midway框架,整体加入ts,类型系统和oop,对大规模编程来说是非常好的。另外GraphQL也有很强的应用落地场景,尤其是Apollo项目带来的改变最大,极大的降低了落地成本。已经用rust重写的deno稳步进展中,没有火起来,但也有很高的关注度,它不会替代Node.js,而是基于Node之上更好的尝试。

今日的Node.js存在的问题是会用很容易,做到高可用不容易,毕竟高可用对架构运维要求更好一些,这点对前端同学要求会更难一些。做到高可用之后,做性能调优更难。其实,所有这些难点的背后是基于前端工程师的角度来考虑的,这也是非常现实的问题。

对于很多团队,上Node是找死,不上Node是等死。在今天web框架已经相当成熟,所以如何破局,是当下最破解需要解决的问题。

你可能会感觉Node.js热度不够,但事实很多做Node.js的人已经投身到研发模式升级上了。对于今天的Node.js来说,会用很容易,但用好很难,比如高可用,性能调优,还是非常有挑战的。我们可以假想一下,流量打网关,网关根据流量来实例化容器,加载FaaS运行时环境,然后执行对应函数提供服务。在整个过程中,不许关心服务器和运维工作,不用担心高可用问题,是不是前端可以更加轻松的接入Node.js。这其实就是当前大厂前端在做的前端基于Serverless的实践,比如基于FaaS如何做服务编排、页面渲染、网关等。接入Serverless不是目的,目的是让前端能够借助Serverless创造更多业务价值。

为何如此钟爱SSR?

在2017年底,优酷只有passport和土豆的部分页面用Node.js,QPS不高,大多是一些尝试性业务,优酷PC和H5核心页面还都是PHP模板渲染。最近2年基于阿里强大的技术体系,我们也对PC、H5多端进行了技术改造。今年双十一是React SSR第一次扛双十一,具有一定意义,这里简单总结回顾和展望。

背景就不赘述了,参见《看优酷 Node 重构之路,Serverless SSR 未来可期》

image.png

  • 将优酷C端核心页面全部用Node重写,完成了PHP到Node.js的迁移。在没有PHP同学的情况下,前端可以支撑业务。
  • 性能提升明显,从v1(Bigpipe+jQuery)到v2(React SSR),性能逐步提升。PC页面首屏渲染降到150ms、播放器起播时间从4.6秒优化到2秒。H5站上了React SSR后,性能提升3倍,H5唤端率提升也极其明显,头条短视频唤端率由5.68%提升到9.4%,环比提升65%。单机性能qps从80提升150+(压测最高可以到300左右)。
  • QPS过万,2年没有p4以上故障,相对来说是比较稳定的。扛过双十一、世界杯,最高三倍以上的流量。
  • 在集团前端委员会承担Serverless SSR专项。

裕波曾经问我,为何如此钟爱SSR?

从前端的角度看,它是一个相对小的领域。PC已经非主流,H5想争王者,却不想被rn、weex中间截胡。怎么看,SSR能做的都有限。但是,用户体验提升是永远的追求,另外web标准化是正统,在二者之间,和Node做结合,除了SSR,目前想不到更好的解法。

贴着C端业务,从后端手里接过来PC、H5,通过Node构建自己的生存之地是必然的选择。

活下来之后就开始有演进,沉淀,通过C端业务和egg-react-ssr开源项目的沉淀,我们成功的打通2点。

  1. 写法上的统一:CSR和SSR可以共存,继而实现二种模式的无缝切换
  2. 容灾降级方案:从Node SSR无缝切换到Node的CSR,做到第一层降级,从Node CSR还可以继续降到CDN的CSR

2019年,另外一个风口是Serverless,前端把Serverless看成是生死之地,下一代研发模式的前端价值证明。那么,在这个背景下,SSR能做什么呢?基于FaaS的SSR如何呢?继续推演,支持SSR,也可以支持CSR,也就是说基于FaaS的渲染都可以支持的。于是和风驰商量,做了Serverless端侧渲染方向的规划。

本来SSR是Server-side render,演进为Serverless-side render。元彦给了一个非常好概念命名,Caaf,即Component as a fuction。渲染层围绕在以组件为核心,最终统统简化到函数层面。

在今天看,SSR是成功的,一个曾经比较偏冷的点已经慢慢变得主流。集团中,基于React/Rax的一体化开发,可以满足前端所有开发场景。优酷侧的活动搭建已经升级到Rax1.0,对外提供SSR服务。在uc里,已经开始要将egg-react-ssr迁移到FaaS上,代码已经完成迁移。

  • PC/中后台,React的CSR和SSR
  • 移动端/H5,Rax的CSR和SSR。尤其是Rax SSR给站外H5提供了非常好的首屏渲染时间优化,对C端或活动支持是尤其有用的。

在2020年,基于FaaS之上的渲染已经获得大家的认可。另外大量的Node.js的BFF应用已经到了需要治理的时候,BFF感觉和当年的微服务一样,太多了就会牵扯到管理成本,这种情况下Serverless是个中台内敛的极好解决方案。对前端来说,SSR让开发变得简单,基于FaaS又能很好的收敛和治理BFF应用,结合WebIDE,一种极其轻量级基于Serverless的前端研发时代已经来临了。

Serverless-side render概念升级

从BFF到SFF

了解SSR之前,我们先看一下架构升级,从BFF到SFF的演进过程。

BFF即 Backend For Frontend(服务于前端的后端),也就是服务器设计 API 时会考虑前端的使用,并在服务端直接进行业务逻辑的处理,又称为用户体验适配器。BFF 只是一种逻辑分层,而非一种技术,虽然 BFF 是一个新名词,但它的理念由来已久。

在Node.js世界里,BFF是最合适的应用场景。常见的API、API proxy、渲染、SSR+API聚合,当然也有人用来做网关。

从Backend For Frontend升级Serverless For Frontend,本质上就是利用Serverless基建,完成之前BFF的工作。那么,差异在哪里呢?

image.png

核心是从Node到FaaS,本质上还是Serverless,省的其实只是运维和自动扩缩容的工作,一切看起来都是基建的功劳,但对于前端来说,却是极为重大的痛点解决方案,能够满足所有应用场景,基于函数粒度可以简化开发,乃生死必争之地。

SFF前后端分工

Serverless简单理解是FaaS+BaaS。FaaS是函数即服务,应用层面的对外接口,而BaaS则是后端即服务,更多的是业务系统相关的服务。当下的FaaS还是围绕API相关的工作为主,那么,前端如何和Serverless绑定呢?

Serverless For Frontend(简称SFF)便是这样的概念,基于Serverless架构提供对前端开发提效的方案。

下面看一下SFF分工,这张图我自认为还是非常经典的。首先将Serverless劈成2半,前端和后端,后端的FaaS大家都比较熟悉了,但前端页面和FaaS如何集成还是一片待开发的新领域。

image.png

举个例子,常见BFF的例子,hsf调用获得服务端数据,前端通过ctx完成对前端的输出。这时有2种常见应用场景

  1. API,同后端FaaS(RPC居多)
  2. 页面渲染(http居多)

基于FaaS的页面渲染对前端来说是必须的。从beidou、Next.js、egg-react-ssr到Umi SSR,可以看出服务端渲染是很重要的端侧渲染组成部分。无论如何,React SSR都是依赖Node.js Web应用的。那么,在Serverless时代,基于函数即服务(Functions as a Service,简写为FaaS)做API开发相关是非常简单的。

1)无服务,不需要管运维工作
2)代码只关系函数粒度,面向API变成,降低构建复杂度
3)可扩展

image.png

目前还是Serverless初期,大家还是围绕API来做,那么,在FaaS下,如何做好渲染层呢?直出HTML,做CSR很明显是太简单了,对于React这种高级玩法如何集成呢?

其实我们可以做的更多,笔者目前能想到的Serverless时代的渲染层具有如下特点。

  • 采用Next.js/egg-react-ssr写法,实现客户端渲染和服务端渲染统一
  • 采用Umi SSR构建,生成独立umi.server.js做法,做到渲染
  • 采用Umi做法,内置Webpack和React,简化开发,只有在构建时区分客户端渲染和服务端渲染,做好和CDN如何搭档,做好优雅降级,保证稳定性
  • 结合FaaS API,做好渲染集成。 为了演示Serverless下渲染层实现原理,下面会进行简要说明。在Serverless云函数里,一般会有server.yml作为配置文件,这里以lamda为例子。

image.png

SSR概念升级

现状

  1. 现有FaaS主要是针对API层做扩展,视图渲染是一个新的命题。
  2. 竞品Serverless.com提供了Components类似的视图渲染层方案
  3. 如何打造一个基于阿里技术栈又有业界领先的端侧渲染解决方案

业界还缺少最佳实践,这是极好的机会。因此,我们对SSR做了概念上的升级(感谢justjavac大佬的提示)

image.png

Serverless端渲染层,是针对 SSR 做概念和能力升级

  • SSR 从 Server side render 升级为 Serverless side render,基于FaaS环境,提供端侧页面渲染能力。
  • Serverless渲染层涵盖的范围扩展,从服务器端渲染升级到同时支持 CSR 和 SSR 2种渲染模式。

在 Serverless 背景下,页面渲染层包含2种情况。

  • 基于 FaaS 的客户端渲染
  • 基于 FaaS 的服务器端渲染

目标是提供基于 FaaS 的页面渲染描述规范,提供标准化组件描述,统一组件写法,用法简单,易实现,可扩展。因此,我们制定了SSR-spec规范,下面会详细讲解。

Serverless-side render规范和实现原理

在讲规范之前,我们先简单了解3个术语。

image.png

CSR和SSR

先科普一下CSR和SSR的概念
客户端渲染(简称CSR),简单理解就是html是没有被动态数据灌入的,即所谓的静态页面。比如通过React、Rax编写的组件,打包构建后,以html文件形式分发到CDN上,不需要Node.js支持,就是非常典型的CSR。

image.png

资源加载完成后(注意:只有一个bundle,一次性吐出),通过React中的render API进行页面渲染。优点是不需要服务端接入,简单,对于性能要求不高的页面是非常合适的。中后台应用大多是CSR,优化也都是打包环节玩。

服务器端渲染(SSR),简单理解就是html是由服务端写出,可以动态改变页面内容,即所谓的动态页面。早年的php、asp、jsp这些Server page都是SSR的。但基于React技术栈,又有些许不同,server bundle构建的 时候,要吐多少模块,是server端决定的。client bundle和之前一样,差别在于这次是hydrate,而非render。

image.png

hydrate是 React 中提供在初次渲染的时候,去复用原本已经存在的 DOM 节点,减少重新生成节点以及删除原本 DOM 节点的开销,来加速初次渲染的功能。主要使用场景是服务端渲染或者像prerender等情况,所以在图中hydrate之后才是tti时间。

如果想全局了解CSR和SSR,共分5个阶段,参考下图。

image.png

纯服务端渲染和纯客户端渲染是2个极端,React SSR是属于中间的,这种服务端吐出的粒度是可以根据业务来控制的,可以服务端多一点,性能会差,也可以服务端吐出刚好够首屏的数据,其他由客户端来处理,这种性能会好很多。Static SSR和预渲染的CSR也是特定场景优化的神器。

最佳写法

了解了CSR和SSR的区别,下面我们看一下最佳写法是如何演进的。业内最好的实现大概是next.js了,抛开负责度不谈,单就写法来说,它确实是最合理的。

既然是基于React做法,核心肯定以Component为主,在Component上扩展静态方法用于接口请求是很好的实践。写法如下。

image.png

早年写过bigpipe相关事项,其中模块成为biglet,它的作用是获取接口,结合tpl生成html。

image.png

biglet的生命周期如下。

before
.then(self.fetch.bind(self))
.then(self.parse.bind(self))
.then(self.render.bind(self))
end
AI 代码解读

fetch是获取接口数据,parse解析数据,最终赋值给data。render是模板引擎编译的函数。每个函数的返回值都约定是promise,便于做流程控制。

很明显,biglet和Component是异曲同工的,而fetch是对象上的方法,必须实例化biglet才能调用,而next的做法getInitialProps是静态方法,不必实例化,内存和复用性上都是非常好的。

这点在egg-react-ssr项目技术选型调研期,我们就已经达成一致了。问题是,next只支持SSR,如何能够更好的支持CSR?做到真正的组件级别的同构。于是,基于这种写法,通过高阶组件进行包装,轻松实现了CSR,核心代码如下。

image.png

既然写法上统一了,那么,我们还能进一步进行优化么?核心点在网络获取部分。我们能看到的gRPC-web或isomorphic-fetch,分别实现了:1)RPC和http的约定,2)CSR和SSR中fetch统一。给我们带来的启示是在getInitialProps里,我们还可以做更多同构的玩法。

image.png

在webpack打包构建server bundle了的时候会注入isBrowser变量。

const plugins = [
  new webpack.DefinePlugin({
    '__isBrowser__': false //eslint-disable-line
  })
]
AI 代码解读

以此来区分CSR和SSR做同构兼容就更简单了。

Page.getInitialProps = async (ctx) => {
    if (__isBrowser__) {
        // for CSR
    } else {
        // for SSR
    }
}
AI 代码解读

以上做法,都是我们基于 https://github.com/ykfe/egg-react-ssr 提炼出来的实践,这些都是SSR-spec的基础。

FaaS和SSR如何结合

有了egg-react-ssr,确立了最佳写法,接下来就是结合FaaS做好集成。

image.png

对比一下,getInitialProps的参数和FaaS函数的参数都有context,这个是非常好的

解法:给 context 扩展SSRRender方法。

为了演示Serverless下渲染层实现原理,下面会进行简要说明。在Serverless云函数里,一般会有server.yml作为配置文件,这里以lamda为例子。

image.png

通过这个配置,我们可以看出函数app.server对应的http请求路径是'/',这个配置其实描述的就是路由信息。对应的app.server函数实现如下图。

image.png

通过提供ctx.SSRRender方法,读取dist目录下的Page.server.js完成服务端渲染。

核心要点:

  • SSRRender方法比较容易实现
  • 采用类似Umi SSR的方式,将源码打包到Page.server.js文件中
  • 在发布的时候,将配置,app.server函数和Page.server.js等文件上传到Serverless运行环境即可

架构升级4阶段

纵观SSR相关技术栈的演进过程,我们大致可以推出架构升级的4阶段。

  • CSR,很多中后台都是这样的开发的,最常见
  • 其次是阿里开源的beidou,基于egg做的React SSR,这是一个集成度很高的项目,很好用,难度也很大
  • Umi SSR是基于egg-react-ssr上演进出来的,在umi之上,用户不需要关心webpack,但打包后的代码返回的是stream,这点抽象,云谦做的非常到位,对于开发者来说,还是需要自建Node web server的。
  • 在Serverless里,具体怎么玩是需要我们来创造的。

image.png

对照上图,说明如下

  1. 在CSR中,开发者需要关心React和Webpack
  2. 在SSR中,开发者需要关心React、Webpack和Egg.js
  3. 在Umi SSR同构中,开发者需要关心React和Egg.js,由于Umi内置了Webpack,开发者基本不需要关注Webpack
  4. 在Serverless时代,基于FaaS的渲染层,开发者需要关心React,不需要关心Webpack和Egg.js

在这4个阶段中,依次出现了CSR和SSR,之后在同构实践中,对开发者要求更高,甚至是全栈。所有这些经验和最佳实践的积累,沉淀出了更简单的开发方式,在Serverless环境下,可以让前端更加简单、高效。

组件即函数

对于组件写法,我们继续抽象,将布局也拉出来。

function Page(props) {
  return <div> {props.name} </div>
}

Page.fetch = async (ctx) => {
  return Promise.resolve({
    name: 'Serverless side render'
  })
}

Page.layout = (props) => {
    const { serverData } = props.ctx
    const { injectCss, injectScript } = props.ctx.app.config
    return (
      <html lang='en'>
        <head>
          <meta charSet='utf-8' />
          <meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no' />
          <meta name='theme-color' content='#000000' />
          <title>React App</title>
          {
            injectCss && injectCss.map(item => <link rel='stylesheet' href={item} key={item} />)
         }
        </head>
        <body>
          <div id='app'>{ commonNode(props) }</div>
          {
            serverData && <script dangerouslySetInnerHTML={{
              __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(serverData)}`
            }} />
          }
          <div dangerouslySetInnerHTML={{
            __html: injectScript && injectScript.join('')
          }} />
        </body>
      </html>
    )
}

export default Page
AI 代码解读

layout目前看只有第一次渲染有用,但做Component抽象是可以考虑的。现在是首次渲染模式,以后不排除递归组件树的方式(结合bigpipe可以更嗨),那时layout还是有用的。

这样看来,render、fetch、layout是函数,结合Serverless.yml(f.yml)配置,能否将他们放到配置里呢?

路由由f.yml的配置文件中,所以在f.yml增加render配置扩展,具体如下。

functions:
  home:
    handler: index.handler
    render:
      - Component: src.home.index
      - layout: src.home.layout
      - fetch: src.home.fetch
      - mode: SSR | CSR(默认SSR)
      - injectScript(自己改loyout更好)
          - runtime~Page.js
          - vendor.chunk.js
          - Page.chunk.js
      - injectCSS
          - Page.chunk.css
      - serverBundle: Page.server.js
    events:
      - http:
          path: /
          method:
            - GET
  news:
    handler: index.handler
    render:
      - Component: src.news.index
      - layout: src.news.layout
      - fetch: src.news.fetch
      - mode: SSR | CSR(默认SSR)
    events:
      - http:
          path: /
          method:
            - GET
AI 代码解读

元彦提了一个非常好的命名:组件即函数。最贴切不过。

将渲染、接口请求、布局分别拆成独立函数,放到配置文件里。如此做法,可以保证函数粒度的职责单一,对于可选项默认值也更友好。比如没有接口请求就不调用fetch,或者没有布局使用默认布局。

image.png

这里再拔高一下,CSR和SSR写法一致了,这种写法可以和FaaS结合,也就是说写法上拆成函数后,前端关心的只有函数写法了,使得面向组件开发更容易。

我们在抽象一下,提炼3重境界。

  • 组件即函数,就是上面将的内容。
  • 页面即函数,对开发者而言,其实页面的概念不大,第一次渲染布局,然后entry执行而已,如果抛开构建和配置细节,页面就是第一个组件,即函数
  • 页面即服务,是我之前提的概念,每个页面对应一个Node服务,这样的好处是避免服务器雪崩,同时可以降低页面开发复杂度。

对于页面即服务来说,一个FaaS函数提供http,天然就是独立服务,在基建侧,网关根据流量决定该服务的容器个数,完美的解决了页面渲染过程的所有问题,也就是我们只需要关注组件写法,组件写法又都是函数。所以,组
件即函数,是Serverless渲染层最好的概括。

下面这张图很好的表达了组件即函数的核心:统一写法和用法。

image.png

制定规范之前,定位还是先要想明白的。

  • 在FaaS rutime之上,保证可移植性
  • 通过CSR和SSR无缝切换,可以保证首屏渲染效率
  • 由于面向组件和配置做到轻量级开发,可以很好的结合

统一写法和用法是件约定大于配置的事儿,约定才是最难的,既要保证功能强大,还要写法简单,又要有扩展性。显然,这是比写代码更有挑战的事儿。

SSR规范

统一写法,上一小结已经讲过了。

image.png

接下来就是规范相关的周边,如下图。

image.png

构建,扩展,跨平台,以及目录都需要约定。

SSR-spec规范主要定义 SSR 特性,组件写法、目录结构以及 f.yml 文件扩展的编写规范。目录结构待讨论,例如新增功能的API与删除功能的API理论上应该放在一个project当中,此时应该在src目录下建立不同的文件夹来隔离不同函数的模块.

├── dist // 构建产物
│   ├── Page.server.js // 服务端页面bundle
│   ├── asset-manifest.json // 打包资源清单
│   ├── index.html // 页面承载模版文件,除非想换成传统的直接扔一个html文件部署的方式
│   └── static // 前端静态资源目录
│       ├── css
│       └── js
├── config // 配置
│   ├── webpack.js // webpack配置文件,使用chainWebpackConfig方式导出,非必选
│   └── other // 
├── index.js // 函数入口文件
├── f.yml // FaaS函数规范文件
├── package.json
├── src // 存放前端页面组件
│   ├── detail // 详情页
│   │   ├── fetch.js // 数据预取,非必选
│   │   ├── index.js // React组件,必选
│   │   └── layout.js // 页面布局,非必选,没有默认使用layout/index.js
│   ├── home // 首页
│   │   ├── fetch.js
│   │   ├── index.js
│   │   └── layout.js
│   └── layout
│       └── index.js // 默认的布局文件,必选,脚手架默认生成
└── README.md //
AI 代码解读

命令用法

$ SSR build
$ SSR deploy
AI 代码解读

生成的dist目录结构如下。

  • dist

    • funcName

      • static

        • clientBundle.js
        • js
        • css
        • images
      • serverBundle.js

构建命令

$ SSR build
$ SSR build --spa
$ SSR build hello
$ SSR build hello2
AI 代码解读

Serverless集成步骤,通用方案集成

$ SSR xxx
$ Serverless deploy // f deploy
AI 代码解读

这里以Umi为例,开发过程分3个步骤。

  1. 本地源码组件开发,然后通过umi dev完成构建
  2. 如果是线上,可以走线上构建服务(webpack打包),如果需要修改,可以走
  3. 构建后的产物结合FaaS函数,直接发布到Serverless平台上

image.png

规范里还有很多点也是有思考的,比如多组件支持是基于bigpipe的方式,首先写入layout布局,然后处理多个组件的组合逻辑,最终res.end即可。另外,组件上如果只有fetch方法,没有render方法也是没有问题的。写法有2种,Component的值是数组,即串行方式。Component的值是对象,即并行方式。限于篇幅,这里就不一一赘述了。参见http://gitlab.alibaba-inc.com/Node/SSR-spec

落地实践、性能和未来思考

打包与构建

Umi的实现是非常巧妙的,核心在于构建后的server bundle返回值是stream,解耦了对web框架的依赖。在当时还没有实现更好的,所以以Umi为例。

image.png

构建产物,各个文件大小的说明,有2种方式。

  • Node_modules打包到bundle,对FaaS runtime无依赖。
  • Node_modules不打包到bundle,放到FaaS runtime里。

这2种方式打包大小可以接受,性能上第二种会更好一点,但没有差很多。

image.png

快速切换CSR还是SSR

前面说了写法上的统一,在工程实践中,可以在配置里,直接设置type快速切换CSR还是SSR。在公司内部,还可以通过diamand配置下发的方式进行动态控制。

image.png

其实SSR-spec规范里,还做了更多扩展.

//检查query的信息或者url查询参数或者头信息
conf.mode = req.query.SSR || req.headers['x-mode-SSR'];
AI 代码解读

容灾打底方案

简单说,3层容灾

  • Node SSR优先,Node调用hsf。
  • Node CSR通过diamind可以快速切换,html是Node吐出的,前端走MTop请求。
  • 当Node服务挂掉,走CDN上的纯CSR,前端MTop请求。

该流程有以下优点:

  • 构建方式一致

    • 服务端/客户端文件构建方式一致
  • 发布方式一致

    • 发布方式一致,统一发布到 CDN,前端资源可以使用 CDN 加速
  • 无需服务端发布

    • 组件代码变动统一使用 diamond 下发版本号,无需服务端发布
  • 及时生效

    • diamond 配置下发后可及时生效

如图。

image.png

性能优化

性能优化的要点

  • 控制SSR中server端占的比例,性能和体验是鱼和熊掌不可兼得。看业务诉求。
  • 能缓存的尽量缓存,和BFF应用一样。

这里举个例子,对接口字段瘦身,就可以渠道意想不到的效果。

image.png

性能对比

优酷PC的React SSR性能很好,从v1(Bigpipe+jQuery)到v2(React SSR),性能逐步提升。PC页面首屏渲染降到150ms、播放器起播时间从4.6秒优化到2秒。H5站上了React SSR后,性能提升3倍,H5唤端率提升也极其明显,头条短视频唤端率由5.68%提升到9.4%,环比提升65%。单机性能qps从80提升150+(压测最高可以到300左右)。

image.png

淘宝的Rax SSR也性能优异,以一个带数据请求的真实 Rax SSR 应用为例,性能对比数据显示:WIFI 下, SSR 的首屏呈现时间相比 CSR 提升 1 倍;弱网环境下,SSR 相比 CSR 提升约 3.5 倍。

参见水澜Rax SSR:重塑 SSR 应用的开发体验

SSR Demo 地址:https://Rax-demo.now.sh/SSR/home
CSR Demo 地址:https://Rax-demo.now.sh/CSR/home

未来思考

从用户访问页面流程,具体如下。

image.png

要点

  • 应用网关,肯定是要有的,毕竟要挂域名,反向代理等
  • 页面,已经可以放到FaaS上,FaaS之上的http网关可以满足基本需求,离应用级别的还差很多。
  • API代理,这个基于Node FaaS函数非常容易实现
  • API,调用后端服务提供API,比如访问db等,基于Node FaaS函数也是非常容易实现

FaaS细化到函数粒度,在管理上会有巨大挑战,在架构上也需要重新设计。

  • 具有前端特色的函数管理:比如API、Page等类型,path,域名,甚至是具体的应用设置
  • 页面、组件和网关联动,让开发更简单快速
  • 周边,比如监控,统计,数据等等

这里尝试一张图来表示一下前后端的Serverless时代的分工。

image.png

  • 统一接入网关是必须的,主要是处理页面和域名的接入。
  • 对于页面进行抽象,围绕组件和搭建来展开,通过在线|本地构建,最终放到页面托管服务中。有了页面托管,才是万里长城的一小步。
  • 接下对API进行拆分,这也是组件组成里重要的部分。

围绕搭建,可以想象到的是组件和接口的抽象。组件除了智能化我能想到的很少,智能化在计算上也能弹性玩就更有想象力了。对于接口可以再细分

  • 直接操作表,虽不推荐前端做,但确实是必备能力。
  • 通过配置来生成,即元数据管理,对于已有API进行包装,逻辑编排是非常好的。
  • 如果都不满足,自己基于FaaS函数定制就好了。

image.png

搭建本身是提效的,组件和接口都能提效,对于前端的价值是尤其大的。前端Serverless专项里,也是有逻辑编排组的,原因大抵如此。

下面再解释一下页面托管服务实现原理。其实这是页面即服务的升级版,以前每个页面对应一个Node服务,这就导致很多Node服务的运维成本非常高,有了Serverless,依然还是一个页面对应一个FaaS函数,但函数的扩容是Serverless基建做的事儿。也就是说页面托管,其实是基于页面的FaaS函数的管理。垂直到页面管理,一切都自动化,会让开发更简单。

目前每个FaaS函数是可以提供http透出地址的,但这个地址不具备定制能力,所以在页面托管服务之上有一层应用网关是必须的。那么,应用网关和页面页面托管服务之间如何联动呢?

  • 最外层,统一接入网关里做应用管理,每个应用都有对应的域名和子应用网关,二者进行绑定 根据流浪,子应用网关也可以自动扩缩容。
  • 在应用设置里,管理子应用网关包含的path和页面,提供反向代理相关的基础功能即可。
  • 设置完子应用包含的页面之后,系统具备将对应页面同步到子应用网关的能力,并且当页面更新的时候能够自动同步,类似于etcd/consul等服务发现同步功能。

有了这部分设计,开发者只需要关注页面的编写就好了。比较上面的3点配置在系统中并不经常做。

image.png

基于上面的设计,目的是提高开发速度,沉淀前端中台,具体好处如下。

  • 中后台能够一定程度的收敛到一起,配置化
  • 页面和系统分离,应变能力更强,结合微前端可以有更多想象力
  • 所有开发聚焦到页面维度,能够更好的提效,比如组件沉淀,智能化,搭建等都可以更专注。
  • 很多后端服务也能够很好的沉淀和复用,这和后端常说的能力地图类似,将BFF聚合管理,简化开发

image.png

关于未来,我能想到的是

  • 组件:写代码或智能化生成
  • 页面:配置出来
  • 系统:配置出来

只需要组件级别的函数的轻量级开发模式里,必然会简化前端开发方式,提供人效,最终实现技术赋能业务的目的。在“大中台,小前台”的背景下,贡献前端应变能力。

image.png

总结

在《2019,如何放大大前端的业务价值?》一文中,我曾提过:“前端技术趋于成熟,不可否认,这依然是个大前端最好的时代,但对前端来说更重要的是证明自己,不是资源,而是可以创造更多的业务价值。在垂直领域深耕可以让大家有更多生存空间,但我更愿意认为Serverless可以带来前端研发模式上的颠覆,只有简化前后端开发难度,才能更好的放大前端的业务价值。”

致敬所有为Serverless付出的同仁们!

image.png

相关实践学习
1分钟 Serverless搭建高性能网盘
本场景将使用阿里云函数计算、文件存储NAS以及开源项目Kodbox,带大家1分钟Serverless搭建个人高性能网盘,网盘可长期使用。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
打赏
0
0
0
0
293
分享
相关文章
千万级数据秒级响应!碧桂园基于 EMR Serverless StarRocks 升级存算分离架构实践
碧桂园服务通过引入 EMR Serverless StarRocks 存算分离架构,解决了海量数据处理中的资源利用率低、并发能力不足等问题,显著降低了硬件和运维成本。实时查询性能提升8倍,查询出错率减少30倍,集群数据 SLA 达99.99%。此次技术升级不仅优化了用户体验,还结合AI打造了“一看”和“—问”智能场景助力精准决策与风险预测。
338 69
云原生时代的应用架构演进:从微服务到 Serverless 的阿里云实践
云原生技术正重塑企业数字化转型路径。阿里云作为亚太领先云服务商,提供完整云原生产品矩阵:容器服务ACK优化启动速度与镜像分发效率;MSE微服务引擎保障高可用性;ASM服务网格降低资源消耗;函数计算FC突破冷启动瓶颈;SAE重新定义PaaS边界;PolarDB数据库实现存储计算分离;DataWorks简化数据湖构建;Flink实时计算助力风控系统。这些技术已在多行业落地,推动效率提升与商业模式创新,助力企业在数字化浪潮中占据先机。
256 12
harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)
本文由黑臂麒麟(6年前端经验)撰写,介绍ArkTS开发中的常用基础组件与布局组件。基础组件包括Text、Image、Button等,支持样式设置如字体颜色、大小和加粗等,并可通过Resource资源引用统一管理样式。布局组件涵盖Column、Row、List、Grid和Tabs等,支持灵活的主轴与交叉轴对齐方式、分割线设置及滚动事件监听。同时,Tabs组件可实现自定义样式与页签切换功能。内容结合代码示例,适合初学者快速上手ArkTS开发。参考华为开发者联盟官网基础课程。
329 75
harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)
基于阿里云Serverless Kubernetes(ASK)的无服务器架构设计与实践
无服务器架构(Serverless Architecture)在云原生技术中备受关注,开发者只需专注于业务逻辑,无需管理服务器。阿里云Serverless Kubernetes(ASK)是基于Kubernetes的托管服务,提供极致弹性和按需付费能力。本文深入探讨如何使用ASK设计和实现无服务器架构,涵盖事件驱动、自动扩展、无状态设计、监控与日志及成本优化等方面,并通过图片处理服务案例展示具体实践,帮助构建高效可靠的无服务器应用。
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
306 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
174 18
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
197 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
云端问道9期实践教学-省心省钱的云上Serverless高可用架构
详细介绍了云上Serverless高可用架构的一键部署流程
116 10
尽享红利,Serverless构建企业AI应用方案与实践
本次课程由阿里云云原生架构师计缘分享,主题为“尽享红利,Serverless构建企业AI应用方案与实践”。课程分为四个部分:1) Serverless技术价值,介绍其发展趋势及优势;2) Serverless函数计算与AI的结合,探讨两者融合的应用场景;3) Serverless函数计算AIGC应用方案,展示具体的技术实现和客户案例;4) 业务初期如何降低使用门槛,提供新用户权益和免费资源。通过这些内容,帮助企业和开发者快速构建高效、低成本的AI应用。
226 12
活动实践 | 西游再现,函数计算一键部署 Flux 超写实文生图模型部署
这些图片展示了阿里巴巴云开发者生态的多个方面,包括开发工具、技术文档、社区交流、培训认证等内容,旨在为开发者提供全方位的支持和服务。

相关产品

  • 函数计算
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问