乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      詳解如何使用Vue2做服務端渲染

       163九九 2019-04-07

      感興趣的小伙伴,下面一起跟隨512筆記的小編兩巴掌來看看吧!

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

      技術棧

      服務端:Nodejs(v6.3)

      前端框架 Vue2.1.10

      前端構建工具:webpack2.2 && gulp

      代碼檢查:eslint

      源碼:es6

      前端路由:vue-router2.1.0

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

      服務端通信:axios

      日志管理:log4js

      項目自動化部署工具:jenkins

      Vue2與服務端渲染(SSR)

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

      SSR的實現(xiàn)原理

      客戶端請求服務器,服務器根據請求地址獲得匹配的組件,在調用匹配到的組件返回 Promise (官方是preFetch方法)來將需要的數(shù)據拿到。最后再通過

      代碼如下:

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

      將其寫入網頁,最后將服務端渲染好的網頁返回回去。

      接下來客戶端會將vuex將寫入的 __initial_state__ 替換為當前的全局狀態(tài)樹,再用這個狀態(tài)樹去檢查服務端渲染好的數(shù)據有沒有問題。遇到沒被服務端渲染的組件,再去發(fā)異步請求拿數(shù)據。說白了就是一個類似React的 shouldComponentUpdate 的Diff操作。

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

      開啟服務端渲染(SSR)

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

      SSR流程圖

      安裝SSR相關

      復制代碼 代碼如下:

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

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

      vue2使用了虛擬DOM, 因此對瀏覽器環(huán)境和服務端環(huán)境要分開渲染, 要創(chuàng)建兩個對應的入口文件。

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

      使用 $mount 直接掛載

      服務端入口文件 server-entry

      使用vue的SSR功能直接將虛擬DOM渲染成網頁

      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, 判斷如果在服務端渲染時已經寫入狀態(tài),則將vuex的狀態(tài)進行替換,使得服務端渲染的html和vuex管理的數(shù)據是同步的。然后將vue實例掛載到html指定的節(jié)點中。

      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 文件中服務端會傳遞一個context對象,里面包含當前用戶請求的url,vue-router 會跳轉到當前請求的url中,通過 router.getMatchedComponents( ) 來獲得當前匹配組件,則去調用當前匹配到的組件里的 preFetch 鉤子,并傳遞store(Vuex下的狀態(tài)),會返回一個 Promise 對象,并在then方法中將現(xiàn)有的vuex state 賦值給context,給服務端渲染使用,最后返回vue實例,將虛擬DOM渲染成網頁。服務端會將vuex初始狀態(tài)也生成到頁面中。 如果 vue-router 沒有匹配到請求的url,直接返回 Promise中的reject方法,傳入404,這時候會走到下方renderStream的error事件,讓頁面顯示錯誤信息。

      代碼如下:

      // 處理所有的get請求
      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實例作為流
       const renderStream = renderer.renderToStream(context);
        
       // 當塊第一次被渲染時
       renderStream.once('data', () => {
          // 將預先的HTML寫入響應
        res.write(indexHTML.head);
       });
        
       // 每當新的塊被渲染
       renderStream.on('data', chunk => {
          // 將塊寫入響應
        res.write(chunk);
       });
        
       // 當所有的塊被渲染完成
       renderStream.on('end', () => {
        // 當vuex初始狀態(tài)存在
        if (context.initialState) {
          // 將vuex初始狀態(tài)以script的方式寫入到頁面中
         res.write(
          `<script>window.__INITIAL_STATE__=${
           serialize(context.initialState, { isJSON: true })
          }</script>`
         );
        }
        
        // 將結尾的HTML寫入響應
        res.end(indexHTML.tail);
       });
        
       // 當渲染時發(fā)生錯誤
       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的服務端渲染方式,用流式渲染的方式,將HTML一邊生成一邊寫入相應流,而不是在最后一次全部寫入。這樣的效果就是頁面渲染速度將會很快。還可以引入 lru-cache 這個模塊對數(shù)據進行緩存,并設置緩存時間,我一般設置15分鐘的緩存時間。

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

      axios在客戶端和服務端的使用

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

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

      代碼如下:

      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) => {
       // 網絡異常
       return Promise.reject({message: '網絡異常,請刷新重試', 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 文件(用于服務端)

      代碼如下:

      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) => {
       // 網絡異常
       return Promise.reject({message: '網絡異常,請刷新重試', 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;

      由于在服務端,接口不會主動攜帶 cookie,所以需要在headers里寫入cookie。由于接口數(shù)據經常發(fā)生變化,所以沒有做緩存。

      以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持512筆記。

      注:關于詳解如何使用Vue2做服務端渲染的內容就先介紹到這里,更多相關文章的可以留意512筆記的其他信息。

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多