通用Serverless Side Render 框架ssr 重磅来袭, 快来瞄一下

前言

项目地址: github.com/ykfe/ssr

一句话介绍: A future-oriented ssr framework based on midway-faas that implemented serverless-side render specification for faas.

项目背景

2020年Serverless这个概念更加火热。Serverless 解放了端开发者(不仅仅是 Web 开发者)的生产力,让端开发者可以更快、更好、更灵活地开发各种端上应用,不需要投入太多精力关注于后端服务的实现。但是大部分Serverless框架提供的example都是在教你如何搭建一个api服务,对于页面渲染层的例子少之又少。而next.js,nuxt.js这些框架的例子对大部分用户来说理解和使用成本实在是太高了,并且在生产环境使用过程中会遇到各种问题。

由于以上背景,我们基于之前已经开源并且受到广泛好评的[最小而美的Egg + React + SSR 服务端渲染应用骨架]( github.com/ykfe/egg-re… ) (已受到阿里集团内部多个bu以及多个外部公司生产环境使用反馈开发体验远好于next.js等框架)进一步提炼出Serverless场景下的SSR框架。让SSR应用的开发和发布变得更加简单透明友好同样支持SSR/CSR两种渲染模式随时切换。只需5分钟便可以部署一个Faas SSR应用在公网让所有人访问。

应用架构

如何使用

开发者只需5分钟就可以快速的创建并发布一个SSR应用上线

环境准备

$ node -v # 建议版本>=v10.15.0
v12.16.1
$ yarn -v # 建议使用yarn代替npm
1.21.1复制代码

安装脚手架

$ yarn global add ssr # 全局安装ssr脚手架。等同于npm i -g ssr复制代码

创建项目

$ ssr init # 创建example,支持SPA/MPA(开发中)两种类型的应用创建复制代码

本地开发

$ yarn
$ ssr start
$ open http://localhost:3000复制代码

资源构建

$ ssr build
$ ssr build index # 可以对指定的函数进行构建(支持中)复制代码

函数发布

发布命令

$ ssr deploy # 默认发布到阿里云函数计算服务,腾讯云支持中复制代码

为了解决函数发布对应用代码包的大小有要求的问题,我们不能像之前一样随意的安装node_modules并且发布了这样会导致代码大小压缩后也极易超出50MB的限制。这里我们有以下几种方案解决该问题。

fun nas

使用阿里云提供的nas功能将node_modules作为固定依赖上传到云端。但这样有很多缺点,分别是node_modules并不是固定文件,随时有可能有新的模块依赖加入。以及fun nas上传步骤复杂且需要时间。对开发者不友好。

关闭externals选项

如果你使用next.js这些框架,你会发现在对代码大小有限制的runtime平台根本无法发布。因为next这些模块的dependencies包括babel/webpack这些开发依赖。当你安装next模块时这些开发依赖也一并被安装了。这时候你的选择只有不开启externals选项,将这里模块代码全部打包进服务端bundle。这样会导致服务端bundle特别大,执行效率大大降低。

分离核心依赖

所以这里我们特定将SSR框架分为ssr-core,ssr两个主要的库。ssr模块包含本地开发依赖,在生产环境时我们只需要安装ssr-core模块即可运行应用。使得开发环境真正上传的代码压缩后只有3MB。

ssr-spec 开发规范

注:本规范适用于绝大多数的业务场景,如需额外定制请先想清楚是否必要!

前端技术选型

  • 前端框架: React
  • 开发语言: TypeScript
  • 代码风格: Standard
  • 样式处理: less + css modules
  • UI组件: 默认已对antd的使用做打包配置无需额外配置
  • 前端路由: 约定式路由
  • 数据管理: 待支持,暂定使用hooks

应用类型

我们支持单页面应用(SPA)和多页面应用(MPA)两种常见的应用类型的开发。 关于SPA与MPA的区别如下(本表格转载自网络,如有侵权请提issue联系)

SPA

单页面应用一个函数对应一个页面。一个页面对应多个path(即前端路由)。

目录结构

这里我们使用约定式路由。无需手动编写路由配置文件,会根据文件夹名称及路径自动生成路由配置。

.
├── build # web目录构建产物
│   └── index
│       ├── client
│       └── server
├── config.js # 定义应用的配置
├── f.yml
├── package.json
├── src # 存放faas函数的handler
│   └── index.ts
├── tsconfig.json
├── web
│   ├── components # 存放公共组件
│   │   └── header
│   │   │   ├── index.less
│   │   │   └── index.tsx
│   │   └── layout # SPA应用只需要一个默认的layout
│   │       ├── index.less
│   │       └── index.tsx
│   ├── pages # pages目录下的文件夹会映射为前端路由
│   │   ├── index # index文件夹映射为根路由
│   │   │   ├── fetch.ts # 定义fetch文件用来获取数据,会自动注入到组件的props中
│   │   │   ├── index.less
│   │   │   └── render.tsx # 定义render文件用来定义页面渲染逻辑
│   │   └── news
│   │       ├── fetch.ts
│   │       ├── index.less
│   │       └── render$id.tsx # 映射为/news/:id
│   │       └── render$id$.tsx # 映射为/news/:id?
│   ├── tsconfig.json # 仅用于编辑器ts语法检测
│   └── typings.d.ts复制代码

yml文件编写规范

service:
  name: serverless-ssr
provider:
  name: aliyun

functions:
  index:
    handler: index.handler
    render:
      mode: ssr # 指定渲染模式
    events:
      - http:             
          path: /*
          method:
            - get

package:
  artifact: code.zip复制代码

如何发布

$ ssr deploy # 此时只有一个函数需要发布,选择index函数发布即可复制代码

展示形式

ssr-fc.com/ -> index 函数 -> 渲染index组件

ssr-fc.com/news -> index 函数 -> 渲染news组件

MPA

多页面应用一个函数对应一个页面。一个页面对应一个path(即服务端路由)。

目录结构

这里我们的服务端路由存在多个,需要读取yml文件具体函数的配置

.
├── README.md
├── build
│   ├── mpa1
│   │   ├── client
│   │   └── server
│   └── mpa2
│       ├── client
│       └── server
├── f.yml
├── package.json
├── src
│   ├── mpa1handler.ts
│   └── mpa2handler.ts
├── tsconfig.json
├── web
│   ├── components # 存放公共组件
│   │   └── header
│   │   │   ├── index.less
│   │   │   └── index.tsx
│   │   └── layout # 默认的layout
│   │       ├── index.less
│   │       └── index.tsx
│   ├── pages
│   │   ├── index
│   │   │   ├── fetch.ts
│   │   │   ├── index.less
|   |   |   ├── layout.tsx # 每个独立的页面可以有自己的layout
│   │   │   └── render.tsx
│   │   └── news
│   │       ├── fetch.ts
│   │       ├── index.less
│   │       └── render$id.tsx复制代码

yml文件编写规范

service:
  name: serverless-ssr
provider:
  name: aliyun

functions:
  mpa1:
    handler: mpa1.handler
    render:
      mode: ssr
    events:
      - http:             
          path: /
          method:
            - get
  mpa2:
    handler: mpa2.handler
    render:
      mode: ssr
    events:
      - http:             
          path: /news
          method:
            - get

            
package:
  artifact: code.zip复制代码

如何发布

$ ssr deploy # 此时需要在终端选择需要发布哪个函数复制代码

展示形式

ssr-fc.com/ -> mpa1 函数 -> 渲染mpa1文件夹下的render组件

ssr-fc.com/news -> mpa2 函数 -> 渲染mpa2文件夹下的render组件

渲染函数

1)在 FaaS 函数里

在 FaaS 函数里,只需要调用ssr-core提供的render方法传入ctx即可

import { render } from 'ssr-core'

async handler () {
  try {
    const htmlStr = await render(this.ctx)
    return htmlStr
  } catch (error) {
    return error
  }
}复制代码

根据f.yml或者query来判断当前渲染模式

2)在 Node.js Web 框架里

该渲染方式实现是服务端无关的,理论上可以支持任何Node.js框架只需引入render方法以及有一个web目录,用法与Faas函数保持一致。

const Koa = require('koa');
const { render } = require('ssr-core')
const app = new Koa();

//  mount routes from config
app.use(ssr)

// ctx.ssrRender()
app.get('/*', async ctx => {
  ctx.body = render(ctx)
});

app.listen(3000);复制代码

模式切换

// url查询参数或者头信息
conf.mode = req.query.ssr || req.headers['x-mode-ssr'];复制代码
  • ssr(conf)
    • cookie
    • querystring
    • header

此处需要考虑优先级,比如querystring第一,其次是f.yml里的render.mode。

团队介绍

我们来自

@i5ting

(狼叔)团队,致力于探索SSR应用在各种场景下的实践。欢迎有志之士一起加入。

联系邮箱:langshu.ssl@alibaba-inc.com

答疑群

虽然我们已经尽力检查了一遍应用,但仍有可能有疏漏的地方,如果你在使用过程中发现任何问题或者建议,欢迎提 issue 或者 PR 欢迎直接扫码加入钉钉群

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章