VueSSR高阶指南

嗨 各位小伙伴好,好久没有写文章了,这次分享一下我们从使用node以来,前端架构上的一些优化
如果看过我上一篇文章B站的前端之路的小伙伴可能知道 我们从去年开始打烊 使用node 到现在已经经历了一年的迭代,承载的访问量也从百万级别 扩大到了现在的亿级别,这次补充一些干货吧~

vue如何实现热更新

我们都知道,对于node来说,前端vue代码的迭代节奏是很快的,可能一周要迭代几次,但是node的迭代却没那么平凡,可能一周更新一次甚至更久,那么为了node服务的稳定,减少node服务的发布次数,是非常有用的。
配置中心是肯定需要的,因为需要通过配置不同的资源版本号,来通知node服务更新服务上的版本号
那么 我们的vue代码 要如何改造才能实现热更新呢?
我们就以vue官方给的例子来看
以下代码是我截取的两段代码官方案例:
首先他定义了一个createRenderer的方法
里面调用的是vue-ssr的createBundleRender方法来创建的渲染函数

VueSSR高阶指南

然后传入了使用了三个文件,template.html bundle.json 和clientmanifest.json

VueSSR高阶指南

这里可以看到 在createRender的时候 传入的clientMainfest bundle 都是reqire的
那么有同学会想,我要支持热更新 是不是根据require的缓存机制,去定时的清理缓存?虽然也能实现但是其实不用的
我查询了官方的api文档,其实bundle支持三种参数

VueSSR高阶指南

然后再看下vue的源码,如果传入的是一个绝对路径,类似于上面这个案例 require某个dist目录下的bundle.json文件的时候 做了什么处理

VueSSR高阶指南

它判断 如果是一个js 或者json文件路径的 那么 他会先读取这个文件,然后通过json转化一下成对象,然后再走下面的判断是否是oject逻辑
那么,我们不是可以替他做这个事情嘛
我们可以从远程读取到bundle文件 然后将他转化成bundle 然后传入给createBundleRender方法 就可以不用通过require方法去获取了
然后远程bundle文件加上版本号,就可以实现通过配置来热更新

vue项目与node项目分离

为了前后端分离,我们在前端和api层中间,架构了一层node层,用来做服务端渲染,来加快用户的首屏可用和对搜索引擎的友好。项目一开始放置在同一个git仓库里面,分别放在client目录和server目录中(或者类似于vue 官方例子中的一样,node服务可能只有一个sever.js。因为server中可能需要client中的一些资源,所以不得不将他们放在一起。后来通过配置中心驱动之后,client 和server 可以完全独立,通过配置中心建立连接。所以完全可以将client项目和server项目分离开。

VueSSR高阶指南

其实就是在前端项目中,再做了一次前后端分离,这次分离的原因 跟与api的前后端分离有些不一样。这次是因为 第一个 前端vue项目本就是一个完全独立的项目,拖着server项目反而显的不是那么灵活,同样,server里面包含了client,虽然可以独立发布,但是因为迭代周期的不同,在管理分支上面总归有点变扭,索性分开,各过各的
各过各的是极好的,可是开发的时候怎么各过各的啊(f***~),我开发的时候要走服务端渲染的逻辑的啊,你让我先基于客户端开发,然后再配合着node调试一波?那可不是反而增加了开发成本
有没有可以让client独立也能跑ssr的逻辑,然后最后只要跟正式的node服务通过配置中心配合起来就好了呢?
有啊,给client配置一个简单的服务不就好了么?一般的nodessr不都是这样的么 说白了就我上面说的,一个sever.js。里面是一个基于koa的简单服务,加上了koawepack的中间件(koa-webpack),用来做开发时候的热加载。
然后通过不同的启动脚本,来配置上不同的环境变量参数,以此来启动不同的页面开发,这样子,开发就方便多了,npm run start:home 就是开发首页,npm run start:video 就是开发播放页 后面加上server参数就是开发服务端渲染 例如 npm run start:home:server
(这里我只提供一个思路昂~具体实现要讲的东西太多了,这里不太想写 >_>~~)

容灾

既然是个node服务,那么对于服务也要有相应的容灾方案,不然怎么放心将大流量交给它
那么,我们需要一个降级方案以备不时之需(以下内容需要建立在你对vuessr有一定了解的基础之上)
首先 vue 服务端渲染都有两个入口文件,entryclient.js和entryserver.js 如果要支持降级,那么需要在entryclient.js上面动一些手脚,我们仍然以官方例子为例
现在index.temlate.html 增加一个客户端渲染容器,一个名为de-app的div(<!–vue-ssr-outlet–>是服务端渲染的占位符)

VueSSR高阶指南

然后,我们看一下entryclient.js里面

VueSSR高阶指南

这里是用来同步服务端数据到客户端store里面的,那么,如果降级到客户端渲染,这里就需要做一下兼容

VueSSR高阶指南

我们默认服务端渲染一定会有window.__INITIAL_STATE__,如果没有 说明服务端没有帮我们取到数据,也就是降级到了客户端渲染,那么需要重新运行以下asyncData方法来从客户端获取一下数据,然后挂载到我们预先设定好的de-app上面,当然 原本挂载到app上的 也要做一下判断了

VueSSR高阶指南

这样子,服务端如果没有渲染出内容来,那么,页面还是可以通过客户端渲染,重新走一遍逻辑,正常输出页面来。
vue代码改完了,我们在构建的时候,也要以两种目的去打包我们的html,一种是纯粹的模版html(template.html),里面除了一些固定的js引入外,没有vue打包相关的js引入,是用来给服务端渲染当作模版用的(就是上面说的传递给createBundleRender的),另一个打包将构建好的js css引入进去了(degrage.html),可以直接当客户端渲染的静态模版使用 (就是使用两次htmlwebpackplugin 一个传chunks 一个不传)

VueSSR高阶指南

那么具体怎么使用这两个文件呢?
我们准备了三层降级

VueSSR高阶指南
  • 1.首先 node服务上面,自己起了一个服务,用来监测所有的node进程的cpu使用率是否大于设定的阈值,如果超过设定阈值,那么返回我们事先准备好的degrade.html文件,降级掉服务端渲染,可以大大减少服务端的渲染压力,当然也可以手动设置是否需要降级嘛,来去自如
  • 2.如果Node不幸 炸了,那么 需要在slb 这一层上 也就是nginx 做一个配置,如果服务返回的code是5xx,那么将流量指向我们实现发布好的degrade.html
  • 3.如果非常不幸,全炸了,那么如果页面配置了cdn缓存,cdn回源失败,就返回之前缓存上的页面

    那么在极端情况下,其实还是会有首屏页面展示给用户的(数据兜底会让这个方案更完美,下次有机会再补上吧)

    这次就这么多吧,下次可能会补充上一些别的优化和react的一些黑科技~

哔哩哔哩 干杯~

原文链接:https://juejin.im/post/5b8e64c5f265da43481607a1

发表评论

登录后才能评论