缘起

时间真快,现在已经是这个系列教程的下半部 Vue 第 12 篇了,昨天我也简单思考了下,可能明天再来一篇,Vue 就基本告一段落了,因为什么呢,这里给大家说个题外话,当时写博文的时候,只是想给大家增加点儿学习的动力,每天提醒下,完全没有提纲或者安排说明什么的,就是按照我自己学的方向走,正好发现了一个规律就是:每一个系列正好是 1 个引子 + 12 篇正文,不知道大家对这个有没有感觉,大家可能看到我的头像就知道了,哈哈,其实我是一个红迷,正好这里机缘巧合,两个系列都形成了这样的,我自私的给自己画了一个规划,正好是一组判词——十二钗正册,副册,又副册等等(说明:这是我自己的一厢情愿哈,大家如果有红迷爱好者,请不要喷我 [苦笑] ),按照计划,应该会写 9 部,除了引子,正好是 108 篇,哈哈以后的再说吧。这里自己昨天瞎想了一通,如果有红迷爱好者也可以找我哟,加群(867095512)或者个人QQ(3143422472)都行。

因为 Vue 这个系列还是很多的要说的,不过基本的咱们都说了,大家可以再通过传送门看看《Vue 学习12篇》,今天呢,咱们就说说一个老生常谈的问题,就是如何实现 Vue 的 SSR 服务端渲染,大家如果是第一次接触到,可能还比较陌生,不要慌,本文就给大家通过 Nuxt.js 框架,来讲解这个问题,然后为了以后实现咱们的第二个项目,大致会是这个样子(注意页面的源代码已经有内容了):

image

注意:今天仅仅给大家说明 SSR 服务端渲染,会简单说一个小 DEMO ,上图中的框架具体的代码,在咱们的第二个博客项目中会说到,因为这个框架一两篇是说不完的。

零、今天要完成蓝色区块部分

image

一、Vue 的 SSR 到底是个什么?

来自官方的解释:

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

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

羞涩难懂

我的个人理解就是:

1、目前Vue的模式是:

在生成页面的工作中,我们现在是把组件放在浏览器里,然后把 Data 填充到组件中生成 DOM,这也是一般的异步操作的动作,咱们平时一定是这么操作的,先在页面写上 DIV,然后用 Jquery 获取数据,把数据填充到 DIV 里

image

2、SSR的模式呢,转变成了先在服务器中 Data 先把组件先渲染成 Html 字符串,当成静态资源,就像 css 字符串那样,再抛到前台页面。

image

这第二种就是 SSR 服务端渲染,大家应该发现了这个和普通的区别——就是渲染html片段的控制权转向了服务端,那为什么要这么做呢?请往下看。

注意:这里的服务端,并不是在我们的.net core api 中生成的,而是在vue中,我们通过webpack 打包后 node server来处理的。

二、为什么要 SSR 服务端渲染?

1、首先咱们需要说说搜索引擎 —— SEO

咱们打开任何搜索引擎,无论是谷歌,还是百度,亦或者搜狗等等,都能看到各种各样的信息,文字,图片,视频,不知道大家是如何看待这个过程的,以前天真的我以为是各种各样的人,把自己的内容或者文档提交给百度的服务器,然后我们从百度的服务器去读取,搜索,嗯,这个源自于我上高中的时候,搜索各种百度文库的臆想,这个属于我认识的搜索 1.0 。

后来我工作了,第一次开始写 Web ,那个时候经理让写 TDK(Title + Description + Key),当时很好奇为什么要这么说,经理说,是为了 SEO ,额好吧,虽然不是很明白,大概懂了——设置好页面的 TDK 以后,那个搜索引擎就能找到我们的关键字,然后我们就可以在搜索引擎中搜到我们的网站了,嗯~听起来不错,这个时候,我凌乱了,不是说我们必须存进百度的数据库,我们才能搜索到么,太神奇了吧,这就是我认识的搜索 2.0 。

转眼过去一段时间,接触的也越来越多,这个时候我负责了一个旅游游记的项目,老板说,我们的数据才千级别,比较少,用户搜索咱们的不是很方便,让我搞些网上的数据(当然是合法的哈,只是用来展示,划重点),这个时候我才知道了竟然有 爬虫 这个东西!原来网上的资源可以随心所欲的获取(合法的 × 3 !),这个时候回头看引擎,哦!原来他们的都是爬取的网上的信息,举个栗子:大家可以在百度上搜索 “老张的哲学 .net core”,会看到咱们的文章,可以看到不仅有题目,还有文章正文,这也就是说,百度爬取的不仅仅是咱们的 TDK ,还有咱们的文章内容,大概这就是我认识的搜索 3.0 了。

image

所以说,咱们如果需要想让咱们的文章,网站等被搜索引擎爬取,然后被大家所搜索到,必须要设置 TDK 和有页面内容,但是这个时候,我们满心开新的打开我们的 Vue 博客第一版的项目时候,却发现了这个样子。。

image

咱们辛辛苦苦写的文章并没有被浏览器所生成,自然以后不会被爬取到,如果要是我们的商城也是这样,那得少了多少流量,都是钱哟,所以说,如果是带有文章类,内容类,商品类的 Web 项目,一定要解决这个问题,这个就是为什么要 SSR 的第一个原因。

大家可以看看咱们的第二个项目,就是通过 Nuxt 实现的服务端渲染,已经在源代码中,有了内容:

image

2、为 Vue 渲染瓶颈提供帮助

在上面两个流程中,咱们可以看到,普通的客户端渲染,和SSR 的服务端渲染的最大区别就在于,Html 片段到底被谁控制,是 Vue 还是服务端,如果是前端,h5请求 API 的时候,因为涉及到跨域,本身除了服务器的限制,还有用户网络,宽带等诸多限制,咱们需要等待入口页面和 JS 下载成功,才能根据逻辑去获取数据,中间又会出现很多问题。

并且如果当前页面逻辑过多,数据过于繁琐的情况下,我们的 vue 在客户端渲染也会成为性能瓶颈,最明显的就是一些电商公司的首页(比如某宝,那首页打开真是复杂的要命)首次加载的时候,白屏的出现,loading图的渲染,着实让人难堪,虽然现在都采用栅栏预热,但还是不舒服。这是瓶颈问题,如果单单从 Vue 端来解决这个瓶颈,花费比较大,所以这个时候就用到了 SSR 服务端渲染,而且我们可以使用 Redis 去缓存这些页面的 Html 片段,我们加载后会更快。

三、如何实现 SSR 服务端渲染 —— 基于 webpack 的简单程序

注意:今天咱们主要是说明下 SSR 的内容、原理和基本使用,这里简单说一个小Demo栗子,咱们之后的项目会用到一个框架 Nuxt.js

1、基于 webpack 初始化 npm 项目

新建文件夹 VueSSRDemo3 ,进入之后,执行 npm i ,初始化项目

 npm i

会看到一个 package-lock.json 文件,大家还记得这个么,这个简单来说,是保证项目的一致性,保证团结开发的时候都依赖相同的包,这里再补充下:

1、npm 5.0.x 版本,不管package.json怎么变,npm i 时都会根据lock文件下载

package-lock.json file not updated after package.json file is changed · Issue #16866 · npm/npm

这个 issue 控诉了这个问题,明明手动改了package.json,为啥不给我升级包!然后就导致了5.1.0的问题...

**2、npm 5.1.0 **版本后 npm install 会无视lock文件 去下载最新的npm

然后有人提了这个issue why is package-lock being ignored? · Issue #17979 · npm/npm

控诉这个问题,最后演变成5.4.2版本后的规则。

**3、npm 5.4.2 **版本后 why is package-lock being ignored? · Issue #17979 · npm/npm

大致意思是,如果改了package.json,且package.json和lock文件不同,那么执行npm i时npm会根据package中的版本号以及语义含义去下载最新的包,并更新至lock。

2、新建 package.json 依赖包文件

{ "name": "ssr", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "server": "webpack --config ./webpack/webpack.server.js", "client": "webpack --config ./webpack/webpack.client.js" }, "author": "laozhang", "license": "ISC", "dependencies": { "axios": "^0.16.0", "babel": "^6.23.0", "babel-plugin-transform-runtime": "^6.23.0", "babel-polyfill": "^6.26.0", "babel-preset-env": "^1.7.0", "body-parser": "^1.18.3", "compression": "^1.7.2", "express": "^4.15.4", "express-http-proxy": "^1.2.0", "gulp": "^3.9.1", "gulp-shell": "^0.6.5", "http-proxy-middleware": "^0.18.0", "less": "^3.0.4", "less-loader": "^4.1.0", "shell": "^0.5.0", "superagent": "^3.8.3", "vue": "^2.2.2", "vue-meta": "^1.5.0", "vue-router": "^2.2.0", "vue-server-renderer": "^2.2.2", "vue-ssr-webpack-plugin": "^3.0.0", "vuex": "^2.2.1", "vuex-router-sync": "^4.2.0" }, "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "css-loader": "^0.28.4", "style-loader": "^0.18.2", "vue-loader": "^11.1.4", "vue-template-compiler": "^2.2.4", "webpack": "^2.7.0" }
}

3、执行 npm install 安装依赖包

npm install

然后就会增加 node_modules 文件夹,这个大家就很熟悉了。

4、新增部分文件,并依次填写内容

结构如下:

├── dist                               // 保存我们的打包后的文件
├── node_modules                               // 依赖包文件夹
├── entry                               // │   └── entry-server.js                      // 服务端文件
├── src                                 // 我们的项目的源码编写文件
│   ├── views                               // view存放目录
│   │   ├── about.vue                  //about 页面
│   │   ├── like.vue                  //like 页面
│   │   └── Home.vue                        //Home 页面
│   └── App.vue                       // App入口文件
│   └── main.js                        // 主配置文件
│   └── router.js                       // 路由配置文件
└── .babelrc                               // babel 配置文件
└── package.json                             // 项目依赖包配置文件
└── package-lock.json                        // npm5 新增文件,优化性能
└── server.js                        // server 文件
└── README.md                                // 说明文档
image

整体结构就是这样,然后就是开始写入代码了,一共七个文件,大家可以自己试一试,或者直接下载 git 代码

//1、/* entry-server.js */
import { createApp } from '../src/main' export default context => { return new Promise((resolve, reject) => { const app = createApp() // 更改路由app.$router.push(context.url) // 获取相应路由下的组件const matchedComponents = app.$router.getMatchedComponents() // 如果没有组件,说明该路由不存在,报错404if (!matchedComponents.length) { return reject({ code: 404 }) }resolve(app)})} //2、三个 vue 页面,和app vue页面,就是简单的写法,大家可以直接随意 //3、//main.js
import Vue from 'vue' import createRouter from './router' import App from './App.vue'// 导出一个工厂函数,用于创建新的vue实例
export function createApp() { const router = createRouter() const app = new Vue({router,render: h => h(App)}) return app
} /*4、 route.js */ import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)export default function createRouter() {let router = new VueRouter({ // 要记得增加mode属性,因为#后面的内容不会发送至服务器,服务器不知道请求的是哪一个路由mode: 'history',routes: [{alias: '/',path: '/home',component: require('./views/home.vue')},{path: '/like',component: require('./views/like.vue')},{path: '/about',component: require('./views/about.vue')}]}) return router
} /* 5、webpack.server.js */
const path = require('path'); const projectRoot = path.resolve(__dirname, '..');module.exports = { // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)target: 'node',entry: ['babel-polyfill', path.join(projectRoot, 'entry/entry-server.js')],output: {libraryTarget: 'commonjs2',path: path.join(projectRoot, 'dist'),filename: 'bundle.server.js',},module: {rules: [{test: /\.vue$/,loader: 'vue-loader',},{test: /\.js$/,loader: 'babel-loader',include: projectRoot,exclude: /node_modules/,options: {presets: ['es2015']}},{test: /\.less$/,loader: "style-loader!css-loader!less-loader" }]},plugins: [],resolve: {alias: { 'vue$': 'vue/dist/vue.runtime.esm.js'}}
} //6、babelre文件
{ "presets": [ "babel-preset-env" ], "plugins": [ "transform-runtime" ]
} /*7、 server.js */
const express = require('express')() const renderer = require('vue-server-renderer').createRenderer() const createApp = require('./dist/bundle.server.js')['default'] // 响应路由请求
express.get('*', (req, res) => { const context = { url: req.url } // 创建vue实例,传入请求路由信息createApp(context).then(app => {renderer.renderToString(app, (err, html) => { if (err) { return res.state(500).end('运行时错误') }res.send(` <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Vue2.0 SSR渲染页面</title></head><body> ${html} </body></html> `)})}, err => { if(err.code === 404) { res.status(404).end('所请求的页面不存在') }})
}) // 服务器监听地址
express.listen(8089, () => {console.log('服务器已启动!')
})

5、打包文件

npm run server

这个时候,你会发现,我们的dist 文件夹内,多了一个 bundle.server.js 文件

image

6、启动服务

 node server

这个时候我们就可以看到效果了

image

7、查看源代码,发现我们的页面已经渲染成功了!

image

这样我们已经达到了 SSR 的作用

四、结语

因为今天时间的问题,咱们我先把核心文件搭建好了,大家知道了什么是 SSR,以及存在的问题和解决办法,但是具体的文件 entry-server.js 、 webpack-server.js、和server.js 都是什么意思,明天咱们再统一说明,并且顺带给大家引入新的框架 Nuxg.js,一个成熟的 SSR 框架。

五、CODE

https://github.com/anjoy8/Blog.Vue/tree/master/Demo/Vue_SSR

下载后,先 npm install 安装依赖

然后执行打包和启动服务命令

npm run server
node server

最后访问 localhost:8089

QQ群:
867095512 (blod.core)

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十五║初探SSR服务端渲染(个人博客二)...相关推荐

  1. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十七 ║Vue基础:使用Vue.js 来画博客首页(一)...

    缘起 书说前两篇文章< 十五 ║ Vue前篇:JS对象&字面量&this>和 < 十六 ║ Vue前篇:ES6初体验 & 模块化编程>,已经通过对js面 ...

  2. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  3. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性+watch...

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  4. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十三║Vue实战:Vuex 其实很简单

    前言 哈喽大家周五好,马上又是一个周末了,下周就是中秋了,下下周就是国庆啦,这里先祝福大家一个比一个假日嗨皮啦~~转眼我们的专题已经写了第 23 篇了,好几次都坚持不下去想要中断,不过每当看到群里的交 ...

  5. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象字面量this

    缘起 书接上文<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史>,昨天咱们说到了以我的经历说明的web开发经历的 ...

  6. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 我的前后端开发简史...

    ---新内容开始--- 番外 大家周一好呀,又是元气满满的一个周一呀!感谢大家在周一这个着急改Bug的黄金时期,抽出时间来看我的博文哈哈哈,时间真快,已经到第十四篇博文了,也很顺顺(跌跌)利利 (撞撞 ...

  7. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十║Vue基础终篇:组件详解+项目说明...

    缘起 新的一天又开始啦,大家也应该看到我的标题了,是滴,Vue基础基本就到这里了,咱们回头看看这一路,如果你都看了,并且都会写了,那么现在你就可以自己写一个Demo了,如果再了解一点路由,ajax请求 ...

  8. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十二║Vue实战:个人博客第一版(axios+router)...

    前言 今天正式开始写代码了,之前铺垫了很多了,包括 6 篇基础文章,一篇正式环境搭建,就是为了今天做准备,想温习的小伙伴可以再看看<Vue 基础入门+详细的环境搭建>,内容很多,这里就暂时 ...

  9. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十二║Vue实战:个人博客第一版

    前言 今天正式开始写代码了,之前铺垫了很多了,包括 6 篇基础文章,一篇正式环境搭建,就是为了今天做准备,想温习的小伙伴可以再看看<Vue 基础入门+详细的环境搭建>,内容很多,这里就暂时 ...

  10. 从壹开始前后端分离【 .NETCore2.1 +Vue 2 +AOP+DI】框架之一 || 前言

    缘起 作为一个.Net攻城狮已经4年有余了,一直不温不火,正好近来项目不是很忙,闲得无聊,搞一搞新技术,一方面是打发无聊的时间,一方面也是督促自己该学习辣!身边的大神都转行的转行,加薪的加薪,本人比较 ...

最新文章

  1. 《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——2.15 本章小结...
  2. C++算法一些常用的stl函数
  3. ntlm java_深讨Java SE 6 在 HTTP 方面的新特性(NTLM)
  4. 二叉树前序,中序,后序遍历的迭代实现,实现思路及代码
  5. 典型案例:Bug 9776608-多个用户使用错误密码登录同一个用户而造成的用户无法登录异常...
  6. dhcp snooping华为_使用DHCP snooping 功能防止DHCP Server仿冒者攻击(华为交换机)
  7. Windows 2003 Server R2 x64 IIS6.0 eWebEditor无法显示的问题
  8. Tomcat异常:The Tomcat server configuration at\Servers\Tomcat v9.0 Server at localhost-c
  9. 深度学习:语言模型的评估标准
  10. IIS8,OUTLOOK OWA 2013鉴赏
  11. Citrix 桌面云 XenApp_XenDesktop_7.15 部署系列(九)客户端使用
  12. 一文读懂: 什么是用户故事?What is User Stories?
  13. 计算机新建文件的方法,电脑新建文件夹怎么弄,新建文件夹的方法有几种-
  14. win10解决IE浏览器安装不上的问题(卸载依然显示不能安装)
  15. STM32学习心得十九:电容触摸按键实验及相关代码解读
  16. Java中关于子类重写父类方法的坑
  17. chrome扩展设置代理
  18. 关闭依赖jar包日志
  19. SqlServer数据库 时间类型字段添加默认值 设置时间格式
  20. 1:Web开发入门-Java Web

热门文章

  1. Python数据的输出
  2. 加入Web前端学习还有市场吗?自己是否适合学习前端
  3. Supercell:靠两款手游如何做到30亿美金市值?
  4. 在OpenCV里实现直方图反向投影算法
  5. 2021年4月4日腾讯笔试
  6. 计算机工程师考证要求
  7. 【基础知识】Dom基础
  8. python3总结和spider爬虫
  9. THINKPHP5(TP5)新手入门必看教程
  10. 微博平台的RPC服务化实践