vue服务端渲染 同构渲染

引言

自JavaScript诞生以来,前端技术发展非常迅速。移动端白屏优化是前端界面体验的一个重要优化方向,Web 前端诞生了 SSR 、CSR、预渲染等技术。

十年前,几乎所有网站都使用 ASP、Java、PHP 这类做后端渲染,但后来随着 jQuery、Angular、React、Vue 等 JS 框架的崛起,开始转向了前端渲染。2014年起又兴起了同构渲染,号称是未来,集成了前后端渲染的优点,当真如此?

我们先明确三个概念:

后端渲染:后端渲染指传统的 ASP、Java 或 PHP 的渲染机制;

CSR:前端渲染 指使用 JS 来渲染页面大部分内容,代表是现在流行的 SPA 单页面应用;

同构渲染:指前后端共用 JS,首次渲染时使用 Node.js 来直出 HTML。一般来说同构渲染是介于前后端中的共有部分

以及常用性能测试时间点

  • 首次内容绘制FCP(frist conntentful paint) 浏览器将第一个dom渲染到屏幕的时间,也就是通常所说的白屏时间
  • 文档加载时间DCL(domContentLoaded)
  • 首次有意义的绘制FMP(frist meaningful paint) ,就是说主要内容出现在页面上的时间,用户希望看到的主要内容出现在屏幕上的时间

在前端渲染领域,主要有以下几种方式可供选择:

    CSR   预渲染     SSR 同构
优点
  • 不依赖数据
  • 局部刷新,无需每次都进行完整页面请求
  • FP 时间最快
  • 客户端用户体验好
  • 内存数据共享
  • 懒加载
  • 富交互,可使用JS实现各种炫酷效果
  • 节约服务器成本
  • 不依赖数据
  • FCP 时间比 CSR 快
  • 客户端用户体验好
  • 内存数据共享
  • SEO 友好
  • 首屏性能高,FMP 比 CSR 和预渲染快
  • 兼容性问题较优秀
  • SEO 友好
  • 首屏性能高,FMP 比 CSR 和预渲染快
  • 客户端用户体验好
  • 内存数据共享
  • 客户端与服务端代码公用,开发效率高
缺点
  • SEO 不友好
  • FCP 、FMP 慢
  • 首屏白屏问题
  • SEO 不友好
  • FMP 慢
  • 开发成本高(构建)
  • 客户端数据共享成本高
  • 模板维护成本高
  • Node 容易形成性能瓶颈
  • 实施难度大

由上表格可得知,各种渲染模式优缺点各异,看起来并没有那么完美的解决方案,我们只能依据自身产品需求,选择最适合我们的渲染方案。

应用场景

1、一个优秀的产品 ,离不开SEO,它包含了很多方面的知识,一般公司都会配置专门的SEO职位, 毕竟有太多事情要做了。而我们作为一个有追(破 )求(不)完(得)美(已)的前端,在开发的时候,需要做好页面结构科学、标签语义化、站点路由精简、提供必要的爬虫信息(如 Robot.txt,Sitemap,标签 role,ref 等等);然而在现实中CSR大行其道,SPA站点更是数不胜数,用户体验得到了质的提升,然而,然而,为了兼顾SEO,开发者不得不为爬虫提供专门的shadowsite,或者自己顶起下载自己的页面提供给爬虫,或者使用SSR,刀耕火种的年代。。。

2、首屏渲染速度

目前前后端的分离的前端项目需要先加载静态资源,再异步获取数据,最后渲染页面,在这个过程中的前两部页面都是没有数据的,影响了首屏的渲染速度,也就影响了用户的体验。 目前对于首屏渲染速度的提升有许多方案,在ssr之外还有龙骨,墓碑,数据直出。相比于这些方案ssr方案实现是最复杂的,但效果也是最好的。

3、方案选择

vue 中做同构,有两种,一种是基于官方Vue SSR指南推荐的SSR,一种是vueJS通用应用框架 NUXT.

官网方案,可以更直接的控制应用程序,更深入底层,也比较灵活。NUXT,你懂得,就是那种你拿来即用的效果,提供了部分额外功能,e.g. 静态站点,可用于快速实现Vue SSR

SSR和预渲染的使用场景还是有比较明显的区别的,预渲染的使用场景更多的是我们所说的静态页面的形式。而SSR适用于大型的。页面数据处理较多且较为复杂、与服务端有数据交互的功能性网站,一个明显的使用场景就是电商网站

今天为大家介绍的这个,是部分同构方案,开始。。。

使用简介

  

从官网借来的图可知,SSR有两个入口文件,entry-client和entry-server两个文件,都包含了应用代码,webpack会根据这两个入口文件分别打包成给服务端用的,Server Bundle及客户端使用的Client Bundle ,当服务器接收到了来自客户端的请求之后,会创建一个渲染器 bundleRenderer,这个 bundleRenderer 会读取上面生成的 server bundle 文件,并且执行它的代码, 然后发送一个生成好的 html 到浏览器,等到客户端加载了 client bundle 之后,会和服务端生成的DOM 进行 Hydration (判断这个 DOM 和自己即将生成的 DOM 是否相同,如果相同就将客户端的Vue实例挂载到这个 DOM 上, 否则会提示警告)。

而在vue服务器端渲染时,就不能只是使用web-dev-server和web-hot-middle了,因为我们需要添加服务器渲染的node代码逻辑,这样,我们可以自己开一个node服务器,使用webpack-dev-middle中间件进行打包、使用webpack-hot-middle中间件进行热更新,并添加服务器端渲染逻辑,即node端通过引入vue-serverer-renderer插件来渲染服务器端打包的bundle文件到客户端。

如何用?

所以在项目开发期间,其实我们是运行着两个node服务,一个做代理服务,一个提供ssr和其他的一些服务。

1、client-server的作用:

  • 客户端打包bundle,然后提供给浏览器进行混合静态标记,在默认情况下,可以在浏览器端输出vue组件,进而生成、操作DOM,然而,服务端渲染时将同一个组件渲染成浏览器端的Html字符串,但是这些个只是字符串,而非应用程序,比如没有CSS等;该html字符串然后发送给浏览器,然后结合客户端打包,最后将静态标记‘混合’为客户端上,生成完全交互的应用程序
  • 数据同步的问题,在挂在到客户端应用程序之前,需要获取到与服务端应用程序完全相同的数据,即为window.__INITIAL_STATE__,然后通过store.replaceState(window.__INITIAL_STATE__),这样,就会替代本地store中的state,否则,客户端会因为使用与服务器端不同的状态,导致混合失败。
  • 服务器端打包代码是为了提供html静态页面,客户端代码打包时为了后期的交互与数据处理,以及服务端打包失败的的异常处理

2、entry-server的作用:

  • 前端请求过来的时候,根据getMatchedComponents方法 服务端匹配对应的URL,然后会以此寻找对应的组件或者静态资源
  • 该配置主要用于生成 bundle   vue-ssr-server-bundle.json ,生成之后,传递给createBundleRenderer ,这里会检查组件是否有 asyncData 方法,然后下一步
  • pre-fetch,服务器端的数据预获取:如果组件需要预获取数据,我们就调用自己约定好的asyncData 方法,获取到数据,并存储到服务端的store中,然后将解析完成的状态附加给上下文,并且 `template` 选项用于 renderer 时,状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。下面是一个页面简单请求的例子
  • 异常处理,如果在预获取数据过程中出错了,我们给一个标识  serverError,并注入HTML中,然后浏览器端可以根据此状态进行重新渲染,或者异常展示都可以。

2、由于在node环境中,无法用webpack进行CSS文件处理,所以在配置文件中我们需要对服务端渲染时,进行CSS白名单处理

1 externals: TARGET_NODE? nodeExternals({whitelist: [/\.css$/] }):undefined

3、我们从打包出来的代码中可以看到,是vue-ssr-server-bundle.json,而非常规的JS文件。这是因为node环境下,每次打包成js文件,你得考虑node的热部署,并且node环境也不支持sourcemap,所以引入了  vue-server-renderer 组件,这种方式类似于常规的render,支持热部署,支持source map ,在配置文件中,我们配置了该组件下的服务端渲染插件,可以使得服务端渲染输出的是json文件。

4、

在CSR模式下,我们开发过程中会进行热部署,这样会大大提高工作效率。

 1 let bundle
 2 serverCompiler.watch({}, (err, stats) => {
 3   if (err) {
 4     throw err
 5   }
 6   stats = stats.toJson()
 7   stats.errors.forEach(error => console.error(error))
 8   stats.warnings.forEach(warn => console.warn(warn))
 9   const bundlePath = path.join(
10     webpackConfig.output.path,
11     ‘vue-ssr-server-bundle.json‘
12   )
13   bundle = JSON.parse(mfs.readFileSync(bundlePath, ‘utf-8‘))
14   console.log(‘new bundle generated‘)
15 })

 注意事项

  1. 代码执行环境不同引起的bug

    1. 服务端是没有window,document对象的,storage的实现类也甭想了。。。location更不用说了。。如果加了这些个对象的引用和操作,在服务器端会引起报错,node若报错,可想而知。。
    2. 生命周期的钩子函数  beforeCreate和created会在SSR过程中调用,但是也同时会在客户端执行。。。写代码前最好判断一下你的执行环境。
  2.   接口代理问题:可以采用DevServer进行代理转发请求,或者用axios也可以,不然存在跨域问题
  3. 服务端渲染 的时候必须路由必须使用history模式,处理好请求不在的回调
  4. cookie穿透:因为http请求是先到SSR服务器,再有SSR服务器去后端服务器器扭曲想要的数据接口,客户端请求的时候是带着cookie数据的,而SSR服务器请求后端接口的时候,却没有相应的cookie数据,因此在SSR服务器进行接口请求的时候,我们需要手动拿到客户端的cookie传给后端服务器。我们使用是axios,就可以手动设置axios请求的headers字段,达到cookie穿透的目的。
  5. 数据泄露:因为使用了vuex,如果不使用惰性加载,容易造成数据泄露的情况发生,任何需要登录获取数据的情况,建议在客户端进行。

异常处理

  1、服务器预获取数据的异常处理,参考上面的entry-server中所说,让客户端主动获取数据,再次尝试渲染

  2、在服务端数据预获取的生命周期结束后的渲染页面过程中出现的异常,包括各种操作数据的语法错误等,如对undefined取属性。编写过程要注意全局环境下的代码,是否试用,做环境判断。

缓存策略 

虽然 Vue 的服务器端渲染(SSR)相当快速,但是由于创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接(pure string-based)的模板的性能相当。在 SSR 性能至关重要的情况下,明智地利用缓存策略,可以极大改善响应时间并减少服务器负载,这是一个取舍的过程。vue服务区缓存分为页面缓存、组建缓存和接口缓存;

页面缓存

将渲染完成的页面缓存到内存中,同时设置最大缓存数量和缓存时间。 优势:大幅度提高页面的访问速度 代价:增加服务器内存的使用

 1 const microCache = LRU({
 2   max: 100, // 最大缓存的数目
 3   maxAge: 1000 // 重要提示:条目在 1 秒后过期。
 4 })
 5 const isCacheable = req => {
 6   // 判断是否需要页面缓存
 7   if (req.url && req.url === ‘/‘) {
 8     return req.url
 9   } else {
10     return false
11   }
12 }
13 const handleRequest = async (ctx, next) => {
14   const req = ctx.req
15   const res = ctx.res
16   const cacheable = isCacheable(req)
17   if (cacheable) {
18     const hit = microCache.get(res.url)
19     if (hit) {
20       return res.end(hit)
21     }
22   }
23 ...
24 ...
25 }

组件缓存

使用较少,本次并未涉及

接口缓存

将通用的接口缓存到内存,减少服务端接口请求的时间

 get (url, params = {}) {
        // url = baseUrl + ‘/sa‘ + url
        url = baseUrl + url
        const key = md5(url + JSON.stringify(params))
        // 判断是否有缓存,直接返回缓存结果
        if (params.cache && microCache.get(key)) {
          return Promise.resolve(microCache.get(key))
        }
        let Cookie = ‘‘
        if (params.req && params.req.headers && params.req.headers.cookie) {
          Cookie = params.req.headers.cookie
        }
        return new Promise((resolve, reject) => {
          axios({
            url,
            params,
            headers: {
              ‘X-Requested-With‘: ‘XMLHttpRequest‘,
              ‘Cookie‘: Cookie
            },
            method: ‘get‘
          }).then(res => {
            // 判断是否需要缓存 如果需要缓存缓存数据
            if (params.cache && microCache) {
              microCache.set(key, res.data)
            }
            resolve(res.data)
          }).catch(error => {
            reject(error)
          })
        })
      },

  

结论

我们是否真正的需要做同构渲染,这取决因素有很多,主要有,SEO,首屏时间比较重要的产品可考虑。

运用该技术并没有想象中的轻松,对前端开发有一定的要求,编写过程要谨慎,涉及构建设置和部署的更多要求,还需要更多的服务器端负载,总之,我们可能需要的支持会更多一点。

代码呈现

Demo已上传至github,以供参考,如若对您有帮助,给个小星星还是很开心的,传送门

原文地址:https://www.cnblogs.com/shengxiaguangnian/p/10836622.html

时间: 2024-10-10 20:09:51

vue服务端渲染 同构渲染的相关文章

vue服务端渲染提取css

vue服务端渲染,提取css单独打包的好处就不说了,在这里主要说的是抽取css的方法 要从 *.vue 文件中提取 CSS,可以使用 vue-loader 的 extractCSS 选项(需要 vue-loader12.0.0+) // webpack.config.js const ExtractTextPlugin = require('extract-text-webpack-plugin') // CSS 提取应该只用于生产环境 // 这样我们在开发过程中仍然可以热重载 const is

解析Nuxt.js Vue服务端渲染摸索

本篇文章主要介绍了详解Nuxt.js Vue服务端渲染摸索,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. Nuxt.js 十分简单易用.一个简单的项目只需将 nuxt 添加为依赖组件即可.Vue因其简单易懂的API.高效的数据绑定和灵活的组件系统,受到很多前端开发人员的青睐.国内很多公司都在使用vue进行项目开发,我们正在使用的简书,便是基于Vue来构建的.我们知道,SPA前端渲染存在两大痛点:(1)SEO.搜索引擎爬虫难以抓取客户端渲染的

[译]利用React Router4实现的服务端直出渲染(SSR)

我们已经熟悉React 服务端渲染(SSR)的基本步骤,现在让我们更进一步利用 React RouterV4 实现客户端和服务端的同构.毕竟大多数的应用都需要用到web前端路由器,所以要让SSR能够正常的运行,了解路由器的设置是十分有必要的 基本步骤 路由器配置 前言已经简单的介绍了React SSR,首先我们需要添加ReactRouter4到我们的项目中 $ yarn add react-router-dom # or, using npm $ npm install react-router

服务端和客户端渲染

服务端渲染:DOM树在服务端生成,然后返回给前端. 客户端渲染(SSR):前端去后端取数据生成DOM树. 服务端渲染的优点: 1.尽量不占用前端的资源,前端这块耗时少,速度快. 2.有利于SEO优化,因为在后端有完整的html页面,所以爬虫更容易爬取信息. 服务端渲染的缺点: 1.不利于前后端分离,开发的效率降低了. 2.对html的解析,对前端来说加快了速度,但是加大了服务器的压力. 客户端渲染的优点: 1.前后端分离,开发效率高. 2.用户体验更好,我们将网站做成SPA(单页面应用)或者部分

vue服务端渲染添加缓存的方法

什么是服务器端渲染(SSR)? Vue.js 是构建客户端应用程序的框架.默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM.然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序. 服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行. 缓存 虽然 Vue 的服务

Vue服务端渲染和Vue浏览器端渲染的性能对比

Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司做Vue项目的时候,一直苦于产品.客户对首屏加载要求,SEO的诉求,也想过很多解决方案,本次也是针对浏览器渲染不足之处,采用了服务端渲染,并且做了两个一样的Demo作为比较,更能直观的对比Vue前后端的渲染. talk is cheap,show us the code!话不多说,我们分别来看两个D

实例PK(Vue服务端渲染 VS Vue浏览器端渲染)

Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司做Vue项目的时候,一直苦于产品.客户对首屏加载要求,SEO的诉求,也想过很多解决方案,本次也是针对浏览器渲染不足之处,采用了服务端渲染,并且做了两个一样的Demo作为比较,更能直观的对比Vue前后端的渲染. 话不多说,我们分别来看两个Demo:(欢迎star 欢迎pull request) 1.浏

vue服务端渲染页面缓存和组件缓存的实例详解

vue缓存分为页面缓存.组建缓存.接口缓存,这里我主要说到了页面缓存和组建缓存 页面缓存: 在server.js中设置 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 const LRU = require('lru-cache') const microCache

Vue.js与 ASP.NET Core 服务端渲染功能整合

http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gy?ngy?si 译者:oopsguy.com 我真的很喜欢在前端使用 Vue.js,Vue 服务端渲染直到第二个版本才被支持. 在本例中,我想展示如何将 Vue.js  服务端渲染功能整合 ASP.NET Core. 我们在服务端使用了 Microsoft.AspNetCore.SpaServices 包,该包提供 ASP.N