vue3-vite2-ts-template
托管地址: github-vue3-vite2-ts-template
命令
啟動/打包 命令
技術棧:
命令行
通過安裝Tool,來可視化地使用模板,因為倉庫中的模板大多數都不會全部用到,你可以通過tool去按需引入它們
npm i enjoy-project-tool -g
創建模板
當然,作為模板的伴生工具,我還會繼續維護并且持續提出新的feature來減輕我們開發負擔
Tool是使用TS開發的,如果你感興趣可以提pr,這是Tool的倉庫
類型文檔/組件文檔
文檔待補充,暫定使用
代碼提交
舊版本的husky和新版還是有很多不一樣的,所以如果你以前用過husky那么你要在代碼提交這里做更多邏輯的話,可以去看看最新的文檔。
模板中只攔截了pre_commit這個鉤子,目標就是在pre_commit的時候對代碼進行lint和自動修復以及美化,而且僅要對暫存區的文件lint,所以使用了lint-staged。這個組合太常見了,有需求的開發者可以再這個上層定義一些有趣的功能提pr。
還有一個需求是校驗git commit message的規范,但是對于小團隊來講,校驗這個規范沒有太大必要,也暫時不會對團隊帶來好處,所以愛鼓搗的可以去鼓搗哈。
可以推薦團隊成員使用 git-commit-plugin-vscode
vscode 開發小指南
推薦使用 Volar 插件進行開發,如果你的 IDE 是 Jetbrains 系列的,那么你可能不太需要這個插件,如果你是 vscode 推薦使用 volar。使用 volar,不僅可以在 vue 開發上和jetbrains 的表現一致,還可以得到更完善 vue3 的支持,甚至非常新/在草案的語法糖都能夠快速享受到。
此模板對于vscode有天然的支持,如果你使用vscode,就能使用模板自帶的vscode配置,比如說保存自動lint&fix&prettier或者其他有意思的功能。
模板中自帶了若干個vscode的code-snippets,snippets將會持續更新,它和模板深度貼合,可以幫助你擺脫繁瑣的開發。下面就一一描述幾個snippets的作用:
初始化@types/model/api的提示工具,自動聲明命名空間以及導出
初始化model下的api類,自動引入與之匹配的type類型聲明文件以及其他可能用到的依賴
初始化model下的cache類,自動引入與之匹配的type類型聲明文件以及其他可能用到的依賴
初始化控制器類
初始化vue頁面/組件
AntdV 開發小指南
傳統的 antdv 的按需加載,都會使用 babel-plugin-import 這個插件進行按需分析然后自動引入,但是 antdv 中有很多嵌套的父子組件:
<a-menu> <a-menu-item></a-menu-item></a-menu>
由于內部設計原因,無法使用這個插件進行按需導入。最主要的是我們已經使用了vite,本身就帶有按需導入,我們只需要處理他們的css的按需引入即可。所以使用了2個插件:
第一個插件主要幫助我們自動識別模板中用到的組件,實現自動引入,也就是說我們使用antdv這樣的組件庫的時候,不需要全量引入,甚至不需要手動的import就可以自動實現按需引入,如圖:
而且腳手架內置了按需引入css的邏輯,所以antdv本身的設計原因導致引入css問題開發者也不需要擔心。第二個插件主要是輔助第一個插件做按需引入css邏輯的。第一個插件做的按需引入css有些許問題,比如說antdv里面有很多api調用的組件,比如message,通過message方法調用一個組件,這個時候css不生效,就需要使用第二個插件進行處理。
對于message這樣的api組件的css不生效的原因很簡單,第一個插件僅僅是解析template用到的組件然后自動引入css,但是無法處理import進來的api組件,所以需要第二個插件做處理。
開發指南
這一塊根據自身團隊成員的習慣會逐步調整,所以這里的介紹會經常更改。
這套微不足道的架構足以應對中小APP,也是非常簡單的,主要就是mvc+ts風格。如果你閱讀完整個模板文檔之后,你會發現很多東西都做了模塊化,把業務劃分開了,這也是目前團隊開發沒有注意到的一點,自身開發完爽是爽了,另外一個人維護就要慘了。各種配置,api都找不到,組件/組件參數也找不到,可能為了快速開發,都會去復制老項目和其他頁面的代碼;這雖然也是一種“復用”,但是總歸來說并不是標準的。所以只有將業務劃分開,才能快速定位具體核心代碼,才能快速復用。
類型
src/@types
像大部分工程一樣,把能抽離的type都盡量都抽離到了@types這一層,這一層也暫時根據需求劃分了以下幾個內容:
里面最重度使用的應該是model,我們在model模型中根據業務定義了很多ts,比如user.ts:
namespace TUserApiModel { type ReqLogin = { captcha: string; password: string; username: string; uuid: string; }; type ResLogin = Promise< ActionResult<{ token: string; }> >;}export default TUserApiModel;
這兩個就代表了model里面api層(后面會詳細說明model里面的api),使用Req和Res作為前綴也就是請求和響應的類型,那么我們定義好之后,在整個工程中我就可以這樣使用類型:
那么同理,types文件夾中像store,hook這樣的,也是根據業務劃分,去定義類型的,這里就不再過多闡述了。
模型
src/model
目前model分為2個含義:
前端大部分的數據來源都包含到了,api模型定義了不同業務的api方法,比如user.ts:
import useRequest from '../../hook/useRequest';export default class UserApiModel { async login(params: TUserModel.ReqLogin): TUserModel.ResLogin { return await useRequest({ url: `${params}`, method: 'get', options: { authApi: true } }); }}
useRequest是我們自定義實現的hook函數,我們通過這個hook可以發起請求,那么你可以看到在這個類中定義了login這個方法,入參類型就是TUserModel.ReqLogin, 返回類型就是TUserModel.ResLogin,這個類型都是我們在@types定義的。
再比如說我們搭配kurimudb做了緩存的模塊化,最常用的緩存插件也預裝好了,我們可以在model里面去寫這樣一段代碼:
/model/cache/user.ts
import { Models } from 'kurimudb';import { LocalStorageDriver } from 'kurimudb-driver-localstorage';import { CookieDriver } from 'kurimudb-driver-cookie';export class UserLocalStorage extends Models.keyValue { constructor() { super({ name: 'user', driver: LocalStorageDriver }); }}export class UserCookie extends Models.keyValue { constructor() { super({ name: 'user', driver: CookieDriver }); }}
我們在這里定義了2個kurimudb類,一個是localstorage一個是cookie,我們可以在這里新增一些方法或者直接導出給controller用,因為即便你不新增方法也可以使用kurimudb內置的函數。
我們擁有kurimudb這樣的庫可以解決存儲模塊化的問題,我們不用關心這個緩存的key是否被使用過,只需要設置好唯一的name值,它就能給我們提供一組方便調用的api。另外kurimudb還有sessionstorage和indexDB的插件,如果業務需要可以快速的安裝,然后聲明一個新的類導出即可使用。
控制器
src/controller
在模板默認自帶了一個user.ts例子,我們在上一個model中說明了apiModel和cacheModel,這里的controller就直接引入它們。并且在controller暴露入口。
import UserApiModel from '../model/api/user';import { UserLocalStorage, UserCookie } from '../model/cache/user';export default class UserController { private localStorageModel: UserLocalStorage; private cookieModel: UserCookie; private apiModel: UserApiModel; constructor() { this.apiModel = new UserApiModel(); this.localStorageModel = new UserLocalStorage(); this.cookieModel = new UserCookie(); } async login(req: TUserModel.ReqLogin): TUserModel.ResLogin { return await this.apiModel.login(req); }}
控制器我們還可以對api/cache獲取的數據做處理,比如說,后端返回的數據格式前端不便直接展示,我們應該在controller需要做一層轉譯,比如像這樣:
transform(): { text: string; value: string }[] { const data = { '0': '小明', '1': '小紅' }; let _arr = []; let key: keyof typeof data; for (key in data) { _arr.push({ text: data[key], value: key }); } return _arr; }
視圖(.vue)
以vue來舉例,我們如何在視圖優雅的調用controller?并且如何使用@types定義的類型來鞏固我們的組件?
import TUserApiModel from '../../@types/model/api/user';const login = async (params: TUserModel.ReqLogin) => { await userController.login(params);};// 調用login函數login({ captcha: "", password: "", username: "", uuid: ""})
當調用login函數時候,提供了與ReqLogin不符合的數據結構,是會出現報錯的。同理,我們調用cache也是一樣,需要在controller把cache封裝一層暴露給vue即可。
環境變量
可以根據業務需要,建立業務相關的 env 環境(模式)。 vite-模式文檔
以下是根目錄默認提供了 3 個環境文件,對應了本地,測試,生產環境
內容示例: 根據業務需要進行配置
VITE_APP_API=VITE_APP_SECRET=
那么同理,如果業務需要額外增加新的自定義環境變量,則需要在 src/vite-env.d.ts 中重新定義類型:
/// <reference types="vite/client" />interface ImportMetaEnv { VITE_APP_API: string; VITE_APP_SECRET: string; // 新的環境變量的定義寫這里}
Mock
使用vite-plugin-mock
來做本地開發的mock,模板暫時沒有內置生產環境的mock。
// vite.config.tsviteMockServe({ localEnabled: true //是否開啟本地的mock功能}),
定義mock api:
// /mock/user.tsimport { MockMethod } from 'vite-plugin-mock';export default [ { url: '/api/get', method: 'get', response: (res: any) => { return { code: 0, data: { name: 'this is mock name' } }; } }] as MockMethod[];