Vue 服務端渲染

關於 vue 作服務端渲染,目前主要有倆種解決方案,使用 vue-server-renderer 或者使用 nuxt 。但我的感受使用 nuxt 寫法太死,以及即便你用 nuxt 寫出了 vue ssr 頁面,可能你也只是說熟悉了 nuxt 這個框架,而不清楚 vue ssr 具體的原理。如下我會基於 vue ssr 渲染示例 vue-hackernews-2.0 以及豆瓣 api 實現一個簡單的 vue-ssr。開始以前,請先大體閱讀下官方文檔css

簡單示例

首先經過一個簡單的示例瞭解什麼是服務端渲染。所謂服務端渲染就是經過服務端請求獲取數據,根據 vue 模版渲染好 html 頁面返回給前端,驗證一個頁面是否是經過服務端渲染的能夠在頁面上右鍵查看源代碼有沒有頁面的 html 信息。html

const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: `<div>訪問的 URL 是: {{ url }}</div>`
  })

  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    // 返回 html 信息
    res.end(`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
    `)
  })
})

server.listen(8080)

源碼結構

圖片描述

|--build: webpack 配置文件
|--dist: 編譯後文件目錄
|--log: 日誌目錄
|--node_modules: npm 包
|--public: 公共文件目錄
|--src: 項目開發目錄
    |--api: api 目錄
    |--assets: 資源目錄,圖片,css等
    |--components: 公共組件
    |--router: 路由
    |--store: vuex 狀態管理
    |--util: 公共方法
    |--views: 各目錄對應各個頁面
|--.babelrc: babel 配置
|--eslintrc.js: eslint 配置
|--ecosystem.js: pm2 配置文件
|--package.json: npm 包配置
|--postcss.config.js: postcss 配置
|--config.js: 配置文件
|--server.js: node 服務

瞭解 vue 服務端渲染最主要的是要知道上面的圖片到底講了什麼。前端

store、Router和component

這三者爲無論是服務端渲染仍是客戶端渲染都可使用的公共模塊vue

app.js

定義好 vue 實例 app,路由 router、數據 store。方便服務端與客戶端作同步。node

Server entry 與 Client entry

首先爲何會有 Server entry 和 Client entry 倆個入口。咱們假設頁面有倆個路由。當倆個路由均是經過瀏覽器輸入 url 直接訪問的,則均經過服務端請求數據渲染好頁面返回給前端,倆個頁面均是走 Server entry。當一個路由是經過瀏覽器輸入,而另外一個路由是經過當前路由點擊跳轉到達的,走spa(單頁) 前端請求數據渲染頁面,則第一個路由走 Server entry,跳轉的頁面走 Client entry。
Server entry 與 Client entry 定義了一個鉤子函數 asyncData 參數爲 store 與 router,在服務端執行。同步了客戶端與服務端的路由與數據。webpack

webpack 打包

左側 source 經過 webpack 打包,讓 node 執行 Server enter 打包的代碼,瀏覽器執行 Client entry 打包的代碼。git

同步路由

無論是走服務端渲染仍是客戶端渲染,咱們均使用同一套路由,在 app.js 中定義一個 router 對象,在 Server entryClient entry 中均使用該對象。github

同步數據

服務端渲染好頁面返回給客戶端,客戶端渲染好頁面須要作一些交互修改一些數據,數據是經過服務端請求獲取的,此時還存在服務端,客戶端如何獲取到這些數據呢?
服務端請求的數據會存放在 store 中,在 Server entry 中將 數據賦值給 context.state。執行 renderTostring 時會將數據存放在 window.__INITIAL_STATE__ 返回給前端。Client entry 將會讀取 window.__INITIAL_STATE__ 中的數據存放在 store 中。這樣就能夠在 store 中獲取到數據。web

異步請求

前端頁面直接調用第三方接口會報跨域錯誤,vue-hackernews-2.0 是使用 firebase 作處理,我這邊直接在 node 端定義了倆個路由經過後端去請求。vuex

遇到的坑

從主頁跳到頁面詳情頁時,後端請求接口獲取到的數據我經過詳情頁 key - value的形式存放在 store 中,當請求的屢次不一樣的詳情也時致使返回的 window. INITIAL_STATE 數據量爆炸,頁面加載緩慢。其實只需每一個路由建一個 key 便可,例詳情頁只創建一個 detail 的 key,請求的數據賦值給 detail 便可。見 issue

參考

https://ssr.vuejs.org/zh/
https://github.com/vuejs/vue-hackernews-2.0

相關文章
相關標籤/搜索