Vue-js 服務器端渲染指南

默認情況下,可以在瀏覽器中輸出 Vue 組件,進行生成 DOM 和操作 DOM。然而,也可以將同一個組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器。

簡單理解是將組件或頁面通過服務器生成 HTML 字符串,再發送到瀏覽器,最後將靜態標記 "混合" 爲客戶端上完全交互的應用程序。

使用 SSR 的利弊

SSR 的優勢

1、更利於 SEO。

不同爬蟲工作原理類似,只會爬取源碼,不會執行網站的任何腳本(Google 除外,據說 Googlebot 可以運行 javaScript)。使用了 React 或者其它 MVVM 框架之後,頁面大多數 DOM 元素都是在客戶端根據 js 動態生成,可供爬蟲抓取分析的內容大大減少 (如圖一)。另外,瀏覽器爬蟲不會等待我們的數據完成之後再去抓取我們的頁面數據。服務端渲染返回給客戶端的是已經獲取了異步數據並執行 JavaScript 腳本的最終 HTML,網絡爬中就可以抓取到完整頁面的信息。

2、更利於首屏渲染

首屏的渲染是 node 發送過來的 html 字符串,並不依賴於 js 文件了,這就會使用戶更快的看到頁面的內容。尤其是針對大型單頁應用,打包後文件體積比較大,普通客戶端渲染加載所有所需文件時間較長,首頁就會有一個很長的白屏等待時間。

SSR 的侷限

1、服務端壓力較大

本來是通過客戶端完成渲染,現在統一到服務端 node 服務去做。尤其是高併發訪問的情況,會大量佔用服務端 CPU 資源;

2、開發條件受限

在服務端渲染中,只會執行到 componentDidMount 之前的生命週期鉤子,因此項目引用的第三方的庫也不可用其它生命週期鉤子,這對引用庫的選擇產生了很大的限制;

3、學習成本相對較高

除了對 webpack、React 要熟悉,還需要掌握 node、Koa2 等相關技術。相對於客戶端渲染,項目構建、部署過程更加複雜。

使用服務器端渲染 (SSR) 時還需要有一些權衡之處:

開發條件所限。瀏覽器特定的代碼,只能在某些生命週期鉤子函數中使用;一些外部擴展庫可能需要特殊處理,才能在服務器渲染應用程序中運行。

涉及構建設置和部署的更多要求。與可以部署在任何靜態文件服務器上的完全靜態單頁面應用程序 (SPA) 不同,服務器渲染應用程序,需要處於 Node.js server 運行環境。

更多的服務器端負載。在 Node.js 中渲染完整的應用程序,顯然會比僅僅提供靜態文件的 server 更加大量佔用 CPU 資源,因此如果你預料在高流量環境下使用,請準備相應的服務器負載,並明智地採用緩存策略。

在對你的應用程序使用服務器端渲染 (SSR) 之前,你應該問的第一個問題是,是否真的需要它。這主要取決於內容到達時間對應用程序的重要程度。例如,如果你正在構建一個內部報表,初始加載時的額外幾百毫秒並不重要,這種情況下去使用服務器端渲染 (SSR) 將是一個小題大作之舉。然而,加載時間要求是絕對關鍵的指標,在這種情況下,服務器端渲染 (SSR) 可以幫助你實現最佳的初始加載性能。

服務器端渲染 vs 預渲染 (SSR vs Prerendering)

如果你調研服務器端渲染 (SSR) 只是用來改善少數營銷頁面(例如 /, /about, /contact 等)的 SEO,那麼你可能需要預渲染。無需使用 web 服務器實時動態編譯 HTML,而是使用預渲染方式,在構建時 (build time) 簡單地生成針對特定路由的靜態 HTML 文件。優點是設置預渲染更簡單,並可以將你的前端作爲一個完全靜態的站點。

如果你使用 webpack,你可以使用 prerender-spa-plugin 輕鬆地添加預渲染。

基本用法

npm install vue vue-server-renderer --save

與服務器集成

npm install express --save
const Vue = require('vue')
const server = require('express')()
// 第 1 步:創建一個 renderer
const renderer = require('vue-server-renderer').createRenderer()
server.get('\*', (req, res) => {
  // 第 2 步:創建一個 Vue 實例
  const app = new Vue({
    data: {
      url: req.url
    },
    template: \`<div>訪問的 URL 是:{{ url }}</div>\`
  })
  // 第 3 步:將 Vue 實例渲染爲 HTML
  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(\`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
    \`)
  })
})
server.listen(8080)

在 Node.js 服務器中使用時相當簡單直接。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。