首先这篇博客并不是ssr建议教程,需要ssr入门的我建议也不要搜索博客了,因为官网给出了详细的入门步骤,只需要step by step就可以了,这篇博客的意义是如何使用ssr,可能不同的人有不同的意见,我舍弃了ssr中的vuex和vue-router增加了redis,serverfetch等等实现了适合自己公司的业务,个人认为并不是所有的东西都值得吸收,对我来说我能用到的只是ssr将vue生成一个html和对应的js。

虾面我们来看看什么是服务端渲染?

官网给出的解释:

Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。

服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。

ssr的服务端渲染大致的意思就是vue在客户端将标签渲染成的整个html片段的工作在服务端完成,服务端形成的html片段直接返回给客户端这个过程就叫做服务端渲染。

举个例子:

正常情况下我们使用vue或react框架浏览器获取所有资源后做的事情

1.浏览器加载所有资源(html,css,js,img...)-->2.cdn-->3.返回资源-->4.vue请求server获取业务数据-->5.返回数据渲染成html片段-->6.css渲染片段成一个网页-->用户

没错这里面最耗时的时间是4,5这两步骤,h5请求serverapi的过程本身除了服务器的限制,还有用户网络,宽带等等诸多限制,并且当页面逻辑过多,数据过于繁琐的情况下,我们的vue在client端渲染也会成为性能瓶颈,最明显的就是一些电商公司的首页,商品详情页等等。测试这个过程在优化前大概需要500ms左右,即使经过优化也需要200ms左右,这个时间几乎是难以接受的,并且我们在用户网络不是很好的情况下,如果我们serverfetch的过程需要500ms,再加上其他的各种请求资源,手机性能等等,用户就要看到将近一秒的白屏时间,这个明显是很差的用户体验。

ssr渲染

1.浏览器加载所有资源(html,css,js,img...)-->2.cdn-->3.返回资源-->4.css渲染片段成一个网页-->用户

这里我们不只是用ssr,我们也需要把所有的html片段缓存在node内存中,这个html片段一定只能放在内存中,不要想着要一小片redis内存和其他server端共用,因为并发亮极大的情况下出得流量有可能直接让redis挂掉。而这个性能放在node的内存中几乎可以忽略不计。我们如果需要存的时间很短的话,那么我们放在内存中并没有问题,因为实时数据刷新五秒可能就换一份内存数据,但是如果我们长时间去存这个备份可能就会出现数据不一致的问题,我们都知道一般线上部署node服务最少需要三台服务,而每一台的数据我们很难保证一只,用户a可能两个请求一个打到nodeA服务器上,另一个打到nodeB服务器上,这样就会出问题。这种内存只适合存那种时间很短的缓存,如果我们需要存几个小时那种我们还要考虑redis,因为我们需要数据实时同步,但是我们只能存储serverfetch的数据,而不能存整个html。一个ssr的时间大概是5ms左右,一台服务器的1s承受量就是1000/5*60% = 120个请求,也就是说我们三台服务器的请求并发量大概能承受360-400左右,超出就要红色预警了!!这对那些并发量极大的项目并不合适,所有我们中和考虑,这个无非就是时间换空间,空间换时间的游戏。我们可以选择增加缓存,也可以添加服务器!

上手有一定难度!!!

首先你需要熟悉webpack2,vue,vuex,vue-router(vue的全家桶),node,express。个别逻辑还需要redis等等后端资源,如果你想做到极致(并发情况下不穿透),我们还需要了解锁的概念,同时我们也需要知道如何处理避免死锁,事务等等机制!

用户体验优化,如何做到更快的让用户看到页面呢?

首先最开始考虑的就是模版渲染,我们知道我们在本地打开本地html文件的时候几乎是瞬间就能看到页面的所有内容,那么我们有可能让用户直接看到一个用户页面么?

首先我想到的就是node的各种渲染模版,ejs?jade?我们可以通过node server端去fetch我们后台的所有数据,之后把数据拼成一个html直接给用户,这样确实能实现我们想要的东西,但不是最好的,首先我们目前市面上的三大框架vue,react,angular我们需要摒弃,我们还要把所有的业务逻辑拆分,因为有了框架的限制,这些都是不现实的,并且我们直接用server端的模版对于我们前端开发来说效率也是极低。

不管是react还是vue都有基于自己框架的服务端渲染。

今天我们来说一下基于vue的ssr

ssr官网

https://ssr.vuejs.org/zh/

ssr的好处官网已经给出,最吸引我的只有两点

1.更好的 SEO

2.更快的内容到达时间(time-to-content)

基本上按照官网step by step都可以写一个很小的vuessr的demo一些基础细节我们不去介绍了。官网给出的ssr大概的流程

vue-router在ready之前fetch所有vue的业务数据调用asyncData钩子,之后获取的数据去更新vuex之后我们渲染vue组件的时候组件获取所有的vuex的store数据,拼接成一个html字符串。

首先我们的需要两份webpack打包入口,一份去压缩client,一份去压缩server。

client的一端是new一个vue的实例然后通过app.$mount('#app')将其挂载到 DOM

server的一端我们需要返回一个promise,我们可以在这里fetchpro的数据放在这个promise里面return,这里我们可以new一个promise,也可以使用fetch,或vue的axios。(注意我们所有需要在服务端渲染的数据都要在这里获取到,然后再client端也要获取到,我们所有的数据不能放在vue中的mounted中获取,因为这样和客户端渲染没什么区别,vue暴漏的这个环境支持window也就是说这个位置其实是client端做的,也就是在ssr所有功能实现之后在执行,这样我们和之前就没有任何区别了)

client,和server需要import你的vue所有组件,之后就会吧所有的vue组件渲染成你需要的html,这里官网给的例子需要你们去使用vue的全家桶,而我刚刚说的serverfetch就不需要使用vue-router和vuex,我们已经把所有需要的数据在ssr之前就直接放进vue中,通过props的形式传给组件

app.js

export function createApp (obj) {
    const app = new Vue({
      render: h => h(App.default, obj)
    })
	return { app }
}

  我们在client和server压缩入口就把所有内容传入组件,这样我们就可以实现把内容数据传到组件里面,实现vue的ssr

我的webpack:client

var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
const VueSSRServerPlugin = require('vue-server-renderer/client-plugin')
const isProd = process.env.NODE_ENV === 'production'
console.log('NODE_ENV--->', process.env.NODE_ENV)
module.exports = {
    //页面入口文件配置
    entry: {
        index : './build/index/entry-client.js'
    },
    target: 'web',
    devtool: isProd?false:'#source-map',
    //入口文件输出配置
    output: {
        path: 'dist/index',
        filename: 'client_index_[hash].js',
      },
    module: {
      noParse: /es6-promise\.js$/, // avoid webpack shimming process
      rules: [
        {
        	test: /\.vue$/,
      	  loader: 'vue-loader'
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/
        },
        {
          test: /\.(png|jpg|gif|svg)$/,
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: '[name].[ext]?[hash]'
          }
        },
        {
          test: /\.css$/,
          use: ['vue-style-loader', 'css-loader']
        },
        {
          test: /\.es6$/,
          loader: "babel-loader",
          exclude: /node_modules/
        },
      ]
    },
    resolve: {
      alias: {
        'vue$': 'vue/dist/vue.common.js',
      }
    },
    externals: {
      "jquery": "$",
      'Vue': true,
      'Swiper': true,
      'VueLazyload': true,
      '$': true
    },
    plugins: [
        // new webpack.optimize.UglifyJsPlugin({
        //   compress: { warnings: isProd?false:true }
        // }),
        // new ExtractTextPlugin({
        //   filename: 'common.[chunkhash].css'
        // }),
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
          'process.env.VUE_ENV': '"server"'
        }),
        new VueSSRServerPlugin()
    ]
};

  server:

var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const isProd = process.env.NODE_ENV === 'production'
console.log('NODE_ENV--->', process.env.NODE_ENV)
module.exports = {
    //页面入口文件配置
    entry: {
        index : './build/index/entry-server.js'
    },
    target: 'node',
    devtool: isProd?false:'#source-map',
    //入口文件输出配置
    output: {
        path: 'dist/index',
        filename: 'server-bundle.js',
        libraryTarget: 'commonjs2'
      },
    module: {
      noParse: /es6-promise\.js$/, // avoid webpack shimming process
      rules: [
        {
          test: /\.vue$/,
        	loader: 'vue-loader'
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/
        },
        {
          test: /\.(png|jpg|gif|svg)$/,
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: '[name].[ext]?[hash]'
          }
        },
        {
          test: /\.css$/,
          use: ['vue-style-loader', 'css-loader']
        },
        {
          test: /\.es6$/,
          loader: "babel-loader",
          exclude: /node_modules/
        },
      ]
    },
    resolve: {
      // alias: {
      //   'vue$': 'vue/dist/vue.js' // 'vue/dist/vue.common.js' for webpack 1
      // }
    },
    externals: nodeExternals({
    // do not externalize CSS files in case we need to import it from a dep
        whitelist: /\.css$/,
        "jquery": "$",
        'Vue': true,
        'Swiper': true,
        'VueLazyload': true,
        '$': true,
    }),
    plugins: [
        // new webpack.optimize.UglifyJsPlugin({
        //   compress: { warnings: isProd?false:true }
        // }),
        // new ExtractTextPlugin({
        //   filename: 'common.[chunkhash].css'
        // }),
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
          'process.env.VUE_ENV': '"server"'
        }),
        new VueSSRServerPlugin()
    ]
};

  但是上面的形式我们需要每次访问页面都需要请求后台server的接口,这样的接口完全是没必要的,试想一下如果首页我们每秒都有500个请求,那么我们server端就先挡雨请求了1000次api,这样的消耗毫无疑问是过大的,那么我们需要怎么去做到接口的缓存呢?

  我们使用的node是express框架,然后在进入/index的时候我们去fetch后台server的数据,然后我们可以把数据传到client和server的config中,而不是每次在client,server中请求,然后我们每次内存缓存失效我们再去从新fetch后台server,这样我们假设每秒500个请求量,我们在node 端缓存5s,一共是2500个请求数量,我们在node其实只是请求了一次后台的server之后每次拿的node内存去返回用户html,这种效果很定是极好的,也极大的缓解了我们后台server的压力!

我做的公司首页迁移ssr效果:

43ms就获取了所有的数据,mobile端流量大概是电脑*10的时间,(其实4g状态下和电脑wifi也是不相上下的,几乎上下波动都在1m~2m左右),假设我们手机网速很一般,时间*10就是0.4s的时间,也就是说在用户首次访问过我们页面的情况下,只要手机中有缓存我们可以一最快的数据打开页面,即使用户在首次访问,我们的时间也可以控制在1s就能让用户看到大体的网页框架,而不是看了一秒的白屏!因为用户获取的其实就是node缓存的html,这个就跟在网上看一个html的专题页面没什么区别!我们节省的时间也就说我们client去请求接口的时间和框架渲染的时间,这个白屏的时间我们相当于缓存在了node中,既不占用内存,也能让用户有一个更高的用户体验。

追求极致的用户体验ssr(基于vue的服务端渲染)的更多相关文章

  1. Vue.js 服务端渲染业务入门实践

    作者:威威(沪江前端开发工程师) 本文原创,转载请注明作者及出处. 背景 最近, 产品同学一如往常笑嘻嘻的递来需求文档, 纵使内心万般拒绝, 身体倒是很诚实. 接过需求,好在需求不复杂, 简单构思 后 ...

  2. ASP.NET Core 与 Vue.js 服务端渲染

    http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gyöngyösi 译者:oop ...

  3. NET Core 与 Vue.js 服务端渲染

    NET Core 与 Vue.js 服务端渲染 http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/原作者: ...

  4. vue.js 服务端渲染nuxt.js反向代理nginx部署

    vue.js的官方介绍里可能提到过nuxt.js,我也不太清楚我怎么找到这个的 最近项目vue.js是主流了,当有些优化需求过来后,vue还是有点力不从心, 比如SEO的优化,由于vue在初始化完成之 ...

  5. Egg + Vue 服务端渲染工程化实现

    在实现 egg + vue 服务端渲染工程化实现之前,我们先来看看前面两篇关于Webpack构建和Egg的文章: 在 Webpack工程化解决方案easywebpack 文章中我们提到了基于 Vue ...

  6. vue服务端渲染之nuxtjs

    前言 本篇主要针对nuxtjs中的一些重要概念整理和代码实现! 在学习vue服务端渲染之前,先搞清楚几个概念: 什么是客户端渲染(CSR) 什么是服务端渲染(SSR) CSR和SSR有什么异同 客户端 ...

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

    http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gyöngyösi 译者:oop ...

  8. Vue 爬坑之路(十一)—— 基于 Nuxt.js 实现服务端渲染(SSR)

    直接使用 Vue 构建前端单页面应用,页面源码时只有简单的几行 html,这并不利于网站的 SEO,这时候就需要服务端渲染 2016 年 10 月 25 日,zeit.co 背后的团队对外发布了一个 ...

  9. 使用 PHP 来做 Vue.js 的 SSR 服务端渲染

    对于客户端应用来说,服务端渲染是一个热门话题.然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说. 我发布了两个库让 PHP 从服务端渲染成为可能.spatie/se ...

随机推荐

  1. 【SQL Server备份恢复】维护计划实现备份:每周数据库完整备份、每天差异备份、每小时日志备份

    在数据库管理中,数据库备份是非常重要的. 通过维护计划向导,可以很方便的完成数据库备份. 下面的例子说明了如何实现数据库的备份,具体的备份策略是:每周日一次完整备份.每天差异备份(除周日外).每小时日 ...

  2. Practical Node.js (2018版) 第8章:Building Node.js REST API Servers

    Building Node.js REST API Servers with Express.js and Hapi Modern-day web developers use an architec ...

  3. 『TensorFlow』pad图片

    tf.pad()文档如下, pad(tensor, paddings, mode='CONSTANT', name=None, constant_values=0)    Pads a tensor. ...

  4. Descriptors;Hello1 project中的Web.xml

    Deployment Descriptors(描述符)是一个xml文件,用来描述如何部署一个模块或者应用(根据描述符中定义的配置和容器选项).举例来说,一个EJB的部署描述符会向EJB容器传递如何管理 ...

  5. 使用python来访问Hadoop HDFS存储实现文件的操作

    原文:http://rfyiamcool.blog.51cto.com/1030776/1258292 在调试环境下,咱们用hadoop提供的shell接口测试增加删除查看,但是不利于复杂的逻辑编程 ...

  6. 序列化模块— json模块,pickle模块,shelve模块

    json模块 pickle模块 shelve模块 序列化——将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化. # 序列化模块 # 数据类型转化成字符串的过程就是序列化 # 为了方便存储和网 ...

  7. 关于规范NOIP试题管理办法的通知

    由CCF主办的NOIP赛事举行在即,保密起见,现将有关规定发给各省赛区组织单位. 1.NOI各省组织单位负责试题保密工作. 2.NOIP初赛试卷为纸质版,复赛试卷为电子版. 3.在初赛进行中,如有选手 ...

  8. day34-python操作redis三

    Hash类型操作 Hash类型操作 Redis在内存中存储hash类型是以name对应一个字典形式存储的 hset(name,key,value) #name对应的hash中设置一个键值对(不存在,则 ...

  9. git 操作规范

    分支描述 长期存在 online 主分支,负责记录上线版本的迭代,该分支代码与线上代码是完全一致的. dev 开发分支,该分支记录相对稳定的版本,所有的feature分支都从该分支创建. 多套开发环境 ...

  10. bootstrap之编译CSS和Javascript-0基础安装grunt教程

    昨天晚上看到 bootstrap 全局CSS样式中 使用Less 章节中提到的通过grunt重新编译CSS和Javascript文件,对于我这样从未接触过windows cmd node控制台 npm ...