从今天开始,我们开启《手把手搭建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"
到这里项目初始化就完成了,我们还有一些其他的配置需要做,这个就留在下一节吧。