【譯】構建Vue大型應用的10個最佳實踐

這些是我構建大型Vue項目得出的最佳實踐,這些技巧將幫助你更高效的編碼,而且使其更容易維護和協做。

在我今年的自由職業生涯中我有幸開發了一些大型Vue程序。我所說的這些項目使用了大量Vuex stores 😰 ,不少Vue組件(有數百個)和不少視圖(pages)😄。對我而言這是很是有意義的經歷,我發現了不少使擴展的方法。同時我還須要修復一些亂七八糟的錯誤用法。🍝javascript

因此我將分享個人10個最佳實踐,若是你有大型項目須要開發推薦你使用他們。html

1. 使用Slots可使你的組件更強大和便於理解。

最近我寫了一篇文章some important things you need to know regarding slots in Vue.js。 主要講了爲何使用Slots能夠提升組件複用且易於維護。vue

🧐 可是這和大型Vue項目有啥關係呢。我將描繪一個使用他們解決你痛點的藍圖。java

假如我要開發一個popup。起初看起來沒有什麼難點,僅僅是包括標題,描述和一些按鈕。 因此把全部東西都看成props不就完了嗎。 我用了三個自定義props,而且click按鈕的時候觸發一個事件。 就是這麼簡單! 😅ios

隨着項目的不斷髮展,業務須要顯示許多其餘新內容:表單字段,不一樣的按鈕(取決於顯示在哪一個頁面上)、卡片、頁腳和列表。經過添加更多的props能夠解決這個問題。😩可是隨着業務發展,組件變的太複雜了。由於他包含了不少子組件,須要觸發不少個事件。🌋我遇到了坑爹的問題,修改了一個功能後影響了其餘page上的功能。我創造了一個怪物而不是一個可維護的組件!🤖git

可是,一開始使用slots可能會更好。最終我使小組件來重構這個組件。使他更容易維護、好理解、好擴展。github

<template>
  <div class="c-base-popup">
    <div v-if="$slot.header" class="c-base-popup__header">
      <slot name="header">
    </div>
    <div v-if="$slot.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="$slot.actions" class="c-base-popup__actions">
      <slot name="actions">
    </div>
    <div v-if="$slot.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>

根據經驗在我看來,由熟練使用slots的開發人員構建項目對未來項目的可維護性有更重要的意義。vuex

⚠️ 經驗規則,當子組件中使用了父組件的props時,應該使用slots。

2.好好組織的你Vuex store

一般,一個新的Vue開發人員學習Vuex是由於兩個問題:npm

  • 當一個組件須要重一個比較遠的組件(嵌套層級或者兄弟組件:譯者注)訪問數據時。
  • 須要持有一個銷燬組件的數據時。

這樣他建立第一個Vuex store,學習moudles的用法而且組織程序時。💡
問題是建立modules時沒有單一模式可循。我強烈建議必定要想清楚如何組織他們。據我所知,不少人更喜歡按照功能來組織他們(我也是:譯者注)。例如:json

  • Auth.
  • Blog.
  • Inbox.
  • Settings.

就我來講,用從API得到的數據模型組織更容易理解。例子:

  • Users
  • Teams
  • Messages
  • Widgets
  • Articles

用那個取決於本身,可是從長遠來看組織良好的Vuex store更具生產力。這樣也容易是新人融入而且繼承你的初衷。

3.用Actions調用api和提交數據。

個人大部分(不是所有)API調用都在Vuex的actions中,你必定想知道爲何這樣作。🤨

🤷🏼‍簡單的說是由於拉取數據時須要在store中commit。還有就是他提供了我喜歡的封裝和複用。其餘緣由就是:

  • 若是我在兩個地方(blog和home page)獲取第一個頁面的數據。我只需使用不一樣的參數調用便可獲得數據,初次以外沒有重複的代碼被調用。
  • 若是須要建立一些邏輯來避免重複拉取數據,只須要在一個地方拉取一次。除了給服務器減負之外,我還能夠在任何地方使用這些數據。
  • 我能夠在actions中最終Mixpanel事件,基於維護性使問題變的容易分析。個人代碼中大部分action中只有一個Mixpanel調用,😂我沒必要關注數據和發送這種工做方式太爽了。

4.使用mapState、mapGetters、mapMutations和mapAction精簡代碼。

當你在組件中訪問state/getters或者調用actions/mutations時一般須要建立多個計算屬性。使用mapState,mapGetters,mapMutations和mapActions能夠未來自store modules中的數據集中在一個地方,這樣能夠精簡代碼而且更好理解。

// 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"])
  }
};

你想要的這裏都有Vuex官方文檔。🤩

5. 快使用API Factories

我一般會建立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);
};
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);
  }
});

這樣我能夠方便的在組件或Vuex操做中調用他們,以下:

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

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);
}

7.遵照一個commit命名規則。

在項目發展的過程當中,常常須要關注組件的變動歷史。若是團隊中有人沒有遵照commit慣例,那麼將很難理解他們所作的事情。

我老是使用並推薦Angular commit message guidelines。我全部的項目中都會使用他,一般團隊中的其餘人也會發現他的好處。

遵照這些規則使commit更加可讀,在查看項目歷史時使得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 file更新更多。

8.始終在生產環境中凍結Package的版本。

我知道...全部軟件包都應遵循 the semantic versioning rules.。但實際狀況並不是如此。😅

爲了不一個依賴影響了整個項目在半夜被拖起來,凍結全部程序包的版本可使你一覺睡到天明而且工做愉快。 😇

這很簡單:避免以^開頭的版本:

{
  "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>

10.追蹤第三方程序包的大小

多人合做一個項目時,若是沒人關注安裝的依賴包數量很快變的難以置信。爲了不程序變慢(尤爲是在移動網絡環境),我這VSC中使用import cost package這樣就能夠編輯器中看到導入的包有多大,而且找出大的緣由。

例如在最近的項目中,導入了整個lodash庫(壓縮後24kB)。 有啥子問題? 僅僅使用cloneDeep方法。 經過import cost package找到了問題,咱們經過如下方式解決了該問題:

npm remove lodash
npm install lodash.clonedeep

在使用的地方導入:

import cloneDeep from "lodash.clonedeep";
⚠️ 爲了進一步優化,咱們還可使用Webpack Bundle Analyzer包經過樹狀圖來可視化Webpack輸出文件的大小。

在大型Vue項目中還有其餘最佳實踐嗎? 請在下面的評論中告訴我,或者在Twitter @RifkiNada上與我聯繫。 🤠


相關文章
相關標籤/搜索