我來教你如何組織 Vue 項目
介紹
在啟動 Vue 項目時,思考項目結構至關重要。主要考慮因素是預期項目的規模。在本篇博文中,我將探討適用于不同規模 Vue 項目的各種結構。這個考慮與康威定律相吻合:
"設計系統的組織受限于產生這些組織溝通結構的設計。" - 梅爾·康威
基本上,康威定律暗示了您的 Vue 應用程序的架構將固有地反映出您的組織架構,從而影響您應該如何規劃項目的結構。
一些常規規則
在我們開始介紹不同的項目結構之前,我想強調一些通用的規則,這些規則適用于每種結構,大部分來自于官方的 Vue 風格指南。
基礎組件命名
為您的 UI 組件使用前綴。
不好的
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
好的
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
緊密耦合的組件名稱
將緊密耦合的組件名稱放在一起。
不好的
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
好的
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
組件名稱中單詞的順序
組件名稱應該以最高級別(通常是最通用的)的單詞開頭,并以描述性的修改詞結尾。
不好的
components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
好的
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
測試
決定如何組織您的測試以及將它們放置在何處可能是另一個博文的主題。在本文中,我們將探討將測試放置在單獨的文件夾中,其中每個測試文件反映源代碼。或者,您可以將測試文件放置在它們所測試的文件旁邊。這兩種方法都是有效的。
方法 1:單獨的測試文件夾
/vue-project
|-- /src
| |-- /components
| | |-- MyComponent.vue
| |-- /views
| | |-- HomeView.vue
|-- /tests
| |-- /components
| | |-- MyComponent.spec.js
| |-- /views
| | |-- HomeView.spec.js
|-- package.json
|-- ...
方法 2:內聯測試文件
/vue-project
|-- /src
| |-- /components
| | |-- MyComponent.vue
| | |-- MyComponent.spec.js
| |-- /views
| | |-- HomeView.vue
| | |-- HomeView.spec.js
|-- package.json
|-- ...
扁平式方法
在啟動小規模 Vue 項目(如概念驗證)時,您可能更喜歡簡單直接的文件夾結構以避免復雜性:
/src
|-- /components
| |-- BaseButton.vue
| |-- BaseCard.vue
| |-- PokemonList.vue
| |-- PokemonCard.vue
|-- /composables
| |-- usePokemon.js
|-- /utils
| |-- validators.js
|-- /layout
| |-- DefaultLayout.vue
| |-- AdminLayout.vue
|-- /plugins
| |-- translate.js
|-- /views
| |-- Home.vue
| |-- PokemonDetail.vue
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /assets
| |-- /images
| |-- /styles
|-- /tests
| |-- ...
|-- App.vue
|-- main.js
原子設計
對于較大的 Vue 應用程序,采用原子設計方法可能是有利的。這種方法將組件組織成從簡單到復雜的層次結構:
? 原子(Atoms):基本元素(例如按鈕、圖標)
? 分子(Molecules):由原子組成的組合體(例如搜索欄)
? 有機體(Organisms):復雜組件(例如導航欄)
? 模板(Templates):顯示組件結構的布局
? 頁面(Pages):具有真實數據的實際 UI 屏幕
這種方法確保了可擴展性和可維護性,并且能夠在簡單和復雜組件之間平滑過渡。
/src
|-- /components
| |-- /atoms
| | |-- AtomButton.vue
| | |-- AtomIcon
.vue
| |-- /molecules
| | |-- MoleculeSearchInput.vue
| | |-- MoleculePokemonThumbnail.vue
| |-- /organisms
| | |-- OrganismPokemonCard.vue
| | |-- OrganismHeader.vue
| |-- /templates
| | |-- TemplatePokemonList.vue
| | |-- TemplatePokemonDetail.vue
|-- /pages
| |-- PageHome.vue
| |-- PagePokemonDetail.vue
|-- /composables
| |-- usePokemon.js
|-- /utils
| |-- validators.js
|-- /layout
| |-- LayoutDefault.vue
| |-- LayoutAdmin.vue
|-- /plugins
| |-- translate.js
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /assets
| |-- /images
| |-- /styles
|-- /tests
| |-- ...
|-- App.vue
|-- main.js
模塊
隨著項目規模的擴大,考慮采用模塊化的單塊架構。這種結構封裝了每個功能或領域,增強了可維護性,并為可能的演變向微服務方向做好了準備:
/src
|-- /core
| |-- /components
| | |-- BaseButton.vue
| | |-- BaseIcon.vue
| |-- /models
| |-- /store
| |-- /services
| |-- /views
| | |-- DefaultLayout.vue
| | |-- AdminLayout.vue
| |-- /utils
| | |-- validators.js
|-- /modules
| |-- /pokemon
| | |-- /components
| | | |-- PokemonThumbnail.vue
| | | |-- PokemonCard.vue
| | | |-- PokemonListTemplate.vue
| | | |-- PokemonDetailTemplate.vue
| | |-- /models
| | |-- /store
| | | |-- pokemonStore.js
| | |-- /services
| | |-- /views
| | | |-- PokemonDetailPage.vue
| | |-- /tests
| | | |-- pokemonTests.spec.js
| |-- /search
| | |-- /components
| | | |-- SearchInput.vue
| | |-- /models
| | |-- /store
| | | |-- searchStore.js
| | |-- /services
| | |-- /views
| | |-- /tests
| | | |-- searchTests.spec.js
|-- /assets
| |-- /images
| |-- /styles
|-- /scss
|-- App.vue
|-- main.ts
|-- router.ts
|-- store.ts
|-- /tests
| |-- ...
|-- /plugins
| |-- translate.js
功能分割設計
功能分割設計是一種組織大型和長期項目以便更易于管理和擴展的方法。此方法將應用程序分成不同的層,每個層具有特定的角色:
? 應用程序(App):全局設置、樣式和提供者。
? 頁面(Pages):使用實體、功能和小部件構建完整頁面。
? 小部件(Widgets):將實體和功能組合成一致的 UI 塊,如 IssueList 或 UserProfile。
? 功能(Features):處理添加價值的用戶交互,例如發送評論、添加到購物車或搜索用戶。
? 實體(Entities):表示核心業務模型,如用戶、產品和訂單。
? 共享(Shared):提供與特定業務邏輯無關的可重用實用程序和組件,如 UIKit、庫和 API。
/src
|-- /app
| |-- App.vue
| |-- main.js
| |-- app.scss
|-- /processes
|-- /pages
| |-- Home.vue
| |-- PokemonDetailPage.vue
|-- /widgets
| |-- UserProfile.vue
| |-- PokemonStatsWidget.vue
|-- /features
| |-- pokemon
| | |-- CatchPokemon.vue
| | |-- PokemonList.vue
| |-- user
| | |-- Login.vue
| | |-- Register.vue
|-- /entities
| |-- user
| | |-- userService.js
| | |-- userModel.js
| |-- pokemon
| | |-- pokemonService.js
| | |-- pokemonModel.js
|-- /shared
| |-- ui
| | |-- BaseButton.vue
| | |-- BaseInput.vue
| | |-- Loader.vue
| |-- lib
| | |-- api.js
| | |-- helpers.js
|-- /assets
| |-- /images
| |-- /styles
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /tests
| |-- featureTests.spec.js
這種設置非常適合大型項目,因為它使得項目更容易擴展和保持整潔。要了解有關這些層如何工作的更多詳細信息,請查看官方的功能分割設計文檔。
圖片
微前端
微前端將微服務的思想應用于 Web 應用程序的前端部分。這意味著不同的團隊可以獨立處理 Web 應用程序的不同部分,而不會相互干擾。每個部分,或“微前端”,都可以獨立運行,并可以單獨更新。這是一個 SPA 的基本概述。請注意,本文不會深入介紹微前端的工作原理。
? 應用程序 Shell:這是控制主要布局和站點路由的主要控制器。它將所有微前端連接在一起。
? 分解的 UI:每個微前端都專注于應用程序的特定部分。它們可以使用不同的技術進行開發,并可以分別更新。
圖片
主要優點是微前端讓團隊可以在不等待其他團隊的情況下更新應用程序的各個部分,這可以加快開發速度。然而,這種設置可能會使應用程序更復雜,難以管理和保持一致。
有用的資源:
? 微前端 - 將微服務思想擴展到前端開發
? 馬丁·福勒關于微前端
這種策略非常適合具有多個開發團隊的大型、復雜項目。每個團隊都可以專注于特定的業務需求,而不會影響其他團隊的工作,可能使用最適合其部分的技術。
結論
圖片
希望現在清楚了,您應該選擇一個反映您組織規模和復雜性的結構。此外,更先進的結構將值得一篇獨立的博文;我只是想為您提供一個良好的概述。一般來說,您的團隊越大、越復雜,或者擁有更多的團隊,您就越應該朝著更好地分隔這些概念的結構努力。基本上,您團隊的結構將指導您確定最適合您需求的項目結構。
方法 | 描述 | 優點 | 缺點 |
扁平式方法 | 簡單的結構,適合小項目或概念驗證。 | - 易于實施 - 最小設置 | - 不可擴展 - 隨著項目增長而混亂 |
原子設計 | 基于組件復雜性的分層結構。 | - 可擴展 - 有組織 - 可重用組件 | - 管理層面的開銷 - 復雜的設置 |
模塊 | 封裝功能的模塊化結構。 | - 可擴展 - 封裝特性 | - 可能存在重復 - 可能變得復雜 |
功能分割設計 | 將項目組織成功能層和切片。 | - 高內聚 - 明確的功能分離 | - 初始復雜性 - 需要徹底規劃 |
微前端 | 應用程序的每個部分都可以單獨部署。 | - 獨立部署 - 可擴展 | - 復雜性高 - 需要團隊之間的協調 |