vue ssr 實現方式學習筆記

爲何要寫本文呢,話說如今 vue-ssr 官網上對 vue 服務端渲染的介紹已經很全面了,包括各類服務端渲染框架好比 Nuxt.js 、 集成 Koa 和vue-server-renderer 的 node.js 框架 egg.js,都有本身的官網和團隊在維護,文檔真是面面俱到功能強大,可是,我我的在剛開始看這些資料的時候,老是忍不住發起靈魂三問:「我是誰?我在哪?我在幹什麼?」,提早沒有相關知識的人開始學這些,確定是要走一些彎路或者卡在某個點一段時間的,因此我想把個人學習經驗作下總結,一方面方便本身之後查閱,一方面也會在文中加一些針對官網上沒有細說的點的理解,但願能幫助你減小些學習成本,畢竟這是一個知識共享的時代嘛。本文不涉及到源碼解析,主要講解如何實現 vue 的服務端渲染,比較適合 vue-ssr 小白閱讀,下面咱們進入正文:

先說下基本概念:

ssr 的全稱是 server side render,服務端渲染,vue ssr 的意思就是在服務端進行 vue 的渲染,直接對前端返回帶有數據,而且是渲染好的HTML頁面;而不是返回一個空的HTML頁面,再由vue 經過異步請求來獲取數據,再從新補充到頁面中。html

這麼作的最主要緣由,就是搜索引擎優化,也就是SEO,這更利於網絡爬蟲去爬取和收集數據。前端

爲何這樣就有利於網絡爬蟲爬取呢?

這裏簡單說一下爬蟲的爬取方式,爬蟲經過訪問 URL 獲取一個頁面後,會獲取當前HTML中已存在的數據,也能夠理解爲把拿到的 HTML 頁面轉爲了字符串內容,而後解析、存儲這些內容,可是若是頁面中有些數據是經過異步請求得到的,那麼爬蟲是不會等待異步請求返回以後才結束對頁面數據的解析的,這樣就會沒有爬取到這部分數據,很不利於其餘搜索引擎的收錄。vue

這也就是爲何單頁面網站是不具有良好的SEO效果的,由於單頁面返回的就是一個基本爲空的 HTML 文件,裏面就一個帶有ID的元素等待掛載而已,頁面的內容都是經過 js 後續生成的,好比這樣:node

<!DOCTYPE html>
<html lang="en">
  <head><title>Hello</title></head>
  <body><div id="app"></div></body>
  <script src="bundle.js"></script>
</html>

但對於不少公司來講,公司的產品是但願能被百度、谷歌等搜索引擎收錄以後,進行排名,進一步的被用戶搜索到,能更利於品牌的推廣、流量變現等操做,要實現這些,就必須保證產品的網頁是可以被網絡爬蟲爬取到的,顯然一個完整的帶有所有數據的頁面更利於爬蟲的爬取,固然如今也有不少方法能夠去實現針對頁面異步數據的爬取,github 上也開源了不少的爬蟲代碼,可是這顯然對於爬蟲來講更加的不友好、成本更高。webpack

SSR 固然也是有着其餘的好處的,好比首屏頁面加載速度更快,用戶等待時間更短等,其餘更多概念能夠查看官網 https://ssr.vuejs.org/zh/ ,這些官網上都有介紹。git

代碼實現

下面咱們結合官網上的代碼,作一下代碼實操,來加深下理解:github

在官網中,提供了一個使用模塊 vue-server-renderer 簡單實現 vue 服務端渲染的示例:
新建一個文件夾vue-ssr-demo,進入其中執行以下命令:web

// 安裝模塊 
npm install vue vue-server-renderer --save

建立文件 server.jsnpm

// vue-ssr-demo/server.js 示例代碼

//第一步,建立vue實例
const Vue = require('vue');
const app = new Vue({
    template: "<div>hello world</div>"
});

//第二步,建立一個renderer
const renderer = require('vue-server-renderer').createRenderer();
//第三步,將vue渲染爲HTML
renderer.renderToString(app, (err, html)=>{
  if(err){
      throw err;
  }
  console.log(html);
});

保存以上代碼後,在 vue-ssr-demo 文件夾下打開命令行工具,執行 node server.js 命令,可獲得以下 HTML 內容:api

➜ vue-ssr-demo node server.js
<div data-server-rendered="true">hello world</div>

好,上面的例子中咱們已經讓 vue 在服務端,也就是 node 環境下運行起來了,到這裏其實已經實現了 vue 的服務端渲染了。

但是,實際項目中使用哪有這麼簡單,起碼數據還沒渲染啊,那接下來咱們看看如何渲染數據:

vue-ssr 渲染數據的方式有兩種,咱們先看下第一種:

// server.js
const data_vue = {
    word: 'Hello World!'
};
//第一步,建立vue實例
const Vue = require('vue');
//vue 實例化過程當中插入數據
const app = new Vue({
    data: data_vue,
    template: "<div>{{word}}</div>"
});

//第二步,建立一個renderer
const renderer = require('vue-server-renderer').createRenderer();

//第三步,將vue渲染爲HTML
renderer.renderToString(app, (err, html)=>{
    if(err){
        throw err;
    }
    console.log(html);
});

第一種方式,在建立 vue 實例時,將須要的數據傳入 vue 的模板,使用方法與客戶端 vue 同樣;運行 server.js 結果以下,數據 data_vue 已經插入到 vue 模板裏面了:

➜  vue-ssr-demo node server.js
<div data-server-rendered="true">Hello World!</div>

第二種,模板插值,這裏咱們也直接先放代碼:

const data_vue = {
  word: 'Hello World!'
};
const data_tpl = {
  people: 'Hello People!'
};
//第一步,建立vue實例
const Vue = require('vue');
const app = new Vue({
  data: data_vue,
  template: "<div>{{word}}</div>"
});

//第二步,建立一個 renderer 實例
const renderer = require('vue-server-renderer').createRenderer({
  template: "<!--vue-ssr-outlet--><div>{{people}}</div>"
});

//第三步,將vue渲染爲HTML
renderer.renderToString(app, data_tpl, (err, html)=>{
  if(err){
      throw err;
  }
  console.log(html);
});

這裏咱們增長了數據 data_tpl,你會發現,在 renderToString 方法中傳入了這個參數,那麼這個參數做用在哪裏呢?這就要看下官網中關於 createRenderer 和 renderToString 方法的介紹了,

createRenderer: 使用(可選的)選項建立一個 Renderer 實例。
const { createRenderer } = require('vue-server-renderer')
const renderer = createRenderer({ / 選項 / })

在選項中,就有一個參數叫 template,看官網怎麼說的:

template: 爲整個頁面的 HTML 提供一個模板。此模板應包含註釋 <!--vue-ssr-outlet-->,做爲渲染應用程序內容的佔位符。

爲整個頁面的 HTML 提供一個模板。此模板應包含註釋 <!--vue-ssr-outlet-->,做爲渲染應用程序內容的佔位符。

模板還支持使用渲染上下文 (render context) 進行基本插值:

使用雙花括號 (double-mustache) 進行 HTML 轉義插值 (HTML-escaped interpolation);
使用三花括號 (triple-mustache) 進行 HTML 不轉義插值 (non-HTML-escaped interpolation)。

根據介紹,在建立 renderer 實例時,能夠經過 template 參數聲明一個模板,這個模板用來幹嗎呢?就用來掛載 vue 模板渲染完成以後生成的 HTML。這裏要注意一下,當建立 renderer 實例時沒有聲明 template 參數,那麼默認渲染完就是 vue 模板生成的 HTML;當建立 renderer 實例時聲明瞭 template 參數,必定要在模板中增長一句註釋 「<!--vue-ssr-outlet-->」 做爲 vue 模板插入的佔位符,不然會報找不到插入模板位置的錯誤。

再次運行 server.js ,結果以下,vue 模板已成功插入,且 template 模板中的 {{people}} 變量也因在 renderToString 方法中第二位參數的傳入,顯示了數據:

➜  vue-ssr-demo node server.js
<div data-server-rendered="true">Hello World!</div><div>Hello People!</div>

若是咱們把 template 換成一個 HTML 頁面的基本架構,來包裹 vue 模板,是否是就能獲得一個完整頁面了呢?咱們來試一下:

const data_vue = {
    word: 'Hello World!'
};
const data_tpl = {
    people: 'Hello People!'
};
//第一步,建立vue實例
const Vue = require('vue');
const app = new Vue({
    data: data_vue,
    template: "<div>{{word}}</div>"
});

//第二步,建立一個renderer
const renderer = require('vue-server-renderer').createRenderer({
    template: `<!DOCTYPE html>
    <html lang="en">
      <head><title>Hello</title></head>
      <body>
        <!--vue-ssr-outlet--><div>{{people}}</div>
      </body>
    </html>`
});

//第三步,將vue渲染爲HTML
renderer.renderToString(app, data_tpl, (err, html)=>{
    if(err){
        throw err;
    }
    console.log(html);
});

運行 server.js ,結果以下,咱們獲得了一個完整的 HTML 頁面,且成功插入了數據:

➜  vue-ssr-demo node server.js
<!DOCTYPE html>
<html lang="en">
      <head><title>Hello</title></head>
      <body>
        <div data-server-rendered="true">Hello World!</div><div>Hello People!</div>
      </body>
</html>

好,如今頁面生成了,該怎麼顯示呢?這裏咱們藉助下框架 Koa 實現,先來安裝:

npm install koa -S

而後修改 server.js ,以下:

const data_vue = {
    word: 'Hello World!'
};
const data_tpl = {
    people: 'Hello People!'
};

const Koa = require('koa');
//建立 koa 實例
const koa = new Koa();

const Vue = require('vue');

//建立一個renderer
const renderer = require('vue-server-renderer').createRenderer({
    template: `<!DOCTYPE html>
    <html lang="en">
      <head><title>Hello</title></head>
      <body>
        <!--vue-ssr-outlet--><div>{{people}}</div>
      </body>
    </html>`
});

// 對於任何請求,app將調用該異步函數處理請求:
koa.use(async (ctx, next) => {
    // await next();
    
    //建立vue實例
    const app = new Vue({
        data: data_vue,
        template: "<div>{{word}}</div>"
    });

    //將vue渲染爲HTML
    const body = await renderer.renderToString(app, data_tpl);
    ctx.body = body;
});

// 在端口3001監聽:
koa.listen(3001);
console.log('app started at port 3001...');

運行 server.js :

➜  vue-ssr-demo node server.js
app started at port 3001...

而後打開瀏覽器,輸入網址 http://localhost:3001/ ,便可看到運行後的效果。

這樣就實現了一個簡單的服務端渲染項目,可是咱們在日常開發的時候,確定不會這麼簡單的去構建一個項目,必然會用到一些,好比打包、壓縮的工具,這篇就寫到這裏,下一篇咱們嘗試使用 webpack 來構建一個 vue 的服務端渲染項目。

若有問題,歡迎指正!謝謝!

相關文章
相關標籤/搜索