最近在学习 React 的服务端渲染,因而使用 Express+React 写了一个 Demo,用于对比和客户端渲染的差别。github 地址css
先看一下效果吧(刚发布貌似 easy-mock 官网就挂了,😂😂):html
一、访问 服务器端渲染 Online Demo前端
二、咱们能够看到,首屏数据很快的就显示出来了,但是页面的进度条却还在加载中(由于客户端 js 很大)。node
三、当进度条加载完成后,页面才能进行交互操做(切换路由,登陆等)。react
四、查看网页源代码,页面内容都在页面中。ios
效果不明显的话,能够打开控制台,在 Network 栏 Disable cache,而后刷新。nginx
经过此次简单的访问,咱们就能看出服务器端渲染的 2 大特色,首屏直出
,SEO 友好
。git
一、访问 客户端渲染 Online Demogithub
二、咱们能够看到,首屏至少等待了 6 秒才渲染出来,这对于通常的用户,是难以容忍的。redux
三、不过一旦渲染完成,页面就当即可交互了(切换路由,登陆等)。
四、查看网页源代码,页面只有一个空 div 容器,而没有实际内容。
经过此次访问,咱们就能看出客户端渲染的特色,首屏加载时间长
,SEO 不友好
,但可见便可操做
。
其实咱们在访问客户端渲染的页面时,请求到的只是一个 html 空壳,里面引入了一个 js 文件,全部的内容都是经过 js 进行插入的,相似于这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>ssr</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
复制代码
正是由于页面是由 js 渲染出来的,因此会带来以下几个问题:
一、页面要等待 js 加载,并执行完成了才能展现,在这期间页面展示的是白屏
。
二、爬虫不能识别 js 内容,因此抓取不到任何数据,不利于 SEO 优化
。
为了解决这 2 个问题,咱们可使用服务器端渲染。
以前说道,客户端渲染的页面,请求到的是一个 html 空壳,而后经过 js 去渲染页面。那若是请求到的直接是一个渲染好的页面,是否是就能够解决这 2 个问题了呢?
没错,服务器端渲染就是这个原理。
一、服务器端使用 renderToString 直接渲染出包含页面信息的静态 html
。
二、客户端根据渲染出的静态 html 进行二次渲染
,作一些绑定事件等操做。
服务器端没有 DOM,Window 等概念,因此只能渲染出字符串,不能进行事件绑定,样式渲染等。
只有第一次访问页面时才使用服务器端渲染,以后会被客户端渲染接管。
接下来咱们一块儿来写一个 React 服务器端渲染 Demo。
这里使用 react-router 对先后端代码进行同构。
一、客户端
使用 react-router-dom 下的 BrowserRouter
进行前端路由控制。
二、服务器端
使用 react-router-dom 下的 StaticRouter
进行静态路由控制,具体操做以下:
使用 StaticRouter 中经过 context 能够和前端页面通讯,传参。
在 React 中,咱们经常使用 redux 来存储数据,管理状态。
一、客户端
使用 redux 进行状态管理,使用 react-redux 提供的 Provider 为组件注入 store。
二、服务器端
和客户端同样,但每一次接收到请求需产生一个新的 store,避免多个用户操做同一个 store。
一、客户端
使用 axios 在 componentDidMount 中请求数据。
二、服务器端
一样使用 axios 去请求数据,可是服务器端不会触发 componentDidMount 生命周期。咱们能够在后端匹配到路由的时候,进行数据请求,并把数据存入 redux 中的 store,而后渲染出包含数据的 html 页面,为了不客户端二次请求,服务器端向 window 中注入 REDUX_STORE 数据,客户端直接使用此数据做为客户端 redux 的初始数据,以避免发生数据抖动。
具体操做以下:
一、客户端
使用 css-loader,style-loader 打包编写好的 css 代码并插入到页面中。
二、服务器端
因为 style-loader 会插入到页面,而服务器端并无 document 等概念,因此这里使用 isomorphic-style-loader 打包 css 代码。
SEO 主要是针对搜索引擎进行优化,为了提升网站在搜索引擎中的天然排名,但搜索引擎只能爬取落地页内容(查看源代码时可以看到的内容),而不能爬取 js 内容,咱们能够在服务器端作优化。
常规的 SEO 主要是优化:文字
,连接
,多媒体
因为网页上的文字,连接,图片等信息都是产品设计好的,技术层面不能实现优化。咱们须要作的就是优化页面的 title,description 等,让爬虫爬到页面后可以展现的更加友好。
这里借助于 react-helmet 库,在服务期端进行 title,meta 等信息注入。
如今,咱们成功地经过服务器端渲染解决了首次加载白屏时间
和 SEO 优化
。但也带来了一些问题:
以上两个问题归根结底仍是钱的问题。服务器压力大,能够经过买更多的服务器来解决。可维护性增大,能够招募更多人来维护。可是对于小型团队来讲,增长服务器,招募更多维护人员,都会额外增长的支出,因此在选择服务器端渲染时,要权衡好利弊。
若是只是想优化 SEO,不妨使用预渲染来实现,推荐使用 prerender 库来实现。
prerender 库的原理:先请求客户端渲染的页面,把客户端渲染完成以后的结果,拿给爬虫看
,这样爬虫获取到的页面就是已经渲染好的页面。prerender 库在使用时会开启一个服务,经过传递 url 来解析客户端渲染页面,这就须要咱们对服务器端架构进行调整。
一、 nginx 判断访问类型
2.一、 用户访问 :直接走客户端渲染
2.二、 爬虫访问 :走预渲染
经过这个 Demo,让我加深了对服务器端的理解,若有错误,麻烦多多指正,谢谢你们!
若是以为有用得话给个 ⭐ 吧。react-ssr-demo