Skip to main content

现代化的开发概念

tip

非原创声明,只是进行适当修改,相关内容来源:

  1. https://github.com/chengpeiquan/learning-vue3

在本章最开始的时候提到了 SPA / SSR / SSG 等词汇,这些词汇是一些现代前端工程化开发的概念名词缩写,代表着不同的开发模式和用户体验。

当下主流的前端框架都提供了这些开发模式的支持,因此在学习前端工程化和 Vue 开发的过程中,会不定期的看到这一类词汇,在实际工作业务的技术选型时,面对不同的业务场景也要考虑好需要使用什么样的开发模式,提前了解这些概念,对以后的工作也会很有帮助。

MPA 与 SPA

首先来看 MPA 与 SPA ,这代表着两个完全相反的开发模式和用户体验,它们的全称和中文含义如下:

名词全称中文
MPAMulti-Page Application多页面应用
SPASingle-Page Application单页面应用

多页面应用

MPA 多页面应用是最传统的网站体验,当一个网站有多个页面时,会对应有多个实际存在的 HTML 文件,访问每一个页面都需要经历一次完整的页面请求过程:

# 传统的页面跳转过程

从用户点击跳转开始:
---> 浏览器打开新的页面
---> 请求【所有】资源
---> 加载 HTML 、CSS 、 JS 、 图片等资源
---> 完成新页面的渲染

MPA 的优点

作为最传统也是最被广泛运用的模式,自然有它的优势存在:

  • 首屏加载速度快

因为 MPA 的页面源码都是实实在在的写在 HTML 文件里,所以当 HTML 文件被访问成功,内容也就随即呈现(在不考虑额外的 CSS 、 图片加载速度的情况下,这种模式的内容呈现速度是最快的)。

  • SEO 友好,容易被搜索引擎收录

如果读者有稍微了解过一些 SEO 知识,会知道除了网页的 TKD 三要素之外,网页的内容也影响收录的关键因素,传统的多页面应用,网页的内容都是直接位于 HTML 文件内,例如下面这个有很多内容的网页:

右键查看该网页的源代码,可以看到网页内容对应的 HTML 结构也是包含在 .html 文件里。

tip

网页的 TKD 三要素是指一个网页的三个关键信息,含义如下:

T ,指 Title ,网站的标题,即网页的 <title>网站的标题</title> 标签。

K ,指 Keywords ,网站的关键词,即网页的 <meta name="Keywords" content="关键词1,关键词2,关键词3" /> 标签。

D ,指 Description ,网站的描述,即网页的 <meta name="description" content="网站的描述" /> 标签。

这三个要素标签都位于 HTML 文件的 <head /> 标签内。

  • 容易与服务端语言结合

由于传统的页面都是由服务端直出,所以可以使用 PHP 、 JSP 、 ASP 、 Python 等非前端语言或技术栈来编写页面模板,最终输出 HTML 页面到浏览器访问。

MPA 的缺点

说完 MPA 的优点,再来看看它的缺点,正因为有这些缺点的存在,才会催生出其他更优秀的开发模式出现。

  • 页面之间的跳转访问速度慢

正如它的访问流程,每一次页面访问都需要完整的经历一次渲染过程,哪怕从详情页 A 的 “相关阅读” 跳转到详情页 B ,这种网页结构一样,只有内容不同的两个页面,也需要经历这样的过程。

  • 用户体验不够友好

如果网页上的资源较多或者网速不好,这个过程就会有明显的卡顿或者布局错乱,影响用户体验。

  • 开发成本高

传统的多页面模式缺少前端工程化的很多优秀技术栈支持,前端开发者在刀耕火种的开发过程中效率低下。如果是基于 PHP 等非前端语言开发,工作量通常更是压在一名开发者身上,无法做到前后端分离来利用好跨岗位协作。

tip

此处列举的多页面应用问题均指传统开发模式下的多页面,之所以特地说明,是因为后文还会有新的技术栈来实现多页面应用,但实现原理和体验并不一样。

单页面应用

正因为传统的多页面应用存在了很多无法解决的开发问题和用户体验问题,催生了现代化的 SPA 单页面应用技术的诞生。

SPA 单页面应用是现代化的网站体验,与 MPA 相反,不论站点内有多少个页面,在 SPA 项目实际上只有一个 HTML 文件,也就是 index.html 首页文件。

它只有第一次访问的时候才需要经历一次完整的页面请求过程,之后的每个内部跳转或者数据更新操作,都是通过 AJAX 技术来获取需要呈现的内容并只更新指定的网页位置。

tip

AJAX 技术( Asynchronous JavaScript and XML )是指在不离开页面的情况下,通过 JavaScript 发出 HTTP 请求,让网页通过增量更新的方式呈现给用户界面,而不需要刷新整个页面来重新加载,是一种 “无刷体验” 。

SPA 在页面跳转的时候,地址栏也会发生变化,主要有以下两种方式:

  1. 通过修改 Location:hash 修改 URL 的 Hash 值(也就是 # 号后面部分),例如从 https://example.com/#/foo 变成 https://example.com/#/bar
  2. 通过 History API 的 pushState 方法更新 URL ,例如从 https://example.com/foo 变成 https://example.com/bar

这两个方式的共同特点是更新地址栏 URL 的时候,均不会刷新页面,只是单纯的变更地址栏的访问地址,而网页的内容则通过 AJAX 更新,配合起来就形成了一种网页的 “前进 / 后退” 等行为效果。

tip

Vue Router 默认提供了这两种 URL 改变方式的支持,分别是 createWebHashHistory 的 Hash 模式和 createWebHistory 对应的 History 模式,在 路由的使用一章可以学习更多 Vue 路由的使用。

理解了实现原理之后,可以把 SPA 的请求过程简化为如下步骤:

# SPA 页面跳转过程

从用户点击跳转开始:
---> 浏览器通过 `pushState` 等方法更新 URL
---> 请求接口数据(如果有涉及到前后端交互)
---> 通过 JavaScript 处理数据,拼接 HTML 片段
---> 把 HTML 片段渲染到指定位置,完成页面的 “刷新”

SPA 的优点

从上面的实现原理已经能总结出它的优势了:

  • 只有一次完全请求的等待时间(首屏加载)
  • 用户体验好,内部跳转的时候可以实现 “无刷切换”
  • 因为不需要重新请求整个页面,所以切换页面的时候速度更快
  • 因为没有脱离当前页面,所以 “页” 与 “页” 之间在切换过程中支持动画效果
  • 脱离了页面跳页面的框架,让整个网站形成一个 Web App ,更接近原生 App 的访问体验
  • 开发效率高,前后端分离,后端负责 API 接口,前端负责界面和联调,同步进行缩短工期

这也是为什么短短几年时间, SPA 的体验模式成为前端领域的主流。

SPA 的缺点

虽然 SPA 应用在使用过程中的用户体验非常好,但也有自身的缺点存在:

  • 首屏加载相对较慢

由于 SPA 应用的路由是由前端控制, SPA 在打开首页后,还要根据当前的路由再执行一次内容渲染,相对于 MPA 应用从服务端直出 HTML ,首屏渲染所花费的时间会更长。

  • 不利于 SEO 优化

由于 SPA 应用全程是由 JavaScript 控制内容的渲染,因此唯一的一个 HTML 页面 index.html 通常是一个空的页面,只有最基础的 HTML 结构,不仅无法设置每个路由页面的 TDK ,页面内容也无法呈现在 HTML 代码里,因此对搜索引擎来说,网站的内容再丰富,依然只是一个 “空壳” ,无法让搜索引擎进行内容爬取。

为了减少用户等待过程中的焦虑感,可以通过增加 Loading 过程,或者 Skeleton 骨架屏等优化方案,但其实也是治标不治本,因此为了结合 SPA 和 MPA 的优点,又进一步催生出了更多实用的技术方案以适配更多的业务场景,在后面的小节将逐一介绍。

CSR 与 SSR

在了解了 MPA 与 SPA 之后,先了解另外两个有相关联的名词: CSR 与 SSR ,同样的,这一对也是代表着相反的开发模式和用户体验,它们的全称和中文含义如下:

名词全称中文
CSRClient-Side Rendering客户端渲染
SSRServer-Side Rendering服务端渲染

正如它们的名称,这两者代表的是渲染网页过程中使用到的技术栈。

客户端渲染

MPA 多页面应用与 SPA 单页面应用 部分的介绍过的 SPA 单页面应用,正是基于 CSR 客户端渲染实现的(因此大部分情况下, CSR 等同于 SPA ,包括实现原理和优势),这是一种利用 AJAX 技术,把渲染工作从服务端转移到客户端完成,不仅客户端的用户体验更好,前后端分离的开发模式更加高效。

但随之而来的首屏加载较慢、不利于 SEO 优化等缺点,而 SPA 的这几个缺点,却是传统 MPA 多页面应用所具备的优势,但同样的, MPA 也有着自己开发成本高、用户体验差等问题。

既然原来的技术方案无法完美满足项目需求,因此在结合 MPA 的优点和 SPA 的优点之后,一种新的技术随之诞生,这就是 SSR 服务端渲染。

服务端渲染

和传统的 MPA 使用 PHP / JSP 等技术栈做服务端渲染不同,现代前端工程化里的 SSR 通常是指使用 Node.js 作为服务端技术栈。

tip

在 工程化神器 Node.js 一节会介绍 Node ,以及它对前端工程化带来的重大变化,现代前端工程化发展离不开它的存在。

传统的服务端渲染通常由后端开发者一起维护前后端代码,需要写后端语言支持的模板、 JavaScript 代码维护成本也比较高;而 SSR 服务端渲染则是交给前端开发者来维护,利用 Node 提供的能力进行同构渲染,由于本身前后端都使用 JavaScript 编写,维护成本也大大的降低。

SSR 技术利用的同构渲染方案( Isomorphic Rendering ),指的是一套代码不仅可以在客户端运行,也可以在服务端运行,在一些合适的时机先由服务端完成渲染( Server-Side Rendering )再直出给客户端激活( Client-Side Hydration ),这种开发模式带来了:

  • 更好的 SEO 支持,解决了 SPA 单页面应用的痛点
  • 更快的首屏加载速度,保持了 MPA 多页面应用的优点
  • 和 SPA 一样支持前后端分离,开发效率依然很高
  • 有更好的客户端体验,当用户完全打开页面后,本地访问过程中也可以保持 SPA 单页面应用的体验
  • 统一的心智模型,由于支持同构,因此没有额外的心智负担

那么,使用 Vue 开发项目时,应该如何实现 SSR 呢?

Vue 的 SSR 支持非常好, Vue 官方不仅提供了一个 Vue.js 服务器端渲染指南 介绍了基于 Vue 的 SSR 入门实践,还有基于 Vue 的 Nuxt.jsQuasar 框架帮助开发者更简单地落地 SSR 开发,构建工具 Vite 也有内置的 Vue SSR 支持。

Pre-Rendering 与 SSG

在介绍了 SSR 服务端渲染技术后,读者可能会想到一个问题,就是 SSR 的开发成本总归比较高,如果本身项目比较简单,例如一个静态博客,或者静态官网、落地页等内容不多,仅需要简单的 SEO 支持的项目需求,是否有更简便的方案呢?

以下两种方案正是用于满足这类需求的技术:

名词全称中文
Pre-RenderingPre-Rendering预渲染
SSGStatic-Site Generation静态站点生成

预渲染

预渲染也是一种可以让 SPA 单页面应用 解决 SEO 问题的技术手段。

预渲染的原理是在构建的时候启动无头浏览器( Headless Browser ),加载页面的路由并将访问结果按照路由的路径保存到静态 HTML 文件里,这样部署到服务端的页面,不再是一个空的 HTML 页面,而是有真实内容的存在,但由于只在构建时运行,因此用户每次访问的时候 HTML 里的内容不会产生变化,直到下一次构建。

tip

无头浏览器( Headless Browser ),指没有 GUI 界面的浏览器,使用代码通过编程接口来控制浏览器的行为,常用于网络爬虫、自动化测试等场景,预渲染也使用它来完成页面的渲染,以获取渲染后的代码来填充 HTML 文件。

预渲染和 服务端渲染 最大的区别在于,预渲染只在构建的时候就完成了页面内容的输出(发生在用户请求前),因此构建后不论用户何时访问, HTML 文件里的内容都是构建的时候的那份内容,所以预渲染适合一些简单的、有一定的 SEO 要求但对内容更新频率没有太高要求、内容多为静态展示的页面。

例如企业用于宣传的官网页面、营销活动的推广落地页都非常适合使用预渲染技术,现代的构建工具都提供了预渲染的内置实现,例如这个教程: 用 Vite 更简单的解决 Vue3 项目的预渲染问题 ,就是通过 Vite 的内置功能来实现预渲染,最终也运用到了公司的业务上。

静态站点生成

SSG 静态站点生成是基于预渲染技术,通过开放简单的 API 和配置文件,就让开发者可以实现一个预渲染静态站点的技术方案。

它可以让开发者定制站点的个性化渲染方案,但更多情况下,通常是作为一些开箱即用的技术产品来简化开发过程中的繁琐步骤,这一类技术产品通常称之为静态站点生成器( Static-Site Generator ,也是简称 SSG )。

常见的 SSG 静态站点生成器有:基于 Vue 技术的 VuePressVitePress ,自带了 Vue 组件的支持,还有基于 React 的 Docusaurus ,以及很多各有特色的生成器,例如 JekyllHugo 等等。

如果有写技术文档或者博客等内容创作需求,使用静态站点生成器是一个非常方便的选择,通常这一类产品还有非常多的个性化主题可以使用。

ISR 与 DPR

在现代化的开发概念这一节,从 MPA 多页面应用到 SPA 单页面应用 ,再到 CSR 客户端渲染和 SSR 服务端渲染 ,以及 Pre-Rendering 预渲染与 SSG 静态站点生成 ,似乎已经把所有常见的开发场景覆盖完了。

那接下来要讲的 ISR 和 DPR 又是什么用途的技术方案呢?先看看它们的全称和中文含义:

名词全称中文
ISRIncremental Site Rendering增量式的网站渲染
DPRDistributed Persistent Rendering分布式的持续渲染

当网站的内容体量达到一定程度的时候,从头开始构建进行预渲染所花费的时间会非常久,而实际上并不是所有页面的内容都需要更新,这两项技术的推出是为了提升大型项目的渲染效率。

ISR 增量式的网站渲染,通过区分 “关键页面” 和 “非关键页面” 进行构建,优先预渲染 “关键页面” 以保证内容的最新和正确,同时缓存到 CDN ,而 “非关键页面” 则交给用户访问的时候再执行 CSR 客户端渲染,并触发异步的预渲染缓存到 CDN 。

这样做的好处是,大幅度的提升了每次构建的时间,但由于只保证部分 “关键页面” 的构建和内容正确,所以访问 “非关键页面” 的时候,有可能先看到旧的内容,再由 CSR 刷新为新的内容,会丢失一部分用户体验。

更多 ISR 技术细节可以阅读 Netlify 的开发者体验总监 Cassidy Williams 的一篇文章: Incremental Static Regeneration: Its Benefits and Its Flaws

DPR 分布式的持续渲染则是为了解决 ISR 方案下可能访问到旧内容的问题,这也是由 Cassidy Williams 发起的一个提案,详情可在 GitHub 查看:Distributed Persistent Rendering (DPR)

由于目前这两项技术还在发展初期,能够支持的框架和服务还比较少,在这里建议作为一种技术知识储备提前了解,在未来的某一天有业务需要的时候,也可以知道有这样的方案可以解决问题。