2019-03-12
maxiee.github.io 是一个基于 react-static 的 React 静态网站。它与传统的静态博客有很多异同。在这个系列中,我准备介绍 react-static,它是一个非常优秀的 React 静态网站生成器。本文是第一篇,我们先来看看 React 静态网站。
React 静态网站与传统的静态博客相比,有很多相同之处,也有很多异同之处。在本文中,我试图将这些异同讲清楚,希望能展示出 React 静态网站对静态网站开发带来的巨大提升。
首先,我们先从最简单的 HTML 网页说起。
让我们回到互联网的原始时代,没有数据库、没有 PHP、没有 API。
那时的主页真的就只是一个 HTML 文件,比如上面写着:
这就是最简单的网页,它的结构如下:
其中:
这种网页我们将之成为静态网页(没有 API 请求、没有数据库查询,只需要文件服务器托管即可展示)。
为了更好地理解静态 HTML 网页,我们再来说说他的反义词,动态网页。
动态网页往往是跟 Web 框架相关联,比如 Django、Flask、Laravel、Wordpress。
对于一个传统的 MVC 网站,当用户访问 url 时,Web 框架会经历这些过程:
从中可以看出,动态网页是在用户请求时现学现卖,匆匆忙忙拼凑出页面返回。
而静态网页则是一开始就把数据填充进去了,什么时候要就直接把文件扔过去,更潇洒一些。
静态博客(Hexo、Jekyll、Hugo……)同样也是基于上节中古老的静态网页技术。如果你搭建并使用过静态博客,对其应该再熟悉不过了。
GitHub Pages 就是著名的静态网站托管服务。我的 maxiee.github.io 就是托管在上面。任何人写一个静态的 HTML 页面,都可以部署到 GitHub Pages,作为静态网站供人访问。
使用静态博客进行写作时,我们并不是直接徒手写 HTML(那样效率太低了),而是使用 Markdown 语法进行写作。比如按照如下的目录结构:
.
└── content
└── about
| └── _index.md // <- https://example.com/about/
├── posts
| ├── firstpost.md // <- https://example.com/posts/firstpost/
| ├── happy
| | └── ness.md // <- https://example.com/posts/happy/ness/
| └── secondpost.md // <- https://example.com/posts/secondpost/
└── quote
├── first.md // <- https://example.com/quote/first/
└── second.md // <- https://example.com/quote/second/
静态博客又称为静态博客生成器,是因为它通过一个命令行,将这些 Markdown 文件经过模板套用,渲染为文章 HTML,又将这些文章网页连同首页、归档页、关于页等等,共同组装成为一个网站,即静态博客。
当生成器构建完成的时候,这个网站的内容变固定下来了,部署到远端后(如 GitHub Pages),用户每次打开都展示同样的内容。
直到下一次需要重新生成(比如写作了新文章),再次执行生成器,经过一番渲染与组装,网站产生了新的快照。
下面我们再用图像来展示这个过程:
① Markdown 文章转换为 HTML 的过程:
② 整个网站,所有 Markdown 转换组装为整个静态博客站点的过程:
很多人也许会奇怪,React 怎么会跟静态网站建立起联系来呢?因为说到 React,往往就会提到 SPA(Single Page Application,单页应用)。
单页应用是什么呢?在上面的维基百科链接中有详细的定义。在这里我直接给出直观上的认识:
在线的 Photoshop-like 网站,打开网址就是一个图片编辑程序
在线的 Rogue-like 游戏网站,react-rpg
著名的 Gmail
Office 365 网页版
提到这些网站我们会发现,他们与传统的新闻网站不同,他们都是应用(Application)软件。
对于传统的新闻网站或者论坛,主要作用是展示内容,同时处理部分表单提交需求。而对于 SPA 来说,交互性大大提高。
React 就是一个现在最流行的 SPA 开发技术。
使用功能 React 开发的 SPA Web 网站有一个特点,它一般由两部分组成:
一个 index.html,里面几乎是空的,除了导入一个 JavaScript 脚本
一堆 JavaScript 脚本,我们把他们整体看待,他们是 Webpack 打包出的 Bundle
这有点像 Android APK。
既然网站的逻辑全在 JavaScript Bundle 中,就会带来一个问题——包体积、启动时间。
针对这个问题的解法是分包、懒加载,这也是前端领域的一个热门话题。
分包、懒加载值得就是把 Bundle 碎片化,在每个页面都只加载其所必要的数据即可。这样既加快了首次打开速度,有不影响用户体验,通过预加载技术,更能将体验达到用户无感知。
说到这里不知你发现没有,SPA 也是由纯的 HTML、CSS、Java 所组成的,这与前面的静态 HTML 网页是一样的!
事实也是的确如此。我们用 React 开发的应用,也可以托管在 GitHub Page 上。
注:尽管 GitHub Page 本身没有完全支持,但是通过一点小 hack 即可实现,详情参见一、二。
但是也有不同之处,以博客为例,在启动起来之后博客只有一个框架,与 APP 相似,它需要再发起网络请求来拉取数据,比如拉取文章列表。
这个列表既可以有一个 PHP API 返回,也可以是 GitHub Pages 某个路径上的 json 文件。
博客中运行的 React 代码会解析返回的数据,并展示到页面上。
前阵子比较流行的前后端分离,就是指这个事情。这样就把动态网页中网络框架(后端)跟前端页面(前端)解耦了,各玩各的。
SPA 也是静态网站,与静态 HTML 相比,静态 HTML 是所有数据完全包含在内了,而 SPA 只包含了一个壳子,数据需要等壳子加载好后,在通过请求拉取。
这一节最让人懵逼了……怎么说呢?看看这一句:在上一节中,我们说 SPA 也是一个静态网站;在本节中,我们来看如何将 SPA 静态化。
你懵了吗?不管你信不信,我反正是懵了。哈哈哈,言归正传。
我们在上一节中说到:
SPA 静态的东西只有一层壳,数据是网页加载好后再去加载的。这里面会有几个问题:
从中可以看出,这种网站是很受网络情况影响的,如果网速不佳,体验会大大下降。
让我们换一个角度来想:
这个思路就是 SPA 静态化,换做一个比较流行的说法,叫 SSR(Server-Side Rendering,服务端渲染)。参考文献一、二、三。
SSR 指的是在服务端就将 React 应用渲染为最终的静态 HTML,返回给用户。
在具体实施时,有两种不同的做法,分别发生在不同的阶段。
比较常用的是在网络框架阶段进行渲染。
具体来说,当用户请求 url 的时候,网络框架获取数据,同时在 Server 侧执行 React 应用的代码,跑出最终的 DOM 结果,返回给用户。
这样既加快了速度,又减少了流量的开销。
不知你有没有发现,前面讲了前后端分离,这种做法看起来是不是又前后端结合了呢?
其实并没有,SSR 对于后端而言,应该做成一个无感知的框架,相当于为前端提供了一种 Cache 服务。
后端还是后端,前端还是前端,两者并没有发生业务上的耦合。
还有一种更加纯粹的 SSR 方法,其实称之为 BSR(Builder-Side Rendering) 更合适。
具体说来,是在 Webpack 工程构建完成的时候,跑起一个无头浏览器(如 Puppeteer),按照 Router 把每一个网页都跑一遍,对每个网页,都将浏览器执行的最终结果保存为静态 HTML 页面。
这样,一个 React 应用就完全变成了跟 Hexo、Jekyll 一样的静态博客了。
react-static 就是基于这种方法进行的。许多流行的 React Static Site Generator 都是基于这种方法进行的(如 Gatsby)。
说了一大堆,终于说到我们系列的主角——react-static。
它是一个渐进式的 React 静态网站生成器。怎么理解呢?
React SPA 静态网站生成器,这个我们已经在前几节中讲明白了。
至于渐进式是什么意思,我们先不管它。
有了 react-static,不是说任何 React 网站通过它都能变静态。react-static 是一个框架,它定义了一些规则。React 应用必须按照他定义的概念、规则来编写,才能工作。
如果是一个既有的 React 应用,则必须按照 react-static 的概念、规则进行改造,才能工作。
react-static 所定义的概念、规则,我打算放在下一篇中详细介绍。
在本文中,我们只要理解为:
如果认为 SPA 静态化打出了纯静态 HTML 站就完了,那就太天真了。
在每个纯静态 HTML 的末尾,依旧会有对 Bundle 的引用链接!
这是什么意思呢?
因此,这一切的发生在背后,而用户毫无感知。
那这有什么用呢?这样做的用处是:
费了这么大的劲,就是让用户用访问静态网站的速度,得到 SPA 的丰富体验。
在 maxiee.github.io 上有一个今年过了多少天的进度条。如果你仔细看会发现:
知道这是为什么了吧!那个过时的时间正是我构建(Snapshot)的时间,哈哈。
没想到写了这么多,这个概念想说清楚的确不容易。
由于我不是专门的前端工程师,在术语和理解上会有错误和理解不对的地方。欢迎批评指正,可以通过微博或者邮件与我联系。
我会在学习理解正确后改正错误,多谢!
react-static 是一个很好的框架,通过它很多网站都能静态化,这会节省很多服务器开销。
像我就直接关闭了之前的 Wordpress 虚拟主机,改在 GitHub Pages 上托管博客。
免费省钱到不是我刻意追求的,主要是省时省力,好维护,折腾起来也更有意思。
在后续的文章中,我将会介绍 react-static 的各种使用方法。欢迎关注!