SPA与SSR

个人博客与简书同步:zhuzhaohua.com

概述

在之前的文章《前后端分离详解》中,提到单页面应用(SPA)有其弊端。本文将解释SPA所遇到的问题以及为了解决这些问题,所做的取舍。

SPA的优点

它是前后端分离的最佳实践。

  • 关注点分离

    单页面应用符合【关注点分离】这一架构基本原则,它只关注表现层,与后台松耦合;

  • 用户体验好

    画面无需刷新,数据异步获取,页面流畅、网络占用较小;

  • 减轻服务器压力

    单页面应用采用的是客户端渲染,减轻了后台渲染画面的压力;

  • 表现层与后台解耦

    这种解耦,是多端化、服务化的前提条件;

SPA的缺点

  • 首屏加载缓慢

    在第一次访问应用时,会首先将整个应用所需要的框架资源加载进来,这其中包括SPA框架的内容,各种工具库等。在加载完这些资源后,才会开始渲染首屏画面。虽然在后续的使用中有很好的体验,但这第一次的加载确实会有一些卡顿或延迟;

  • SEO不友好

    SEO(搜索引擎优化)是指利用搜索引擎规则提高网站曝光率的手段,也就是让别人可以通过搜索引擎搜索到你的网页内容。SPA天生对SEO是免疫的,因为国内SEO爬虫一般是抓取网络内容而无视脚本,而SPA采用hash实现路由,并不会请求后台,即便通过ajax与后台交互,所获得的也只是json,并非网页资源。更可气的是,SPA首屏是通过js异步加载的,爬虫不会像你的浏览器一样在那里转圈圈等着资源加载完。

  • 复杂度

    如果是传统开发,只要功底深,用记事本都能写出来一张复杂的画面。但单页面应用是高度工程化的,各大框架都有自己的开发工具,比如vue-cli,就是基于vue生态的脚手架。为了实现单页面应用,需要理解前端的组件化,需要学习webpack,需要理解前端router、状态管理、ajax的封装、数据mock等等。而且要考虑更多的因素,比如单页面应用需要自己实现画面的前进后退。

客户端渲染

上文所述的缺点,其实都是一个原因,就是客户端渲染,那么究竟什么是客户端渲染?光靠嘴说,可能没那么直观,接下来以本博客网站为例,实际说明。

本站是使用vuepress搭建(这并不是本文重点,但如果你感兴趣,可以参看我的《本博客搭建教程》)。

博客的主体是一个单页面应用,在开发模式下,我们看看登录首页,究竟发生了什么事情:


1.png

localhost:8080是我本地开发环境的地址,那么在这个请求发出后,应该会得到博客的首页。的确,从响应可以看到,是一个html的结构:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title></title>
  <link rel="icon" href="/img/logo.jpeg"></head>
  <body>
    <div id="app"></div>
  <script type="text/javascript" src="/assets/js/app.js"></script></body>
</html>

但这个html实在是太单薄了对吗?body里有一个id为app的DIV,然后就是一个app.js的脚本。画面上其他的东西都是怎么来的呢?
玄机就在这个app.js脚本中,画面上的所有的内容都是从这个脚本开始渲染出来的,从网络上来看,localhost之后,就是加载app.js,然后加载各种js,画面就一层一层的被渲染出来,这就是典型的客户端渲染:
浏览器从后台获取基础画面以及脚本,然后通过脚本渲染画面,这个渲染的过程发生在浏览器,所以被称之为客户端渲染,你要叫它浏览器渲染也没毛病。

那么我们再来思考上文提到的SEO问题,爬虫只会抓网络请求,而且没有处理js的能力,所以,这个爬取的过程,得不到任何有价值的信息(因为html里什么都没有),也就做不了SEO,也就没人能搜索到你的网站,除非直接输入网址。

服务端渲染-SSR

为了解决客户端渲染首屏慢、无法SEO这两大问题,前端人真的是绞尽脑汁。历经千辛万苦建设起来的单页面应用的高楼大厦,可不能就这么倒掉啊。

其实要解决这两个问题,非常的简单,就是回到过去,采用服务端渲染。

那么什么是服务端渲染呢?

JSP和Thymeleaf都是服务端渲染。浏览器向服务器发一个请求,服务器通过后台逻辑去组装数据,然后绑定在模板文件中进行画面渲染,将渲染后的页面通过字符流返回给浏览器。说白了就是让服务端返回一张完整的html,而不是给浏览器一个脚本让它自己去渲染。

但是很明显,传统的服务端渲染不是前后端分离的。前后端分离和单页面应用是我们不可撼动的底线,但我们还要服务器渲染,二者鱼和熊掌,怎么可能兼得呢???

预渲染的妥协

有一种比较缓和的办法,也就是本网站使用的vuepress框架所采用的办法,叫做预渲染。

这种方式旨在改善某部分画面的SEO,比如你的首页,或者某些需要被渲染的页面(如公司介绍)。它可以在构建的时候,生成某些画面的简单渲染版本。还是以本站举例,这次我们看看生产构建完的版本是什么样的:


2.png

这次请求返回的内容不再是空洞的html里,相对复杂了一些,包含了一些关键字。

我们再看看具体的某一篇文章:


3.png

这篇文章,甚至可以看到具体的文本内容。

这就是预渲染所做的事情,它提前把一些页面内容渲染好,并“挂载”在其对应的路由中,当这个路由触发的时候,会优先去读取这个提前渲染了的页面。这个页面的加载速度会很快,而且内容很饱满,是可以SEO的。

(本文旨在阐明概念,技术细节不是本文重点,这里就不详细介绍预渲染的实现方法,如果感兴趣,可以搜一下prerender-spa-plugin。)

预渲染可以解决一些问题,对于比较小的需求,比如个人网站、公司网站、产品介绍之类的还是可以应对的。但它并没有改变客户端渲染的本质,只不过是部分画面的关键内容得到了提前的渲染,整个站点绝大部分内容的渲染依旧是在客户端完成的,而且,最最重要的是数据依旧通过ajax异步获取,这对于大型网站,比如电商,数据交互特别多、页面逻辑比较复杂的场景,页面的一部分样式已经展现了出来,但商品数据迟迟不能刷新、要转很久的圈。这种情况下,用户体验依旧很差。

还需要妥协的彻底一点。

更彻底的妥协

更彻底的妥协,就是回到过去。。。回到那个后台制霸的年代,回到那个服务器渲染的年代。。。但,今时不同往日,即便是服务器渲染,我们也不再会选择jsp或者mvc。我们有node和mvvm,即便是做后台,也要做前端人自己的后台,前端人不会再看后台的脸色了!

这种全新思路的集大成者,是react生态的Next.js 和 vue生态的Nuxt.js。名字很像,因为nuxt对标的就是next。(据说angular原生支持服务端渲染)

这种思路需要NodeServer作服务器,就像正常开发单页面应用一样去编写程序,服务器在启动时,会执行它的构建过程,它需要构建服务端与客户端两套应用,前者用来服务端渲染,后者用来混合静态标记。

这里解释下【静态标记】。也许你会问,既然已经有了服务器渲染的版本,渲染完了就把html返回给浏览器不就行了吗?为什么还要整出来一套客户端的版本?问题在于,我们大费周章的采用服务器渲染的目的就是减少客户端的渲染,优先把有用的内容推给浏览器,让它尽快的展示给用户,那么这个渲染完的html就需要是静态的,它不具备单页面应用那些复杂的动态效果,所以需要一个“客户端激活”的过程,而这个激活的过程,需要把服务端渲染的画面与静态版本进行比对,并且标记需要激活的节点。

另外需要注意的是,由于mvvm将在node服务器中运行,而非浏览器,所以它将不能使用特定的api,比如浏览器的window、document等等,而且生命周期函数也会受到限制。

这种node+mvvm的服务器渲染方式与tomcat+mvc没什么本质区别,只不过技术栈采用的是前端的技术栈。它依旧是前后端分离,因为表现层与业务层依旧解耦,只不过这里的表现层不再使用静态资源,而是动态渲染的。

结语

如果你之前没有接触过服务端渲染,读到这也许会纳闷,搞得这么复杂,费这么大劲,值得吗?其实技术实现上远比上面介绍的还要复杂。但请你看看标题:妥协,这篇文章通篇使用妥协这个字眼,这也许是前端人的无奈吧。

笔者技术粗浅,斗胆认为当前的这套方法论有待商榷,因为它所引入的复杂程度已经超过它所能解决的问题。笔者作为一名搬砖的码农,感觉当前的这套工具使用起来不是那么的得心应手。SPA与SSR都仍在发展的路上,我相信在不远的将来,必定会有一套鱼和熊掌都能兼得的更好的方案,大神们加油!

常见问题

1.我应该用SPA还是SSR?

SSR最主要的使用场景是面向互联网,面向用户,也就是所谓的2C。无论是SEO优化还是提高首屏加载的速度,其实都是为了让它在网络上有更好的表现。但如果你是要做一个企业级的内部管理系统或者一个管理后台,也就是2B,那么SPA就可以了。如何选择,没有一定之规,主要看实际的需求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352