渲染模式
在引出技术方案前,我先普及下web渲染模式,按照通常的分类web渲染模式有CSR、SSR、SSG、ISR。
CSR - Client Side Rendering - 客户端渲染
CSR
就是我们常见的 SPA
所使用的渲染方式,所有的主流框架都支持,或者说:只要是在客户端渲染过程中使用到了脚本都可以算作客户端渲染。
CSR
主要流程为:

-
浏览器加载页面
-
加载对应的脚本
-
脚本执行时向页面中渲染内容,此步骤一般包含两种方式:
- 向一个空节点中渲染内容,一般应用于纯粹的
CSR
应用。这里使用的就是上面提到的挂载组件的功能。 - 向一个已有内容的节点中渲染内容,通常应用于
CSR
与其它渲染模式(SSR
、SSG
、ISR
)结合的场景下
- 向一个空节点中渲染内容,一般应用于纯粹的
CSR
的使用场景定义也很简单,如果在客户端页面有动态需求或需要交互则必须使用。
SSR - Server Side Rendering - 服务端渲染
SSR
是另一个比较常见的渲染模式,使用这种渲染模式可以从服务端直接返回要渲染的静态内容。
其常见流程为:

- 浏览器发起
HTTP
请求对应的页面 - 服务端接收到请求后准备渲染页面所需要的数据
- 将所需要的数据传入需要渲染的页面组件中然后通过
renderToString
输出为静态内容 - 拼接页面模版、水合脚本等将生成的静态内容返回到浏览器,浏览器进行渲染
- 浏览器渲染内容,执行水合脚本恢复页面交互和动态能力
纯粹的 SSR
指代的接收到请求、输出静态内容、返回浏览器的模式。水合的相关部分是属于 CSR
的内容。
要注意水合并不是必须的,可以按需选择。比如如果你的需求是要对不同的用户展示不同的页面,然而页面上并没有任何可以交互或动态的内容,那完全可以忽略水合的部分。
SSR
一般应用于以下场景:
- 出于首页打开速度、用户体验、
SEO
等目的需要让用户更快的看到页面首屏内容 - 想要预先渲染的页面内容中存在动态的内容
SSG - Static Site Generation - 静态站点生成
SSG
现在也比较常见,它所指代的是在构建阶段就将页面所需要的数据准备好然后将需要的页面通过脚本构建为静态内容的模式。
其常见流程为:

- 在构建阶段构建脚本遍历所有需要静态构建的页面
- 获取渲染所需要的数据并通过
renderToString
输出为静态内容 - 将静态内容拼接页面模版和水合脚本等内容后保存到文件中
- 浏览器发起请求时从服务端返回静态页面(一般直接使用静态文件服务器即可)
- 浏览器渲染内容,执行水合脚本恢复页面交互和动态能力
纯粹的 SSG
指代的同样是不包含 CSR
部分的内容,即构建阶段生成静态页面并在请求时直接将静态页面返回的过程。水合过程同样不是必须的,视需求决定即可。
SSG
一般应用于以下场景:
- 出于首页打开速度、用户体验、
SEO
等目的需要让用户更快的看到页面首屏内容 - 页面中基本都是静态内容,变动很少或变动的时机比较固定
所以常用于通过 CMS
生成内容、博客站点等静态内容较多的场景。
ISR - Incremental Static Regeneration - 增量静态再生
ISR
目前使用的不多,它算是 SSG
的一种增强版,指的是在 SSG
的基础上,服务端在收到页面请求时会对页面的时效性进行判断,如果认定失效则会对该页面进行增量构建的一种模式。
其常见的流程如下:

可以看出 ISR
在构建和客户端环节没有任何的变化,而是增加了 Server
端的逻辑:
- 在服务端收到对应页面请求时服务端会先返回当前内容然后对页面做失效验证
- 如果页面实现,服务端会对失效的页面进行后台增量构建
- 当下次请求到达时如果新的页面已经生成成功则会返回新页面的内容,但在此之前还会继续使用旧页面的内容
当然上述的逻辑并不绝对,先增量构建再返回也同样是 ISR
,只是一般这样会影响到用户体验一般不推荐。
ISR
适用的场景是:
- 网站匹配
SSG
场景 - 但对页面有一定的实时性要求
比如说天气预报页面,可能半小时更新一次即可,或者是新闻页面,在存在新数据时再进行增量构建也是一种解决方案。
根据场景如何选择
在选择渲染模式时我们通过以下逻辑进行简单的判断:
-
客户端页面是否需要动态或交互能力,如果要则
CSR
为必选 -
如果页面有
SEO
、首屏、性能等需求-
如果页面中想要静态展示的内容对每次访问都可能存在差异------比如每个用户看到的页面信息不同,则可以选择
SSR
-
如果页面中静态展示的内容对每次访问没有差异性即可选择
SSG
- 如果页面中的静态内容变动较为频繁,则可选择
ISR
- 如果页面中的静态内容变动较为频繁,则可选择
-
其次还要注意 SSR
和 ISR
都需要服务端的支持,所以如果只有静态文件服务器那需要的改动就比较大了。
成本考虑
在几种渲染模式中,SSG 成本是最低的,网站静态化后直接推到云存储对象服务,云存储对象很便宜,如果网站流量很大再挂上便宜的CDN服务,也是轻轻松松应对激增的流量访问。
其他几种渲染模式 CSR、SSR、ISR 都需要服务端的支持,云服务器的成本是远高于云存储对象服务的。只有在网站需要实时计算的动态内容才需要服务端,动态内容意味着不确定性,那么就要部署能实时计算服务,不管扩容性还是算力成本都是很大的。所以如果你的网站比较少动态数据,也少有需要持久化的数据,比如博客、电商等,那么使用 SSG 是完全够用的。
技术方案
Jamstack
下面就是重头戏了。如何选 SSG 技术栈?
SSG 的框架其实挺多的至少几十种,我之前在网络搜上SSG或静态网站生成器很少全面新鲜的文章,走了不少走弯路。
后来我搜到 For fast and secure sites | Jamstack 这个网站,里面有全面的 SSG 框架 和 headlessCMS 框架。 这个网站对 Jamstack 的概念 说的很抽象,JAM 其实是 Javascript、APIs、Markup 三个术语的首字母组合。通俗来说,Jamstack 就是使用 SSG(Static Site Generators)技术,并且不依赖 Web 服务的前端技术栈。
"A modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup"
--- Mathias Biilmann (CEO & Co-founder of Netlify).
- Javascript:网页渲染工具;JAMStack 并没有限制使用何种框架或是库
- APIs:一系列服务端行为的抽象,主要通过 https 与 Javascript 交互。可以是第三方提供的服务,也可以是自己搭建的 function
- Markup:网站是托管在 CDN 上的静态资源,Markup 就是生成这些资源的源文件。刚提出 Markup 概念的时候,大家都看好 Markdown 作为 Markup 语言,但是这些年更常用的是 Vue 或是 JSX 文件
遇到 Jamstack 我才知道可以这么玩,SSG 再加个 headlessCMS, 可以headlessCMS完善了内容的管理和完善了SSG架构中一部分不那么实时变化的动态内容需求。我之前在别的公司的时候也有内部的headlessCMS 的系统,不过叫数据管理系统,在一些场景确实好用,可以用它实现配置系统的效果。headlessCMS把它翻译为无头内容管理系统我觉得更符合它的本质,用来管理各种各样的内容。
极致低成本技术方案
Jamstack 技术栈不限制使用的框架和库,所以可以有非常多的组合,下面分享我的一个实践。
SSG 框架我选用 astro ,我看了很多vue或react的 SSG ,但都不能满足我的一个需求。我想要直接拖个html目录或markdown文件即可生成页面这样我可以轻松分享一个笔记软件导出的html到个人网站中,只有 astro 能满足我这个需求。并且astro很先进,它有个很特别的islands特性,islands就是类似微前端但更先进的技术,能够支持各种各样的UI框架,vue、react、svelte等主流框架轻松拿捏。而且它还可以支持SSR和CSR。非常灵活强大。
headlessCMS 框架我选用 strapi , strapi 是开源的,有插件系统支持扩展,并且交互设计的很简单易上手。数据库支持sqlite
,这样可以通过COS服务直接同步strapi,并不需要采购云服务器或云数据库。
源码管理和发布使用 rclone 直接推腾讯COS服务,因为腾讯官方的cosbrowser工具只有上传模式以及不能过滤文件,而 rclone 可以做到像git一样同步资源。
此外前端我还接了 cloudflare 反向代理腾讯COS,省去了域名备案、https证书、CDN的钱。
如下图我的示例网站,首页的链接列表和文章页的内容都是通过对接strapi静态生成的。



成本统计
腾讯COS服务10G1年10元,另外文件上传和访问会产生一些请求费或流量费,如果访问量不高,1个月可能1元不到,然后域名费1年免费到几十元丰俭由人,整体算下来建站成本1年不到百元。域名其实可有可无,没有域名大部分厂商的对象存储可以直接对外访问。但我觉得有必要搞个域名,可以隐藏真实的cos服务器地址防止盗刷和DDoS攻击。