# ssr **Repository Path**: yuan_jin_stack/ssr ## Basic Information - **Project Name**: ssr - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: dev - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-04 - **Last Updated**: 2021-03-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

SSR


A most advanced ssr framework on Earth that implemented serverless-side render specification for faas and traditional web server.

githubActions cypress download standardjs License Node

`ssr` 框架是为前端框架在服务端渲染的场景下所打造的开箱即用的服务端渲染框架。 此框架脱胎于 [egg-react-ssr](https://github.com/ykfe/egg-react-ssr) 项目和`ssr` v4.3版本(midway-faas + react ssr),在之前的基础上做了诸多演进,通过插件化的代码组织形式,支持任意服务端框架与任意前端框架的组合使用。开发者可以选择通过 Serverless 方式部署或是以传统 Node.js 的应用形式部署,并且我们专注于提升 Serverless 场景下服务端渲染应用的开发体验,打造了一站式的开发,发布应用服务的功能。最大程度提升开发者的开发体验,将应用的开发,部署成本降到最低。 在最新的 v5.0 版本中,同时支持 React 和 Vue 的服务端渲染框架,且提供一键以 Serverless 的形式发布上云的功能。我们可以非常有自信说它是地球上最先进的ssr框架。如果你希望获得开箱即用的体验且能够一键部署上云,请选择 `ssr` 框架。 ## 哪些应用在使用 正在使用这个项目的公司(应用), 如果您正在使用但名单中没有列出来的话请提 [issue](https://github.com/ykfe/ssr/issues),欢迎推广分享,我们将随时提供技术支持

优酷视频

阿里影业娱乐宝
vmate 积分商城
Vmate短视频
火炽星原CRM
火炽星原CRM
牛牛搭
牛牛搭
cvte
希沃帮助中心
腾讯微卡
腾讯微卡
微脉
微脉
腾讯手游助手
腾讯手游助手
国家现代农业科技创新中心
国家现代农业科技创新中心

部署于阿里云示例应用

部署于腾讯云示例应用
## Features - 🌱 极易定制:前端支持 React/Vue 等现代Web框架; - 🚀 开箱即用:内置 10+ 脚手架配套扩展,如Antd、Vant、TS、Hooks等; - 🧲 插件驱动:基于插件架构,用户更加专注于业务逻辑; - 💯 Serverless优先:一键发布到各种Serverless平台,也支持传统Web Server,比如Egg、Midway、Nest等。 - 🛡 高可用场景,可无缝从SSR降级到CSR,最佳容灾方案。 ## 已实现的功能 🚀 表示已经实现的功能 | 里程碑 | 状态 | | ---------------------------------------------------------------------- | ---- | | 支持任意服务端框架与任意前端框架的组合使用。(Serverless/Midway/Nestjs) + (React/Vue) | 🚀 | | 最小而美的实现服务端渲染功能 | 🚀 | | 针对Serverless 场景对代码包的大小的严格限制,将生产环境的代码包大小做到极致 | 🚀 | | 同时支持约定式前端路由和声明式前端路由 | 🚀 | | React 场景下 All in JSX,Vue 场景 All in template,没有传统模版引擎,所有部分包括 html layout 布局皆使用 JSX/Vue 来编写生成 | 🚀 | | 渲染模式切换:服务端渲染一键降级为客户端渲染 | 🚀 | | 统一不同框架服务端客户端的数据获取方式,做到高度复用 | 🚀 | | 类型友好,全面拥抱 TS | 🚀 | | 支持无缝接入 [antd](https://github.com/ant-design/ant-design) [vant](https://vant-contrib.gitee.io/vant/#/) 无需修改任何配置 | 🚀 | | 支持使用 less 作为 css 预处理器 | 🚀 | | 实现 React/Vue SSR 场景下的[优秀代码分割方案](https://zhuanlan.zhihu.com/p/343743374) 首屏性能做到极致 | 🚀 | | React 场景下使用 useContext + useReducer 实现极简的[跨组件通信](#React跨组件通信)方案,摒弃传统的 redux/dva 等数据管理方案 | 🚀 | | 支持在阿里云 [云平台](https://zhuanlan.zhihu.com/p/139210473)创建使用 | 🚀 | | ssr deploy 一键部署到[阿里云](https://www.aliyun.com/)平台 | 🚀 | | ssr deploy --tencent 无需修改任何配置一键部署到[腾讯云](https://cloud.tencent.com/)平台 | 🚀 | | | 支持 [vite](https://vite-design.surge.sh/) + [vue3](http://v3.vuejs.org/) 在 SSR 场景下的组合使用 | | ## 与 Next.js/Nuxt.js 等框架的对比 详细的技术细节对比可以查看本人在2020年 [Node.js party 上所做的分享](https://github.com/zhangyuang/2020-NodeParty-PPT),从以下 9 个技术细节方面与 Next/Nuxt/easy-team 等等框架的做法进行对比。 1、Node.js 环境如何加载前端组件 2、组件数据如何获取 3、HMR 热替换功能怎么实现 4、CSS 如何处理 5、如何拼接成完成的 html 结构返回 6、双端渲染结果不一致怎么办 7、如何进行代码分割 8、如何降级为客户端渲染 9、生产环境如何发布应用 以下简单介绍一下比较显著的优点 - 优先考虑 Serverless,我们为应用在 Serverless 场景使用做了诸多优化包括内置发布命令一键发布到多个平台,以及对 Serverless 场景下的代码包大小优化 - 轻量,核心源代码 2400 行 vs next.js 18w 行 vs nuxt.js 2w行,简洁的核心代码意味着更少的黑盒以及更少的性能损耗,事实上我们的性能等于直接调用框架提供的原生 API 无任何中间层 - 没有恶心的 .next, .nuxt 这种隐藏文件夹包含着几万行通过 模版渲染/Webpack 打包出来的可读性极差的代码,当你的应用出错时,你几乎无法从这些隐藏文件中获得任何有效信息 - 接地气,在 SSR 场景使用 UI 框架是一件不简单的事情,我们内置对世界上最流行的 UI 框架 ant-design 的支持。无需用户做额外配置 - 没有传统模版引擎,多数开发者是都十分厌恶使用传统模版引擎且需要引入额外的库和学习成本。我们没有模版引擎,根据场景 All in JSX 或者 Vue template 来编写 html 布局 - 没有 style-loader,不存在本地开发使用 style 标签,线上环境使用 css 文件这种开发体验割裂的情况。我们统一使用独立的 css 文件且支持 HMR 和动态加载 - 风格统一,无论是 React/Vue 运行的本质始终都是 js,我们在两种框架的 SSR 实现思路一模一样,实现代码的高度复用,使用本框架无论是从 React 切换成 Vue 或者反过来都十分轻易 - 功能丰富,UI 框架、代码分割、HMR、TS、Serverless、SSR 降级 CSR 开发所需要的功能应有尽有 - 示例丰富,默认示例 cover 大多数真实线上应用场景,包含 服务端框架选择、前端调用 Node.js 接口的方式、前端页面路由跳转的数据获取,应用部署等所有功能用例在 example 中都有体现。我们拥有丰富的线上大规模 SSR 应用开发经验,用户使用过程中遇到的任何问题都有策略解决。 - 没有 runInNewContext,我们不像其他框架的做法一样使用 vm 模块创建上下文来解析服务端 bundle,所以我们的性能是极高的,可以简单理解为与 Vue 的 renderer 提供的 runInNewContext: false 功能类似(选项为 false 本质是调用 runInThisContext)。虽然无需每次都创建一次新的上下文但 Vue 官方文档的做法仍然需要使用 vm 模块来解析代码在性能上会有一定损耗。由于代码执行的当前上下文就是服务端的 global 对象所以要注意我们的前端组件代码中应该避免去修改 global 对象。且记住 vm 模块也并不是安全沙箱机制。ref: https://ssr.vuejs.org/zh/api/#runinnewcontext http://nodejs.cn/api/vm.html ## Serverless for Frontend > Serverless 解放了端开发者(不仅仅是 Web 开发者)的生产力,让端开发者可以更快、更好、更灵活地开发各种端上应用,不需要投入太多精力关注于后端服务的实现。” 传统应用开发流程 ![](https://img.alicdn.com/tfs/TB1CE7FB5_1gK0jSZFqXXcpaXXa-1402-150.png) Serverless 应用开发流程 ![](https://img.alicdn.com/tfs/TB1hZgHB7T2gK0jSZPcXXcKkpXa-1136-174.png) 使用本框架开发 Serverless SSR 应用开发流程 ![](https://img.alicdn.com/tfs/TB1wzqpCkP2gK0jSZPxXXacQpXa-1880-256.jpg) 相比于传统服务端应用开发,我们将细节在底层统一抹平。前端开发者只需要关注业务逻辑,无需感知服务器的运行状况。成本和心智负担大大降低,只需要申请一个域名即可将应用发布到公网让所有用户可以访问。 ## 线上案例 通过访问以下链接来预览该框架通过 Serverless 一键部署到阿里云/腾讯云服务的应用详情。 通过使用 queryParams `csr=true` 来让 SSR 服务端渲染模式一键降级为 CSR 客户端渲染模式,也可以通过 `config.js` 来进行配置。 - http://ssr-fc.com/ 部署到阿里云的 React SSR 应用 - http://ssr-fc.com?csr=true 部署到阿里云的 React SSR 应用, 以 CSR 模式访问 - http://tx.ssr-fc.com 部署到腾讯云的 React SSR 应用 - http://tx.ssr-fc.com?csr=true 部署到腾讯云的 React SSR 应用, 以 CSR 模式访问 - http://vue.ssr-fc.com 部署到阿里云的 Vue SSR 应用 - http://vue.ssr-fc.com?csr=true 部署到阿里云的 Vue SSR 应用, 以 CSR 模式访问 ## Getting Start 迅速开始一个应用 ### 环境准备 ```bash $ node -v # 建议版本>=v10.15.0 v12.16.1 ``` ### create-ssr-app 我们提供了 [create-ssr-app](https://github.com/zhangyuang/create-ssr-app) 脚手架,可迅速创建不同类型的 example。如无特殊需求,我们推荐创建 Serverless 类型的应用,可享受一站式的应用开发,部署能力。 ```bash $ npm init ssr-app my-ssr-project --template=serverless-react-ssr # 创建 React SSR 应用,可通过 Serverless 服务一键发布应用上云 $ npm init ssr-app my-ssr-project --template=serverless-vue-ssr # 创建 Vue SSR 应用,可通过 Serverless 服务一键发布应用上云 $ npm init ssr-app my-ssr-project --template=midway-react-ssr # 创建 React SSR 应用,基于 Midway Node.js 框架提供的能力以传统 Node.js 应用的形式部署 $ npm init ssr-app my-ssr-project --template=midway-vue-ssr # 创建 Vue SSR 应用,基于 Midway Node.js 框架提供的能力以传统 Node.js 应用的形式部署 $ npm init ssr-app my-ssr-project --template=nestjs-react-ssr # 创建 React SSR 应用,基于 Nestjs Node.js 框架提供的能力以传统 Node.js 应用的形式部署 $ npm init ssr-app my-ssr-project --template=nestjs-vue-ssr # 创建 Vue SSR 应用,基于 Nestjs Node.js 框架提供的能力以传统 Node.js 应用的形式部署 ``` ### 本地开发 ```bash $ npm i $ npm start # 等价于 ssr start $ open http://localhost:3000 ``` ### 资源构建 ```bash $ npm run build # 等价于 ssr build $ GENERATE_ANALYSIS=true npm run build # 可视化生成构建产物 ``` ### 发布上云 发布命令, 我们针对 Serverless 场景的代码包做了优化,生产环境仅依赖一个 core 模块即可运行应用,将发布速度做到极致。 ```bash $ npm run deploy # 支持发布多个平台默认发布到阿里云 等价于 ssr deploy $ npm run deploy:tencent # 发布到腾讯云 等价于 ssr deploy --tencent ``` ### 本地调试 借助 [debug](https://github.com/visionmedia/debug) 模块的能力,开发者可以在本地开发过程中获取一些构建渲染过程的信息。 ```bash $ DEBUG=ssr:* npm start # 打印所有的 ssr 模块提供的 debug 信息 ``` ## 生态系统 | Project | Status | Description | |---------|--------|-------------| | [ssr] | [![ssr-status]][ssr] | cli for ssr framework | | [ssr-core-vue] | [![ssr-core-vue-status]][ssr-core-vue] | core render for vue | | [ssr-core-react] | [![ssr-core-react-status]][ssr-core-react] | core render for react | | [ssr-plugin-faas] | [![ssr-plugin-faas-status]][ssr-plugin-faas] | provide start deploy feature by [midway-faas](https://www.yuque.com/midwayjs/faas)| | [ssr-plugin-midway] | [![ssr-plugin-midway-status]][ssr-plugin-midway] | provide start and build fetature by [midway@2.0](https://midwayjs.org/) | | [ssr-plugin-nestjs] | [![ssr-plugin-nestjs-status]][ssr-plugin-nestjs] | provide start and build feature by [Nestjs](https://docs.nestjs.com/) | | [ssr-plugin-react] | [![ssr-plugin-react-status]][ssr-plugin-react] | develop react application only be used in development | | [ssr-plugin-vue] | [![ssr-plugin-vue-status]][ssr-plugin-vue] | develop vue application only be used in development | | [ssr-server-utils] | [![ssr-server-utils-status]][ssr-server-utils] | server utils in Node.js environment | | [ssr-client-utils] | [![ssr-client-utils-status]][ssr-client-utils] | client utils in browser environment | | [ssr-hoc-react] | [![ssr-hoc-react-status]][ssr-hoc-react] | provide hoc component for react | | [ssr-types] | [![ssr-types-status]][ssr-types] | provide common types | | [ssr-webpack] | [![ssr-webpack-status]][ssr-webpack] | start local server and build production bundle by webpack | [ssr-status]: https://img.shields.io/npm/v/ssr.svg [ssr-client-utils-status]: https://img.shields.io/npm/v/ssr-client-utils.svg [ssr-core-react-status]: https://img.shields.io/npm/v/ssr-core-react.svg [ssr-core-vue-status]: https://img.shields.io/npm/v/ssr-core-vue.svg [ssr-hoc-react-status]: https://img.shields.io/npm/v/ssr-hoc-react.svg [ssr-plugin-faas-status]: https://img.shields.io/npm/v/ssr-plugin-faas.svg [ssr-plugin-midway-status]: https://img.shields.io/npm/v/ssr-plugin-midway.svg [ssr-plugin-nestjs-status]: https://img.shields.io/npm/v/ssr-plugin-nestjs.svg [ssr-plugin-react-status]: https://img.shields.io/npm/v/ssr-plugin-react.svg [ssr-plugin-vue-status]: https://img.shields.io/npm/v/ssr-plugin-vue.svg [ssr-server-utils-status]: https://img.shields.io/npm/v/ssr-server-utils.svg [ssr-types-status]: https://img.shields.io/npm/v/ssr-types.svg [ssr-webpack-status]: https://img.shields.io/npm/v/ssr-webpack.svg [ssr]: https://github.com/ykfe/ssr/tree/dev/packages/cli [ssr-client-utils]: https://github.com/ykfe/ssr/tree/dev/packages/client-utils [ssr-core-react]: https://github.com/ykfe/ssr/tree/dev/packages/core-react [ssr-core-vue]: https://github.com/ykfe/ssr/tree/dev/packages/core-vue [ssr-hoc-react]: https://github.com/ykfe/ssr/tree/dev/packages/hoc-react [ssr-plugin-faas]: https://github.com/ykfe/ssr/tree/dev/packages/plugin-faas [ssr-plugin-midway]: https://github.com/ykfe/ssr/tree/dev/packages/plugin-midway [ssr-plugin-nestjs]: https://github.com/ykfe/ssr/tree/dev/packages/plugin-nestjs [ssr-plugin-react]: https://github.com/ykfe/ssr/tree/dev/packages/plugin-react [ssr-plugin-vue]: https://github.com/ykfe/ssr/tree/dev/packages/plugin-vue [ssr-server-utils]: https://github.com/ykfe/ssr/tree/dev/packages/server-utils [ssr-types]: https://github.com/ykfe/ssr/tree/dev/packages/types [ssr-webpack]: https://github.com/ykfe/ssr/tree/dev/packages/webpack 阅读下文以获得本应用更加详细的使用方式。包括应用组织规范以及如何配置域名使得用户可以在公网访问。 ## 在阿里云使用 发布命令 ```bash $ npm run deploy # 支持发布多个平台默认发布到阿里云 等价于 ssr deploy ``` 首次发布需要输入阿里云账户信息,并且在阿里云控制台开通函数计算服务。账户信息在函数计算[控制台](https://fc.console.aliyun.com/fc)查看。 ![](https://img.alicdn.com/tfs/TB1fZzQB.z1gK0jSZLeXXb9kVXa-1446-1262.jpg) 将 AccountId 以及 Key Secret 在下面输入,只需要输入一次信息会储存在本地,之后 deploy 无需做该操作。 ![](https://img.alicdn.com/tfs/TB10vYVBYY1gK0jSZTEXXXDQVXa-2044-528.jpg) #### 阿里云配置域名 发布成功后得到一个临时的 http 地址`http://xxxx.test.functioncompute.com`。可以暂时用来预览服务,之后我们需要配置自己的域名通过 CNAME 的形式转发到该服务。 接着在阿里云函数计算控制台设置域名对应的函数即可在公网通过域名来访问该函数。`阿里云控制台域名服务` -> `域名解析设置` -> `函数计算控制台` -> `自定义域名`。之后打开[域名](http://ssr-fc.com)便能够访问发布的函数。 ![](https://res.wx.qq.com/op_res/GDCAu3r8xuYV5Bgvw8zZO5rzihDpXqBL-SpfARK_fo4iB3tzatF1vHJak0QCiNcRZpeggLEDlnhgzywCx2FxMQ) ![](https://gw.alicdn.com/tfs/TB1g_CwB7P2gK0jSZPxXXacQpXa-1254-698.jpg) ![](https://gw.alicdn.com/tfs/TB1JZGyB1H2gK0jSZFEXXcqMpXa-1468-1012.jpg) ## 在腾讯云使用 无需做任何配置文件的修改即可一键发布到腾讯云! 发布命令 ```bash $ npm run dploy:tencent # 发布到腾讯云 等价于 ssr deploy --tencent ``` 首次发布时需要使用微信扫终端展示的二维码注册/登陆腾讯云服务。 如果想详细的了解腾讯云发布功能可参考[文档](https://www.yuque.com/midwayjs/faas/deploy_tencent_faq) 发布后同样我们可以得到平台返回的一个地址, 需要绑定域名后才能正确的访问页面渲染服务。否则由于访问 /test 路径造成服务端路由和客户端路由不一致会导致页面内容闪现后白屏。 ![](https://res.wx.qq.com/op_res/mbNMsqF_px3tS0x_x1fryyR3Z5RipX3Lo8PIzvcAVxyXwoQyvQz0lQev-W2io3AP) 默认发布到测试环境, 这里建议在第一次发布后显示在 yml 中指定要发布的[serviceID](https://www.yuque.com/midwayjs/faas/deploy_tencent_faq), 否则每次发布将会创建一个新的 server 实例。 在腾讯云[API](https://console.cloud.tencent.com/apigateway/service-detail)网关平台进行域名的绑定以及函数发布到正式环境的操作 在腾讯云[SCF](https://console.cloud.tencent.com/scf)平台可以进行函数的管理调试以及日志查看 如何复用 serviceId 如下 ```yml service: name: serverless-ssr-spa provider: name: aliyun # 无需修改 name 通过 ssr deploy --tencent 指定腾讯云即可 region: ap-hongkong serviceId: service-xxx ``` #### 腾讯云配置域名 在发布到腾讯云时 midway-faas 支持通过 [provider.region](https://www.yuque.com/midwayjs/faas/serverless_yml) 来设置发布的服务器区域。 如果发布的区域是国内则绑定的域名需要在腾讯云进行备案服务,如果是香港则无需备案。默认绑定域名后需要通过 [tx.ssr-fc.com/release](http://tx.ssr-fc.com) 来访问具体的环境。也可以通过自定义路径映射使得不需要添加 /release 也可以访问到具体的环境。 ![](https://res.wx.qq.com/op_res/Ln1MuNWmmfNDyTuJlooXiGdhwtCtz_4rVDi_qvmuUEoL_mo6PNsd3z4d7z9RBj17) ### 结合阿里云开发平台 本框架可结合阿里云开发平台,使用 CloudIDE 全程上云开发 Serverless SSR 应用使用方式可参考该[教程](https://zhuanlan.zhihu.com/p/139210473)。 ### 结合 Midway.js 为了 cover 到所有的场景,我们也支持以 [Midway.js](https://midwayjs.org/) 作为 Node.js 框架以传统 Node.js 的服务进行部署。使用方式与 Serverless 场景类似。 可参考 midway 文档得到更详细的描述 ```bash $ npm init ssr-app my-ssr-project --template=midway-react-ssr # 创建 React SSR 应用,基于 Midway Node.js 框架提供的能力以传统 Node.js 应用的形式部署 ``` 通过上述命令创建基于 Midway 的 React SSR 应用后 ```bash $ npm i $ npm start # 本地开发启动服务 $ open http://localhost:3000 # 访问应用 $ npm run build # 本地资源构建 $ npm run prod # 通过 egg-scripts 生产环境多进程模式运行, 默认以 daemon 模式在后台运行 $ npm run stop # 生产环境停止服务 ``` ## 开发规范 `注:本规范适用于绝大多数的业务场景,我们已经尽力将默认的规范和配置做到最优如无特殊需求请不要额外定制` ### 通过插件组合功能 我们目前提供了如下插件, 参考现有插件来开发一个新的插件是非常容易的事情。你可以根据自己的应用类型来自行开发对应的插件,例如 plugin-nest、plugin-egg, plugin-koa 等 服务端框架插件 - plugin-faas 基于 [midway-faas](https://www.yuque.com/midwayjs/faas) - plugin-midway 基于 [midway@2.0](https://midwayjs.org/) - plugin-nestjs 基于 [Nestjs](https://docs.nestjs.com/) 前端框架插件 - plugin-react 基于 React - plugin-vue 基于 Vue 它们之间可以任意的进行组合。如何在 example 中使用插件如下。 ```js // plugin.js const { faasPlugin } = require('ssr-plugin-faas') const { reactPlugin } = require('ssr-plugin-react') module.exports = { serverPlugin: faasPlugin(), clientPlugin: reactPlugin() } ``` ### 前端技术选型 不同的前端框架在技术选型方面会有一些差别,但我们尽量规定一套规范,使得不同框架之间的差异性做到最小,默认都使用约定式路由。如无特殊必要建议使用默认选项。 在代码规范方面我们将一系列的 eslint-plugin 进行整合,使得只需要安装一个依赖即可同时检测 .vue|ts|tsx 文件 #### React 技术选型 - 前端框架: React v17, 实时跟进 React17的新特性 - 开发语言: TypeScript - 代码风格: [eslint-config-standard-react-ts](https://github.com/zhangyuang/standardjs-react) - 样式处理: less + css modules - UI 组件: 默认已对 antd 的使用做打包配置无需额外配置 - 前端路由: 约定式路由/声明式路由 - 数据管理: 使用 React Hooks 提供的 useContext + useReducer 实现极简的[数据管理方案](#React跨组件通信), 摒弃传统的 redux/dva 等数据管理方案 #### Vue 技术选型 - 前端框架: Vue2.0, Vue3.0 将会在下一个版本与 Vite 一起推出 - 开发语言: TypeScript - 代码风格: [eslint-config-standard-vue-ts](https://github.com/zhangyuang/standardjs-vue) - 样式处理: less + vue scoped - UI 组件: 默认已对 vant 的使用做打包配置无需额外配置 - 前端路由: 约定式路由/声明式路由 - 数据管理: vuex ### 应用类型 由于本框架同时具备 SSR 服务端渲染能力 以及 loadable 代码分割能力。我们天生可以看作既是单页面应用也是多页面应用。表现如下 - 用户可以通过 react-router/vue-roueter 的形式进行页面之间的跳转。此时是纯前端的跳转不会向服务器发送请求视为单页面应用页面之间的互相跳转 - 同时用户也可以通过 a 标签的形式来进行页面之间的跳转。此时视为在服务端渲染一个新页面。视为多页面应用之间的互相跳转,由于我们具备 SSR 能力,此时页面的源代码是新页面具备 SEO 能力以及首屏直出页面能力 - 每个独立页面之间的代码是互相分离互不冗余的 #### 应用介绍 注意: - 我们的策略是将所有负责页面渲染的服务端路由都对应同一个 FaaS 函数。例如 首页和详情页是打到同一个 FaaS 函数。共享函数的资源。优势是便于开发管理。且每一个服务端路由都可对应多个前端路由 - 如果你一定要将首页和详情页分别部署到不同的函数。我们建议你分成两个 Repo 分别进行开发部署 ##### 目录结构 无论前端框架是 React/Vue, 我们 follow 同一套目录结构规范 这里我们使用约定式前端路由。无需手动声明路由配置文件,会根据文件夹名称及路径自动生成路由配置。 `注: 我们目前不支持嵌套路由,也就是子路由` ```bash . ├── build # web目录构建产物 │   ├── client │   └── server ├── config.js # 定义应用的配置 ├── f.yml # 可选,Serverless 场景下需要创建 ├── package.json ├── src # 存放服务端 Node.js 相关代码 │   └── index.ts ├── tsconfig.json # 服务端 Node.js 编译配置文件 ├── web # 存放前端组件相关代码 │   ├── components # 存放公共组件 │   │   └── header # 公共头部 │   │   │ ├── index.less │   │   │ └── index.tsx │   │   └── layout # 页面 html 布局 │   │   ├── index.less │   │   └── index.tsx │   ├── pages # pages目录下的文件夹会映射为前端路由,存放页面级别的组件 │   │   ├── index # index文件夹映射为根路由 │   │   │   ├── fetch.ts # 定义fetch文件用来统一服务端/客户端获取数据的方式,通过 __isBrowser__ 变量区分环境 │   │   │   ├── index.less │   │   │   └── render.tsx # 定义render文件用来定义页面渲染逻辑 │   │   └── detail │   │   ├── fetch.ts │   │   ├── index.less │   │   └── render$id.tsx # 映射为 /detail/:id │  │  └── render$id$.tsx # 映射为 /detail/:id? │   │   └── user │   │   ├── fetch.ts │   │   └── render$id.tsx # 多级路由按照规则映射为 /detail/user/:id │   ├── tsconfig.json # 仅用于编辑器ts语法检测 │   └── typings.d.ts ``` ##### yml 文件编写规范 更加详细的字段描述可以参考 midway-faas 的[使用文档](https://www.yuque.com/midwayjs/faas) ```yml service: name: serverless-ssr-spa provider: name: aliyun functions: # 函数列表 index: handler: index.handler events: # 页面渲染服务 - http: path: / method: get - http: path: /detail/* method: get api-index: # api 数据接口服务 handler: api.handler events: - http: path: /api/index method: get api-detail: handler: api.detail.handler events: - http: path: /api/detail/* method: get render: # 静态资源目录 handler: render.handler events: - http: path: /client/* method: get aggregation: # 将上述 functions 聚合成一个 ssr 函数发布 ssr: deployOrigin: false functionsPattern: - '*' package: include: - build artifact: code.zip ``` ##### 展示形式 http://ssr-fc.com/ -> ssr 函数 -> 渲染 index 组件 http://ssr-fc.com/detail/* -> ssr 函数 -> 渲染 detail 组件 ### 应用原理解析 点击[此处](./images/ykfe-ssr.png)查看高清大图 ![](./images/ykfe-ssr.png) ### FAQ 以下记录应用开发过程中常见问题 #### 从老版本升级 针对于使用老版本用户,可以轻松升级到新版的架构 ```bash $ npm i ssr-core-react # 或者是 ssr-core-vue 根据实际需要选择 $ npm i ssr-plugin-faas ssr-plugin-react --save-dev # 根据实际技术栈安装对应依赖 ``` ```js // 创建 plugin.js 根据实际技术栈写入以下内容 const { faasPlugin } = require('ssr-plugin-faas') const { reactPlugin } = require('ssr-plugin-react') module.exports = { serverPlugin: faasPlugin(), clientPlugin: reactPlugin() } ``` 替换 Node.js 代码中的 `ssr-core` 模块为新的 `ssr-core-react` 即可 #### Vue 全局注册组件 之前写在 `main.js` 中的全局注册组件方法可以无缝搬迁到 `layout/App.vue` 当中 ```vue // layout/App.vue ``` #### 使用 UI 框架 React 场景下我们已经对 antd 进行兼容,Vue 场景已经对 vant 进行兼容,若你要使用其他 UI 框架不做额外配置是一定会报错的。这里以 [vant](https://vant-contrib.gitee.io/vant/#/) 举例子,讲述如何引入。 注: 本框架已经支持直接使用 antd, vant UI 框架,下列代表只是讲述原理,无需重复配置 ```js import Button from 'vant/lib/button'; import 'vant/lib/button/index.less'; // 手动导入的情况这里建议使用这种方式来导入样式文件而不是 import 'vant/lib/button/style' 这样导入的是一个 js 文件 ``` 使用手动按需引入的情况几乎不会出任何问题。但要注意 1、必须使用 lib 目录下的文件,不要用 es,es 模块在服务端无法解析 2、如果是 import `css|less` 文件则不会有问题,但很多 UI 框架例如 antd, vant 这些都会导出一个 js 文件去 require 要用到的 css 文件,这种情况不做额外配置是一定会出错的 这里需要额外在 config.js 配置白名单,使得服务端打包的时候让 Webpack 去处理这种类型的 js 文件 ```js // config.js module.exports = { cssModulesWhiteList: [], whiteList: [/vant.*?style/] } ``` 以 vant 为例,它导出的是 `lib/Button/style/index.js` 文件 以 antd 为例,它导出的是 `lib/Button/style/css.js` 文件 所以 antd 场景下我们需要这么写 `/antd.*?css/` (我们默认配置已包含) 使用 babel-plugin-import 除了上面提到的 whiteList 配置之外还需要创建 babel.config.js ```js // babel.config.js module.exports = { plugins: [ ['import', { libraryName: 'vant', libraryDirectory: 'lib', // 这里一定要用 lib style: true // vant 场景写 true 代表 style/index.js antd 场景写 css 代表 style/css.js }, 'vant'] ] }; ``` #### 降级为客户端渲染 我们可以通过在请求 url 的 query 后面添加 `?csr=true` 来以客户端渲染模式进行渲染。但覆盖度不够。 在正式的线上应用执行阶段。我们一般使用以下方式来进行降级 ##### 通过 config.js 发布的时候支持2种模式,默认是`mode: 'ssr'`模式,你也可以通过 config.js 中的 `mode: 'csr'` 将csr设置默认渲染模式。 ##### 通过 core 模块提供的 render 方法降级 `ssr-core-react` 和 `ssr-core-vue` 模块均支持该方式 在应用执行出错 catch 到 error 的时候降级为客户端渲染。也可根据具体的业务逻辑,在适当的时候通过该方式降级 `csr` 模式 ```js import { render } from 'ssr-core-react' try { const htmlStr = await render(this.ctx) return htmlStr } catch (error) { const htmlStr = await render(this.ctx, { mode: 'csr' }) return htmlStr } ``` 当server出现问题的时候,这样的容灾做法是比较好的。更好的做法是网关层面,配置容灾,将请求打到cdn上。 ##### 通过类似于 ActiveMQ、RabbitMQ、RocketMQ、Kafka 等消息中间件或者实时的接口请求来读取配置 代码修改很简单。 ```js const config = await http.get('xxx') // 通过接口|消息中间件拿到实时的config,可以做到应用不发版更新渲染模式 const htmlStr = await render(this.ctx, config) ``` 此种场景多用于应急预案处理。 #### 如何自定义页面标题, meta 等信息 由于我们 All in jsx/template, 这块的实现也是非常简单的。layout 在服务端被渲染时可以拿到请求的 ctx,根据 ctx 上的信息来 render 不同的信息 Vue 使用方式如下 ```vue ``` React 使用则更简单 ```js const Layout = (props: LayoutProps) => { // 注:Layout 只会在服务端被渲染,不要在此运行客户端有关逻辑 const { state } = useContext(window.STORE_CONTEXT) const { injectCss, injectScript } = props.staticList! return ( {props.ctx.request.path === '/' ? '首页' : '其他页面'}