Vite系列(二):我基于Vite搞了一個(gè)項(xiàng)目模板

因卓誒-原文鏈接

vue3-vite2-ts-template

托管地址: github-vue3-vite2-ts-template

  • [x] 使用最新版本的 vite 和 vue3
  • [x] antdv 真正意義上的按需加載組件以及組件css
  • [x] git 提交前的 lint-stage+husky 校驗(yàn)和美化代碼(prettier), 多人協(xié)作風(fēng)格統(tǒng)一
  • [x] 開發(fā)預(yù)設(shè) eslint 校驗(yàn)和自動(dòng)修復(fù)以及 Editorconfig
  • [x] 自帶開發(fā)常用依賴,antdv, axios, day, querystring...
  • [x] 適合中小項(xiàng)目的 typescipt 的 mvc 風(fēng)格架構(gòu)
  • [x] 工具方法貫徹 hook 風(fēng)格,且預(yù)裝 vueuse
  • [x] scss 基本工具庫封裝,頁面和頁面無需引入,直接使用預(yù)定義的全局變量/函數(shù)
  • [x] vite/rollup 打包優(yōu)化
  • [x] storage,cookie TS版本的模塊化方案
  • [x] 預(yù)設(shè) Pinia 狀態(tài)管理的模塊化以及類型聲明
  • [x] 預(yù)設(shè)開發(fā)環(huán)境的 vite-plugin-mock
  • [x] 預(yù)設(shè)自動(dòng)裝載路由 vite-plugin-pages
  • [ ] SSR/CSR 優(yōu)化
  • [ ] 業(yè)務(wù)組件/type 類型文檔自動(dòng)生成,且在啟動(dòng)開發(fā)服務(wù)器時(shí),自動(dòng)打開 doc
  • [ ] 動(dòng)畫方案
  • [ ] 預(yù)裝業(yè)務(wù)常用的 webcomponents 組件(團(tuán)隊(duì)自己開發(fā)組件庫)
  • 命令

    啟動(dòng)/打包 命令

    技術(shù)棧:

  • vue3
  • vueRouter4
  • pinia
  • typescript
  • 命令行

    通過安裝Tool,來可視化地使用模板,因?yàn)閭}庫中的模板大多數(shù)都不會(huì)全部用到,你可以通過tool去按需引入它們

    npm i enjoy-project-tool -g

    創(chuàng)建模板

    當(dāng)然,作為模板的伴生工具,我還會(huì)繼續(xù)維護(hù)并且持續(xù)提出新的feature來減輕我們開發(fā)負(fù)擔(dān)

    Tool是使用TS開發(fā)的,如果你感興趣可以提pr,這是Tool的倉庫

    類型文檔/組件文檔

    文檔待補(bǔ)充,暫定使用

  • dumi作為組件庫文檔
  • 代碼提交

    舊版本的husky和新版還是有很多不一樣的,所以如果你以前用過husky那么你要在代碼提交這里做更多邏輯的話,可以去看看最新的文檔。

    模板中只攔截了pre_commit這個(gè)鉤子,目標(biāo)就是在pre_commit的時(shí)候?qū)Υa進(jìn)行l(wèi)int和自動(dòng)修復(fù)以及美化,而且僅要對(duì)暫存區(qū)的文件lint,所以使用了lint-staged。這個(gè)組合太常見了,有需求的開發(fā)者可以再這個(gè)上層定義一些有趣的功能提pr。

    還有一個(gè)需求是校驗(yàn)git commit message的規(guī)范,但是對(duì)于小團(tuán)隊(duì)來講,校驗(yàn)這個(gè)規(guī)范沒有太大必要,也暫時(shí)不會(huì)對(duì)團(tuán)隊(duì)帶來好處,所以愛鼓搗的可以去鼓搗哈。

    可以推薦團(tuán)隊(duì)成員使用 git-commit-plugin-vscode

    vscode 開發(fā)小指南

    推薦使用 Volar 插件進(jìn)行開發(fā),如果你的 IDE 是 Jetbrains 系列的,那么你可能不太需要這個(gè)插件,如果你是 vscode 推薦使用 volar。使用 volar,不僅可以在 vue 開發(fā)上和jetbrains 的表現(xiàn)一致,還可以得到更完善 vue3 的支持,甚至非常新/在草案的語法糖都能夠快速享受到。

    下載volar地址

    此模板對(duì)于vscode有天然的支持,如果你使用vscode,就能使用模板自帶的vscode配置,比如說保存自動(dòng)lint&fix&prettier或者其他有意思的功能。

  • 有那么一點(diǎn)智能的代碼模板
  • 模板中自帶了若干個(gè)vscode的code-snippets,snippets將會(huì)持續(xù)更新,它和模板深度貼合,可以幫助你擺脫繁瑣的開發(fā)。下面就一一描述幾個(gè)snippets的作用:

  • model-init-type
  • 初始化@types/model/api的提示工具,自動(dòng)聲明命名空間以及導(dǎo)出

  • model-init-api
  • 初始化model下的api類,自動(dòng)引入與之匹配的type類型聲明文件以及其他可能用到的依賴

  • model-init-cache
  • 初始化model下的cache類,自動(dòng)引入與之匹配的type類型聲明文件以及其他可能用到的依賴

  • controller-init
  • 初始化控制器類

  • vue-init
  • 初始化vue頁面/組件

    AntdV 開發(fā)小指南

    傳統(tǒng)的 antdv 的按需加載,都會(huì)使用 babel-plugin-import 這個(gè)插件進(jìn)行按需分析然后自動(dòng)引入,但是 antdv 中有很多嵌套的父子組件:

    <a-menu>  <a-menu-item></a-menu-item></a-menu>

    由于內(nèi)部設(shè)計(jì)原因,無法使用這個(gè)插件進(jìn)行按需導(dǎo)入。最主要的是我們已經(jīng)使用了vite,本身就帶有按需導(dǎo)入,我們只需要處理他們的css的按需引入即可。所以使用了2個(gè)插件:

  • vite-plugin-components
  • vite-plugin-style-import
  • 第一個(gè)插件主要幫助我們自動(dòng)識(shí)別模板中用到的組件,實(shí)現(xiàn)自動(dòng)引入,也就是說我們使用antdv這樣的組件庫的時(shí)候,不需要全量引入,甚至不需要手動(dòng)的import就可以自動(dòng)實(shí)現(xiàn)按需引入,如圖:

    而且腳手架內(nèi)置了按需引入css的邏輯,所以antdv本身的設(shè)計(jì)原因?qū)е乱隿ss問題開發(fā)者也不需要擔(dān)心。第二個(gè)插件主要是輔助第一個(gè)插件做按需引入css邏輯的。第一個(gè)插件做的按需引入css有些許問題,比如說antdv里面有很多api調(diào)用的組件,比如message,通過message方法調(diào)用一個(gè)組件,這個(gè)時(shí)候css不生效,就需要使用第二個(gè)插件進(jìn)行處理。

    對(duì)于message這樣的api組件的css不生效的原因很簡單,第一個(gè)插件僅僅是解析template用到的組件然后自動(dòng)引入css,但是無法處理import進(jìn)來的api組件,所以需要第二個(gè)插件做處理。

    開發(fā)指南

    這一塊根據(jù)自身團(tuán)隊(duì)成員的習(xí)慣會(huì)逐步調(diào)整,所以這里的介紹會(huì)經(jīng)常更改。

    這套微不足道的架構(gòu)足以應(yīng)對(duì)中小APP,也是非常簡單的,主要就是mvc+ts風(fēng)格。如果你閱讀完整個(gè)模板文檔之后,你會(huì)發(fā)現(xiàn)很多東西都做了模塊化,把業(yè)務(wù)劃分開了,這也是目前團(tuán)隊(duì)開發(fā)沒有注意到的一點(diǎn),自身開發(fā)完爽是爽了,另外一個(gè)人維護(hù)就要慘了。各種配置,api都找不到,組件/組件參數(shù)也找不到,可能為了快速開發(fā),都會(huì)去復(fù)制老項(xiàng)目和其他頁面的代碼;這雖然也是一種“復(fù)用”,但是總歸來說并不是標(biāo)準(zhǔn)的。所以只有將業(yè)務(wù)劃分開,才能快速定位具體核心代碼,才能快速復(fù)用。

    類型

    src/@types

    像大部分工程一樣,把能抽離的type都盡量都抽離到了@types這一層,這一層也暫時(shí)根據(jù)需求劃分了以下幾個(gè)內(nèi)容:

  • controller
  • model
  • hook
  • store
  • 里面最重度使用的應(yīng)該是model,我們?cè)趍odel模型中根據(jù)業(yè)務(wù)定義了很多ts,比如user.ts:

    namespace TUserApiModel {  type ReqLogin = {    captcha: string;    password: string;    username: string;    uuid: string;  };  type ResLogin = Promise<    ActionResult<{      token: string;    }>  >;}export default TUserApiModel;

    這兩個(gè)就代表了model里面api層(后面會(huì)詳細(xì)說明model里面的api),使用Req和Res作為前綴也就是請(qǐng)求和響應(yīng)的類型,那么我們定義好之后,在整個(gè)工程中我就可以這樣使用類型:

    那么同理,types文件夾中像store,hook這樣的,也是根據(jù)業(yè)務(wù)劃分,去定義類型的,這里就不再過多闡述了。

    模型

    src/model

    目前model分為2個(gè)含義:

  • api
  • cache
  • 前端大部分的數(shù)據(jù)來源都包含到了,api模型定義了不同業(yè)務(wù)的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是我們自定義實(shí)現(xiàn)的hook函數(shù),我們通過這個(gè)hook可以發(fā)起請(qǐng)求,那么你可以看到在這個(gè)類中定義了login這個(gè)方法,入?yún)㈩愋途褪荰UserModel.ReqLogin, 返回類型就是TUserModel.ResLogin,這個(gè)類型都是我們?cè)贎types定義的。

    再比如說我們搭配kurimudb做了緩存的模塊化,最常用的緩存插件也預(yù)裝好了,我們可以在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    });  }}

    我們?cè)谶@里定義了2個(gè)kurimudb類,一個(gè)是localstorage一個(gè)是cookie,我們可以在這里新增一些方法或者直接導(dǎo)出給controller用,因?yàn)榧幢隳悴恍略龇椒ㄒ部梢允褂胟urimudb內(nèi)置的函數(shù)。

    我們擁有kurimudb這樣的庫可以解決存儲(chǔ)模塊化的問題,我們不用關(guān)心這個(gè)緩存的key是否被使用過,只需要設(shè)置好唯一的name值,它就能給我們提供一組方便調(diào)用的api。另外kurimudb還有sessionstorage和indexDB的插件,如果業(yè)務(wù)需要可以快速的安裝,然后聲明一個(gè)新的類導(dǎo)出即可使用。

    控制器

    src/controller

    在模板默認(rèn)自帶了一個(gè)user.ts例子,我們?cè)谏弦粋€(gè)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);  }}

    控制器我們還可以對(duì)api/cache獲取的數(shù)據(jù)做處理,比如說,后端返回的數(shù)據(jù)格式前端不便直接展示,我們應(yīng)該在controller需要做一層轉(zhuǎn)譯,比如像這樣:

    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來舉例,我們?nèi)绾卧谝晥D優(yōu)雅的調(diào)用controller?并且如何使用@types定義的類型來鞏固我們的組件?

    import TUserApiModel from '../../@types/model/api/user';const login = async (params: TUserModel.ReqLogin) => {  await userController.login(params);};// 調(diào)用login函數(shù)login({  captcha: "",  password: "",  username: "",  uuid: ""})

    當(dāng)調(diào)用login函數(shù)時(shí)候,提供了與ReqLogin不符合的數(shù)據(jù)結(jié)構(gòu),是會(huì)出現(xiàn)報(bào)錯(cuò)的。同理,我們調(diào)用cache也是一樣,需要在controller把cache封裝一層暴露給vue即可。

    環(huán)境變量

    可以根據(jù)業(yè)務(wù)需要,建立業(yè)務(wù)相關(guān)的 env 環(huán)境(模式)。 vite-模式文檔

    以下是根目錄默認(rèn)提供了 3 個(gè)環(huán)境文件,對(duì)應(yīng)了本地,測試,生產(chǎn)環(huán)境

  • .env
  • .env.dev
  • .env.prod
  • 內(nèi)容示例: 根據(jù)業(yè)務(wù)需要進(jìn)行配置

    VITE_APP_API=VITE_APP_SECRET=

    那么同理,如果業(yè)務(wù)需要額外增加新的自定義環(huán)境變量,則需要在 src/vite-env.d.ts 中重新定義類型:

    /// <reference types="vite/client" />interface ImportMetaEnv {  VITE_APP_API: string;  VITE_APP_SECRET: string;  // 新的環(huán)境變量的定義寫這里}

    Mock

    使用vite-plugin-mock來做本地開發(fā)的mock,模板暫時(shí)沒有內(nèi)置生產(chǎn)環(huán)境的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[];

    其他的庫

  • dayjs
  • axios
  • vueuse
  • kurimudb
  • query-string
  • 最后編輯于
    ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
    【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
    平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

    友情鏈接更多精彩內(nèi)容