建立和維護大型Vue.js專案的10個最佳實踐

Yujiaao 發表於 2021-09-27
Vue

這是我在使用大型程式碼庫進行 Vue 專案時開發的最佳實踐。這些技巧將幫助您開發更有效的程式碼,更易於維護和共享。

今年的自由職業生涯中,我有機會從事一些大型Vue應用程式的工作。我所談論的專案有超過12個Vuex 儲存,大量元件(有時數百個)和許多檢視(頁面)。實際上,這對我來說是非常有意義的經歷,因為我發現了許多有趣的模式來使程式碼可擴充套件。我還必須修復一些導致著名的義大利麵條程式碼難題的錯誤做法。🍝

因此,今天,我將與您分享10個最佳實踐,如果您要處理大量的程式碼庫,我建議您遵循這些最佳實踐。♀️

1.使用插槽(slot)使元件更易於理解並且功能更強大

我最近寫了一篇文章,介紹有關Vue.js中的插槽您需要了解的一些重要事項。它著重說明插槽如何使您的元件更可重用且更易於維護,以及為什麼要使用它們。

🧐但是,這與大型Vue.js專案有什麼關係?一圖勝千言,所以我將為您畫一張圖片,這是我第一次後悔不使用它們。

有一天,我只需要建立一個彈出視窗。乍一看,沒有什麼真正複雜的,只是包括標題,描述和一些按鈕。所以我要做的就是把所有東西都當作屬性。最後,我用了三個屬性來定製元件,當人們單擊按鈕時會發出一個事件。十分簡單!😅

但是,隨著專案的不斷髮展,團隊要求我們在其中顯示許多其他新內容:表單欄位,不同的按鈕(取決於顯示在哪個頁面上),卡片,頁尾和列表。我發現,如果我繼續使用屬性來使這個元件不斷擴充套件,似乎也可以。但是上帝,😩我錯了!該元件很快變得太複雜了,以至於無法理解,因為它包含了無數的子元件,使用了太多的屬性併發出了大量事件。🌋我經歷了一種可怕的情況,當您在某處進行更改時,它最終以某種方式破壞了另一頁上的其他內容。我搞了個科學怪人的怪物,而不是一個可維護的元件!🤖

但是,如果我從一開始就依賴插槽,情況可能會更好。最後,我重構了所有東西以提供這個小元件。易於維護,更快地理解並且可擴充套件性更高!

<template>
  <div class="c-base-popup">
    <div v-if="$slots.header" class="c-base-popup__header">
      <slot name="header">
    </div>
    <div v-if="$slots.subheader" class="c-base-popup__subheader">
      <slot name="subheader">
    </div>
    <div class="c-base-popup__body">
      <h1>{{ title }}</h1>
      <p v-if="description">{{ description }}</p>
    </div>
    <div v-if="$slots.actions" class="c-base-popup__actions">
      <slot name="actions">
    </div>
    <div v-if="$slots.footer" class="c-base-popup__footer">
      <slot name="footer">
    </div>
  </div>
</template>
<script> export default {
  props: {
    description: {
      type: String,
      default: null
    },
    title: {
      type: String,
      required: true
    }
  }
} </script> 

我的觀點是,根據經驗,由知道何時使用插槽的開發人員構建的專案確實對其未來的可維護性有很大的影響。這樣就可以減少發出事件的次數,使程式碼更易於理解,並且可以在內部顯示所需的任何元件時提供更大的靈活性。

⚠️作為一個經驗法則,請記住,當最終在子元件的父元件中複製子元件的屬性時,應該從這一點開始使用插槽。

2.正確組織您的 Vuex 儲存

通常,新的 Vue.js 開發人員開始學習 Vuex,因為他們偶然發現了以下兩個問題:

  • 他們要麼需要從樹結構中實際上相距太遠的另一個元件訪問給定元件的資料,要麼
  • 他們需要資料在元件銷燬後繼續存在。

那是他們建立第一個 Vuex 儲存,瞭解模組並開始在應用程式中進行組織的時候。💡

問題是建立模組時沒有單一模式可以遵循。但是,👆🏼我強烈建議您考慮如何組織它們。據我瞭解,大多數開發人員都喜歡按功能組織它們。例如:

  • 驗證碼
  • 部落格
  • 收件箱
  • 設定

就我而言,我發現根據它們從API提取的資料模型來組織它們時更容易理解。例如:

  • 使用者數
  • 隊伍
  • 留言內容
  • 小部件
  • 文章

您選擇哪一個取決於您。唯一要記住的是,從長遠來看,組織良好的 Vuex 儲存將使團隊更具生產力。這也將使新來者更容易在加入您的團隊時就將您的想法圍繞您的程式碼庫。

3.使用操作(Vuex Actions)進行 API 呼叫和提交資料

我的大多數API呼叫(如果不是全部)都在我的 Vuex 操作(vuex actions)中進行。您可能想知道:為什麼這裡呼叫更好?🤨

僅僅因為它們中的大多數都提取了我需要在儲存(vuex store)中提交的資料。此外,它們提供了我真正喜歡的封裝性和可重用性。我這樣做還有其他一些原因:

  • 如果我需要在兩個不同的地方(例如部落格和首頁)獲取文章的首頁,則可以使用正確的引數呼叫適當的排程程式。資料將被提取,提交和返回,除了排程程式呼叫外,沒有重複的程式碼。
  • 如果我需要建立一些邏輯來避免在提取第一頁時提取它,則可以在一個地方進行。除了減少伺服器上的負載之外,我還有信心它可以在任何地方使用。
  • 我可以在這些操作(vuex actions)中跟蹤我的大多數 Mixpanel 事件,從而使分析程式碼庫真正易於維護。我確實有一些應用程式,其中所有 Mixpanel 呼叫都是在操作中單獨進行的。當我不必瞭解跟蹤什麼不跟蹤什麼以及何時傳送時,😂這種方式工作會給我帶來有多大的快樂。
譯註: Mixpanel 是一家資料跟蹤和分析公司,允許開發者跟蹤各種使用者行為,比如使用者瀏覽的頁面數,iPhone 應用分析,Facebook 應用互動情況,以及 Email 分析。類似Firebase一樣的埋點分析工具。

4.使用 mapState,mapGetters,mapMutations 和 mapAction 簡化程式碼庫

當您只需要訪問state/getter或在元件內部呼叫action/mutation時,通常無需建立多個計算屬性或方法。使用mapStatemapGettersmapMutationsmapActions可以幫助你縮短你的程式碼,通過分組來化繁為簡,從你儲存裡模組一個地方就能掌握全域性。

// NPM
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {
  computed: {
    // Accessing root properties
    ...mapState("my_module", ["property"]),
    // Accessing getters
    ...mapGetters("my_module", ["property"]),
    // Accessing non-root properties
    ...mapState("my_module", {
      property: state => state.object.nested.property
    })
  },
  methods: {
    // Accessing actions
    ...mapActions("my_module", ["myAction"]),
    // Accessing mutations
    ...mapMutations("my_module", ["myMutation"])
  }
}; 

的JavaScript

Vuex官方文件中提供了您在這些便捷幫助器上所需的所有資訊。🤩

5.使用 API 工廠

我通常喜歡建立一個this.$api可以在任何地方呼叫以獲取API端點的助手。在專案的根目錄下,我有一個api包含所有類的資料夾(請參閱下面的其中一個)。

api
├── auth.js
├── notifications.js
└── teams.js 

每個節點都將其類別的所有端點分組。這是我在 Nuxt 應用程式中使用外掛初始化此模式的方式(這與標準 Vue 應用程式中的過程非常相似)。

// PROJECT: API
import Auth from "@/api/auth";
import Teams from "@/api/teams";
import Notifications from "@/api/notifications";
export default (context, inject) => {
  if (process.client) {
    const token = localStorage.getItem("token");
    // Set token when defined
    if (token) {
      context.$axios.setToken(token, "Bearer");
    }
  }
  // Initialize API repositories
  const repositories = {
    auth: Auth(context.$axios),
    teams: Teams(context.$axios),
    notifications: Notifications(context.$axios)
  };
  inject("api", repositories);
}; 

的JavaScript

export default $axios => ({
  forgotPassword(email) {
    return $axios.$post("/auth/password/forgot", { email });
  },
  login(email, password) {
    return $axios.$post("/auth/login", { email, password });
  },
  logout() {
    return $axios.$get("/auth/logout");
  },
  register(payload) {
    return $axios.$post("/auth/register", payload);
  }
}); 

的JavaScript

現在,我可以簡單地在我的元件或 Vuex 操作中呼叫它們,如下所示:

export default {
  methods: {
    onSubmit() {
      try {
        this.$api.auth.login(this.email, this.password);
      } catch (error) {
        console.error(error);
      }
    }
  }
}; 

的JavaScript

6.使用 $config 訪問您的環境變數(在模板中特別有用)

您的專案可能在某些檔案中定義了一些全域性配置變數:

config
├── development.json
└── production.json 

我喜歡通過this.$config助手快速訪問它們,尤其是當我在模板中時。與往常一樣,擴充套件Vue物件非常容易:

// NPM
import Vue from "vue";
// PROJECT: COMMONS
import development from "@/config/development.json";
import production from "@/config/production.json";
if (process.env.NODE_ENV === "production") {
  Vue.prototype.$config = Object.freeze(production);
} else {
  Vue.prototype.$config = Object.freeze(development);
} 

的JavaScript

7.遵循一個約定來寫提交註釋

隨著專案的發展,您將需要定期瀏覽元件的提交歷史記錄。如果您的團隊沒有遵循相同的約定來書寫他們的提交說明,那麼將很難理解每個團隊成員的行為。

我總是使用並推薦Angular commit訊息準則。在我從事的每個專案中,我都會遵循它,在許多情況下,其他團隊成員也會很快發現遵循它也更好。

遵循這些準則會導致更具可讀性的訊息,從而在檢視專案歷史記錄時更易於跟蹤提交。簡而言之,這是它的工作方式:

git commit -am "<type>(<scope>): <subject>"
# Here are some samples
git commit -am "docs(changelog): update changelog to beta.5"
git commit -am "fix(release): need to depend on latest rxjs and zone.js" 

看看他們的README檔案以瞭解更多約定。

8.始終在生產專案時凍結軟體包的版本

我知道...所有軟體包都應遵循語義版本控制規則。但實際情況是,其中一些並非如此。😅

為避免因您的一個依賴項在半夜醒來破壞了整個專案,鎖定所有軟體包的版本會使您的早晨工作壓力減輕。😇

它的意思很簡單:避免使用以^開頭的版本:

{
  "name": "my project",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "axios": "0.19.0",
    "imagemin-mozjpeg": "8.0.0",
    "imagemin-pngquant": "8.0.0",
    "imagemin-svgo": "7.0.0",
    "nuxt": "2.8.1",
  },
  "devDependencies": {
    "autoprefixer": "9.6.1",
    "babel-eslint": "10.0.2",
    "eslint": "6.1.0",
    "eslint-friendly-formatter": "4.0.1",
    "eslint-loader": "2.2.1",
    "eslint-plugin-vue": "5.2.3"
  }
} 

9.顯示大量資料時使用 Vue 虛擬滾動條

當您需要在給定頁面中顯示很多行或需要迴圈訪問大量資料時,您可能已經注意到該頁面的呈現速度很快。要解決此問題,可以使用vue-virtual-scoller

npm install vue-virtual-scroller 

它將僅渲染列表中的可見項,並重用元件和dom元素,以使其儘可能高效。它真的很容易使用,順滑得很!✨

<template>
  <RecycleScroller
    class="scroller"
    :items="list"
    :item-size="32"
    key-field="id"
    v-slot="{ item }"
  >
    <div class="user">
      {{ item.name }}
    </div>
  </RecycleScroller>
</template> 

的HTML

10.跟蹤第三方程式包的大小

當很多人在同一個專案中工作時,如果沒有人關注它們,那麼已安裝軟體包的數量會迅速增加,令人難以置信。為了避免您的應用程式變慢(尤其是在行動網路變慢的情況下),我在Visual Studio Code中使用了匯入費用包。這樣,我可以從編輯器中直接看到匯入的模組庫有多大,並且可以檢視匯入的模組庫過大時出了什麼問題。

例如,在最近的專案中,匯入了整個 lodash 庫(壓縮後大約24kB)。問題在於,專案裡僅僅使用cloneDeep 一個方法。通過在匯入費用包中識別此問題後,我們通過以下方式解決了該問題:

npm remove lodash
npm install lodash.clonedeep 

然後可以在需要的地方匯入clonedeep函式:

import cloneDeep from "lodash.clonedeep"; 

的JavaScript

為了進一步優化,您還可以使用Webpack Bundle Analyzer軟體包通過互動式可縮放樹狀圖來視覺化Webpack輸出檔案的大小。

處理大型Vue程式碼庫時,您還有其他最佳實踐嗎?請在下面的評論中告訴我,或者在Twitter @RifkiNada上與我聯絡。🤠

關於作者

娜達·裡基(Nada Rifki)

 title=

Nada 是一位 JavaScript 開發人員,他喜歡使用 UI 元件來建立具有出色 UX 的介面。她專門研究 Vue.js,喜歡分享任何可以幫助她的前端 Web 開發人員的東西。Nada還涉足數字營銷,舞蹈和中文領域。