Nuxt.js服務端渲染實踐,從開發到部署

wmui發表於2017-12-04

感悟

經過幾個週六週日的嘗試,終於解決了服務端渲染中的常見問題,當SEO不在是問題的時候,或許才是我們搞前端的真正的春天,其中也遇到了一些小坑,Nuxt.js官方還是很給力的,提issue後很積極的給予幫助,再次感謝Nuxt.js的開發團隊。

路由鑑權

第一個攔路虎就是登陸時候的鑑權問題,如何把token儲存到本地。官方使用express-session解決這個問題,但是這樣做後端也需要使用nodejs,而我們公司使用的PHP。轉念一想或許cookie可以一試,於是我是這樣做的:

app.post('/api/login', function (req, res) {
  // 後臺驗證使用者資訊,並返回token
  async function login () {
    const { data } = await axiosServer.post('/login', req.body)
    return data
  }

  login().then(function (data) {
    // 把token儲存到cookie中
    const { token } = data
    if (token) {
      res.cookie('token', token, {
        maxAge: 60000 * 60 * 24
      })
    }
    // 原封不動返回
    return res.json(data)
  })
})
複製程式碼

我把登入請求用nodejs做了一次轉發,把使用者提交的資料傳給後端,後端返回的token設定到cookie裡,然後把資料返會給前端,前端再用vuex儲存token狀態,這樣token同時存在於cookie和記憶體裡,重新整理頁面也是正常的 前端儲存token:

  async nuxtServerInit ({ dispatch, commit }, { req, res }) {
    if (req.cookies && req.cookies.token) {
      // 儲存token
      commit('SET_USER', req.cookies.token)
    }
  },
  // SET_USER
  SET_USER (state, token) {
    state.token = token
  },
複製程式碼

於是這個問題就這樣解決了,所有需要儲存到本地的資料都可以這樣做來解決

渲染元件內的資料

另一個小問題是components裡資料如何渲染。在Nuxt.js中只有page裡的元件有fetchasyncData方法,所以當我們使用layout佈局頁面時如果元件需要請求資料,就無法渲染了,解決方法是在nuxtServerInit方法裡初始化元件內的資料,如下:

  async nuxtServerInit ({ dispatch, commit }, { req, res }) {
    // 初始化元件內的資料
    await dispatch('ADMIN_INFO')
    await dispatch('TAGS')
    await dispatch('ARCHIVES')
  }
複製程式碼

這樣元件內的資料也可渲染成功了

過濾器的使用

Nuxt.js的plugins設計的個人感覺還是很人性化的,用起來簡直是不能再簡單。在plugins新建一個filters.js,過濾器可以這樣玩:

import Vue from 'vue'
// 時間格式化
export function formatDate (date, fmt) {
  let newDate = new Date(date)
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (newDate.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  let o = {
    'M+': newDate.getMonth() + 1,
    'd+': newDate.getDate(),
    'h+': newDate.getHours(),
    'm+': newDate.getMinutes(),
    's+': newDate.getSeconds()
  }
  for (let k in o) {
    if (new RegExp(`(${k})`).test(fmt)) {
      let str = o[k] + ''
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str))
    }
  }
  return fmt
}
let filters = {
  formatDate
}

Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})
export default filters
複製程式碼

然後在nuxt.config.js中註冊一下:

  plugins: [
    '~plugins/filters.js'
  ]
複製程式碼

在元件中就可以這樣happy的用起來了:

<!-- 時間格式化 -->
<div>
 <span>{{date | formatDate('yyyy-MM-dd')}}</span>
</div>
複製程式碼

中介軟體

比如說使用者未登入狀態下,通過路由闖入了需要鑑權的頁面,我們可以自定義一些錯誤:

// auth.js
export default function ({ store, error }) {
// 可通過元件的props接收error資訊
  if (!store.state.token) {
    error({
      message: 'cookie失效或未登入,請登入後操作',
      statusCode: 403
    })
  }
}

複製程式碼

在元件中使用該中介軟體:

export default {
  middleware: 'auth',
  // 還可以把使用者重定位到登入頁
  fetch ({redirect, store}) {
    if (!store.state.token) {
      redirect('/login')
    }
  },
}
複製程式碼

多級路由巢狀

官方說這種情況用的較少,但是我發現用的挺多的,比如說不同分類又有不同分頁,這樣分類和分頁都要是動態路由,如圖所示:

Nuxt.js服務端渲染實踐,從開發到部署
編譯後的結果:

Nuxt.js服務端渲染實踐,從開發到部署

專案部署

大概在8月份時候,寫了幾篇關於如何部署nodejs專案的文章,回頭看寫的果然比較菜,隨著時間推移,修復了一些錯誤,發現了一些錯誤,整體寫的太亂。於是抽了一天時間,在新的伺服器上一邊實踐一邊記錄,把上面幾篇文章用gitbook彙總了一下,不在這裡展開了,太長了,增加了自動部署的相關內容

專案實踐

這個小專案是我在幾月前寫的,最近一月用Nuxt.js進行了重構,前端使用了Nuxt.js + vuex,後端使用了Nodejs + MongoDB, 用vue寫了一個markdown編輯器,支援圖片上傳和服務端渲染,效果圖:

首頁

Nuxt.js服務端渲染實踐,從開發到部署

編輯器

Nuxt.js服務端渲染實踐,從開發到部署
GitHub
gitbook

相關文章