iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
1
Modern Web

從 0 開始建一個 Static Site Generator系列 第 28

Day 28: 介紹 Vue 的 Server Side Render

雖然一開始說 Vue 因為有 Single File Component ,所以要 Server Side Render 可能會碰到需要用 bundler 的情況,不過用 React 時,在最後碰到圖片時還是非要用 hook require 的方式來解決,實際上早點用 bundler 或許也不用做到這樣,回到正題,雖然我個人是 React 派的,但 Vue 在某些方面真的做的很好,這篇也會提到

Vue 做好了什麼

這邊提到的只是就這個系列而言,我沒有要來寫一篇 React 跟 Vue 的比較文 (雖然我寫過,但那是很久以前的事了)

在 Vuex 中分離 actionmutation

還記得我們把 Redux 的 actions 全部保存下來嗎?但實際上有些只是用來觸發 AJAX 之類的非同步的工作用的 action ,並不是真的要改變資料,而在 Vuex 中, actionmutation 有明確的工作分別, mutation 才能改變資料,如果用 Vuex 就只要保存 mutation 就夠了

非同步的 vue-router

或許知道這個東西的人可能比較少, vue-router 的 middleware 是非同步的,所以 vue-router 從網址改變,到實際跳轉網頁前還可以做一些事,也可以反悔,取消掉使用者的跳轉, react-router 則是要跳轉完才可以開始動作,不知道你有沒有想到這東西可以用在哪?可以用在抓資料上,只要在 middleware 中加入抓資料的程式碼,我們也不用自己先把資料抓完才開始 render 了,只要等到 vue-router 通知我們網址已經轉過去了 (正常情況下應該是沒有機會用到 router.onReady 這個 API 吧)

SFC

這個其實有好有壞,壞處之前講過了,因為一定要編譯,所以初期會多出 bundler 要設定,不過好處是除了現有的 html, scriptstyle ,它可以加入自訂的區塊,這個功能也很少用,不過你可以看看 Gridsome ,它就用這個功能來放 page query 跟 static query ,雖然 page query 沒有這個問題,但 static query 是要用 babel 從原始碼中抽出來的,它也是正常的程式碼的一部份,要從一份原始碼中將其區格出來也是一個麻煩,雖然差別我是沒有覺得到很大

Vue 的 SSR

Vue 基本的 SSR 該說是大同小異嗎?同樣的也是 renderToStringrenderToStream,不過不一樣的是,該說 Vue 的定位真不愧是框架, html 的 template 也可以由它產生, Vuex 的初始 state 也會幫你加入產生的 html 中 (前題是如果你有提供的話)

Vue 的元件其實有個 API 叫 serverPrefetch,它會在 Server 端被執行,讓你可以在 Server 端呼叫 Vuex 的 action ,從而把資料存進去:

<script>
import {mapActions} from 'vuex'
export default {
  serverPrefetch() {
    return this.fetchData()
  },

  methods: {
    ...mapActions(['fetchData']),
  },
}
</script>

這個 API Vue 也會自動的等待它完成,所以在 Vue 中,完全不用擔心之前碰到的什麼 render 過程是同步的問題,另外 Vue 的元件上還有個屬性:

<script>
export default {
  // created 跟 beforeCreate 才會在 server 端執行,但 beforeCreate 時 Vue 的 instance 又還沒建好
  created() {
    // 這個物件會跟 render 時傳入的一個物件是同一個,所以可以用這邊傳資料回去給 render 的程式
    this.$ssrContext.foo = 42
  }
}
</script>

在 render 時 Vue 要傳入一個 object :

import { createRenderer } from 'vue-server-renderer'

const renderer = createRenderer()

// 這就會是上面的 `$ssrContext`
const context = {}
// 這樣就能取得完整的 html
const html = await renderer.renderToString(app, context)

下一篇我們再來實際用一次 Vue 的 SSG


上一篇
Day 27: Incremental build
下一篇
Day 29: 實作 Vue 的 Server Side Render
系列文
從 0 開始建一個 Static Site Generator30

尚未有邦友留言

立即登入留言