精讀《Nuxtjs》

黃子毅發表於2019-10-28

1 引言

Nuxt 是基於 Vue 的前端開發框架,這次我們通過 Introduction toNuxtJS 視訊瞭解框架特色以及前端開發框架的基本要素。

nuxt 與 next 結構很像,可以結合在一起看

視訊介紹了 NuxtJs 的安裝、目錄結構、頁面路由、導航模版、asyncData、meta、vueX。

這是一個入門級視訊,所以上面所列舉的特徵都是一個前端開發框架的最核心的基本要素。一個前端開發框架,安裝、目錄結構、頁面路由、導航模版一定是最要下功夫認真設計的。

asyncData 和 Vuex 都在解決資料問題,meta 則是通過約定語法控制網頁 meta 屬性,這部分值得與 React 體系做對比,在精讀部分再展開。

Nuxtjs 前端開發框架不僅提供了腳手架的基本功能,還對專案結構、程式碼做了約定,以減少程式碼量。從這點可以看出,腳手架永遠圍繞兩個核心目標:讓每一行原始碼都在描述業務邏輯;讓每個專案結構都相同且易讀

20 年前,幾百行 HTML、Css、Js 程式碼就能完成一個完整的專案,只需要遵守 W3C 的基本規範就足夠了,每一個專案程式碼都簡單清晰,而且由於沒有複雜的業務邏輯,導致程式碼結構也非常簡單。但現在前端專案複雜度逐漸升高,一個大型專案原始碼數量可能達到幾十萬行、幾百萬行,這是 W3C 規範沒有設想到的,因此出現了各種工程化與模組化方案解決這個複雜度問題,也引發了各個框架間約定的割裂,且設計合理程度各不相同。

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 章節介紹。

assetsstatic

分別存放不需被編譯的資原始檔與非 .vue 的靜態檔案,比如 scss 檔案。

由於 .vue 檔案整合了 html、js、css,因此一般不會再額外定義樣式檔案在 static 資料夾中。

當然,這是 Vue 生態的特別之處,在 React 生態中會存在大量 .scss 檔案混雜在各個目錄中,比較影響閱讀。

middlewareplugins

中介軟體與外掛,這兩個目錄是可選的,作為一種定製化擴充能力。

.nuxt

為實現約定路由等便捷功能,啟動專案時需要自動生成一些檔案作為真正專案入口,這些檔案就儲存在 .nuxt 目錄下,gitingore 且無需手動修改。

nuxt.config.js

nuxt 使用 js 檔案作為配置檔案,比 json 配置檔案擴充性更好一些,這個檔案也是整個專案唯一的配置檔案。

基本上 pageslayoutsstoreassets、以及唯一的配置檔案基本成為現代前端開發框架的標配。

頁面路由

nuxt 支援約定路由:

├── pages
│   ├── home.vue
│   └── index.vue
複製程式碼

上述目錄結構描述了兩個路由://home

也支援引數路由,只要以下劃線作為字首命名檔案,就定義了一個動態引數路由:

├── pages
│   ├── videos
│   │   └── _id.vue
複製程式碼

/videos/* 都會指向這個檔案,且可以通過 $route.params.id 拿到這個 url 引數。

另一個特性是巢狀路由:

├── pages
│   ├── videos
│   │   └── index.vue
│   └── videos.vue
複製程式碼

videos.vuevideos/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 框架做了幾件事情:

  1. 統一執行命令。
  2. 統一開發框架。
  3. 統一目錄與程式碼規範。
  4. 內建公共 utils 函式。

統一執行命令

命令列是所有開發者每天都要用上十幾次甚至幾十次的場景,試想一下團隊中專案分別有如下這麼多不同的啟動命令會怎麼樣?

  1. npm start.
  2. monkey dev.
  3. npm run ng.
  4. npm run bootstrap & banana start.
  5. ...

我永遠不知道下一個專案該如何啟動,這大大降低了開發效率。更嚴重的是,有的專案可以通過 npm run docs 檢視文件,有的專案不能;有的專案 npm run build 可以觸發編譯,有的專案卻無需編譯,等等,所謂的環境不一致或者說遷移成本,學習成本,都是由最開始負責搭建專案腳手架的同學對架構設計不一致導致的,然而沒有必須用 monkey dev 才能執行起來的專案,但專案卻可能因為被設計為 monkey dev 啟動而顯得與其他專案格格不入,甚至難以統一維護。

Nuxtjs 等前端開發框架統一執行命令就是為了解決這個問題,統一開發者習慣需要很長的時間週期,但這個趨勢不可擋。

統一開發框架

雖然現在 React、Vue、Angular 框架各有利弊,但如果一個團隊的專案同時使用了兩個以上的框架,沒有人會覺得這是一件好事。

誠然每個框架都有自己的特點,在不同維度都一些優勢,但三大框架能並存,說明各自都沒有絕對的殺手鐗來消滅對方。

對開源來說,多元化是活力的源動力,但對一家公司來說,多元化就是一場災難,至今沒有一個框架敢說自己的優勢是 “與其他框架混合使用可以提升整體開發效率”。

前端開發框架要解決的最重要問題也是這一點,無論如何只能選擇一種開發框架,Nuxtjs 選擇了 Vue,Nextjs 選擇了 React。

統一目錄與程式碼規範

目錄和程式碼規範不會從根本上影響專案的通用性,因為不同的目錄結構可以通過對映來相容,不同的程式碼規範不會影響程式碼執行。所以目錄與程式碼規範真正影響的是一個程式設計師對專案的 “解碼成本”。

所謂解碼成本,就是程式設計師理解專案邏輯所需要的成本。如果你是一個銷售主管,讓團隊週報統一用一種格式彙總絕對比 “用自己喜歡的方式彙總” 效率高,而對程式設計也一樣,一個完全不同的目錄結構和程式碼規範對程式設計師來說是巨大的閱讀阻礙,甚至可能引發噁心反應。

所以不同的目錄結構和程式碼規範是沒有必要的壁壘,除非你的團隊已經對某種規範產生達成了牢固的共識,否則最好和其他團隊共享相同的目錄結構與程式碼規範。改變程式碼規範是一件很難得事情,但只要不同規範的團隊間產生了長期合作關係,規範統一就勢必會被提上議程,那麼為何不能在公司層面早一點達成共識,提前消除這種痛苦呢?

所以統一目錄與程式碼規範是前端開發框架需要優先確定的,很多時候不要去質疑為什麼目錄叫 layouts 而不叫 layout,因為這個規範背後形成的協同網路規模越大,叫什麼名字就越不重要。

內建公共 utils 函式

讓業務開發更聚焦,還可以通過抽取通用的邏輯的方式解決,但需要解決兩個問題:

  1. 雖然將公共函式抽成 npm 包可以解決程式碼複用問題,但關鍵是怎麼保證你的程式碼能被別人複用?
  2. 如何讓業務通用的 utils 程式碼有效沉澱並從專案中移除?

腳手架內建公共 utils 函式就為了解決這個問題。上面幾個小節解決了通用命令、框架、規範,但實際程式碼中,router history fetch store 等等概念也都是可以統一的,沒有一個專案必須用定製的 fetch 函式才能取數,但一開始就定製了 fetch 會導致耦合了不可預期的、沒有必要的業務邏輯,成為理解與提效的阻礙。

所以統一這些能統一的包,是進一步提效的關鍵。也許有人會覺得斷了自己造輪子的路,但就像我們如今都不會重寫瀏覽器核心邏輯一樣,穩定的邏輯不僅帶來了全行業的提效,還催生了前端崗位帶來大量的就業,同樣的,統一底層通用函式,其實是斷了無意義產出這條路,每個人都有追求更高價值事情的權利,不要把自己困在反覆造 fetch 函式這個低水平的活裡。

4 總結

如果一個專案沒有使用類似 Nuxtjs 開發框架,它面臨的不僅僅是技術選型不統一的問題,久而久之這種專案勢必成為 程式碼孤島,當塵封在程式碼倉庫幾年後,一系列文件工具連結都失效後,就成為誰也不想碰,不敢碰的高危程式碼。

所以我們今天不僅要看到 Nuxtjs 提供的能力對專案開發有多麼便捷,更要看到這類框架帶來的協同效應有多麼巨大,如果它不能成為整個前端的標準,至少要成為你們公司,或者你們團隊的標準。

討論地址是:精讀《Nuxtjs》 · Issue #213 · dt-fe/weekly

如果你想參與討論,請 點選這裡,每週都有新的主題,週末或週一釋出。前端精讀 - 幫你篩選靠譜的內容。

關注 前端精讀微信公眾號

精讀《Nuxtjs》

版權宣告:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證

相關文章