細說 Vue 組件的服務器端渲染

細說 Vue 組件的服務器端渲染

聲明:須要讀者對 NodeJs、Vue 服務器端渲染有必定的瞭解

如今,先後端分離與客戶端渲染已經成爲前端開發的主流模式,絕大部分的前端應用都適合用這種方式來開發,又特別是 React、Vue 等組件技術的發展,更是使這種方式深刻人心。html

但有一些應用,客戶端渲染就會遇到一些問題了:前端

  1. 須要作 SEO(搜索引擎優化),但客戶端渲染的 html 中幾乎沒有可用的信息
  2. 須要首屏快速加載,但客戶端渲染通常是長時間的加載動畫或者白屏

若是能把客戶端渲染的組件化技術(React、Vue 等)與傳統的後端渲染的方式有效的結合起來,二者兼具,那就太完美了。vue

因此,此次就來聊聊 Vue 組件的服務器端渲染。react

根據社區現有的一些方案,結合本身的實踐,針對團隊技術力量的不一樣,說說不一樣應用場景選擇方案時的優先級。git

1. NodeJs 渲染中間層

通常先後端的工做流是 後端 -> 前端github

傳統的後端渲染模式是後端負責包括 url、接口、模板渲染等,前端與後端耦合在一塊兒,固然這種方式正在慢慢的退出歷史舞臺。ajax

主流的客戶端渲染則是後端只提供接口(若有須要,能夠提供必要的 url),前端與後端只經過接口交流數據,路由與渲染都在前端完成。apache

而 NodeJs 渲染中間層的工做流則是 後端 -> NodeJs -> 前端(NodeJs 渲染中間層由前端開發人員掌握)。json

圖片描述

這種模式下,後端只提供接口,傳統的服務器端路由(url)、模板渲染則都有 NodeJs 層接管。這樣,前端開發人員能夠自由的決定哪些組件須要在服務器端渲染,哪些組件能夠放在客戶端渲染,先後端徹底解耦,但又保留了服務器端渲染的功能。後端

這種方案最成熟的是 nuxt.js

若是有須要,你們能夠本身去 nuxt.js 官方文檔 看看具體的使用方法和詳細的功能。

應該說,這種方式是目前最完美的一種方案,但也有一些隱患:

  1. 增長了一個 NodeJs 中間層,應用性能會有所下降
  2. 增長了架構的複雜度、不穩定性,也下降了應用的安全性
  3. 對於高併發應用,NodeJs 層會很容易造成瓶頸
  4. 對開發人員要求高了不少

因此,這種方式適合對併發量、安全性、穩定性等要求不高,但又須要作 SEO 或首屏快速加載的頁面。

固然,若是你可以本身改造相關的工具,就另當別論了。

2. 保留後端模板渲染

當不能使用 NodeJs 中間層時,而又要達到 SEO 與首屏快速響應的目的時,在傳統的後端模板渲染的基礎上,就須要對前端的頁面加以適當的改造。

2.1 首屏快速響應

首屏快速響應就意味着首屏渲染所需的數據是跟 HTML 文件一塊兒到達瀏覽器的,這些數據當前是由後端模板引擎嵌入到 HTML 頁面中的。

以 Java 的 freemarker 模板引擎爲例:

html 中以 script 的方式獲取模板的數據,這樣就算是在本地調試、開發,也不會報錯)。

<script>
  window.globalData = {
    stringValue: '${stringValueTplName}',
    intValue: parseInt('${intValueTplName}', 10),
  };
</script>

若是是複雜的 Json 數據或者其餘複雜的模板數據(好比列表數據),則能夠像下面這樣接收:

<script type="text/tpl" id="tpl-script-json">
  window.tmpData = {
    jsonValue: ${jsonValueTplName},
  };
</script>

<script>
  try {
    eval(document.getElementById('tpl-script-json').innerText);
  } catch (e) {
    window.tmpData = { jsonValue: {} };
  }
  
  window.globalData = {
    jsonValue: window.tmpData.jsonValue,
  };
</script>

這樣,你就能夠在組件裏使用 window.globalData 的數據了,而不用另外用接口獲取數據,達到加快首屏渲染的目的,並且本地開發、調試也不會報錯。

若是你使用了本地數據 Mock 功能,也能夠很容易的與這種方式結合在一塊兒,只要稍加改造:

  1. 在代碼中定義本地和服務器兩個環境,本地環境使用 Mock 數據,服務器環境使用 window.globalData
  2. 可使用 see-ajax, see-fetch 來簡化這種方式的開發

此外,還有一些措施來進一步加快首屏渲染:

  1. 儘可能減小首屏加載的腳本文件大小,其餘腳本能夠按需加載
  2. 若是須要,能夠將 CSS、JS 內容注入到 HTML 中,這樣就只會發起一個請求,也能夠加快加載速度

2.2 SEO 優化

在上面加載首屏渲染的基礎上,對於 SEO 優化也能夠作相應的改造。

其實,在客戶端渲染已慢慢成爲主流開發模式的同時,搜索引擎也在跟進這種變化。

截至目前,Google 和 Bing 能夠很好對同步 JavaScript 應用程序進行索引,也就是說,即便是客戶端渲染,但只要是同步數據渲染(非 Ajax 獲取數據,好比模板數據),搜索引擎也能抓取到相應的 HTML 片斷。

(國內的百度搜索與360搜索等暫時尚未跟進動態)

但爲了兼容全部的搜索引擎,能夠像下面改造:

  1. 先由後端模板引擎渲染一些 HTML 片斷,僅給搜索引擎抓取,不做爲給用戶展現的頁面
  2. 而後再由客戶端渲染同步或異步的數據給用戶展現真正的頁面
<div>
  <!-- 這裏放置由後端模板引擎渲染的專給搜索引擎抓取的片斷,用戶不可見 -->
</div>

<script>
  // 接收同步數據
  window.globalData = {
    stringValue: '${stringValueTplName}',
    intValue: parseInt('${intValueTplName}', 10),
  };
</script>

3. 導出靜態 html

若是頁面沒有動態數據,那就好辦了,直接把組件導出爲靜態 html,而後由客戶端激活。

具體過程能夠參考 官方文檔

這種方案比較好的是 nuxt.js generate 靜態 HTML 文件。

目錄結構:

- pages/                # 頁面結構目錄
  - index.vue 
  - second.vue
  - ... 
- nuxt.config.js        # 配置文件
- package.json

- dist                  # 導出靜態 HTML 文件的默認目錄

導出靜態 HTML 文件

npx nuxt generate

若是一個項目裏有多個 pages,能夠這樣構建:

目錄結構:

- nuxt.config.js        # 配置文件
- package.json

- src/
  - home/               # home 頁面 
    - pages/            # 頁面結構目錄
      - index.vue 
      - second.vue
      - ...
      
    - dist              # 導出靜態 HTML 文件的默認目錄
  - about/              # about 頁面 
    - pages/            # 頁面結構目錄
      - index.vue 
      - second.vue
      - ...
      
    - dist              # 導出靜態 HTML 文件的默認目錄

導出靜態 HTML 文件

npx nuxt generate src/home -c ../../nuxt.config.js    # home 頁面
npx nuxt generate src/about -c ../../nuxt.config.js   # about 頁面

除了上面提到的這些方式外,固然還有其餘的方式,好比:

  1. 使用 Chrome Headless 模式獲取組件的靜態 HTML,參考 react-snap, puppeteer
  2. 官方 vue-server-renderer 導出靜態 HTML

4. 總結

由於模式的改變,服務器端渲染與傳統的後端模板渲染工做方式有很大的不一樣,因此在開發時須要與後端開發人員作好溝通,避免認知上的不一樣致使協做不協調。

後續

更多博客,查看 https://github.com/senntyou/blogs

做者:深予之 (@senntyou)

版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證

相關文章
相關標籤/搜索