從零到一,如何搭建起完整的 Vue3 前端項目架構(gòu)?
由于 vue3.2 版本的發(fā)布,
復(fù)制代碼
4.4 封裝 SVG 的圖標(biāo)組件
svg 圖標(biāo)比較小,而且都是可讀的 xml 文本,所以我們把它直接放在項目中即可,通過 vite-plugin-svg-icons 插件,實現(xiàn)自動引入 svg 圖標(biāo)。
配置 vite.config.ts:
plugins:?[
??viteSvgIcons({
????iconDirs:?[resolve(process.cwd(),?'src/assets/icons')],
????symbolId:?'icon-[dir]-[name]',
??}),
]
復(fù)制代碼
封裝一個 vue 組件:
復(fù)制代碼
首先將下載的 .svg 圖標(biāo)放入 @/assets/icons 文件夾下
復(fù)制代碼
name 放置在 @/assets/icons 文件夾下的文件名。 color 顏色填充,使用此項會默認(rèn)覆蓋圖標(biāo)顏色。
5.按需自動引入組件
unplugin-vue-components[77] 是一款非常強大的插件(極力推薦),核心功能就是幫助你自動按需引入組件,Tree-shakable,只注冊你使用的組件。這里說一下他的兩個核心使用方式和配置方式。
此插件不僅支持 vue3,同時也支持 vue2,并且支持 Vite、Webpack、Vue CLI、Rollup。
5.1 安裝與配置
安裝:
npm?i?unplugin-vue-components?-D
復(fù)制代碼
配置:
//?vite.config.ts
import?Components?from?'unplugin-vue-components/vite'
export?default?defineConfig({
??plugins:?[
????Components({?/*?options?*/?}),
??],
})
復(fù)制代碼
這里的 options 可以配置一些選項,后面提到的組件庫注冊會使用到。
5.2 改變?nèi)纸M件注冊方式
我們通常將全局的組件封裝在 @/src/components 中,然后通過 app.component() 注冊全局組件。使用此插件后,無需手寫注冊,直接在模板中使用組件即可:
這里引入官方的示例:
復(fù)制代碼
自動編譯為:
復(fù)制代碼
5.3 自動引入組件庫
在使用組件庫時,常規(guī)組件我們也會注冊到全局,如果使用局部注冊由于頁面中會使用到多個組件,會非常麻煩,所以這個功能絕佳,例如我們使用 ant-design-vue 組件庫。
直接在模板中使用即可,無需手動注冊或局部引用:
按鈕
復(fù)制代碼
當(dāng)然,你還需要在 vite 中引入它的解析器:
import?Components?from?'unplugin-vue-components/vite'
import?{?AntDesignVueResolver?}?from?'unplugin-vue-components/resolvers'
export?default?defineConfig({
??plugins:?[
????Components({
??????resolvers:?[
????????AntDesignVueResolver(),
??????]
????})
??],
})
復(fù)制代碼
目前支持的解析器,根據(jù)你的喜好去選擇:
Ant Design Vue[78] Element Plus[79] Element UI[80] Headless UI[81] IDux[82] Naive UI[83] Prime Vue[84] Vant[85] VEUI[86] Varlet UI[87] View UI[88] Vuetify[89] VueUse Components[90] Quasar[91]
6.樣式
項目中最好使用通用樣式,可以創(chuàng)建 src/styles 目錄存放,這里推薦一些分類:
styles
??├──?antd?#?組件庫樣式覆蓋,命名自取,這里以?ant?design?為例
??├──?color.less?#?顏色
??├──?index.less?#?入口
??├──?global.less?#?公共類
??├──?transition.less?#?動畫相關(guān)
??└──?variable.less?#?變量
復(fù)制代碼
6.1 預(yù)設(shè)基礎(chǔ)樣式
相信用過 normalize[92] 的同學(xué)不在少數(shù),它可以重置 css 樣式,使各瀏覽器效果保持一致。后面的章節(jié)會提到 tailwind.css,它內(nèi)置了預(yù)設(shè)樣式重置的功能,與 normalize 還是有一定的區(qū)別,有興趣的同學(xué)可以了解一下[93]。
6.2 CSS 預(yù)處理器
雖然 vite 原生支持 less/sass/scss/stylus,但是你必須手動安裝他們的預(yù)處理器依賴,例如:
npm?install?-D?less
復(fù)制代碼
如何選擇預(yù)處理器?
推薦使用你是所使用的組件庫的樣式語言,因為 css 預(yù)處理器學(xué)會一種后,入手其他幾乎沒有學(xué)習(xí)成本。
6.3 開啟 scoped
沒有加 scoped 屬性,會編譯成全局樣式,造成全局污染。
復(fù)制代碼
6.4 深度選擇器
有時我們可能想明確地制定一個針對子組件的規(guī)則。
如果你希望 scoped 樣式中的一個選擇器能夠作用得“更深”,例如影響子組件,你可以使用 >>> 操作符。有些像 Sass 之類的預(yù)處理器無法正確解析 >>>。這種情況下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——兩者都是 >>> 的別名,同樣可以正常工作。
7.布局
頁面整體布局是一個產(chǎn)品最外層的框架結(jié)構(gòu),往往會包含導(dǎo)航、頁腳、側(cè)邊欄等。在頁面之中,也有很多區(qū)塊的布局結(jié)構(gòu)。在真實項目中,頁面布局通常統(tǒng)領(lǐng)整個應(yīng)用的界面,有非常重要的作用,所以單獨拆分出來也是非常有必要的。
在腳手架中,所有的通用布局組件都應(yīng)該放在 src/layouts 中,這種封裝比較簡單,這里就不貼代碼了,大家按照自己實際情況自行發(fā)揮,在此僅提供一下封裝思路。
7.1 常規(guī)的布局
BasicLayout
基礎(chǔ)頁面布局,包含了頭部導(dǎo)航,側(cè)邊欄等。
BlankLayout
空白的布局。
7.2 特殊的布局
RouteLayout
如果你的項目在路由切換中需要對某些二級頁面進行緩存,那么推薦你創(chuàng)建一個 RouteLayout,通過路由 meta 中的配置,返回 router-view 或者使用 keep-alive 包裹的 router-view。
UserLayout
用于用戶登錄注冊等頁面抽離出來。
PageLayout
基礎(chǔ)布局,包含了面包屑等信息,內(nèi)含 slot。
8.集成 Tailwind.css
Tailwind.css[94] 在我第一次看到它的時候,內(nèi)心是比較反感的,但實際上手之后又覺得真香。從 vue2 項目中,我已經(jīng)引入了 tailwind,整體的開發(fā)結(jié)果就是,基本很少再使用 標(biāo)簽去轉(zhuǎn)本定義一些 class 和樣式,畢竟起名字這種事,一個是涉及到規(guī)范,一個是涉及到英語。如果你選擇 tailwind,CSS 預(yù)處理器的作用就會顯得微乎其微,因為你無需再自定定義各種變量和 mixins。
總體來說,學(xué)習(xí)成本并不高,花上兩個小時足夠上手,記住不用死記硬背那些類名。
8.1 效率提升
很多人總是說樣式要與 HTML 分離,現(xiàn)在為什么又要提倡 tailwind 這種與 HTML 緊密結(jié)合的工具?這是因為現(xiàn)在使用 vue 這類框架已經(jīng)高度組件化,樣式分離是為了方便復(fù)用和維護,但在組件化面前樣式分離只能是降低開發(fā)效率。
下面介紹一下 tailwind 提供了哪些提升效率的功能:
提供了大量的功能類,極大的提高了可維護性。 響應(yīng)式設(shè)計,各種設(shè)備一把梭。 懸停、焦點和其它狀態(tài)。 深色模式。 支持配置,例如顏色方面很難做到跟你的設(shè)計師統(tǒng)一。 不用為起名字而糾結(jié)???
8.2 JIT 模式
如果你的環(huán)境支持 postcss8( vue/cli 構(gòu)建的 vue2 項目是 postcss7 ),那么 JIT 模式直接帶你起飛。
超快的構(gòu)建速度。 支持變體,你甚至可以這么寫 sm:hover:active:disabled:opacity-75。支持任意樣式,例如 md:top-[-113px]。開發(fā)和生產(chǎn)環(huán)境結(jié)果是一致的,(我在 vue2 項目中就遇到過組件庫構(gòu)建結(jié)果不一致的問題)。
如果你使用 vscode 那你一定要安裝 Tailwind CSS IntelliSense[95] 插件,它可以自動補全類名,顯著降低學(xué)習(xí)成本。
8.3 關(guān)于打包體積
使用默認(rèn)配置,未壓縮是 3739.4kB ,Gzip壓縮 是 293.9kB,Brotli壓縮 是 73.2kB。這似乎看起來很大,這是因為 tailwind 提供了成千上萬的功能類,其中絕大部分你不會使用到。
當(dāng)構(gòu)建生產(chǎn)時,你應(yīng)該使用 purge 選項來 tree-shake 優(yōu)化未使用的樣式,并優(yōu)化您的最終構(gòu)建大小當(dāng)使用 Tailwind 刪除未使用的樣式時,很難最終得到超過 10kb 的壓縮 CSS。
還有一點,Atom CSS 極大的提升了樣式的復(fù)用程度,從而直接降低了構(gòu)建體積。
9.vuex 替代方案 pinia
由于 vuex 4 對 typescript 的支持讓人感到難過,所以狀態(tài)管理棄用了 vuex 而采取了 pinia[96]。
忘記在哪看到,尤大好像說 pinia[97] 可能會代替 vuex,所以請放心使用。
9.1 為什么采用 Pinia ?
Pinia 的 API 設(shè)計非常接近 Vuex 5的提案[98]。(作者是 Vue 核心團隊成員)無需像 Vuex 4自定義復(fù)雜的類型來支持 typescript,天生具備完美的類型推斷。模塊化設(shè)計,你引入的每一個 store 在打包時都可以自動拆分他們。 無嵌套結(jié)構(gòu),但你可以在任意的 store 之間交叉組合使用。 Pinia 與 Vue devtools 掛鉤,不會影響 Vue 3 開發(fā)體驗。
下面簡單的介紹一下如何使用 Pinia,并對比 vuex 有哪些區(qū)別與注意事項,具體請參考官方文檔[99]。
9.2 創(chuàng)建 Store
Pinia 已經(jīng)內(nèi)置在腳手架中,并且與 vue 已經(jīng)做好了關(guān)聯(lián),你可以在任何位置創(chuàng)建一個 store:
import?{?defineStore?}?from?'pinia'
export?const?useUserStore?=?defineStore({
??id:?'user',
??state:?()?=>({}),
??getters:?{},
??actions:?{}
})
復(fù)制代碼
這與 Vuex 有很大不同,它是標(biāo)準(zhǔn)的 Javascript 模塊導(dǎo)出,這種方式也讓開發(fā)人員和你的 IDE 更加清楚 store 來自哪里。
Pinia 與 Vuex 的區(qū)別:
id 是必要的,它將所使用 store 連接到 devtools。 創(chuàng)建方式: new Vuex.Store(...)(vuex3),createStore(...)(vuex4)。對比于 vuex3 ,state 現(xiàn)在是一個函數(shù)返回對象。 沒有 mutations,不用擔(dān)心,state 的變化依然記錄在 devtools 中。
9.3 State
創(chuàng)建好 store 之后,可以在 state 中創(chuàng)建一些屬性了:
state:?()?=>?({?name:?'codexu',?age:?18?})
復(fù)制代碼
將 store 中的 state 屬性設(shè)置為一個函數(shù),該函數(shù)返回一個包含不同狀態(tài)值的對象,這與我們在組件中定義數(shù)據(jù)的方式非常相似。
在模板中使用 store:
現(xiàn)在我們想從 store 中獲取到 name 的狀態(tài),我們只需要使用以下的方式即可:
{{userStore.name}}</h1>
const?userStore?=?useUserStore()
return?{?userStore?}
復(fù)制代碼
注意這里并不需要 userStore.state.name。
雖然上面的寫法很舒適,但是你一定不要用解構(gòu)的方式去提取它內(nèi)部的值,這樣做的話,會失去它的響應(yīng)式:
const?{?name,?email?}?=?useUserStore()
復(fù)制代碼
9.4 Getters
Pinia 中的 getter 與 Vuex 中的 getter 、組件中的計算屬性具有相同的功能,傳統(tǒng)的函數(shù)聲明使用 this 代替了 state 的傳參方法,但箭頭函數(shù)還是要使用函數(shù)的第一個參數(shù)來獲取 state ,因為箭頭函數(shù)處理 this 的作用范圍:
getters:?{
??nameLength()?{
????return?this.name.length
??},
??nameLength:?state?=>?state.name.length,
??nameLength:?()=>?this.name.length???
}
復(fù)制代碼
9.5 Actions
這里與 Vuex 有極大的不同,Pinia 僅提供了一種方法來定義如何更改狀態(tài)的規(guī)則,放棄 mutations 只依靠 Actions,這是一項重大的改變。
Pinia 讓 Actions 更加的靈活:
可以通過組件或其他 action 調(diào)用 可以從其他 store 的 action 中調(diào)用 直接在商店實例上調(diào)用 支持同步或異步 有任意數(shù)量的參數(shù) 可以包含有關(guān)如何更改狀態(tài)的邏輯(也就是 vuex 的 mutations 的作用) 可以 $patch方法直接更改狀態(tài)屬性
actions:?{
??async?insertPost(data){
????await?doAjaxRequest(data);
????this.name?=?'...';
??}
}
復(fù)制代碼
9.6 Devtools
腳手架已內(nèi)置下面的代碼,這將添加 devtools 支持:
import?{?createPinia,?PiniaPlugin?}?from?'pinia'
Vue.use(PiniaPlugin)
const?pinia?=?createPinia()
復(fù)制代碼
時間旅行功能貌似已經(jīng)可以使用了,這塊后續(xù)會關(guān)注。
10.基于 mitt 處理組件間事件聯(lián)動
如果你曾經(jīng)是 Vue2.x 的開發(fā)者,那么請閱讀下面引用官方文檔[100]的一段話:
我們從實例中完全移除了
$on、$off和$once方法。$emit仍然包含于現(xiàn)有的 API 中,因為它用于觸發(fā)由父組件聲明式添加的事件處理函數(shù)。在 Vue 3 中,已經(jīng)不可能使用這些 API 從組件內(nèi)部監(jiān)聽組件自己發(fā)出的事件了,該用例暫沒有遷移的方法。但是該 eventHub 模式可以被替換為實現(xiàn)了事件觸發(fā)器接口的外部庫,例如
mitt或tiny-emitter。
10.1 為什么選擇 mitt ?
足夠小,僅有 200bytes。 支持全部事件的監(jiān)聽和批量移除。 無依賴,不論是什么框架都可以直接使用。
10.2 嚴(yán)重警告
我們已經(jīng)無法在項目中使用 eventBus,僅推薦你在特殊場合下使用 mitt,它并不是開發(fā)的常態(tài),你一定要確保知道自己在做什么?否則你的項目將難以維護!!!
10.3 如何使用 mitt ?
在使用 mitt 前建議請閱讀官方文檔[101]:
腳手架默認(rèn)提供一個可以直接使用的對象:
import?emitter?from?'@/libs/emitter';
復(fù)制代碼
當(dāng)然你也可以引入已經(jīng)安裝好的 mitt:
import?mitt?from?'mitt'
const?emitter?=?mitt()
復(fù)制代碼
mitt 提供了非常簡單的 API,下面代碼是官方演示:
//?listen?to?an?event
emitter.on('foo',?e?=>?console.log('foo',?e)?)
//?listen?to?all?events
emitter.on('*',?(type,?e)?=>?console.log(type,?e)?)
//?fire?an?event
emitter.emit('foo',?{?a:?'b'?})
//?clearing?all?events
emitter.all.clear()
//?working?with?handler?references:
function?onFoo()?{}
emitter.on('foo',?onFoo)???//?listen
emitter.off('foo',?onFoo)??//?unlisten
復(fù)制代碼
11.異步請求
絕大多數(shù)項目想必逃脫不了接口的對接,如果你的項目存在大量的接口,我建議做到以下幾點:
封裝請求。 統(tǒng)一的 API 接口管理。 Mock 數(shù)據(jù)功能(根據(jù)需求斟酌使用)。
上述的主要目的就是在幫助我們簡化代碼和利于后期的更新維護。
11.1 基于 axios 的封裝
相信開發(fā)過 vue2 項目的同學(xué)已經(jīng)對 axios 非常熟悉的,在這里提供一些封裝的思路:
通過 import.meta.env.VITE_APP_BASE_URL獲取環(huán)境變量,配置baseURL,如果接口存在多個不同域名,可以通過 js 變量控制。設(shè)置 timeout請求超時、斷網(wǎng)情況處理。設(shè)置請求頭,攜帶 token。異常攔截處理,后端通過你攜帶的 token判斷你是否過期,如果返回401你可能需要跳轉(zhuǎn)到登錄頁面,并提示需要重新登錄。響應(yīng)攔截,通常后端返回 code、data、msg,如果是請求正常,我們可以直接返回 data 數(shù)據(jù),如果是異常的 code,我們也可以在這里直接彈出報錯提示。 無感刷新 token,如果你的 token 過期,可以通過后端返回的 refreshToken 調(diào)用刷新接口,獲取新的 token。當(dāng)然這里涉及到很多細(xì)節(jié),例如終端請求、重新發(fā)送請求、重新請求列隊。 中斷請求,例如頁面切換時,我們要中斷正在發(fā)生的請求。
相關(guān)代碼(僅供參考)[102]
11.2 為 axios 增加泛型的支持
到目前為止,axios 請求返回的類型是 any,這時我們對請求后的數(shù)據(jù)進行操作時,沒有享受到 ts 帶來的類型提示,這顯然不符合我們的預(yù)期。
這時我們要做的就是重新聲明 axios 模塊:新建一個 shims.d.ts,然后在調(diào)用時加上泛型。
import?{?AxiosRequestConfig?}?from?'axios';
declare?module?'axios'?{
??export?interface?AxiosInstance?{
????any>(config:?AxiosRequestConfig):?Promise;
????requestany>(config:?AxiosRequestConfig):?Promise;
????getany>(url:?string,?config?:?AxiosRequestConfig):?Promise;
????deleteany>(url:?string,?config?:?AxiosRequestConfig):?Promise;
????headany>(url:?string,?config?:?AxiosRequestConfig):?Promise;
????postany>(url:?string,?data?:?any,?config?:?AxiosRequestConfig):?Promise;
????putany>(url:?string,?data?:?any,?config?:?AxiosRequestConfig):?Promise;
????patchany>(url:?string,?data?:?any,?config?:?AxiosRequestConfig):?Promise;
??}
}
復(fù)制代碼
做好這一步后,你就必須在創(chuàng)建接口時,聲明請求相應(yīng)數(shù)據(jù)的類型。
11.3 封裝更方便的 useRequest
設(shè)想一下,編寫請求代碼時,我們通常會定義這么幾個變量:
data: 儲存請求數(shù)據(jù) loading: 請求加載狀態(tài)
尤其是 loading,我們需要在請求前設(shè)置為 true,請求結(jié)束后設(shè)置為 false。
上面的封裝方式,是對基礎(chǔ)的功能封裝,因為我們在使用 vue3,所以可以進行再一次的封裝成為 hook,我們使用起來會更加方便。
例如下面這個樣子:
使用 useRequest 定義一個接口:
export?default?getUserInfo(id)?{
??return?useRequest({
????method:?'get',
????url:?'/api/user',
????params:?{?id?}
??})
}
復(fù)制代碼
使用此接口:
const?{?data,?loading?}?=?getUserInfo();
復(fù)制代碼
注意這里的 data 是響應(yīng)式的。
這是我想到的一種思路,目前還沒有做很好的封裝,相關(guān)代碼僅供參考[103],你也可以借鑒一些成熟方案,比如 vueuse 中的 useFetch[104],但是他是基于 Fetch API 設(shè)計的,并不符合我的預(yù)期要求,有更好的方案請大家在下面留言。
11.4 統(tǒng)一的 API 接口管理
自從前端和后端分家之后,前后端接口對接就成為了常態(tài),而對接接口的過程就離不開接口文檔,比較主流就是 Swagger,但是如何在前端項目中更好的去管理跟后端對接的接口呢?
在 src 目錄中 創(chuàng)建 api 目錄,內(nèi)部目錄應(yīng)按照后端制定的模塊創(chuàng)建。
每個模塊中創(chuàng)建多個 ts 文件,一個接口應(yīng)對應(yīng)一個 ts 文件,其中包含了以下內(nèi)容:
請求參數(shù)的類型聲明。 響應(yīng)數(shù)據(jù)的類型聲明。 返回定義好的請求函數(shù)(url、method、params、data 等)。
統(tǒng)一去定義和管理 API 接口,只要后端規(guī)范的命名和你認(rèn)真的寫好類型聲明,對前端來說 typescript 就是最好的接口文檔。
11.5 mock
vite 使用 mock 數(shù)據(jù)非常簡單,你可以使用 vite-plugin-mock[105] 插件,如果你了解 mockjs,你可以快速上手。
12.路由
路由和菜單是組織起一個應(yīng)用的關(guān)鍵骨架。
12.1 創(chuàng)建路由三部曲
通常一個項目需要做到這幾步:
使用 createRouter 創(chuàng)建路由,這時候根據(jù)需求選擇 Hash 路由或者 History 路由。 根據(jù)業(yè)務(wù)需求配置路由,注意這里很可能就用到前文提到過的布局組件。 如果有權(quán)限相關(guān)的業(yè)務(wù),你需要創(chuàng)建 permission.ts 在路由鉤子觸發(fā)時做一些事情。
如果你的頁面比較多,建議你創(chuàng)建 routes 目錄,分模塊聲明路由。
參考代碼[106]
12.2 使用 meta 豐富你的路由
vue-router4.x 支持 typescript,配置路由的類型是 RouteRecordRaw,這里 meta 可以讓我們有更多的發(fā)揮空間,這里提供一些參考:
title: string; 頁面標(biāo)題,通常必選。 icon?: string; 圖標(biāo),一般配合菜單使用。 auth?: boolean; 是否需要登錄權(quán)限。 ignoreAuth?: boolean; 是否忽略權(quán)限。 roles?: RoleEnum[]; 可以訪問的角色 keepAlive?: boolean; 是否開啟頁面緩存 hideMenu?: boolean; 有些路由我們并不想在菜單中顯示,比如某些編輯頁面。 order?: number; 菜單排序。 frameUrl?: string; 嵌套外鏈。
這里只提供一些思路,每個項目多多少少會涉及到這些問題,具體如何實現(xiàn)請查閱資料自行解決。
13.項目性能與細(xì)節(jié)優(yōu)化
13.1 開啟 gzip
開啟 gzip 可以極大的壓縮靜態(tài)資源,對頁面加載的速度起到了顯著的作用。
使用 vite-plugin-compression[107] 可以 gzip 或 brotli 的方式來壓縮資源,這一步需要服務(wù)器端的配合,vite 只能幫你打包出 .gz 文件。此插件使用簡單,你甚至無需配置參數(shù),引入即可。
13.2 頁面載入進度條
頁面路由切換時,附帶一個加載進度條會顯得非常友好,不至于白屏?xí)r間過長,讓用戶以為頁面假死。
這時候我們可以用到 nprogress[108],在路由切換時開啟和關(guān)閉:
import?NProgress?from?'nprogress';
router.beforeEach(async?(to,?from,?next)?=>?{
??NProgress.start();
});
router.afterEach((to)?=>?{
??NProgress.done();
});
復(fù)制代碼
13.3 Title
在不同的路由下顯示不同的標(biāo)題是常規(guī)的操作,我們可以通過路由鉤子獲取 meta 中的 title 屬性改變標(biāo)簽頁上的 title。
你可以使用 vueuse 提供的 useTitle[109],或者 window.document.title 自行封裝。
你也可以通過環(huán)境變量將你的主標(biāo)題拼接在路由標(biāo)題的后面:
const?{?VITE_APP_TITLE?}?=?import.meta.env;
復(fù)制代碼
13.4 解決移動端使用 vh 的問題
有興趣的同學(xué)可以嘗試一下 chrome 移動端瀏覽器上的 100vh,是真正的視口高度的 100% 嘛。
為了解決這一問題,我們可以通過 postCss 插件解決。
安裝 postcss-viewport-height-correction[110] 插件:
npm?install?-D?postcss-viewport-height-correction
復(fù)制代碼
在 postcss.config.js 中增加 plugin:
module.exports?=?{
??plugins:?{
????'postcss-viewport-height-correction':?{},
??},
}
復(fù)制代碼
添加這一段 js 代碼在全局,你可以直接添加在 index.html 上即可:
const?customViewportCorrectionVariable?=?'vh';
function?setViewportProperty(doc)?{
??let?prevClientHeight;
??const?customVar?=?`--${customViewportCorrectionVariable?||?'vh'}`;
??function?handleResize()?{
????const?{?clientHeight?}?=?doc;
????if?(clientHeight?===?prevClientHeight)?return;
????requestAnimationFrame(function?updateViewportHeight()?{
??????doc.style.setProperty(customVar,?`${clientHeight?*?0.01}px`);
??????prevClientHeight?=?clientHeight;
????});
??}
??handleResize();
??return?handleResize;
}
window.addEventListener('resize',?setViewportProperty(document.documentElement));
復(fù)制代碼
13.5 可以常駐的 JavaScript 庫
前文提到過的 vueuse[111],非常強大,強烈建議嘗試。 lodash[112],用了都說好,早用早下班。
14.代碼風(fēng)格與流程規(guī)范
14.1 ESLint
不管是多人合作還是個人項目,代碼規(guī)范都是很重要的。這樣做不僅可以很大程度地避免基本語法錯誤,也保證了代碼的可讀性。
這里推薦使用 airbnb 規(guī)范。
配置參考[113]
14.2 StyleLint
盡管前文提到過 tailwind,可以讓你幾乎不寫 css,但是涉及到團隊協(xié)作,這一點也要嚴(yán)謹(jǐn)。
StyleLint 是一個強大的、現(xiàn)代化的 CSS 檢測工具, 與 ESLint 類似, 是通過定義一系列的編碼風(fēng)格規(guī)則幫助我們避免在樣式表中出現(xiàn)錯誤,配合編輯器的自動修復(fù),可以很好的統(tǒng)一團隊項目 css 風(fēng)格。
配置參考[114]
14.3 代碼提交規(guī)范
在多人協(xié)作的背景下,git 倉庫和 workflow 的作用很重要。而對于 commit 提交的信息說明存在一定規(guī)范,現(xiàn)使用 commitlint + husky 規(guī)范 git commit -m "" 中的描述信息。我們都知道,在使用 git commit 時,git 會提示我們填入此次提交的信息。可不要小看了這些 commit,團隊中規(guī)范了 commit 可以更清晰的查看每一次代碼提交記錄,還可以根據(jù)自定義的規(guī)則,自動生成 changeLog 文件。
提交格式(注意冒號后面有空格):
<type>[optional?scope]:?
復(fù)制代碼
type :用于表明我們這次提交的改動類型。 optional scope:可選,用于標(biāo)識此次提交主要涉及到代碼中哪個模塊。 description:一句話描述此次提交的主要內(nèi)容,做到言簡意賅。
Type 類型
build:編譯相關(guān)的修改,例如發(fā)布版本、對項目構(gòu)建或者依賴的改動 chore:其他修改, 比如改變構(gòu)建流程、或者增加依賴庫、工具等 ci:持續(xù)集成修改 docs:文檔修改 feat:新特性、新功能 fix:修改bug perf:優(yōu)化相關(guān),比如提升性能、體驗 refactor:代碼重構(gòu) revert:回滾到上一個版本 style:代碼格式修改, 注意不是 css 修改 test:測試用例修改
關(guān)于 commitlint + husky 的配置文章有很多,大同小異,請根據(jù)自己的實際情況配置。
15.編寫使用文檔
做到這一步,你的整個腳手架開發(fā)已經(jīng)接近于尾聲,但是你做了這么多,你的同事并不知道如何使用,甚至你過一段時間也會忘記,所以你必須養(yǎng)成良好的編寫文檔習(xí)慣。
15.1 使用 vitepress 搭建文檔
這里我推薦使用 vuepress 或者 vitepress,說實話你只寫文檔 vitepress 會讓你更舒服,因為它很快。
vitepress[115] 很適合構(gòu)建博客網(wǎng)站、技術(shù)文檔,就是因為它可以直接用 markdown 進行書寫,所有寫過博客的人,都應(yīng)該對它不陌生。一個 .md 文件,即可生成一張頁面,十分方便。
創(chuàng)建一個 vitepress 文檔實在是太過于簡單,你可以參考官方文檔,或者參考我的文檔[116]。
15.2 文檔部署
如果你的團隊可以幫助你搭建 CI/CD 自動部署是再好不過了,如果沒有這個條件,你也可以通過 github 提供的 actions 功能,完成自動部署。
代碼參考[117]
16.插件
如果你想更痛快的用上述功能,建議你安裝下面的插件。
16.1 VSCode 插件
Vue Language Features \(Volar\)[118],你現(xiàn)在查 Volar 可能找不到,你需要的是這個。 Vue 3 Snippets[119],vue3 快捷輸入。 Tailwind CSS IntelliSense[120],tailwind 代碼提示。 Stylelint[121] Prettier - Code formatter[122] ESLint[123]
16.2 Chrome 插件
Vue.js devtools[124],你當(dāng)然要安裝支持 vue3 的版本,而且此版本對 pinia 支持的也非常友好。
源碼
上述內(nèi)容,均可在我的開源項目 X-BUILD[125] 中找到相關(guān)源碼,如果可以幫到你,請給一顆 star 或點贊鼓勵我貢獻出更多的開源項目或文章。
參考
《基于Vue的前端架構(gòu),我做了這15點》[126] 《搭建自己的腳手架—“優(yōu)雅”生成前端工程》[127] 《Vuex4 對 TypeScript 并不友好,所以我選擇 Pinia》[128] 《前端腳手架 webpack 遷移 Vite2 踩坑實踐》[129]
作者:codexu
https://juejin.cn/post/7025524870842679310
???“分享、點贊、在看” 支持一波??
