vue SSR 服務端渲染記錄

前幾天瞭解了下vue 服務端渲染的流程,記錄下。首先,什麼是ssr(服務端渲染 Server Side Rendering),爲何須要?html

服務端渲染是什麼

先後端分離以後,頁面加載的流程是,前端異步請求拿到數據渲染頁面。服務端渲染就是在後端把數據取好,拼好頁面的DOM樹發給前端,到瀏覽器解析渲染。有沒有想到先後端分離以前,由後端把數據塞進模版,前端負責顯示的過去。(有沒有種天下之勢,合久必分,分久必合的感慨哈哈哈哈哈)前端

服務端渲染優勢

  • 頁面的SEO, 異步拿數據顯示對爬蟲不友好
  • 首屏渲染速度快,更好的用戶體驗

服務端渲染原理

接下來,介紹下vue 服務端實現原理及流程。
vue SSR流程圖vue

  1. SSR 有兩個入口文件client-entry,server-entry , webpack打包以後,生成 server-bundle, client-bundle
  2. 服務器收到瀏覽器的請求,建立一個bundleRenderer,讀取1生成的server-bundle,執行代碼(具體作了什麼後面會講到),生成html發送到前端
  3. 把第二步生成的html跟前端的client-bundle進行混合(hydrate),混合時判斷client-bundle 的DOM節點跟服務端返回的html裏DOM節點是否相同,是的話掛載(vue中的$mount)到這個節點上,頁面渲染完畢

用白話形容,服務端獲取頁面所需的數據以後,拼出html,把html轉成string發送到前端,前端把html插入到指定節點,渲染頁面,OK了。
表情node

服務端數據預取

看看官網的demo,服務端怎麼作的服務端數據預取。webpack

// entry-server.js
import { createApp } from './app'
export default context => {
  return new Promise((resolve, reject) => {
    const { app, router, store } = createApp()
    router.push(context.url)
     // 等到 router 將可能的異步組件和鉤子函數解析完
    router.onReady(() => {
      //獲取相匹配的組件
      const matchedComponents = router.getMatchedComponents()
      if (!matchedComponents.length) {
        return reject({ code: 404 })
      }
      // 對全部匹配的路由組件調用 `asyncData()`
      Promise.all(matchedComponents.map(Component => {
        if (Component.asyncData) {
          return Component.asyncData({
            store,
            route: router.currentRoute
          })
        }
      })).then(() => {
        // 在全部預取鉤子(preFetch hook) resolve 後,
        // 咱們的 store 如今已經填充入渲染應用程序所需的狀態。
        // 當咱們將狀態附加到上下文,
        // 而且 `template` 選項用於 renderer 時,
        // 狀態將自動序列化爲 `window.__INITIAL_STATE__`,並注入 HTML。
        context.state = store.state
        resolve(app)
      }).catch(reject)
    }, reject)
  })
}
  1. 根據router拿出相匹配的組件,客戶端定義asyncData(數據預取函數,拿數據),服務端asyncData,獲取數據
  2. 把源數據和狀態寫進store(數據和狀態存儲容器,store獨立於業務組件,詳情可查看Vuex),避免客戶端和服務端狀態不對等。狀態寫進window.__INITIAL_STATE__格式,客戶端可拿到

bundleRenderder

html渲染好以後,轉成string發到客戶端,客戶端插入到對應DOM節點下就能夠啦~web

const { createBundleRenderer } = require('vue-server-renderer')
const renderer = createBundleRenderer(serverBundle, {
  runInNewContext: false, // 推薦
  template, // (可選)頁面模板
  clientManifest // (可選)客戶端構建 manifest
})
// 在服務器處理函數中……
server.get('*', (req, res) => {
  const context = { url: req.url }
  // 這裏無需傳入一個應用程序,由於在執行 bundle 時已經自動建立過。
  // 如今咱們的服務器與應用程序已經解耦!
  renderer.renderToString(context, (err, html) => {
    // 處理異常……
    res.end(html)
  })
}

服務端渲染一些坑

  • document 對象找不到,因爲前端使用的 window,在 node 環境不存在
  • 數據預獲取時,組件還沒有實例化(沒法使用 this ),數據請求及格式化等操做都應該放置在store處理
相關文章
相關標籤/搜索