從今天開始,我們開啟《手把手搭建Vue3中后臺框架》系列文章,這是一個我們已經在生產中實際使用的項目,技術棧是:
- 前端:Vue3 + TypeScript + Vite + Pinia + NAIveUI
我會在工作之余抽時間把整體框架的開發過程一點一點寫出來,另外UI組件庫我將更換為NaiveUI 有技術不到位的地方,希望大家能指正出來。今天我們就從項目創建開始。
使用 Vite 創建項目
pnpm create vite
√ Project name: ... OpenDataV
√ Select a framework: » vue
√ Select a variant: » vue-ts
啟動項目
cd OpenDataV
pnpm install
pnpm run dev
配置基礎開發功能
創建完項目后,我們需要配置一些基礎功能來滿足開發要求,主要有以下幾點:
- 目錄別名配置
- 打包配置
- 開發服務配置
- 環境變量的使用配置
目錄別名配置
在項目開發的過程中,我們需要使用導入文件,可以采用相對導入和絕對導入的方式,相對導入在有些地方需要使用多個..來進行目錄定位,所以通常我們都使用絕對定位,為了方便導入,可以給指定目錄設置別名,引入是就不需要寫長長的目錄了。
首先在在vite.config.ts中增加別名配置:
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
find: /@//,
replacement: resolve(__dirname, 'src') + '/'
}
],
extensions: ['.ts', '.js', '.jsx', '.tsx'],
}
})
在使用path這個包之前,需要安裝@types/node這個包,因為我們使用的是ts,所以在項目當中就會有ts類型檢查。因為有很多庫并沒有遷移至ts,所以ts提供了一種中間的處理方式,就是.d.ts文件,用來給特定的庫添加類型說明。node本身并沒有遷移至ts,所以我們在使用一些node庫的時候就會報錯,因此就需要安裝類型說明:@types/node,只要安裝在開發依賴下即可。
extensions的配置是使用別名時要忽略的文件后綴,官方不建議忽略.vue后綴,因此我們只配置了.ts、.js、.tsx、.jsx
配置完vite以后,我們還要配置tsconfig.json文件,讓ts也認識這個別名。
{
"compilerOptions": {
"baseUrl": "./", // 基礎根目錄
"paths": {
"@/*": ["src/*"]
}
}
配置好別名以后,就可以在引入模塊時使用了。
打包配置
主要是配置打包的目標版本和分塊大小,target表示在打包時無論我們使用的是哪個版本的JAVAScript標準,都處理成es2015兼容版本。
build: {
target: 'es2015',
chunkSizeWarningLimit: 1500
}
開發服務配置
當我們創建好項目啟動的時候,默認啟動項目的時候只能通過localhost訪問,而且端口并不是我們指定的,所以我們首先要配置訪問限制,方便其他人也能查看我們的開發頁面,并要指定端口。
server: {
https: false,
host: true,
port: 3000
}
開發過程中一般不需要啟用https,host可以配置為指定IP,也可以配置為布爾型,如果我們希望所有IP都能訪問,可以將其配置為0.0.0.0或者true。
除了以上配置外,還有一個配置項proxy,這是一個代理配置,可以理解為網絡代理,就是把我們的請求代理到其他的地址。要搞清楚proxy的用法,首先我們要了解前后端分離以后前端是怎么獨立運行的。
在傳統的web開發過程中,一般是通過后端來渲染前端頁面數據,例如我們使用的Django Jinjia模板等。這個時候在開發的過程中就需要把整個服務跑起來。但是前后端分離的開發模式將前端和后端徹底分開了,僅通過API連接起來,這就使得前端開發的時候并不需要后端服務器,這種方式是怎么做到的呢?其實就是前端自己啟動一個服務器來渲染前端頁面數據,而不是通過后端渲染,只通過API來獲取后端數據。
前后端完全分離的開發模式使得前端與后端的鏈接僅僅是中間的數據。那么如果在功能開發前就定義好接口和返回的數據格式,前端就可以通過假數據來測試已開發的功能,不需要等后端開發完后才能測試。對于假數據我們有多種方式去實現它,最常見的就是mock,因為前端已經有了自己的服務器,我們只要把假數據寫到json文件中,通過前端服務器發給前端頁面就可以了。實際上依然是前端從服務器拿到數據再渲染頁面,只不過這個服務器是前端的自己啟動的,而數據是固定的假數據而已。
理解上這個過程以后,我們再來看看proxy這個配置的意義。因為我們和后端約定好了接口和返回數據的格式,因此在編寫前端頁面的時候我們就可以寫好這些請求和處理,但是我們的前端可以要從多個后端獲取數據或者我們開發的時候是從本地服務器獲取數據,但是聯調的時候又要從真實后端獲取數據,這個時候proxy就派上用場了。我們先來看一下proxy的配置示例:
proxy: {
// 字符串簡寫寫法
'/foo': 'http://localhost:4567',
// 選項寫法
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, '')
}
}
proxy是通過{key: options}的方式去配置的,其中key是請求的前綴,而options則是我們需要轉發的實際地址,例如以上示例:
- /foo開頭的請求轉發到地址:http://localhost:4567
也就是說當我們在前端發送了/foo/xxx這個請求后,實際的請求會發送到http://localhost:4567這個服務去,而得到的返回值也是從這里發回來的。
- /api開頭的請求轉發到地址:http://jsonplaceholder.typicode.com,并將地址中的api去掉
也就是說/api/user/info這個請求最終會變成http://jsonplaceholder.typicode.com/user/info請求。
通過代理的這種方式我們就可以很方便的切換數據來源,但是要注意了,這只是在開發階段使用,如果部署到生產環境后就失效了,因為在生產環境我們前端是不會啟動自有服務器的,通常都是通過Nginx服務進行靜態資源的轉發。所以要記住了:以上只在開發階段有用。
明確了以上知識點,那么proxy的配置就根據實際情況了使用了。在這里我們先不配置。
環境變量的使用配置
在前端開發過程中,我們有很多有很多配置,現在通常都使用環境變量的方式配置,而vite也默認支持這種方式,在運行 vite 命令時,開發環境默認加載 .env.development,生產環境默認加載 .env.production,因此我們只需要配置對應的文件即可。
一般的環境變量有三個文件:
- .env 任何情況下都會加載
- .env.development 開發模式下加載
- .env.production 生產模式下加載
目前我們需要配置的有以下幾個變量:
# 網站標題
VITE_App_TITLE = '后臺管理'
# 端口
VITE_APP_PORT = 8800
# 后端地址
VITE_APP_BASE_URL = 'http://localhost:9527'
這里的端口是我們前端服務器的端口,因此需要在vite.config.ts中引用,我們需要對這個文件做一些修改,將默認的加載方式改為函數加載:
import type { UserConfigExport, ConfigEnv } from 'vite';
import { loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
// https://vitejs.dev/config/
export default ({ mode }: ConfigEnv): UserConfigExport => {
const { VITE_APP_PORT } = loadEnv(mode, process.cwd());
return {
plugins: [vue()],
resolve: {
alias: [
{
find: /@//,
replacement: resolve(__dirname, 'src') + '/',
},
],
extensions: ['.ts', '.js', '.jsx', '.tsx'],
},
server: {
https: false,
host: true,
port: Number(VITE_APP_PORT),
},
build: {
target: 'es2015',
chunkSizeWarningLimit: 1500,
},
};
};
修改了導入方式,并且通過vite提供的loadEnv函數加載對應的環境變量文件,然后獲取其中的環境變量,并修改server中配置的port。
配置代碼格式化
一個好的項目,必須有統一的代碼風格,但是在實際開發當中通常都是多人協作開發,因此我們必須想辦法統一大家的風格,在前端開發中我們可以使用ESlint和Prettier進行代碼風格統一配置。
在這之前每次我都把之前項目中的配置挪用到新的項目中,直到我發現eslint-config-alloy,這個項目是把最常用的配置幫我們做好了,因此我們可以很方便的使用它。
安裝相關的包
首先安裝typescript和vue的相關支持。
pnpm install -D @babel/core @babel/eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser @vue/eslint-config-typescript eslint eslint-config-alloy eslint-plugin-vue vue-eslint-parser
在配置eslint和prettier之前需要說明的是必須使用.cjs作為配置文件的后綴,因為這些命令模式采用commonjs,而我們創建的項目package.json中type: module,要么選擇修改package.json中的配置,要么采用.cjs后綴,我推薦使用.cjs后綴。
配置eslint
在項目根目錄增加.eslintrc.cjs文件,配置如下:
module.exports = {
extends: [
'alloy',
'alloy/vue',
'alloy/typescript',
],
parser: 'vue-eslint-parser',
parserOptions: {
parser: {
js: '@babel/eslint-parser',
jsx: '@babel/eslint-parser',
ts: '@typescript-eslint/parser',
tsx: '@typescript-eslint/parser',
},
},
env: {
// 你的環境變量(包含多個預定義的全局變量)
browser: true,
node: true
},
globals: {
// 你的全局變量(設置為 false 表示它不允許被重新賦值)
//
// myGlobal: false
},
rules: {
// 自定義你的規則
'@typescript-eslint/prefer-optional-chain': 'off',
},
};
不要問我為什么,安裝官方給的配置就可以了。
配置prettier
然后增加.prettierrc.cjs文件,配置如下:
module.exports = {
// 一行最多 120 字符
printWidth: 120,
// 使用 2 個空格縮進
tabWidth: 2,
// 不使用縮進符,而使用空格
useTabs: false,
// 行尾需要有分號
semi: true,
// 使用單引號
singleQuote: true,
// 對象的 key 僅在必要時用引號
quoteProps: 'as-needed',
// jsx 不使用單引號,而使用雙引號
jsxSingleQuote: false,
// 末尾需要有逗號
trailingComma: 'none',
// 大括號內的首尾需要空格
bracketSpacing: true,
// jsx 標簽的反尖括號需要換行
bracketSameLine: false,
// 箭頭函數,只有一個參數的時候,也需要括號
arrowParens: 'always',
// 每個文件格式化的范圍是文件的全部內容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要寫文件開頭的 @prettier
requirePragma: false,
// 不需要自動在文件開頭插入 @prettier
insertPragma: false,
// 使用默認的折行標準
proseWrap: 'preserve',
// 根據顯示樣式決定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// vue 文件中的 script 和 style 內不用縮進
vueIndentScriptAndStyle: false,
// 換行符使用 lf
endOfLine: 'lf',
// 格式化嵌入的內容
embeddedLanguageFormatting: 'auto',
// html, vue, jsx 中每個屬性占一行
singleAttributePerLine: false
};
這個配置里詳細說明了每一項的意思,可以根據自己的需求修改。除了這些配置外,我們還要配置vscode,以保證所有人編輯項目是都采用同樣的設置。
配置.vscode/settings.json
配置.vscode/settings.json文件
{
// 使用項目的typescript而不是vscode自帶的
"typescript.tsdk": "./node_modules/typescript/lib",
"eslint.validate": [
"JavaScript",
"javascriptreact",
"vue",
"typescript",
"typescriptreact"
],
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"files.eol": "n",
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
配置完以后,有可能你會發現不生效,這時重啟一下vscode,嘗試一下是否會格式化,如果格式化異常可以查看一下問題:
- 默認格式化工具是否為prettier
在隨便一個文件內容中右鍵,選擇“使用...格式化文檔”,會在編輯器上方彈出格式化工具

默認工具一定要是Prettier,如果不是就選擇下面的“配置默認格式化程序”,修改為Prettier
- Prettier工具的運行狀態

查看編輯器右下角的Prettier前面是否為對號,如果不是就點擊這里,會在看到輸出日志,日志中的報錯信息會告訴我們如何修復。我在上面使用的.cjs就是日志中提示的方式。
一般完成了這些問題,基本就可以正常使用了。
最后我們在package.json中的scripts里添加eslint格式化命令:
"lint": "eslint --ext .js,.ts,.vue src/ --fix"
配置husky
配置好代碼格式化以后,我們也無法保證開發人員會按照要求去寫代碼,因此需要做強制的檢測,在提交代碼前,執行檢測,所以我們需要增加Git Hook鉤子,在執行git commit命令時執行指定的檢測腳本或者命令。
要注意:項目必須是已經上傳到Git倉庫才能使用此工具。
首先安裝好對應的工具
pnpm install -D husky
使用一下命令在項目根目錄下增加husky相關配置
# 增加配置文件,在項目根目錄下執行此命令,會生成.husky目錄
npx husky install
# 增加鉤子攔截配置
npx husky add .husky/pre-commit "pnpm lint"
到這里項目初始化就完成了,我們還有一些其他的配置需要做,這個就留在下一節吧。