<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          詳解從零搭建企業(yè)級 vue3 + vite2+ ts4 框架全過程

          共 25376字,需瀏覽 51分鐘

           ·

          2022-03-15 17:45


          大廠技術(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

          1. npm 低于 7+ 的建議升級下 npm,命令npm install npm -g

          2. 也可以不輸入后面的-- --template vue-ts參數(shù)進行手動選擇

          3. 使用 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.jsontsconfig.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

          安裝好依賴插件后,我們就可以在項目根目錄下

          1. 新建一個.eslintrc.js用來配置 ESlint 的相關(guān)規(guī)則

          2. 新建一個 .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-recommendedplugin:@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 --fixstylelint --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)

          就可以在頁面上使用了:


          在使用上,直接照著官方文檔就可以愉快的做 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 文件




          然后在 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給干掉了,其實之前在使用過程中也確實覺得mutationsactions功能有很大程度的重合,這波升級簡直完美。

          當然,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 可以被看做是一個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?讓我們一起成長

          點贊和在看就是最大的支持??

          瀏覽 153
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性爱XXXX黑人XYX性爽 | 日皮视频在线播放 | 中文字幕日本欧美 | 黄色日本欧美 | 久久三级毛片 |