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#介紹構建步驟