欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何使用Vue2做服務(wù)端渲染

 更新時(shí)間:2017年03月29日 11:39:19   作者:莫揚(yáng)的天空  
本篇文章主要介紹了如何使用Vue2做服務(wù)端渲染 ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

花費(fèi)了一個(gè)月時(shí)間,終于在新養(yǎng)車(chē)之家項(xiàng)目中成功部署了vue2服務(wù)端渲染(SSR),并且使用上了Vuex 負(fù)責(zé)狀態(tài)管理,首屏加載時(shí)間從之前4G網(wǎng)絡(luò)下的1000ms,提升到了現(xiàn)在500-700ms之間,SSR的優(yōu)勢(shì)有很多,現(xiàn)在讓我來(lái)跟你細(xì)細(xì)道來(lái)。

技術(shù)棧

服務(wù)端:Nodejs(v6.3)

前端框架 Vue2.1.10

前端構(gòu)建工具:webpack2.2 && gulp

代碼檢查:eslint

源碼:es6

前端路由:vue-router2.1.0

狀態(tài)管理:vuex2.1.0

服務(wù)端通信:axios

日志管理:log4js

項(xiàng)目自動(dòng)化部署工具:jenkins

Vue2與服務(wù)端渲染(SSR)

Vue2.0在服務(wù)端創(chuàng)建了虛擬DOM,因此可以在服務(wù)端可以提前渲染出來(lái),解決了單頁(yè)面一直存在的問(wèn)題:SEO和初次加載耗時(shí)較多的問(wèn)題。同時(shí)在真正意義上做到了前后端共用一套代碼。

SSR的實(shí)現(xiàn)原理

客戶(hù)端請(qǐng)求服務(wù)器,服務(wù)器根據(jù)請(qǐng)求地址獲得匹配的組件,在調(diào)用匹配到的組件返回 Promise (官方是preFetch方法)來(lái)將需要的數(shù)據(jù)拿到。最后再通過(guò)

<script>window.__initial_state=data</script>

將其寫(xiě)入網(wǎng)頁(yè),最后將服務(wù)端渲染好的網(wǎng)頁(yè)返回回去。

接下來(lái)客戶(hù)端會(huì)將vuex將寫(xiě)入的 __initial_state__ 替換為當(dāng)前的全局狀態(tài)樹(shù),再用這個(gè)狀態(tài)樹(shù)去檢查服務(wù)端渲染好的數(shù)據(jù)有沒(méi)有問(wèn)題。遇到?jīng)]被服務(wù)端渲染的組件,再去發(fā)異步請(qǐng)求拿數(shù)據(jù)。說(shuō)白了就是一個(gè)類(lèi)似React的 shouldComponentUpdate 的Diff操作。

Vue2使用的是單向數(shù)據(jù)流,用了它,就可以通過(guò) SSR 返回唯一一個(gè)全局狀態(tài), 并確認(rèn)某個(gè)組件是否已經(jīng)SSR過(guò)了。

開(kāi)啟服務(wù)端渲染(SSR)

Web框架目前我們使用的是express,之前使用過(guò)一次時(shí)間的koa來(lái)做SSR,結(jié)果發(fā)現(xiàn)坑很多,相關(guān)的案例太少,有些坑不太好解決,所以為了線上項(xiàng)目的穩(wěn)定,從而選擇了express。

SSR流程圖

安裝SSR相關(guān)

復(fù)制代碼 代碼如下:

npm install --save express vue-server-renderer lru-cache es6-promise serialize-javascript vue vue-router axios

vue更新到2.0之后,作者就宣告不再對(duì)vue-resource更新,并且vue-resource不支持SSR,所以我推薦使用axios, 在服務(wù)端和客戶(hù)端可以同時(shí)使用。

vue2使用了虛擬DOM, 因此對(duì)瀏覽器環(huán)境和服務(wù)端環(huán)境要分開(kāi)渲染, 要?jiǎng)?chuàng)建兩個(gè)對(duì)應(yīng)的入口文件。

瀏覽器入口文件 client-entry.js

使用 $mount 直接掛載

服務(wù)端入口文件 server-entry

使用vue的SSR功能直接將虛擬DOM渲染成網(wǎng)頁(yè)

client-entry.js 文件

import 'es6-promise/auto';

import { app, store } from './app';

store.replaceState(window.__INITIAL_STATE__);

app.$mount('#app');

在 client-entry.js 文件中引入了app.js, 判斷如果在服務(wù)端渲染時(shí)已經(jīng)寫(xiě)入狀態(tài),則將vuex的狀態(tài)進(jìn)行替換,使得服務(wù)端渲染的html和vuex管理的數(shù)據(jù)是同步的。然后將vue實(shí)例掛載到html指定的節(jié)點(diǎn)中。

server-entry 文件

import { app, router, store } from './app';

const isDev = process.env.NODE_ENV !== 'production';
  
export default context => {
 const s = isDev && Date.now();

 router.push(context.url);
 const matchedComponents = router.getMatchedComponents();

 if (!matchedComponents.length) {
  return Promise.reject({ code: '404' });
 }
  
 return Promise.all(matchedComponents.map(component => {
  if (component.preFetch) {
   return component.preFetch(store);
  }
 })).then(() => {
  return app;
 });
};

在 server-entry 文件中服務(wù)端會(huì)傳遞一個(gè)context對(duì)象,里面包含當(dāng)前用戶(hù)請(qǐng)求的url,vue-router 會(huì)跳轉(zhuǎn)到當(dāng)前請(qǐng)求的url中,通過(guò) router.getMatchedComponents( ) 來(lái)獲得當(dāng)前匹配組件,則去調(diào)用當(dāng)前匹配到的組件里的 preFetch 鉤子,并傳遞store(Vuex下的狀態(tài)),會(huì)返回一個(gè) Promise 對(duì)象,并在then方法中將現(xiàn)有的vuex state 賦值給context,給服務(wù)端渲染使用,最后返回vue實(shí)例,將虛擬DOM渲染成網(wǎng)頁(yè)。服務(wù)端會(huì)將vuex初始狀態(tài)也生成到頁(yè)面中。 如果 vue-router 沒(méi)有匹配到請(qǐng)求的url,直接返回 Promise中的reject方法,傳入404,這時(shí)候會(huì)走到下方renderStream的error事件,讓頁(yè)面顯示錯(cuò)誤信息。

// 處理所有的get請(qǐng)求
app.get('*', (req, res) => {
 // 等待編譯
 if (!renderer) {
  return res.end('waiting for compilation... refresh in a moment.');
 }

 var s = Date.now();
 const context = { url: req.url };
 // 渲染我們的Vue實(shí)例作為流
 const renderStream = renderer.renderToStream(context);
  
 // 當(dāng)塊第一次被渲染時(shí)
 renderStream.once('data', () => {
    // 將預(yù)先的HTML寫(xiě)入響應(yīng)
  res.write(indexHTML.head);
 });
  
 // 每當(dāng)新的塊被渲染
 renderStream.on('data', chunk => {
    // 將塊寫(xiě)入響應(yīng)
  res.write(chunk);
 });
  
 // 當(dāng)所有的塊被渲染完成
 renderStream.on('end', () => {
  // 當(dāng)vuex初始狀態(tài)存在
  if (context.initialState) {
    // 將vuex初始狀態(tài)以script的方式寫(xiě)入到頁(yè)面中
   res.write(
    `<script>window.__INITIAL_STATE__=${
     serialize(context.initialState, { isJSON: true })
    }</script>`
   );
  }
  
  // 將結(jié)尾的HTML寫(xiě)入響應(yīng)
  res.end(indexHTML.tail);
 });
  
 // 當(dāng)渲染時(shí)發(fā)生錯(cuò)誤
 renderStream.on('error', err => {
  if (err && err.code === '404') {
   res.status(404).end('404 | Page Not Found');
   return;
  }
  res.status(500).end('Internal Error 500');
 });
})

上面是vue2.0的服務(wù)端渲染方式,用流式渲染的方式,將HTML一邊生成一邊寫(xiě)入相應(yīng)流,而不是在最后一次全部寫(xiě)入。這樣的效果就是頁(yè)面渲染速度將會(huì)很快。還可以引入 lru-cache 這個(gè)模塊對(duì)數(shù)據(jù)進(jìn)行緩存,并設(shè)置緩存時(shí)間,我一般設(shè)置15分鐘的緩存時(shí)間。

可以參考vue ssr 官方演示項(xiàng)目的服務(wù)端實(shí)現(xiàn) https://github.com/vuejs/vue-hackernews-2.0/blob/master/server.js

axios在客戶(hù)端和服務(wù)端的使用

創(chuàng)建2個(gè)文件用于客戶(hù)端和服務(wù)端的的通信

create-api-client.js 文件(用于客戶(hù)端)

const axios = require('axios');
let api;

axios.defaults.timeout = 10000;

axios.interceptors.response.use((res) => {
 if (res.status >= 200 && res.status < 300) {
  return res;
 }
 return Promise.reject(res);
}, (error) => {
 // 網(wǎng)絡(luò)異常
 return Promise.reject({message: '網(wǎng)絡(luò)異常,請(qǐng)刷新重試', err: error});
});

if (process.__API__) {
 api = process.__API__;
} else {
 api = {
  get: function(target, params = {}) {
   const suffix = Object.keys(params).map(name => {
    return `${name}=${JSON.stringify(params[name])}`;
   }).join('&');
   const urls = `${target}?${suffix}`;
   return new Promise((resolve, reject) => {
    axios.get(urls, params).then(res => {
     resolve(res.data);
    }).catch((error) => {
     reject(error);
    });
   });
  },
  post: function(target, options = {}) {
   return new Promise((resolve, reject) => {
    axios.post(target, options).then(res => {
     resolve(res.data);
    }).catch((error) => {
     reject(error);
    });
   });
  }
 };
}

module.exports = api;

create-api-server.js 文件(用于服務(wù)端)

const isProd = process.env.NODE_ENV === 'production';

const axios = require('axios');
let host = isProd ? 'http://yczj.api.autohome.com.cn' : 'http://t.yczj.api.autohome.com.cn';
let cook = process.__COOKIE__ || '';
let api;

axios.defaults.baseURL = host;
axios.defaults.timeout = 10000;

axios.interceptors.response.use((res) => {
 if (res.status >= 200 && res.status < 300) {
  return res;
 }
 return Promise.reject(res);
}, (error) => {
 // 網(wǎng)絡(luò)異常
 return Promise.reject({message: '網(wǎng)絡(luò)異常,請(qǐng)刷新重試', err: error, type: 1});
});

if (process.__API__) {
 api = process.__API__;
} else {
 api = {
  get: function(target, options = {}) {
   return new Promise((resolve, reject) => {
    axios.request({
     url: target,
     method: 'get',
     headers: {
      'Cookie': cook
     },
     params: options
    }).then(res => {
     resolve(res.data);
    }).catch((error) => {
     reject(error);
    });
   });
  },
  post: function(target, options = {}) {
   return new Promise((resolve, reject) => {
    axios.request({
     url: target,
     method: 'post',
     headers: {
      'Cookie': cook
     },
     params: options
    }).then(res => {
     resolve(res.data);
    }).catch((error) => {
     reject(error);
    });
   });
  }
 };
}

 
module.exports = api;

由于在服務(wù)端,接口不會(huì)主動(dòng)攜帶 cookie,所以需要在headers里寫(xiě)入cookie。由于接口數(shù)據(jù)經(jīng)常發(fā)生變化,所以沒(méi)有做緩存。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue-cli腳手架引入圖片的幾種方法總結(jié)

    vue-cli腳手架引入圖片的幾種方法總結(jié)

    下面小編就為大家分享一篇vue-cli腳手架引入圖片的幾種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Vue頁(yè)面首次載入優(yōu)化的全過(guò)程

    Vue頁(yè)面首次載入優(yōu)化的全過(guò)程

    凡是做SPA的項(xiàng)目,特別是移動(dòng)端的SAP項(xiàng)目,首屏加載速度必定是一個(gè)繞不過(guò)去的話題,下面這篇文章主要給大家介紹了關(guān)于Vue頁(yè)面首次載入優(yōu)化的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • 關(guān)于element中對(duì)el-input 自定義驗(yàn)證規(guī)則

    關(guān)于element中對(duì)el-input 自定義驗(yàn)證規(guī)則

    這篇文章主要介紹了關(guān)于element中對(duì)el-input 自定義驗(yàn)證規(guī)則,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 關(guān)于VUE的編譯作用域及slot作用域插槽問(wèn)題

    關(guān)于VUE的編譯作用域及slot作用域插槽問(wèn)題

    這篇文章主要介紹了VUE 的編譯作用域及slot作用域插槽問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • vue 利用路由守衛(wèi)判斷是否登錄的方法

    vue 利用路由守衛(wèi)判斷是否登錄的方法

    今天小編就為大家分享一篇vue 利用路由守衛(wèi)判斷是否登錄的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Vue.js 中取得后臺(tái)原生HTML字符串 原樣顯示問(wèn)題的解決方法

    Vue.js 中取得后臺(tái)原生HTML字符串 原樣顯示問(wèn)題的解決方法

    這篇文章主要介紹了VUE.js 中取得后臺(tái)原生HTML字符串 原樣顯示問(wèn)題 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • 結(jié)合康熙選秀講解vue虛擬列表實(shí)現(xiàn)

    結(jié)合康熙選秀講解vue虛擬列表實(shí)現(xiàn)

    這篇文章主要為大家介紹了結(jié)合康熙選秀講解vue虛擬列表的原理使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • vue3.x ref()語(yǔ)法糖賦值方式

    vue3.x ref()語(yǔ)法糖賦值方式

    這篇文章主要介紹了vue3.x ref()語(yǔ)法糖賦值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 加載 vue 遠(yuǎn)程代碼的組件實(shí)例詳解

    加載 vue 遠(yuǎn)程代碼的組件實(shí)例詳解

    vue-cli 作為 Vue 官方推薦的項(xiàng)目構(gòu)建腳手架,它提供了開(kāi)發(fā)過(guò)程中常用的,熱重載,構(gòu)建,調(diào)試,單元測(cè)試,代碼檢測(cè)等功能。我們本次的異步遠(yuǎn)端組件將基于 vue-cli 開(kāi)發(fā)
    2017-11-11
  • vue2項(xiàng)目使用exceljs多表頭導(dǎo)出功能詳解

    vue2項(xiàng)目使用exceljs多表頭導(dǎo)出功能詳解

    ExcelJS是一個(gè)用于在Node.js和瀏覽器中創(chuàng)建、讀取和修改Excel文件的強(qiáng)大JavaScript庫(kù),下面這篇文章主要給大家介紹了關(guān)于vue2項(xiàng)目使用exceljs多表頭導(dǎo)出功能的相關(guān)資料,需要的朋友可以參考下
    2024-05-05

最新評(píng)論