感悟
經過幾個周六周日的嘗試,終於解決了服務端渲染中的常見問題,當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里的組件有fetch
和asyncData
方法,所以當我們使用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')
}
},
}
多級路由嵌套
官方說這種情況用的較少,但是我發現用的挺多的,比如說不同分類又有不同分頁,這樣分類和分頁都要是動態路由,如圖所示:
編譯后的結果:
項目部署
大概在8月份時候,寫了幾篇關於如何部署nodejs項目的文章,回頭看寫的果然比較菜,隨着時間推移,修復了一些錯誤,發現了一些錯誤,整體寫的太亂。於是抽了一天時間,在新的服務器上一邊實踐一邊記錄,把上面幾篇文章用gitbook匯總了一下,不在這里展開了,太長了,增加了自動部署的相關內容
結語
以上所有的實踐代碼都在這里,這個小項目是我在幾月前寫的,后來用Nuxt.js進行了重構!