« 回到博客列表

除了 SSR,就没有别的办法了吗

Feb 7th, 2019阅读本文大约需要 8 分钟

SSR 出啥事了

放心,SSR 没出事。

写这篇博客并不是想说 SSR 有什么不好,而是因为一些别的原因。

想象一个这样的场景

作为有追求的开发者,我们都希望自己能够负责一些比较有技术难度的项目。但作为公司业务来说,总会有一些比较简单的需求,需要做几个静态页,比如产品官网、活动页之类的。这些需求虽然没什么挑战性,但总得有人来做。

没有什么是 jQuery 一把梭搞不定的

一般接到这类“简单”的需求,相信绝大部分人的第一反应肯定是 jQuery,尽管它早已落入前端鄙视链的最底层,但依然魅力不减,宝刀未老。配合 BootStrap 又是一把梭,分分钟搞定。

时至今日,这套方案依然可行,很好的满足了业务的需求,对开发者的技术要求也不高,可以说是非常稳了。

那不就行了,你还担心啥?

教练,我想打篮球

这是一个属于 MVVM 的时代,即便是刚入行的新人也都知道:jQuery 不是终点。

Angular、React、Vue,不管谁是你的本命,一旦入坑,就再也回不去了。即便不为框架故,ES 2015+ 了解一下?LESS、SCSS 了解一下?Pug、EJS 了解一下?用了这些那肯定逃不开 Babel、Gulp、Webpack 了吧?

See?不是 jQuery 不行了,而是行业的发展,让开发者更倾向于(至少已经习惯于)用 MVVM 来开发。

老生常谈 SEO

MVVM 的开发体验是不错,极大的解放了前端开发者的生产力。但和 MVVM 经常一起出现的还有另一个让人又爱又恨的东西,叫 SPA。

SPA 的体验非常好,页面切换非常自然。但 SPA 最大的问题,就是缺少对 SEO 的支持。

为了解决这个问题,主流 MVVM 技术栈都提供了对应的 SSR 的方案。

SSR 从根本上解决了 SEO 的问题,但是实践起来比较麻烦。一方面上手难度较高:必须使用 Node.js、业务代码要进行同构化改造、Webpack 需要多一套配置、第三方库需要审查是否支持 SSR;另一方面 SSR 使得前端的工作需要在浏览器和服务器之间来回切换,相比单纯的客户端开发,或是服务端开发,工作内容要更杂。

所以尽管 SSR 很强大,但杀鸡焉用牛刀。

回到未来

SSR 其实并不是什么新鲜玩意儿,早在 SPA 占领世界之前,动态页面本就是由服务端输出的,前端不过是后端代码中的一个视图而已。

我们现在所谈的 SSR 方案,主要得归功于 Node.js。作为一个运行环境,它使得 JS 成为一门全端语言,前端现在所有的繁荣昌盛和麻烦事儿,都源自 Node.js 的诞生。

相比于传统的后端渲染方案,SSR 最大的好处,是兼顾了前端的组件化,和后端输出的效率。顺带地,由于前后端使用了同一门语言,大量代码得以复用。

尽管前端现在开发手段花里胡哨,但网页最终的样子始终没变。

因此总的来说,我们的诉求就是:开发阶段用 MVVM,构建阶段利用工具生成静态页面。

“预渲染”了解一下

显然,我肯定不是第一个提出这个诉求的人,在 SSR 方案出来没多久,就有人开始研究另一种方案 —— 预渲染。

大家都觉得,这事儿不一定非得放到服务器去做,Node.js 只是一个运行环境,不用非把它当做服务器来看。如果能在构建阶段直接把渲染好的 HTML 打出来,问题不就解决了。

于是有人开发出来这样一个 Webpack 插件 —— PrerenderSPAPlugin

这是一个很厉害的插件,不挑技术栈,无论你是 Angular、React、Vue 中谁的粉,只需要简单设定一下路由,就可以在构建阶段直接输出渲染好的静态页面。背后的原理主要是利用 Puppeteer 加载页面,并把加载完成后的内容保存下来。

PrerenderSPAPlugin 的好处是改造成本低,如果你有一个现有的系统,需要进行预渲染改造,那么你只需要调整一下 Webpack 的配置即可,业务代码不用动。

但这个方案只能处理静态的路由,对于动态路由,这个插件暂时还没有很好的办法来解决。

了不起的盖茨比

开发者大多有自己的博客,博客是一种典型的静态站点,过去有 WordPress、JekyII、Hexo 等大名鼎鼎的 CMS,都能生成静态站点。但这些工具目的性都太强,明白儿地告诉你:我就是个博客。

Gatsby 是最近流行起来的一种新型方案,项目始于 2015 年,原本只是个副业,开发了一年之后,发现反响不错,于是 创始人开始全职投入 Gatsby 的开发工作

区别于其它方案,Gatsby 并没有死盯着 CMS 这一个领域,它定位于一种使用 React 技术栈开发站点的方式。不光可以用于开发静态站点,动态站点也完全不在话下。

Gatsby 的页面就是 React 组件,你之前积累的所有 React 知识到这里都可以继续用,可定制性非常高。

Gatsby 不光支持 Markdown 转 HTML 的方式来生成内容,同时还支持从 WordPress 等主流 CMS 导入数据,或通过外部 API 获取数据来动态生成页面,方便迁移。

Gatsby 支持自定义路由,静态动态均可,没有任何固定的路由套路。

Gatsby 支持部署到 Github Page、Now.sh、Surge.sh 等各大主流托管平台。如果你有自己的服务器,你当然也可以自由发挥。

事实上,这篇博客发布之时,我刚刚把整个博客用 Gatsby 彻底改造了一遍,大家可以感受一下。

想得远一点

既然 Gatsby 这么强大,那么我们可不可以用 Gastby 来替代 SSR 呢?在一定条件下是可以的,但目前有几个地方需要注意一下:

1)动态路由(/user/:id)

对于博客这种内容已经确定的,可以在构建期就确定有哪些路由,但如果需要通过外部 API 来获取,就需要 API 支持 GraphQL,否则目前还无法实现。

当然这种情况我们可以换种思路来考虑,使用固定的子路由,通过改变查询参数,在页面载入之后再动态获取内容。这种方法虽然 URL 看上去不那么完美,但解决问题还是可以的。

2)分散式路由

一般我们在使用 React 时都会配合 React-Router 来管理路由,路由的定义是分散的,哪里需要就写到哪里。Gatsby 应该是集中式的管理,通过在 src/pages 目录下创建目录和文件的方式,或者通过 onCreateNode API 手动创建 slug 的方式来定义路由,然后统一生成一份集中式的路由配置。

3)路由的获取

Gatsby 默认会给所有 src/pages 目录下的组件提供 this.props.location,其他组件需要自行处理。

4)Redux 的使用

在 Gatsby 中可以使用 Redux,但使用方式不像一般的 React App 那样简单,需要在特定的 API 中进行关联。Gatsby 不提供入口文件(常见的会是 src/index.js,Gatsby 的 src/pages/index.js 是首页不是根组件),因此无法直接写进去,需要通过钩子,在构建期间添加。

别急

尽管还有一些问题,但 Gatsby 可以说是目前创建静态站点最完善的方案,既满足了一个静态网站所需要的一切,又提供给了开发者非常现代化的开发方式。

项目现在更新很频繁,包括核心库在内,每天都有大量的 commit。我这次改造大概花了一周时间,期间执行过几次 yarn outdated,每次都有一堆的可更新项目,全都是 gatsby- 开头。

频繁更新的背后,是一整个团队不屑的努力。截至发文当时,Gatsby 最新版本是 2.0.117

小结

至此,我们来对比一下前面说到的几个方案。

jQuery SSR Prerender Gatsby
适用范围 任何页面 所有 MVVM 技术栈 所有 MVVM 技术栈 目前仅 React
实施难度
可定制性
对现代化生态的支持度

总的看来,Gatsby 虽然需要投入一些额外的学习成本,但回报率还是比较高的。

本文提及的几个项目可能并非相关领域的唯一选择,我只是在个人的认知范围内,选择了其中比较有代表性的一个来说明观点。如果各位有更好的推荐的,请一定告诉我。

题外话:简单谈一谈 Imgcook

前阵子阿里爸爸放又出来一个大杀器 —— Imgcook,可以把设计稿一键生成可读性很高的代码,让一批前端从业者背后又一凉。

为什么是“又”?

一方面,人们研究设计稿自动转 HTML 的技术也不是一两天了。前有 Pixel2Code 一文惊天下,后有 微软Airbnb 等大厂发力相关技术。另一方面,阿里爸爸在过去一年先后推出过好多这一类自动化的项目:鹿班飞冰Fusion Design

其实这没什么新鲜,Word、Photoshop、Sketch 导出成 HTML 早就已经是存在了很久的功能了。

每次 AI 出点什么新闻,都会让一批人背后一凉,担心什么时候自己就失业了。但在我看来,AI 再厉害不过是个熟练工。如果一件事情只要重复次数多了谁都能来,那它就有可能被 AI 做到,否则,那就不用担心。不管是设计,还是开发,都属于创造型工作,从创意到实现的过程或许能被 AI 代替,但形成创意的过程,再强大的电脑也算不出来。