1、前言 html
一、服务端渲染图解前端
二、简介服务端渲染vue
三、vue-cli脚手架项目建立,实现客户端渲染和服务端渲染node
四、演示demo地址:https://github.com/4561231/ssr-vuewebpack
2、主要内容 git
一、服务端渲染图解参照另外一篇:服务端渲染和客户端渲染github
二、简介服务端渲染web
Vue.js是构建客户端应用程序的框架,默认状况下,能够在浏览器中输出vue组件,进行生成Dom和操做DOM, 然而,也能够将同一个组件渲染成为服务端的字符串,将他们直接发送到浏览器,最后将这些静态标记“激活”为客户端上彻底能够交互的应用程序。也就是你先在前端写好组件页面,而后交到服务端,服务端须要经过他自家的某个程序插件,而后将客户端的组件生成对应的html字符串,最后发送给浏览器。而后浏览器响应出来页面。vue-cli
三、 新建项目,安装依赖路,建立服务端代码express
(1)server.js
const Vue = require('vue') const express = require('express')(); const renderer = require('vue-server-renderer').createRenderer(); //建立vue实例 const app = new Vue({ template:'<div>hello vue</div>' }) //服务器渲染的核心就在于: //经过vue-server-renderer插件的renderToString()方法,将vue实例转化为字符串插入到html中 express.get('/',(req,res)=>{ renderer.renderToString(app, (err,html)=>{ if(err){ return res.state(500).end('运行错误') } //返回给浏览器一串html字符串 res.send(`<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>服务端渲染</title> </head> <body> ${html} </body> </html>`) }) }) express.listen(8888, ()=>{ console.log('服务器已经启动') })
(2)具体实现原理
(3)测试,发现响应回来的文件里面有内容,这样也说明了服务端渲染是对SEO引擎比较好的
(4)小结:咱们使用服务端渲染是为了弥补单页面应用SEO能力不足的问题,实际上咱们第一次在浏览器地址栏输入地址的时候,而且获得返回页面以后,全部的操做仍然是单页面应用在控制的,咱们所作的服务端渲染,只是在平时返回单页面应用hml上增长了对应路由的页面信息,让爬虫好爬取到。
因此项目能够分为客户端渲染和服务端渲染。
四、用vue-cli项目实现服务端渲染
(1)npm建立项目
(2)npm run build的时候打包走的是webpack.prod.config.js这个文件,如今咱们新建一个webpack.server.config.js这个文件,在服务器打包的时候走这个文件
package.json里面加入以下代码
"server":"webpack --config build/webpack.server.conf.js"
webapck.server.config.js添加以下代码
//引入webpack的主要配置 const webpack = require('webpack') const merge = require('webpack-merge') //引入webpack.base.config这个文件是依赖这个基础文件的 const base = require('./webpack.base.config') module.exports=merge(base, { target:'node',//这里要写node 目的是让后端支持require语法 entry:"./src/entry-server.js",//当你服务端在打包的时候,就会走这个入口 output:{ filename:'bundle.server.js',//打包后生成的文件 libraryTarget:'commonjs2' }, plugins:[] })
(2)因为之前生成vue实例的方式是单例的,如今咱们须要在每次请求的时候生成一个vue组件
在mian.js中修改
/* eslint-disable no-new */ //El:’#app至关于document.getElementbyId(‘#app’ 可是在node.js中识别不了这种语法,因此咱们不能这样写 /*new Vue({ el: '#app', router, components: { App }, template: '<App/>' })*/ import {createRouter} from './router' export function createApp(){
const router = createRouter(); const app = new Vue({ router, components:{App}, template:'<App/>' })
return {app}; }
同理最好将路由也写成构造函数形式
export default createrRouter(){ return new Router({ mode:'history', routes:[ { path:'/', name:'Home', component:Home }, { path:'/about', name:'About', component:About }, { path:'/test', name:'Test', component:Test } ] })
(3)npm run server打包生成文件,并在服务端引入客户端生成的打包文件
打包生成文件
在服务端引入打包生成的文件
//须要在服务端配置打包生成的客户端文件 const createApp = require('./dist/bundle.server.js')['default']
(4)服务端拿到客户端打包生成的文件,进行处理
const Vue = require('vue') const express = require('express')(); //须要在服务端配置打包生成的客户端文件 const createApp = require('./dist/bundle.server.js')['default'] const renderer = require('vue-server-renderer').createRenderer(); //服务器渲染的核心就在于: //经过vue-server-renderer插件的renderToString()方法,将vue实例转化为字符串插入到html中 express.get('*',(req,res)=>{ const context = {url:req.url}; createApp(context).then(app=>{//这个app就是刚刚打包以后的app renderer.renderToString(app, (err,html)=>{ if(err){ return res.state(500).end('运行错误') } //返回给浏览器一串html字符串 res.send(`<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>服务端渲染</title> </head> <body> ${html} </body> </html>`) }) })//取到entry.js里面的 }) express.listen(8888, ()=>{ console.log('服务器已经启动') })
(5)测试看到一开始请求的时候就会出现内容,能够看到服务器返回的html文件中,已经有对应页面的SEO信息了。
可是,尚未成功,由于如今反回过来的只是一个页面对应信息,若是你如今切换路由又会对服务器发送一次请求,单页面应用还没成功。可是vue的特色就是利用单页面,
接下来须要配置客户端渲染
(1)在package.json中配
"client": "webpack --config build/webpack.client.conf.js"
(2)新建webpack.client.conf.js
const webpack = require('webpack') const path = require('path') function resolve(dir){ return path.join(__dirname,'..',dir) } module.exports={ entry:"./src/entry-client.js",//打包时走这个文件 output:{ path:path.resolve(__dirname,'../dist'), publicPath:'/dist/', filename:'bundle.client.js' }, plugins:[], resolve:{ extensions:['.js','.vue','.json'], alias:{ 'vue$':'vue/dist/vue.esm.js', '@':resolve('src'), } }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { compilerOptions:{ preserveWhitespace:false } } }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] } ] } }
(3)entry-client.js
//客户端也要建立,由于客户端渲染和服务端渲染是两个不一样的vue实例 import{createApp} from './main' const {app} =createApp(); const router =app.$router; //这里能够拿到app了, window.onload=function(){ app.$mount('#app')//在window加载完成以后 }
(4)npm run client打包生成文件
(5)一样须要在服务器中添加打包的客户端文件
//客户端渲染文件 const exp = require('express'); ///将静态文件目录设置为:项目根目录+/dist express.use('/',exp.static(__dirname+'/dist')); //客户端打包的文件 const clientBundleFileUrl = '/bundle.client.js' //在下面的模板中用script的方式引入 <script src="${clientBundleFileUrl}"></script>
(6)启动服务器,测试
四、总结:
(1)要作ssr服务端渲染首先须要一个Sever entry他的做用是渲染SEO的信息
(2)若是你仅仅只有这四步操做,并无实现单页面应用,而是每次点击的时候都会对服务端发起请求
(3)要实现单页面应用,须要作客户端打包,而后将客户端打包的文件混入到服务端
(4)单页面应用,只有第一次加载的时候才会发送请求,点击a标签的时候加载的是组件,
五、
3、总结
https://ssr.vuejs.org/zh/guide/structure.html#介绍构建步骤