Nuxt.js是一個基于Vue.js的通用應用架構, 它預設了服務端渲染(SSR, Server Side Render)應用所需要的相關配置, 同時也支持生成靜態站點.
1. 背景 & Nuxt簡介
Nuxt
其一目的是為了解決單頁面應用的SEO
問題, 相比于我們平常的SPA
頁面. 在搜索引擎中由于無法從網頁中被抓取內容信息(SPA頁面的信息都是被打包到JS文件中,動態加載到頁面中), 從而無法被用戶所搜索到.
其二是服務端渲染相比于SPA頁面渲染,在網絡環境較差或者客戶端運行在沒有JavaScript的引擎上, 這時基于SSR渲染
的頁面能更好的展現原有的頁面的內容,而單頁面應用可能就會有很長的空白時間, 從而影響到用戶的體驗.
2. Nuxt應用架構
- 客戶端向服務器請求數據
- 服務器端獲取數據從API服務器
- 服務端返回完整HTML頁面給客戶端
- 客戶端頁面渲染使用SPA
- 客戶端直接請求API服務器
3. 項目創建
為了更加方便快速的創建項目, Nuxt.js 團隊提供了一個腳手架工具 create-nuxt-app.確保你已經安裝 npx
(npx 已經被內置自 NPM 5.2.0)
$ npx create-nuxt-app <project-name>
它會讓你進行一些選擇:
- 在集成的服務器端框架之間進行選擇:
- None(默認服務器)
- Express
- Koa
- Hapi
- Feathers
- Micro
- Adonis
- 選擇您喜歡的UI框架:
- None
- Bootstrap
- Vuetify
- Bulma
- Tailwind
- Element UI
- Ant Design Vue
- Buefy
- 選擇你想要的Nuxt模式(universal or SPA)
- 選擇axios module
- 選擇 Eslint
- 選擇 Prettier
當運行完成時,它將安裝所有依賴項,完成后啟動項目:
$ npm run dev
應用現在會運行在 http://localhost:3000
4. 項目開發
4.1 目錄結構
- api: api接口
- assets:靜態資源
- components:組件
- layouts: 布局目錄
- logs: 日志
- middleware:中間件
- pages: 頁面目錄
- plugins:插件
- nuxt.config.js: nuxt 配置文件
4.2 配置
Nuxt.js默認的配置涵蓋了大部分的使用情形, 也可以通過修改 nuxt.config.js
來進行自定義配置.
- plugins: 全局引入的插件
- css: 全局引入的css, scss 等
- head: 可以設置pages的頭部信息, 如titile, meta信息等
- loading:頁面切換的時候加載組件顯示的進度條
- build: 自定義webpack的構建配置
- env: 配置客戶端和服務端共享的環境變量
- cache:是否允許緩存
- router:自定義配置vue-router的信息
4.3 路由
Nuxt.js 會根據
pages
的目錄結構, 自動生成vue-router
模塊的路由配置. 如上圖, 會生成 /dashboard/h5/:h5
, /dashboard/mws/:mws
, ...可以看出路徑根據目錄結構自動生成了, 動態路徑需要在名字前添加下劃線( _ )
4.4 布局
上圖是Nuxt.js的布局架構. 最外層依舊是Document
, 往里一層是一個layout
層,在 Nuxt里面對應目錄中的layouts文件夾,默認的pages下的頁面都會套用 layouts/default.vue
的布局樣式. 其中 <nuxt/> 相當于Vue
中的 slot
插槽的概念,
pages/**.vue的內容都會被填入<nuxt/>,其他的內容嵌套和平時的Vue單頁面應用開發是一樣的.
4.5 Vuex
在根目錄創建 store 目錄,就會默認引用 vuex 模塊,除此之外,還進行了以下的操作:1)將 vuex 模塊 加到 vendors 構建配置中去;2)設置 Vue 根實例的 store 配置項.
Nuxt.js 支持兩種使用 store 的方式:
- 普通方式:
store/index.js
返回一個Vuex.Store
實例 - 模塊方式:store 目錄下的每個 .js 文件會被轉換成為狀態樹指定命名的子模塊 (當然,index 是根模塊,相當于設置了namespaced: true)
Nuxt.js提供了模塊方式的簡單寫法:使用狀態樹模塊化的方式,store/index.js 不需要返回 Vuex.Store
實例,直接將 state
、mutations
和 actions
暴露出來即可。示例如下:
export const state = () => ({
accesstoken: ''
})
export const mutations = {
setAccesstoken (state, accesstoken) {
state.accesstoken = accesstoken
}
}
4.6 異步數據 asyncData
Nuxt.js 增加了一個 asyncData
方法,用于 在設置組件數據 之前 能夠異步獲取 或 處理數據。
由于asyncData
是在組件 初始化 之前被調用的,所以不能通過 this
引用組件的實例對象,可以使用上下文對象來實現某些功能,具體的上下文context
4.7 fetch 方法
與 asyncData
方法類似,不同的是它不會設置組件的數據,作用是設置store
數據。
5. Nuxt 渲染流程
上圖是nuxt整個的渲染流程,在render
之前的幾個階段, 都可以拿到context
去做一些相應操作.
-
nuxtServerInit
是Nuxt.js在服務端初始化的時候定義在store中.這個對我們想要直接傳遞值給服務端非常有用,比如session, user. -
middleware
是一個自定義的方法,在每次渲染頁面之前被調用.它可以注冊到全局下(nuxt.config.js
)也可以注冊在單個頁面或框架上. -
validate
允許在動態路由組件中定義一個過濾器方法. -
asyncDate,fetch
asyncData可以讓我們在頁面繪制前調用方法獲取需要的數據源;第一次時在服務端會被調用,之后客戶端也會在頁面之前被調用.fetch
和asyncData
非常相似,區別只在于fetch
只會用來改變store
的狀態,不能填充數據. *需要的一點.如果在方法中調用this
會報錯.因為asyncData & fetch
在服務端會被調用所以this
的當前組件并沒有實例化 -
Render
被渲染
6. 一些遇到的坑
-
Window 或 Document 對象未定義?
這是因為一些只兼容客戶端的腳本被打包進了服務端的執行腳本中去。 對于只適合在客戶端運行的腳本,需要通過使用 process.browser 變量來判斷導入.
-
服務端渲染v-for 列表
當頁面有列表內容在客戶端渲染,刷新頁面服務端會重復渲染列表結構,生成兩份. 需要用
<no-ssr/>
組件進行設置,從而不在無武器渲染中呈現