詳解從零搭建企業(yè)級 vue3 + vite2+ ts4 框架全過程
大廠技術(shù)??高級前端??Node進階
點擊上方?程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
本文不僅僅是搭建個腳手架這么簡單,還會帶你了解每一步、甚至每一個配置項的作用,和每個配置的知識點
涉及到的知識點:Vue3、Vite、TypeScript、ESlint、Stylelint、Vue-router、Axios、Pinia
本文項目初始化時間為2022/2/19,運行初始化命令獲得的 vite 最新版本為 2.8.0
整個搭建過程體系因為我想把每個點都寫得詳細一點,所以內(nèi)容會很多,全文主要分為兩個部分:
第一部分為開發(fā)環(huán)境及腳手架基本能力的搭建:
基本環(huán)境準備
初始化 vite項目
擴展 vite 配置
配置 TypeScript
接入代碼規(guī)范
第二部分為應(yīng)用層能力的建設(shè):
接入 vue-router
接入 Axios
接入 UI 庫
接入 Pinia
接入 Echarts5
源碼地址:github.com/JasonLuox/f…
內(nèi)容較多,筆者能力也有限,難免會有所遺漏和錯誤,歡迎在評論區(qū)指出,所有合理的批評和建議我都會采納和表示感謝~
寫在前面
早在去年年初的時候,在某乎上刷到了尤大的一條對前端變化的評論(時刻關(guān)注著尤大的一言一行對我們這些基于vue 的開發(fā)者還是很有好處的):

那時好像也是正值 vite2.0 發(fā)布的時候,我滿懷欣喜的就去體驗了下,不得不說,在飽受了 webpack 速度的摧殘之下,vite 簡直是奇跡!
當時正好是負責(zé)項目的整個 UI 重構(gòu),對項目使用的整個前端框架體系都有了一定的認知和熟練,所以也嘗試搭建了 vue3 + vite 的框架體系。當時踩了不少坑,眾所周知在一門新技術(shù)出來的時候,很難通過搜索引擎搜索到相關(guān)的教程/報錯解決方法,唯一有價值的參考就是官方文檔和 issues。當時踩坑結(jié)束后其實就萌發(fā)了寫一篇這樣的文章的打算,不過拖延癥讓我成功拖到了現(xiàn)在。
這一年多來我也在各類公眾號、博客里看到很多類似的文章。雖然現(xiàn)在寫這篇文章有炒冷飯的嫌疑,但正好借著掘金活動的助力,還是打算將這篇鴿了已久的文章通過自己的能力去完成,而且要盡量呈現(xiàn)更多的細節(jié)。我已經(jīng)準備好一臺全新的環(huán)境,一邊搭建一邊撰寫這篇文章,動手實操才是掌握能力/發(fā)現(xiàn)問題最快的方式!
舊項目升級建議
vue3 已經(jīng)發(fā)布很長一段時間了(剛出的時候其實比較多人都是在選擇觀望的,現(xiàn)在都在積極擁抱,不得不說:用過都說好?。兄斓乃俣?,更高效的語法,生態(tài)圈也逐漸完善了起來,對中小型應(yīng)用的開發(fā)完全不在話下??粗a倉庫里的 vue2 項目難免有了些嫌棄的想法,那么到底要不要對 vue2 的項目進行升級呢?
如果所在公司有比較成熟的 UI 規(guī)范的話,一般 UI 規(guī)范都是基于某個特定 UI 庫制定的,所以從 vue2 升級到 vue3 就需要考慮舊項目使用的 UI 庫是否有提供 vue3 的兼容版本。
這點比較坑,我一直想把公司項目升級到 vue3,奈何 UI 庫的 vue3 適配版本還在開發(fā)中沒有正式發(fā)布,所以現(xiàn)在只能等啦,不過框架落后,技術(shù)必須先行,開發(fā)人員的技術(shù)儲備必須時刻保持在行業(yè)前沿才不會被淘汰!
雖然 vue3 幾乎是對 vue2 的全面降維打擊,如果是大體量的產(chǎn)品,我更建議維持舊版本的開發(fā),在新項目上再使用 vue3 + vite ,vue2 與 vue3 在語法、上手難度上都有著一定的差距,盲目的升級不但會加大人力、資源的投入(雖然對技術(shù)人員來說是正相關(guān)的,學(xué)到新技術(shù),開發(fā)出更高效的代碼),但也會增加對產(chǎn)品正常迭代延期的風(fēng)險,要時刻保持認知:一個團隊中不僅僅有技術(shù)開發(fā)人員,更是產(chǎn)品、設(shè)計、交互、測試等多方面的協(xié)作。
當然以上只是個人的淺薄看法,具體情況還需要看各個技術(shù)團隊對新技術(shù)的認知和投入,需要各個技術(shù)負責(zé)人對整體進行考量。
既然是從零開始,那當然得從node 裝起了:
第一部分
零、安裝 Nodejs
為什么要 nodejs ?
大家可能會感到奇怪,我們開發(fā) vue 的,直接引入不就能跑了,裝 node 做什么?
(哈哈,還記得當年是一個后臺開發(fā)問得我這個問題,當時還真沒答上來)
Node.js 是能夠在服務(wù)器端運行 JavaScript 的開放源代碼、跨平臺執(zhí)行環(huán)境。
就像瀏覽器能夠提供 JS 運行的環(huán)境一樣,Nodejs 的作用和瀏覽器一致。
如果只是跑一個簡單的 html ,或者只是在生產(chǎn)環(huán)境運行打包好的靜態(tài)文件,確實是用不上 node.js 的。node.js 的作用其實是提供前端工程化的基石,為了方便你的開發(fā),提高開發(fā)效率的。
比如 vue-cli 腳手架,比如常用的包管理工具npm,比如常用的打包工具 webpack/vite/rollup 等等,node.js 都能夠提供對應(yīng)工具/輪子的運行環(huán)境,這樣就省去了大量的配置過程,對效率提升杠杠的。
兼容性
vite 需要 Node.js 版本 >= 12.0.0
安裝
打開 nodejs 官網(wǎng),我們就選擇最新的長期維護版本進行下載(穩(wěn)定才是一個規(guī)范的開發(fā)團隊需要保證的東西,嘗鮮版更適合單獨奮戰(zhàn)的人/狂熱的技術(shù)愛好者,我用的是windows所以只能展示windows環(huán)境的安裝了)

這里會提示說有一些 npm modules 會依賴 c/c++ 的編輯環(huán)境,圖省事的話也可以勾上,未來也許用的上

安裝結(jié)束后打開命令行(快捷鍵win + r后輸入 cmd)輸入node -v

可以看到已安裝成功的 node.js 版本,到此我們就安裝完畢了!
看不到的需要去配置下環(huán)境變量(右鍵此電腦=>屬性=>高級系統(tǒng)設(shè)置=>高級=>環(huán)境變量=>Path),添加一條對應(yīng)安裝目錄\nodejs就可以了,比如我是默認安裝的,就添加一條C:\Program Files\nodejs\。
正常安裝的話應(yīng)該是會默認幫你添加到環(huán)境變量的,當然難免會有些意外發(fā)生需要手動添加。
安裝cnpm
因為 npm 源畢竟在國外,用起來會比較慢,我們可以安裝淘寶鏡像 cnpm 提升安裝依賴速度
npm install -g cnpm -registry=https://registry.npm.taobao.org
cnpm 的操作命令和使用方式和 npm 是完全一致的
安裝完成后查看是否安裝完成cnpm -v

一、初始化 vite 項目
Home | Vite 官方中文文檔
npm 7+直接運行npm create vite@latest my-vue-app -- --template vue-ts

npm 低于 7+ 的建議升級下 npm,命令
npm install npm -g也可以不輸入后面的
-- --template vue-ts參數(shù)進行手動選擇使用 cnpm 運行這行命令指定項目名稱和模板會不生效,很奇怪的Bug
可以看到,當前目錄下就生成了一個名為 my-vue-app 的 vite 項目了,目錄結(jié)構(gòu)如下
├── public 靜態(tài)資源
├── src
│?? ├── assets ? ? ? ? ? 資源目錄(圖片、less、css等)
│?? ├── components ? ? ? 項目組件
│?? ├── App.vue ? ? ? ? 主應(yīng)用
│?? ├── env.d.ts ? ? ? ? 全局聲明
│?? └── main.ts ? ? ? ? 主入口
├── .gitignore ? ? ? ? ? git忽略配置
├── index.html ? ? ? ? ? 模板文件
├── package.json 依賴包/運行腳本配置文件
├── README.md
├── tsconfig.json ? ? ? ts配置文件
├── tsconfig.node.json ? ts配置文件
└── vite.config.ts ? ? ? vite配置
運行初始化成功后命令行給出的命令
cd my-vue-app
npm install
npm run dev
可以看到項目默認在3000端口運行,構(gòu)建時間只花了 398ms:

瀏覽器打開 http://localhost:3000 ,是標志性的 vue 首頁和一個簡單的累加器組件:

二、拓展 vite配置
和我們熟悉的 webpack 不同,打開 vite 的配置文件vite.config.js可以發(fā)現(xiàn),好像啥都沒有:

公共基礎(chǔ)路徑 base
如果你需要在嵌套的公共路徑下部署項目,只需指定 base 配置項,然后所有資源的路徑都將據(jù)此配置重寫。
由 JS 引入的資源 URL,CSS 中的 url() 引用以及 .html 文件中引用的資源在構(gòu)建過程中都會自動調(diào)整,以適配此選項。公共路徑默認為/,我們指定為當前項目根目錄./即可
base: './'
開發(fā)服務(wù)器選項 server
當我們在沒有任何配置的時候,在運行服務(wù)的時候,vite 是會自動跑在本地的3000端口,所以我們可以擴展下配置
server: {
? ?port: 4000, // 設(shè)置服務(wù)啟動端口號,如果端口已經(jīng)被使用,Vite 會自動嘗試下一個可用的端口
? ?open: true, // boolean | string 設(shè)置服務(wù)啟動時是否自動打開瀏覽器,當此值為字符串時,會被用作 URL 的路徑名
? ?cors: true, // 為開發(fā)服務(wù)器配置 CORS,配置為允許跨域
? ?// 設(shè)置代理,根據(jù)我們項目實際情況配置
? ?proxy: {
? ? ? ?'/api': {
? ? ? ? ? ?target: 'http://127.0.0.1:8000', // 后臺服務(wù)地址
? ? ? ? ? ?changeOrigin: true, // 是否允許不同源
? ? ? ? ? ?secure: false, // 支持https
? ? ? ? ? ?rewrite: path => path.replace(/^/api/, '')
? ? ? }
? }
}
proxy 代理使用的是 http-proxy,用法很簡單,如上配置就是將127.0.0.1:4000/api的請求 url 替換成127.0.0.1:8000,是本地開發(fā)調(diào)試解決跨域問題很常用的一種方式。
別名 resolve.alias
在我們項目開發(fā)過程中,會有很多嵌套層級的目錄,所以要找到某個目錄經(jīng)常用相對路徑../../..,層級一多就顯得眼花繚亂,通過 alIas 別名,我們可以快速地指定首層的目錄,并且相比相對路徑減少了路徑索引的消耗,在性能上來說也是更優(yōu)解
為了后續(xù)更好的文件管理和更加清晰的目錄層級,我們現(xiàn)在在 src 下添加如下目錄,每個目錄的作用后文都會提及
├── src
│?? ├── router ? ? ? ? ? 路由配置
│?? ├── stores ? ? ? 狀態(tài)管理
│?? ├── typings ? ? ? ? ts公共類型
│?? ├── utils ? ? ? ? ? 工具類函數(shù)封裝
│?? └── views ? ? ? ? 頁面視圖
添加別名配置:
// 指定解析路徑
import { resolve } from 'path'
const pathResolve = (dir: string) => resolve(__dirname, dir)
resolve: {
? ?alias: {
? ? ? ?'@': pathResolve('./src'), // 設(shè)置 `@` 指向 `src` 目錄
? ? ? ? views: pathResolve('./src/views'), // 設(shè)置 `views` 指向 `./src/views` 目錄,下同
? ? ? ? components: pathResolve('./src/components'),
? ? ? ? assets: pathResolve('./src/assets'),
? },
},
指定解析路徑使用的 path module需要先安裝@type/node,我們安裝在開發(fā)環(huán)境即可:
npm install @types/node --save-dev
構(gòu)建選項 build
當需要將應(yīng)用部署到生產(chǎn)環(huán)境時,只需運行 npm run build 命令就會執(zhí)行package.json對應(yīng)的vue-tsc --noEmit && vite build命令,從而對項目中使用到的 typescript 類型進行校驗,校驗通過后執(zhí)行打包功能
build: {
? ? ?outDir: 'dist', // 指定打包路徑,默認為項目根目錄下的 dist 目錄
? ? ?terserOptions: {
? ? ? ? ?compress: {
? ? ? ? ? ? ?keep_infinity: true, ?// 防止 Infinity 被壓縮成 1/0,這可能會導(dǎo)致 Chrome 上的性能問題
? ? ? ? ? ? ?drop_console: true, // 生產(chǎn)環(huán)境去除 console
? ? ? ? ? ? ?drop_debugger: true // 生產(chǎn)環(huán)境去除 debugger
? ? ? ? },
? ? },
? ? ?chunkSizeWarningLimit: 1500 // chunk 大小警告的限制(以 kbs 為單位)
}
outDir 可以用來指定打包文件存放的路徑,默認為項目根目錄下的 dist 文件夾
terser 是一個用于 ES6+ 的 JavaScript 解析器和 mangler/compressor 工具包。我們可以通過 terserOptions.compress 屬性對 js 進行一定的壓縮,減少打包文件體積。
chunkSizeWarningLimit默認為500,當打包后單個 chunk 體積超過500就會有警告,在實際項目中太小了,我們這里調(diào)整為1500
vite 的基本配置就到這了。
完整配置
vite.config.js目前的完整配置如下
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
const pathResolve = (dir: string) => resolve(__dirname, dir)
// https://vitejs.dev/config/
export default defineConfig({
?plugins: [vue()],
?build: {
? ?outDir: 'dist', // 指定打包路徑,默認為項目根目錄下的 dist 目錄
? ?terserOptions: {
? ? ?compress: {
? ? ? ?keep_infinity: true, ?// 防止 Infinity 被壓縮成 1/0,這可能會導(dǎo)致 Chrome 上的性能問題
? ? ? ?drop_console: true, // 生產(chǎn)環(huán)境去除 console
? ? ? ?drop_debugger: true // 生產(chǎn)環(huán)境去除 debugger
? ? },
? },
? ?chunkSizeWarningLimit: 1500 // chunk 大小警告的限制(以 kbs 為單位)
},
?resolve: {
? ?alias: {
? ? ?'@': pathResolve('./src'), // 設(shè)置 `@` 指向 `src` 目錄
? ? ?views: pathResolve('./src/views'),
? ? ?components: pathResolve('./src/components'),
? ? ?assets: pathResolve('./src/assets'),
? },
},
?base: './', // 設(shè)置公共基礎(chǔ)路徑
?server: {
? ?port: 4000, // 設(shè)置服務(wù)啟動端口號
? ?open: true, // 設(shè)置服務(wù)啟動時是否自動打開瀏覽器
? ?cors: true, // 允許跨域
? ?// 設(shè)置代理,根據(jù)我們項目實際情況配置
? ?proxy: {
? ? ?'/api': {
? ? ? ?target: 'http://127.0.0.1:8000',
? ? ? ?changeOrigin: true,
? ? ? ?secure: false,
? ? ? ?rewrite: path => path.replace(/^/api/, '')
? ? }
? }
}
})
三、配置 TypeScript
TypsScript 簡介
TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale
TypeScript 是基于Javascript 的強類型編程語言,對任何規(guī)模的項目都能提供更好的工具化體驗。
注:以上描述是官網(wǎng)對于 TypeScript 的定義。
其實偶爾也能看到一些人討論:小型項目或者業(yè)務(wù)場景特別簡單只需要一兩個前端開發(fā)就能完全開發(fā)的項目還有必要用 typescript 嗎?不會平白添加開發(fā)成本嗎?
其實作為一名成熟的業(yè)務(wù)開發(fā)人員,會發(fā)現(xiàn)用到的前端技術(shù)也就來來回回那幾樣,所以當你在團隊中發(fā)現(xiàn)很難在項目中學(xué)到什么的時候,除了跳槽,也可以考慮往項目中加一點新的技術(shù),比如 typecsript,不但能減少bug的產(chǎn)出,還能提升自己的知識儲備,為以后接觸多人協(xié)作的大型項目做鋪墊,何樂而不為呢?
而且在 vite 項目中:
Vite 天然支持引入
.ts文件。Vite 使用 esbuild 將 TypeScript 轉(zhuǎn)譯到 JavaScript,約是
tsc速度的 20~30 倍,同時 HMR 更新反映到瀏覽器的時間小于 50ms。
ts 只要有一定 js 基礎(chǔ)入門也很簡單,以下網(wǎng)站是我覺得還不錯的入門教程供大家學(xué)習(xí)
TypeScript 入門教程
Introduction · TypeScript Handbook(中文版)
tsconfig 文件詳解
在第二步初始化 vite 項目的時候可以看到,項目根目錄下多出了 tsconfig.json和tsconfig.node.json兩個文件
顧名思義,這個文件就是指定了用來編譯這個項目的根文件和編譯選項。(為啥多了個tsconfig.node.json?下文會解釋道)
當我們使用
不帶任何輸入文件的情況下調(diào)用
tsc,編譯器會從當前目錄開始去查找tsconfig.json文件,逐級向上搜索父目錄。不帶任何輸入文件的情況下調(diào)用
tsc,且使用命令行參數(shù)--project(或-p)指定一個包含tsconfig.json文件的目錄。
當命令行上指定了輸入文件時,tsconfig.json文件會被忽略。
還記得我們運行npm run build打包時會執(zhí)行的腳本命令嗎?(在 package.json 里)
"build": "vue-tsc --noEmit && vite build",
vue-tsc是一個基于 volar 的 vue3 命令行類型檢查工具,我們也是可以通過tsconfig.json去配置vue-tsc --noEmit需要檢查的內(nèi)容和方式。
打開tsconfig.json看看,有一些基礎(chǔ)的配置:
{
?"compilerOptions": {
? ?"target": "esnext",
? ?"useDefineForClassFields": true,
? ?"module": "esnext",
? ?"moduleResolution": "node",
? ?"strict": true,
? ?"jsx": "preserve",
? ?"sourceMap": true,
? ?"resolveJsonModule": true,
? ?"esModuleInterop": true,
? ?"lib": ["esnext", "dom"]
},
?"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
?"references": [{ "path": "./tsconfig.node.json" }]
}
tsconfig.node.json
{
?"compilerOptions": {
? ?"composite": true,
? ?"module": "esnext",
? ?"moduleResolution": "node"
},
?"include": ["vite.config.ts"]
}
先來看看tsconfig.json最后一個references,可以看到是用來引用tsconfig.node.json中的內(nèi)容的。
原來 references屬性是 TypeScript 3.0 的新特性,允許將 TypeScript 程序拆分結(jié)構(gòu)化。這和我們寫 vue 組件的思想有著異曲同工之妙,避免了在一個文件中處理過多的內(nèi)容,而是通過拆分成多個文件,分別配置不同的部分,達到更加清晰,可維護性更高的目的。
本文只介紹幾個需要著重理解的配置選項,完整的配置可以參考編譯選項 · TypeScript中文網(wǎng) · TypeScript——JavaScript的超集
include
這個屬性很好理解,就是指定需要編譯的文件范圍。
默認是對 src 下的 .ts、.d.ts、.tsx、.vue結(jié)尾的文件都需要進行編譯。
可以看到tsconfig.node.json中的"include": ["vite.config.ts"]表明這個單獨拆分出來的配置文件只是負責(zé)編譯 vite 的配置文件vite.config.ts
與之相對的,我們可以添加 exclude 配置不需要編譯的文件范圍:
exclude
"exclude": ["node_modules","dist"]
將第三方依賴包、打包后的靜態(tài)文件都排除在外。
compilerOptions.skipLibCheck
作用:忽略所有的聲明文件( *.d.ts)的類型檢查。
"compilerOptions": {
? ?"skipLibCheck": true
}
簡而言之,這個屬性不但可以忽略 npm 不規(guī)范帶來的報錯,還能最大限度的支持類型系統(tǒng)。設(shè)置為 true 就不用怕使用的第三方庫不規(guī)范了。
可能有人好奇,為什么要跳過這些第三方庫的檢查?
我們做類型檢查(以及下文的代碼規(guī)范等)的目的是為了對團隊內(nèi)業(yè)務(wù)代碼開發(fā)保持統(tǒng)一和規(guī)范,以保證開發(fā)成員之間的快速上手和后續(xù)維護。所以我們要做的是將各種規(guī)則集成到業(yè)務(wù)代碼模塊,而一些框架上的或者第三方庫的內(nèi)容就不用多此一舉了。
compilerOptions.baseUrl
作用:設(shè)置baseUrl來告訴編譯器到哪里去查找模塊。所有非相對模塊導(dǎo)入都會被當做相對于 baseUrl。
注意相對模塊的導(dǎo)入不會被設(shè)置的baseUrl所影響,因為它們總是相對于導(dǎo)入它們的文件.
這個設(shè)置的作用和之前構(gòu)建選項 build 中的 base 是類似的,我們配置為當前根目錄即可
"baseUrl": "./"
compilerOptions.paths
作用:模塊名到基于 baseUrl的路徑映射的列表。
請注意"paths"是相對于"baseUrl"進行解析。
還記不記得我們在第三節(jié)配置了路徑別名resolve.alias,為了讓編譯 ts 時也能夠解析對應(yīng)的路徑,我們還需要配置 paths 選項:
"paths": {
? ?"@/*": ["src/*"],
? ?"views/*": ["src/views/*"],
? ?"components/*": ["src/components/*"],
? ?"assets/*": ["src/assets/*"]
}
compilerOptions.isolatedModules
作用:將每個文件作為單獨的模塊
typescript 將沒有導(dǎo)入/導(dǎo)出的文件視為舊腳本文件。因為這樣的文件不是模塊和它們在全局命名空間中合并的任何定義。該配置項會禁止此類文件。將任何導(dǎo)入或?qū)С鎏砑拥奈募家暈槟K
這個設(shè)置在 vite 官方文檔中是被要求應(yīng)該設(shè)置為 true 的,項目初始化的時候并沒有默認加上這條,所以需要我們自己來:
"isolatedModules": true
compilerOptions.types
作用:添加要包含的類型聲明文件名列表,只有在這里列出的模塊的聲明文件才會被加載進來
"types": ["vite/client"]
可以將 vite/client 添加到 types中,這會提供以下類型定義補充:
資源導(dǎo)入 (例如:導(dǎo)入一個
.svg文件)import.meta.env上 Vite 注入的環(huán)境變量的類型定義import.meta.hot上的 HMR API 類型定義
我們需要補充的配置差不多就這些了,現(xiàn)階段完整配置如下:
完整配置
{
?"compilerOptions": {
? ?"baseUrl": "./",
? ?"skipLibCheck": true,
? ?"target": "esnext",
? ?"module": "esnext",
? ?"moduleResolution": "node",
? ?"noImplicitAny": false,
? ?"strict": true,
? ?"jsx": "preserve",
? ?"sourceMap": true,
? ?"resolveJsonModule": true,
? ?"esModuleInterop": true,
? ?"lib": ["esnext", "dom"],
? ?"types": ["vite/client"],
? ?"isolatedModules": true,
? ?"paths": {
? ? ?"@/*": ["src/*"],
? ? ?"views/*": ["src/views/*"],
? ? ?"components/*": ["src/components/*"],
? ? ?"assets/*": ["src/assets/*"]
? }
},
?"include": [
? ?"src/**/*.ts",
? ?"src/**/*.d.ts",
? ?"src/**/*.tsx",
? ?"src/**/*.vue"
],
?"exclude": ["node_modules", "dist"]
}
env.d.ts 文件詳解
打開 src 文件夾下的 env.d.ts 文件,可以看到長這樣
///
declare module '*.vue' {
?import type { DefineComponent } from 'vue'
?// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
?const component: DefineComponent<{}, {}, any>
?export default component
}
讓我們看看第一行的這個三斜杠指令,在官方文檔客戶端類型中解釋到了:
Vite 默認的類型定義是寫給它的 Node.js API 的。要將其補充到一個 Vite 應(yīng)用的客戶端代碼環(huán)境中,請?zhí)砑右粋€ d.ts 聲明文件:/// 。
請注意:三斜杠指令是包含單個XML標簽的單行注釋,注釋的內(nèi)容會做為編譯器指令使用,只有在文件的最頂部才會生效,可以查看TypeScript: Documentation - Triple-Slash Directives學(xué)習(xí)相關(guān)內(nèi)容。
所以這個文件的作用就呼之欲出了:幫助編譯器識別類型。
TypeScript 相比 JavaScript 增加了類型聲明。原則上,TypeScript 需要做到先聲明后使用。這就導(dǎo)致開發(fā)者在調(diào)用很多原生接口(瀏覽器、Node.js)或者第三方模塊的時候,因為某些全局變量或者對象的方法并沒有聲明過,導(dǎo)致編譯器的類型檢查失敗。
當我們遇上Property xxx does not exist on type ...報錯的時候,就可以定位到是沒有聲明過這個方法/屬性。我們就可以在這個文件作全局聲明。
可以看到,該文件已經(jīng)默認為所有的 vue 文件聲明了 DefineComponent的組件類型,這就意味著只要我們的單文件組件使用
的寫法,就能避免 vue 文件中大多數(shù)類型聲明的報錯,比如使用路由的this.$router、this.$route命令
四、接入代碼規(guī)范
代碼規(guī)范
作為一個企業(yè)級框架,代碼規(guī)范是必不可少的。雖然我們使用了具有類型規(guī)范的 typescript,但是仍然無法規(guī)避團隊成員使用不同的開發(fā)風(fēng)格,比如語句結(jié)尾用不用;,縮進使用兩個空格還是四個空格,變量名用小駝峰還是連字符等等等等。
統(tǒng)一的代碼規(guī)范,不但能增強代碼的可維護性,也能提高團隊成員的相互協(xié)作,更可貴的是能夠培養(yǎng)前端開發(fā)者完善的代碼風(fēng)格和開發(fā)意識。
ESlint
簡介
ESlint 被稱作下一代的 JS Linter 工具,能夠?qū)?JS 代碼解析成 AST 抽象語法樹,然后檢測 AST 是否符合既定的規(guī)則。而這些“規(guī)則”,具有非常靈活的配置。
2019 年 1 月,TypeScirpt 官方?jīng)Q定全面采用 ESLint 作為代碼檢查的工具,并創(chuàng)建了一個新項目 typescript-eslint,提供了 TypeScript 文件的解析器 @typescript-eslint/parser 和相關(guān)的配置選項 @typescript-eslint/eslint-plugin 等。話不多說,我們來看看如何接入框架中去吧:
安裝
直接運行命令即可安裝:
npm install --save-dev eslint
ESLint 默認使用的是 Espree 進行語法解析,所以無法對部分 typescript 語法進行解析,因此我么還需要安裝 @typescript-eslint/parser 替換掉默認的解析器
npm install @typescript-eslint/parser --save-dev
接下來需要安裝對應(yīng)的插件 @typescript-eslint/eslint-plugin 它作為 eslint 默認規(guī)則的補充,提供了一些額外的適用于 ts 語法的規(guī)則:
npm install --save-dev @typescript-eslint/eslint-plugin
當然不要忘了安裝eslint-plugin-vue,借用這個 plugin 的能力才能讓 eslint 識別 vue 文件
npm install --save-dev eslint-plugin-vue
安裝好依賴插件后,我們就可以在項目根目錄下
新建一個
.eslintrc.js用來配置 ESlint 的相關(guān)規(guī)則新建一個
.eslintignore文件用來指定不進行 ESlint 校驗的目錄/文件,我們將以下文件/文件夾忽略 ESlint 校驗/build/
/dist/
/node_modules/
*.js
配置
老規(guī)矩,我們來了解一下 ESlint 中幾個比較重要的配置項:
env
作用:提供預(yù)定義的環(huán)境變量。
因為node 或者瀏覽器中的全局變量很多,如果我們一個個聲明會顯得繁瑣,因此就需要用到env,這是對環(huán)境定義的一組全局變量的預(yù)設(shè)。
env: {
? ?browser: true,
? ?es2021: true, ?// 添加所有 ECMAScript 2021 全局變量并自動將 ecmaVersion 解析器選項設(shè)置為 12
? ?node: true,
},
parser
作用:指定要使用的解析器。我們指定為vue-eslint-parser即可
parser: 'vue-eslint-parser',
parserOptions
作用:給解析器傳入一些其他的配置參數(shù)
比如我們之前安裝的@typescript-eslint/parser就可以在這里進行配置
parserOptions: {
? ?parser: '@typescript-eslint/parser',
? ?ecmaVersion: "latest", // 支持的es版本
? ?sourceType: 'module', ?// 代模塊類型,默認為script,我們設(shè)置為module
},
extends
作用:使用預(yù)設(shè)的 lint 包
如果要我們自己去設(shè)置各個規(guī)則未免會顯得繁瑣,所以可以直接使用業(yè)界的最佳實踐
extends: [
? ?'plugin:vue/vue3-recommended',
? ?'plugin:@typescript-eslint/recommended'
],
我們選擇 plugin:vue/vue3-recommended和 plugin:@typescript-eslint/recommended 作為基礎(chǔ)規(guī)則即可
plugins
作用:增強 ESlint 功能
還記得我們最開始安裝的@typescript-eslint/eslint-plugin嗎?它就是用來給 eslint 提供一些額外的適用于 ts 語法的規(guī)則插件名中的 eslint-plugin- 可以省略:
plugins: ['@typescript-eslint'],
rules
作用:創(chuàng)建自定義規(guī)則。
規(guī)則列表:
eslint-plugin-vue
規(guī)則定義值:
off 或 0 - 關(guān)閉規(guī)則
warn 或 1 - 開啟規(guī)則, 使用警告 程序不會退出
error 或 2 - 開啟規(guī)則, 使用錯誤 程序退出
示例:
rules: {
? ?// 禁止出現(xiàn)未使用過的變量
? ?'no-unused-vars': 'error',
? ?// 縮進使用 4 個空格,并且 switch 語句中的 Case 需要縮進
? ?// https://eslint.org/docs/rules/indent
? ?'indent': ['error', 4, {
? ? ? ?'SwitchCase': 1,
? ? ? ?'flatTernaryExpressions': true
? }],
? ?// 只有一個參數(shù)時,箭頭函數(shù)體可以省略圓括號
? ?// https://eslint.org/docs/rules/arrow-parens
? ?'arrow-parens': 'off',
}
雖然我們通過 extends 引入了行業(yè)內(nèi)最佳實踐的一些規(guī)則,但是每個團隊還是有每個團隊自己的開發(fā)習(xí)慣,所以我們可以通過 rules 添加或者修改 extends 中的規(guī)則。
這里我就分享一下我們團隊喜歡用的規(guī)則,當時是團隊leader拉著我們幾個老員工一條一條過出來的。
定義的規(guī)則比較多,為了不占位置,就不直接放代碼了,感興趣的可以直接去代碼倉庫中查看。
其他
做完以上步驟之后,可能有人會發(fā)現(xiàn):咋不管用呢?
這是因為沒有在各自的編輯器開啟 ESlint 的功能,例如 webstorm:

除了編輯器自帶的一鍵修復(fù) ESlint 問題,我們也可以在package.json通過添加如下命令
"lint": "eslint --ext .js,.vue,.ts src",
"lint:fix"": "npx eslint ./src/**/*.vue --fix",
這樣就可以通過npm run lint在控制臺查看不符合規(guī)則的代碼列具,和通過npm run lint:fix快速自動修復(fù) ESlint 問題了,當然,有些問題還是需要手動修復(fù)的。
Stylelint
上面我們通過 ESlint 負責(zé)檢查了 html 和 JavaScrript,css 當然不能缺席,所以我們可以通過接入 Stylelint 規(guī)范 css 的書寫風(fēng)格。
安裝
我們選擇使用 scss 來增強 css 的語法能力,安裝以下包
npm install sass stylelint stylelint-scss --save-dev
日常開發(fā)中,我們主要用到的是 scss 提供的層級能力,這樣對父子級的展示就非常明了,使用示例:
? ?
? ? ? ?
? ?
當然 scss 還有其他變量、混合等好用的功能,可以查看文檔進行學(xué)習(xí)
StyleLint 的初始化和 ESlint 差不多,在項目根目錄下新建兩個文件:
.stylelintrc.js用來配置 stylelint 規(guī)則.stylelintignore用來配置不需要通過 stylelint 約束的文件,我們添加以下文件:# 其他類型文件
*.js
*.ts
*.jpg
*.woff
# 測試和打包目錄
/dist/
/node_modules/
配置
我們安裝都是最新版本的依賴包,所以會有一些額外的配置,比如 stylelint 14 所需要的配置:
Stylelint 14+ 不再包含 Scss,Sass,Less或者SugarSS這種類css的預(yù)編譯器的解析了,所以我們可以通過 extending 共享配置來包含何時的語法解析,我們就使用stylelint-config-standard-scss來作為公共規(guī)則
npm install --save-dev stylelint-config-standard-scss
使用:
"extends": ["stylelint-config-standard-scss"],
當然,為了然 stylelint 能夠讀 vue (.html, .xml, .svelte, .vue etc.)文件,我們還需要安裝postcss-html
npm install --save-dev postcss-html
然后配置 customSyntax 屬性
"customSyntax": "postcss-html"
規(guī)則定義
我們可以使用一些自定義規(guī)則,為了節(jié)省篇幅,可以到代碼倉庫中去查看
使用
我們開啟編輯器/IDE的 stylelint 就可以享受約束帶來的成就感了:

接著在 package.json 中添加如下命令:
"stylelint": "npx stylelint --aei .vue src",
"stylint:fix": "npx stylelint ./src/**/*.vue --fix"
就可以通過npm run stylelint在控制臺快速查看不匹配 stylelint 的文件具體代碼,和npm run stylint:fix一鍵修復(fù)了。
.editorconfig
定義了這么多規(guī)則,但是編輯器不夠智能怎么辦?
敲個tab、回車鍵縮進總是不對,每次手動對齊那不難受的很?
我們可以在項目根目錄下添加.editorconfig文件,這個文件可以幫助開發(fā)者在不同的編輯器和 IDE 之間定義和維護一致的代碼風(fēng)格,使用示例:
# Editor configuration, see http://editorconfig.org
# 表示是最頂層的 EditorConfig 配置文件
root = true
[*] ? ? # 表示所有文件適用
charset = utf-8 ? ? # 設(shè)置文件字符集為 utf-8
indent_style = space ? # 縮進風(fēng)格(tab | space)
indent_size = 4 ? # 縮進大小
end_of_line = lf ? # 控制換行類型(lf | cr | crlf)(lf是\n, cr是\r, crlf是\r\n)
trim_trailing_whitespace = true ? ? # 去除行首的任意空白字符
insert_final_newline = true ? ? # 始終在文件末尾插入一個新行
[*.md] # 表示僅 md 文件適用以下規(guī)則
max_line_length = off
trim_trailing_whitespace = false
git hooks
既然已經(jīng)定義好了這么多的規(guī)則,但如何防止不符合 ESlint 代碼規(guī)范的代碼被提交到 git 倉庫?我們可以使用 husky 和 lint-staged
husky 是控制代碼提交的鉤子,在代碼被提交到 Git 倉庫之前,我們可以在這里做一些預(yù)檢查或者格式化工作。
lint-staged 是一個前端文件過濾的工具(僅僅是文件過濾器),可以對文件系統(tǒng)進行過濾,使得每次提交不必對所有文件進行校驗。
安裝
npm install --save-dev [email protected] lint-staged
注意:最新版本 husky 存在bug,所以我們使用低版本的就可以了
修改 package.json 配置
"husky": {
? ?"hooks": {
? ? ?"pre-commit": "lint-staged"
? }
},
"lint-staged": {
? ?"src/**/*.{ts,vue}": [
? ? ? ?"eslint --fix"
? ],
? ?"*.vue": [
? ? ? ?// stylelint14+ 需要 --custom-syntax postcss-html的配置
? ? ? ?"stylelint --fix --custom-syntax postcss-html"
? ]
},
這樣,每次在 commit 代碼之前,都會校驗?zāi)闾峤坏奈募煾捣享椖恐信渲玫?ESlint 規(guī)則了,不符合則不能提交,且會自動幫你執(zhí)行eslint --fix和stylelint --fix自動修復(fù)部分問題。示例:

基本配置已經(jīng)接入完畢了,接下來,我們就要對框架的應(yīng)用部分進行擴展:
第二部分
五、接入 UI 庫
Naive UI 是尤大推薦的 vue3 UI 庫,全量使用 TypeScript 編寫,但是畢竟是一個比較年輕的 UI 庫,相對于 element 和 ant design 等老牌強者還是略有不足的,在真正的項目級環(huán)境應(yīng)該暫時不會考慮使用 naive ui。本著學(xué)習(xí)新知識的目的,我們還是可以來了解一下的。
UI 庫的使用其實都大差不差,在框架中的引入我們需要考慮的是以下兩點:
按需引入
打包優(yōu)化
按需引入能夠靈活應(yīng)用 tree-shaking的能力將沒有使用到的排除出去,避免打包體積的冗余;而打包優(yōu)化之前在webpack 中比較常用的是對大型的三方庫做單獨打包、避免重復(fù)打包等,如何在 vite 中做打包優(yōu)化呢?哈哈,其實我也不熟,后續(xù)會花時間重點研究一下再補充進來。
首先看看 Naive UI 支持的依賴版本
Vue > 3.0.5
TypeScript > 4.1
好的,沒有什么問題,接下來步入正軌
安裝&引入
我們使用 npm 安裝 naive-ui ,配套的字體 vfonts 就不安裝了,使用默認的即可
npm i -D naive-ui
使用方面,當然最佳實踐是按需引入:
在我們的src/utils新建一個demand-import.ts,將我們?nèi)粘i_發(fā)會使用的比較頻繁的組件引入進來即可
import {
? ?// create naive ui
? ?create,
? ?// component
? ?NButton
} from 'naive-ui'
export const naive = create({
? ?components: [NButton]
})
然后在main.ts中引入
import { createApp } from 'vue'
import App from './App.vue'
import { naive } from './utils/demand-import'
const app = createApp(App as any)
app.use(naive)
就可以在頁面上使用了:
? ?
? ? ? Tertiary
? ?
在使用上,直接照著官方文檔就可以愉快的做 cv 俠了,我就不在此贅述了
如果對性能真的潔癖到極致,可以采用按需引入 + 直接引入的方式,就是對比較常用的組件采用按需引入的方式注冊到全局,對不常用的組件直接在相關(guān)處使用import xxx from 'naive-ui'引入使用。
六、接入 vue-router
vue 強大的單頁面應(yīng)用能力其實主要依靠基于 vue-router 帶來的無縫切換。
安裝
npm install vue-router --save
配置
首先我們在src/views/home新建一個空白的 index.vue 文件
? ?hello vue3
然后在 src/router 目錄下新建一個index.ts,引入剛才新建的文件路由地址設(shè)為首頁/
import {
? ?createRouter, createWebHashHistory, RouteRecordRaw,
} from 'vue-router'
const routes: Array = [
? { path: '/', name: 'Home', component: () => import('views/home/index.vue')}
]
const router = createRouter({
? ?history: createWebHashHistory(), // history 模式則使用 createWebHistory()
? ?routes,
})
export default router
我們使用的是 hash 模式,當然,這是我們團隊的習(xí)慣,history 模式和 hash 也差不多,選擇適合自己的就行
接著在src/main.ts中引入該文件
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app = createApp(App as any)
app.use(router)
在src/App.vue中添加router-view組件
? ?
? ? ? ?
? ?
運行服務(wù),可以看到首頁的內(nèi)容,這樣我們的基本路由就配置成功了

七、接入狀態(tài)管理工具 pinia
pinia 是一個輕量級的狀態(tài)管理庫,屬于 vue3 生態(tài)圈新的成員之一,也可以把它看做 vuex5,同時支持 vue2 和 vue3,模塊化的設(shè)計讓它的結(jié)構(gòu)十分地清晰明了,別的不說,看尤大推文中的預(yù)期就能知道 pinia 的牛逼之處了:

npm install pinia --save
運行完發(fā)現(xiàn)有警告:
peerDependencies WARNING pinia@latest requires a peer of @vue/composition-api@^1.4.0 but none was installed
peerDependencies WARNING [email protected] ? vue-demi@* requires a peer of @vue/composition-api@^1.0.0-rc.1 but none was installed
說 pinia 依賴于@vue/composition-api@^1.4.0包,但是composition-api是 vue2 用到的,可以在 vue2 中使用 vue3的composition-api,我們忽略它就行了。
引入
在 main.ts中引入
import { createPinia } from 'pinia'
app.use(createPinia())
使用
我們以一個簡單的累加器作為例子:在src/stores下新建一個counters.ts文件
首先,我們需要使用defineStore()來定義一個 store
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
? ?state: () => {
? ? ? ?return {
? ? ? ? ? ?count: 0
? ? ? }
? },
? ?getters: {
? ? ? ?count() {
? ? ? ? ? ?return this.count
? ? ? }
? },
? ?actions: {
? ? ? ?increment() {
? ? ? ? ? ?this.count++
? ? ? }
? }
})
注意:
defineStore中的第一個參數(shù)需要在你整個應(yīng)用當中保持唯一。
這種寫法和我們之前使用的 vuex 簡直一模一樣,唯一的區(qū)別就是 pinia 將mutations給干掉了,其實之前在使用過程中也確實覺得mutations和actions功能有很大程度的重合,這波升級簡直完美。
當然,pinia 的魅力自然不止于此,Vue 的 setup 語法帶來的一系列提升才是最大的亮點:
我們可以在defineStore中使用類setup的寫法:直接將上面的配置項替換成一個函數(shù):
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
? ?const count = ref(0)
? ?function increment() {
? ? ?count.value++
? }
? ?return { count, increment }
})
然后在頁面中就可以這樣使用了:
? ? ? ?{{ counter.count }}
? ?
counter 可以被看做是一個reactive對象,所以,counter就像setup中的 props 一樣,解構(gòu)是被禁止使用的:
const counter = useCounterStore()
const { count } = counter
{{ count }}
我們會發(fā)現(xiàn),無論怎樣點擊count的值都不會變化,只會維持它的初始值不變。
當然pinia很貼心的提供了storeToRefs方法,讓我們可以享受解構(gòu)的樂趣:
const { count } = storeToRefs(counter)
八、接入圖表庫 echarts5
B端產(chǎn)品圖表的運用還是很頻繁的,對市面上比較火的幾款圖表庫進行橫向?qū)Ρ群?,還是覺得 echarts 最香。尤其是 echarts5版本接入了很多新特性以及對老版的優(yōu)化,話不多說,我們直接開始接入吧:
安裝&引入
npm install echarts --save
之所以強調(diào)第5版,是因為在這個版本,echarts 增加了性能黨最愛的按需引入:
在src/utils/下新建echarts.ts用來引入我們需要使用的組件
import * as echarts from 'echarts/core'
import {
? ?BarChart,
? ?// 系列類型的定義后綴都為 SeriesOption
? ?BarSeriesOption,
? ?// LineChart,
? ?LineSeriesOption
} from 'echarts/charts'
import {
? ?TitleComponent,
? ?// 組件類型的定義后綴都為 ComponentOption
? ?TitleComponentOption,
? ?TooltipComponent,
? ?TooltipComponentOption,
? ?GridComponent,
? ?GridComponentOption,
? ?// 數(shù)據(jù)集組件
? ?DatasetComponent,
? ?DatasetComponentOption,
? ?// 內(nèi)置數(shù)據(jù)轉(zhuǎn)換器組件 (filter, sort)
? ?TransformComponent,
? ?LegendComponent
} from 'echarts/components'
import { LabelLayout, UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
// 通過 ComposeOption 來組合出一個只有必須組件和圖表的 Option 類型
export type ECOption = echarts.ComposeOption<
? ?| BarSeriesOption
? ?| LineSeriesOption
? ?| TitleComponentOption
? ?| TooltipComponentOption
? ?| GridComponentOption
? ?| DatasetComponentOption
>
// 注冊必須的組件
echarts.use([
? ?TitleComponent,
? ?TooltipComponent,
? ?GridComponent,
? ?DatasetComponent,
? ?TransformComponent,
? ?BarChart,
? ?LabelLayout,
? ?UniversalTransition,
? ?CanvasRenderer,
? ?LegendComponent
])
// eslint-disable-next-line no-unused-vars
const option: ECOption = {
? ?// ...
}
export const $echarts = echarts
就可以在頁面中使用了:
注意:只有在onMounted及之后才能通過document.getElementById拿到頁面上的 dom 元素然后通過$echarts.init(ele)初始化。使用效果:

九、配置統(tǒng)一 axios 處理
前后端的通訊離不開 ajax 方法,而 axios 庫作為前端最流行的 ajax 庫別樹一幟。
除了簡單使用get/post等簡單調(diào)用,我們還可以添加狀態(tài)碼攔截、請求取消、錯誤處理等等能力。但是限于篇幅有限,本文就不做那么復(fù)雜的封裝了,后面會抽空我專門寫一篇從 axios 原理分析到完整的封裝處理。
安裝&引入
npm install axios --save
我們在src/utils下新建一個axios.ts,在這里封裝axios的基本功能
首先引入我們的主角Axios、錯誤處理類型接口AxiosError和響應(yīng)結(jié)果接口AxiosResponse
import Axios, {AxiosError, AxiosResponse} from 'axios'
我們可以通過Axios.create()方法創(chuàng)建一個自定義配置的axios實例
const BASE_URL = 'https://api.example.com'
const TIME_OUT = 10 * 1000
const instance = Axios.create({
? ?baseURL: BASE_URL,
? ?timeout: TIME_OUT
})
比如指定每個請求的baseURL,指定請求的超時時間為10秒
接著我們使用后置攔截器,對獲取的響應(yīng)進行攔截:
instance.interceptors.response.use(
? (res: AxiosResponse) => {
? ? ? ?if (String(res.status).indexOf('2') !== 0) {
? ? ? ? ? ?return {
? ? ? ? ? ? ? ?code: res.status,
? ? ? ? ? ? ? ?message: res.data.message || '請求異常,請刷新重試',
? ? ? ? ? ? ? ?result: false
? ? ? ? ? }
? ? ? }
? ? ? ?return Promise.reject(res.data)
? },
? (error: AxiosError) => {
? ? ? ?if (error && error.response) {
? ? ? ? ? ?errorHandle(error.response.status, error.response)
? ? ? ? ? ?return Promise.reject(error.response)
? ? ? }
? ? ? ?console.log('網(wǎng)絡(luò)請求失敗, 請刷新重試')
? ? ? ?return Promise.reject(error)
? }
)
當我們獲取的響應(yīng)狀態(tài)碼不是以 2 開頭的,視作響應(yīng)失敗
當捕獲到錯誤請求時,可以自定義錯誤處理:
const errorHandle = (status: number, error): void => {
? ?// HTTP狀態(tài)碼判斷
? ?switch (status) {
? ? ? ?case 401:
? ? ? ? ? ?return alert(`Error Code: ${status}, Message: ${error.msg || '登錄失效,請重新登錄'}`)
? ? ? ?case 403:
? ? ? ? ? ?return alert(`Error Code: ${status}, Message: ${error.msg || '你沒有訪問權(quán)限'}`)
? ? ? ?case 500:
? ? ? ? ? ?return alert(`Error Code: ${status}, Message: ${error.msg || '后臺錯誤,請聯(lián)系管理員'}`)
? ? ? ?case 502:
? ? ? ? ? ?return alert(`Error Code: ${status}, Message: ${error.msg || '平臺環(huán)境異常'}`)
? ? ? ?default:
? ? ? ? ? ?alert(`Error Code: ${status}, Message: ${error.msg || '未知錯誤,請刷新重試'}`)
? }
}
最后再導(dǎo)出我們常用的請求方法:
const getPromise = (method, url, params, config = {}) => {
? ?return new Promise((resolve, reject) => {
? ? ? ?instance[method](method, url)(params, config).catch(e => e.response.data)
? ? ? ? ? .then(res => resolve(res))
? ? ? ? ? .catch(err => reject(err))
? })
}
const get = (url: string, params?: any) => getPromise('get', url, { params })
const post = (url: string, params: any, config?: AxiosRequestConfig) => getPromise('post', url, params, config)
export {
? ?get,
? ?post,
}
十一、參考/指引文檔
Vue.js
Home | Vite 官方中文文檔
Node.js
TypeScript: JavaScript With Syntax For Types.
ESLint - Pluggable JavaScript linter
Home | Stylelint
Naive UI: 一個 Vue 3 組件庫
pinia
TypeScript 入門教程
Introduction · TypeScript Handbook(中文版)
Getting Started | Axios Docs
總結(jié)
奈何最近工作確實忙碌,其實很多細節(jié)都省略掉了,當然最早列的寫作大綱其實遠不止這點內(nèi)容,我們還可以添加單元測試,mock 數(shù)據(jù)等等。后續(xù)會不斷的補充與完善~
Node 社群
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
如果你覺得這篇內(nèi)容對你有幫助,我想請你幫我2個小忙:
1. 點個「在看」,讓更多人也能看到這篇文章 2. 訂閱官方博客?www.inode.club?讓我們一起成長 點贊和在看就是最大的支持??
