1 引言
Nuxt 是基於 Vue 的前端開發框架,這次我們通過 Introduction toNuxtJS 視頻了解框架特色以及前端開發框架的基本要素。
nuxt 與 next 結構很像,可以結合在一起看
視頻簡介: NuxtJs 的安裝、目錄結構、頁面路由、導航模版、asyncData、meta、vueX。
這是一個入門級視頻,所以上面所列舉的特征都是一個前端開發框架的最核心的基本要素。一個前端開發框架,安裝、目錄結構、頁面路由、導航模版一定是最要下功夫認真設計的。
asyncData 和 Vuex 都在解決數據問題,meta 則是通過約定語法控制網頁 meta 屬性,這部分值得與 React 體系做對比,在精讀部分再展開。
Nuxtjs 前端開發框架不僅提供了腳手架的基本功能,還對項目結構、代碼做了約定,以減少代碼量。從這點可以看出,腳手架永遠圍繞兩個核心目標:讓每一行源碼都在描述業務邏輯;讓每個項目結構都相同且易讀。
Nuxtjs 等框架要做的就是定義支持現代大型項目的前端研發標准,這個規范具有網絡效應,即用的人越多,價值越大。
接下來我們進入正題,看看 Nuxt 腳手架定義了怎樣的開發規范。
2 概述
安裝
使用 npx create-nuxt-app app-name
創建新項目。這個命令與 create-react-app
一樣,區別主要是模版以及配置不同。
這個命令本質上是拉取一個模版到本地,並安裝 nuxt
系列腳本作為項目依賴,並自動生成一系列 npmScripts:
{ "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", "test": "jest" }, "dependencies": { "nuxt": "^2.0.0" } }
之后即可通過 npm start
等命令開發項目,對大部分項目來說,npmScripts 啟動是最能達成共識的。
這種安裝方式另一個好處是,依賴都被安裝在了本地,即開發環境 100% 內置在項目中。Nuxt 沒有采用全局 cli 命令方式執行,第一是 npmScripts 更符合大家通用習慣,不需要記住不同腳手架繁瑣的名稱與不同約定的啟動命令,第二是全局腳手架一旦進行不兼容升級,老項目就面臨維護難題。
目錄結構
├── .nuxt
├── layouts
├── pages
├── store
├── assets
├── static
├── middleware
├── plugins
├── nuxt.config.js
pages
頁面文件存放的目錄,路徑 + 文件名即路由名,關於更多約定路由的信息,在下一節頁面路由詳細說明。
layouts
模版文件存放的目錄,文件名即模版名,頁面可以通過定義模版在選擇使用的模版。
store
全局數據流目錄,在 vueX 章節介紹。
assets、static
分別存放不需被編譯的資源文件與非 .vue
的靜態文件,比如 scss 文件。
由於 .vue
文件集成了 html、js、css,因此一般不會再額外定義樣式文件在 static 文件夾中。
當然,這是 Vue 生態的特別之處,在 React 生態中會存在大量 .scss
文件混雜在各個目錄中,比較影響閱讀。
middleware、plugins
中間件與插件,這兩個目錄是可選的,作為一種定制化拓展能力。
.nuxt
為實現約定路由等便捷功能,啟動項目時需要自動生成一些文件作為真正項目入口,這些文件就存儲在 .nuxt
目錄下,gitingore 且無需手動修改。
nuxt.config.js
nuxt 使用 js 文件作為配置文件,比 json 配置文件拓展性更好一些,這個文件也是整個項目唯一的配置文件。
基本上 pages、layouts、store、assets、以及唯一的配置文件基本成為現代前端開發框架的標配。
頁面路由
nuxt 支持約定路由:
├── pages
│ ├── home.vue
│ └── index.vue
上述目錄結構描述了兩個路由:/
與 /home
。
也支持參數路由,只要以下划線作為前綴命名文件,就定義了一個動態參數路由:
├── pages
│ ├── videos
│ │ └── _id.vue
/videos/*
都會指向這個文件,且可以通過 $route.params.id
拿到這個 url 參數。
另一個特性是嵌套路由:
├── pages
│ ├── videos
│ │ └── index.vue
│ └── videos.vue
videos.vue
與 videos/index.vue
都指向 /videos
這個路由,如果這兩個文件同時存在,那么外層的 videos 就會作為外層攔截所有 /videos
文件夾下的路由,可以通過 nuxt-child
透出子元素:
# pages/videos.vue
<template>
<div>
videos
<nuxt-child />
</div>
</template>
導航模版
頁面公共邏輯,比如導航條可以放在模版里,模版的目錄在 layouts
文件夾下。
默認 layouts/default.vue
對所有頁面生效,但也可以創建例如 layouts/videos.vue
特殊導航文件,在 pages/
頁面文件通過如下申明指定使用這個模版:
<script> export default { layout: "videos" }; </script>
asyncData
asyncData
是 nuxt 支持的異步取數函數,可以替代 data
。
data
函數:
<script> export default { data() { return {}; } }; </script>
對於異步場景,可以用 asyncData
替代:
<script> export default { async asyncData() { return await fetch("/"); } }; </script>
meta
nuxt 允許在 .vue
頁面文件自定義 head 標簽信息:
<script> export default { headr() { return { title: "", meta: { charset: "utf-8" } }; } }; </script>
這是開發框架提供的特性,不過在 React 體系下可以通過 useTitle
等自定義 Hooks 解決此問題,將框架功能降維到代碼功能,會更容易理解些。
vueX
nuxt 集成了 vuex,在 store/
文件夾下創建數據模型:
export const state = () => ({ videos: [], currentVideo: {} }) export const mutations = { SET_VIDEOS (state, videos) { state.videos = videos } SET_CURRENT_VIDEO (state, video) { state.currentVideo = video } }
接下來就能在 pages
文件夾下的頁面組件使用了:
<script> import { mapState } from "vuex"; export default { async fetch({ $axios, params, store }) { const reponse = await $axios.get(`/videos/${params.id}`); const video = response.data.data.arrtibutes; store.commit("SET_CURRENT_VIDEO", video); } }; </script>
將 return
替換為 store.commit
即可,更多語法可以參考 vuex 文檔。
3 精讀
Nuxtjs 框架做了幾件事情:
- 統一執行命令。
- 統一開發框架。
- 統一目錄與代碼規范。
- 內置公共 utils 函數。
統一執行命令
命令行是所有開發者每天都要用上十幾次甚至幾十次的場景,試想一下團隊中項目分別有如下這么多不同的啟動命令會怎么樣?
- npm start.
- monkey dev.
- npm run ng.
- npm run bootstrap & banana start.
- ...
我永遠不知道下一個項目該如何啟動,這大大降低了開發效率。更嚴重的是,有的項目可以通過 npm run docs
查看文檔,有的項目不能;有的項目 npm run build
可以觸發編譯,有的項目卻無需編譯,等等,所謂的環境不一致或者說遷移成本,學習成本,都是由最開始負責搭建項目腳手架的同學對架構設計不一致導致的,然而沒有必須用 monkey dev
才能運行起來的項目,但項目卻可能因為被設計為 monkey dev
啟動而顯得與其他項目格格不入,甚至難以統一維護。
Nuxtjs 等前端開發框架統一執行命令就是為了解決這個問題,統一開發者習慣需要很長的時間周期,但這個趨勢不可擋。
統一開發框架
雖然現在 React、Vue、Angular 框架各有利弊,但如果一個團隊的項目同時使用了兩個以上的框架,沒有人會覺得這是一件好事。
誠然每個框架都有自己的特點,在不同維度都一些優勢,但三大框架能並存,說明各自都沒有絕對的殺手鐧來消滅對方。
對開源來說,多元化是活力的源動力,但對一家公司來說,多元化就是一場災難,至今沒有一個框架敢說自己的優勢是 “與其他框架混合使用可以提升整體開發效率”。
前端開發框架要解決的最重要問題也是這一點,無論如何只能選擇一種開發框架,Nuxtjs 選擇了 Vue,Nextjs 選擇了 React。
統一目錄與代碼規范
目錄和代碼規范不會從根本上影響項目的通用性,因為不同的目錄結構可以通過映射來兼容,不同的代碼規范不會影響代碼執行。所以目錄與代碼規范真正影響的是一個程序員對項目的 “解碼成本”。
所謂解碼成本,就是程序員理解項目邏輯所需要的成本。如果你是一個銷售主管,讓團隊周報統一用一種格式匯總絕對比 “用自己喜歡的方式匯總” 效率高,而對編程也一樣,一個完全不同的目錄結構和代碼規范對程序員來說是巨大的閱讀阻礙,甚至可能引發惡心反應。
所以不同的目錄結構和代碼規范是沒有必要的壁壘,除非你的團隊已經對某種規范產生達成了牢固的共識,否則最好和其他團隊共享相同的目錄結構與代碼規范。改變代碼規范是一件很難得事情,但只要不同規范的團隊間產生了長期合作關系,規范統一就勢必會被提上議程,那么為何不能在公司層面早一點達成共識,提前消除這種痛苦呢?
所以統一目錄與代碼規范是前端開發框架需要優先確定的,很多時候不要去質疑為什么目錄叫 layouts
而不叫 layout
,因為這個規范背后形成的協同網絡規模越大,叫什么名字就越不重要。
內置公共 utils 函數
讓業務開發更聚焦,還可以通過抽取通用的邏輯的方式解決,但需要解決兩個問題:
- 雖然將公共函數抽成 npm 包可以解決代碼復用問題,但關鍵是怎么保證你的代碼能被別人復用?
- 如何讓業務通用的 utils 代碼有效沉淀並從項目中移除?
腳手架內置公共 utils 函數就為了解決這個問題。上面幾個小節解決了通用命令、框架、規范,但實際代碼中,router
history
fetch
store
等等概念也都是可以統一的,沒有一個項目必須用定制的 fetch
函數才能取數,但一開始就定制了 fetch
會導致耦合了不可預期的、沒有必要的業務邏輯,成為理解與提效的阻礙。
所以統一這些能統一的包,是進一步提效的關鍵。也許有人會覺得斷了自己造輪子的路,但就像我們如今都不會重寫瀏覽器內核邏輯一樣,穩定的邏輯不僅帶來了全行業的提效,還催生了前端崗位帶來大量的就業,同樣的,統一底層通用函數,其實是斷了無意義產出這條路,每個人都有追求更高價值事情的權利,不要把自己困在反復造 fetch
函數這個低水平的活里。
4 總結
如果一個項目沒有使用類似 Nuxtjs 開發框架,它面臨的不僅僅是技術選型不統一的問題,久而久之這種項目勢必成為 代碼孤島,當塵封在代碼倉庫幾年后,一系列文檔工具鏈接都失效后,就成為誰也不想碰,不敢碰的高危代碼。
參考資料: 掘金技術帖子
歡迎關注公眾號,進一步技術交流: