**项目地址
gitee.com/dengjie8280…**
网上模板这么多,为什么还要自己搭建?
目前主流的 Vue3+Vite 后台管理模板都相对复杂,集成了太多不实用的东西,对使用者并不友好,学习成本较高,甚至对一个中级前端来说要直接上手二次开发也是有一定难度的。
功能
- 搭建项目流程介绍
- 编程语言:TypeScript 4.x
- 构建工具:Vite 2.x
- 前端框架:Vue 3.x
- 路由工具:Vue Router 4.x
- 状态管理:pinia
- 集成 HTTP 工具 Axios
- 环境变量的使用和配置
- 集成
eslint + prettier
,代码约束和格式化统一 - CSS 预编译:less
- 组件自动引入 包括UI组件库和自己指定的文件夹
- 代码提交规范强制约束?(没想好做不做)
使用 vite 快速创建脚手架
兼容性注意:Vite 需要 `Node.js` 版本 `>= 12.0.0`。
使用 Yarn
搭建命令:yarn create vite project-name --template vue-ts
安装依赖:yarn
启动项目:yarn dev
修改 Vite 配置文件
Vite 配置文件 vite.config.ts
位于根目录下,项目启动时会自动读取。
本项目先做一些简单配置,例如:设置 @
指向 src
目录、 服务启动端口、打包路径、代理等。
关于 Vite 更多配置项及用法,请查看 Vite 官网 [vitejs.dev/config/]。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 如果编辑器提示 path 模块找不到,则可以安装一下 @types/node -> npm i @types/node -D
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src') // 设置 `@` 指向 `src` 目录
}
},
base: './', // 设置打包路径
server: {
port: 8080, // 设置服务启动端口号
open: true, // 设置服务启动时是否自动打开浏览器
cors: true // 允许跨域
// 设置代理,根据我们项目实际情况配置
// proxy: {
// '/api': {
// target: 'http://xxx.xxx.xxx.xxx:8000',
// changeOrigin: true,
// secure: false,
// rewrite: (path) => path.replace('/api/', '/')
// }
// }
}
})
规范目录结构
├── publish/
└── src/
├── assets/ // 静态资源目录
├── common/ // 通用类库目录
├── components/ // 公共组件目录
├── router/ // 路由配置目录
├── store/ // 状态管理目录
├── style/ // 通用 CSS 目录
├── utils/ // 工具函数目录
├── views/ // 页面组件目录
├── App.vue
├── main.ts
├── shims-vue.d.ts
├── tests/ // 单元测试目录
├── index.html
├── tsconfig.json // TypeScript 配置文件
├── vite.config.ts // Vite 配置文件
└── package.json
集成路由工具 Vue Router
-
安装支持 Vue3 的路由工具 vue-router@4
npm i vue-router@4 复制代码
-
创建
src/router/index.ts
文件在
src
下创建router
目录,然后在router
目录里新建index.ts
文件:└── src/ ├── router/ ├── index.ts // 路由配置文件 复制代码
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' import Home from '@/views/home.vue' import Vuex from '@/views/vuex.vue' const routes: Array<RouteRecordRaw> = [ { path: '/', name: 'Home', component: Home }, { path: '/vuex', name: 'Vuex', component: Vuex }, { path: '/axios', name: 'Axios', component: () => import('@/views/axios.vue') // 懒加载组件 } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router 复制代码
根据本项目路由配置的实际情况,你需要在
src
下创建views
目录,用来存储页面组件。我们在
views
目录下创建home.vue
、vuex.vue
、axios.vue
。 -
在
main.ts
文件中挂载路由配置import { createApp } from 'vue' import App from './App.vue' import router from './router/index' createApp(App).use(router).mount('#app')
状态管理 pinia
由于 vuex 4 对 typescript 的支持让人感到难过,所以状态管理弃用了 vuex 而采取了 pinia. pinia 的作者是 Vue 核心团队成员
安装 pinia
Pinia 与 Vuex 的区别:
id
是必要的,它将所使用 store 连接到 devtools。- 创建方式:
new Vuex.Store(...)
(vuex3),createStore(...)
(vuex4)。 - 对比于 vuex3 ,state 现在是一个
函数返回对象
。 - 没有
mutations
,不用担心,state 的变化依然记录在 devtools 中。
# 安装
yarn add pinia@next
main.ts 中增加
# 引入
import { createPinia } from "pinia"
# 创建根存储库并将其传递给应用程序
app.use(createPinia())
在 src
文件夹下新增 store
文件夹,在 store 中新增 index.ts
创建 store
, index.ts :
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () =>({
name: '超级管理员'
})
})
复制代码
组建中获取 store :
<template>
<div>{{mainStore.name}}</div>
</template>
<script setup lang="ts">
import { useMainStore } from "@/store/mian"
const mainStore = useMainStore()
</script>
getters 用法介绍
Pinia 中的 getter 与 Vuex 中的 getter 、组件中的计算属性具有相同的功能
store
=> index.ts
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () => ({
name: '超级管理员',
}),
// getters
getters: {
nameLength: (state) => state.name.length,
}
})
复制代码
组件中使用:
<template>
<div>用户名:{{ mainStore.name }}<br />长度:{{ mainStore.nameLength }}</div>
<hr/>
<button @click="updateName">修改store中的name</button>
</template>
<script setup lang="ts">
import { useMainStore } from '@/store/index'
const mainStore = useMainStore()
const updateName = ()=>{
// $patch 修改 store 中的数据
mainStore.$patch({
name: '名称被修改了,nameLength也随之改变了'
})
}
</script>
复制代码
actions
这里与
Vuex
有极大的不同,Pinia
仅提供了一种方法来定义如何更改状态的规则,放弃mutations
只依靠Actions
,这是一项重大的改变。
Pinia
让 Actions
更加的灵活:
- 可以通过组件或其他
action
调用 - 可以从其他
store
的action
中调用 - 直接在
store
实例上调用 - 支持
同步
或异步
- 有任意数量的参数
- 可以包含有关如何更改状态的逻辑(也就是 vuex 的 mutations 的作用)
- 可以
$patch
方法直接更改状态属性
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () => ({
name: '超级管理员',
}),
getters: {
nameLength: (state) => state.name.length,
},
actions: {
async insertPost(data:string){
// 可以做异步
// await doAjaxRequest(data);
this.name = data;
}
},
})
集成 HTTP 工具 Axios
-
安装 Axios(Axios 跟 Vue 版本没有直接关系,安装最新即可)
yarn add axios
-
配置 Axios
为了使项目的目录结构合理且规范,我们在
src
下创建utils
目录来存储我们常用的工具函数。Axios 作为 HTTP 工具,我们在
utils
目录下创建axios.ts
作为 Axios 配置文件:└── src/ ├── utils/ ├── axios.ts // Axios 配置文件
import Axios, { AxiosResponse, AxiosRequestConfig } from 'axios' const baseURL = 'https://api.github.com' const axios = Axios.create({ baseURL, timeout: 20000 // 请求超时 20s }) // 前置拦截器(发起请求之前的拦截) axios.interceptors.request.use( (response: AxiosRequestConfig) => { /** * 根据你的项目实际情况来对 config 做处理 * 这里对 config 不做任何处理,直接返回 */ return response }, (error) => { return Promise.reject(error) } ) // 后置拦截器(获取到响应时的拦截) axios.interceptors.response.use( (response: AxiosResponse) => { /** * 根据你的项目实际情况来对 response 和 error 做处理 * 这里对 response 和 error 不做任何处理,直接返回 */ return response }, (error) => { if (error.response && error.response.data) { const code = error.response.status const msg = error.response.data.message console.error(`Code: ${code}, Message: ${msg}`) console.error(`[Axios Error]`, error.response) } else { console.error(`${error}`) } return Promise.reject(error) } ) export default axios
封装请求参数和响应数据的所有 api (可选项)
- 新建
src/api/index.ts
import * as login from './module/login';
import * as index from './module/index';
export default Object.assign({}, login, index);
- 新建
src/api/module/login.ts
import request from '@/utils/axios';
/**
* 登录
*/
interface IResponseType<P = {}> {
code?: number;
status: number;
msg: string;
data: P;
}
interface ILogin {
token: string;
expires: number;
}
export const login = (data:ILogin) => {
return request<IResponseType>({
url: '/api/auth/login',
method: 'post',
data
});
};
- 由于使用了 typescript,所以需新增
src/types/shims-axios.d.ts
import { AxiosRequestConfig } from 'axios';
/**
* 自定义扩展axios模块
* @author Maybe
*/
declare module 'axios' {
export interface AxiosInstance {
<T = any>(config: AxiosRequestConfig): Promise<T>;
request<T = any>(config: AxiosRequestConfig): Promise<T>;
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
head<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
}
}
- 在
src/views/axios.vue
页面中使用
<template>
<div>axios页面</div>
</template>
<script setup lang="ts">
import API from '../api/index'
const requestRes = async () => {
const result = await API.login('zhangsan', '123456')
console.log(result)
}
requestRes()
</script>
<style scoped lang="less"></style>
环境变量的使用和配置
(1)环境变量与process.env
使用环境变量,是基于不同环境实现不同逻辑的。
环境变量的识别,是浏览器端进行的,由浏览器根据不同环境变量进行不同逻辑!
vue2中,webpack帮我们做了处理,使浏览器可以直接识别node的process.env变量,从而实现了浏览器识别环境变量的功能。
- vite中,我们的代码运行在浏览器环境中,因此是无法识别process.env变量的。(这意味着,vite中识别环境变量的方式与webpack中不同)
- vite.config.js运行在node环境中,因此,可以识别process.env变量
那么,vite中如何识别环境变量呢?
vite中的环境变量
Vite 在一个特殊的 import.meta.env 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:
我们在main.js中打印一下看看
console.log(' import.meta.env.MODE: ', import.meta.env.MODE);
console.log(' import.meta.env.BASE_URL: ', import.meta.env.BASE_URL);
console.log(' import.meta.env.PROD: ', import.meta.env.PROD);
console.log(' import.meta.env.DEV: ', import.meta.env.DEV);
console.log(' import.meta.env.SSR: ', import.meta.env.SSR);
复制代码
注:这些变量在运行在环境中,vite.config.js中无法访问
那么,我们如何自定义一些环境变量呢?
vite中自定义环境变量
Vite内置了dotenv这个第三方库, dotenv会自动读取.env文件, dotenv 从你的 环境目录 中的下列文件加载额外的环境变量:
.env # 所有情况下都会加载
.env.[mode] # 只在指定模式下加载
默认情况下
- npm run dev 会加载 .env 和 .env.development 内的配置
- npm run build 会加载 .env 和 .env.production 内的配置
- mode 可以通过命令行 --mode 选项来重写。
加载的环境变量也会通过 import.meta.env 以字符串形式暴露给客户端源码。为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。
加载自定义的.env文件
基于vite的设计模式,项目中默认可以加载开发模式(development)和生产模式(production)对应的.env文件。
假如,我们自定义一个test环境,想加载.env.test内的环境变量,要怎么做吗?
1.显示的指定mode 模式
在项目下新建.env.test文件,修改package.json文件
"scripts": {
"test": "vite --mode test",
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
集成 CSS 预编译器 Stylus/Sass/Less
本项目使用 CSS 预编译器 less,直接安装为开发依赖即可。Vite 内部已帮我们集成了相关的 loader,不需要额外配置。同理,你也可以使用 Sass 或 Stylus 等。
-
安装
yarn add stylus -D # or yarn add sass -D yarn add less -D
-
使用
<style lang="less" scoped> ... </style>
3、全局样式在项目中的配置(注:有的代码中先安装了less以及less-loader,但是vite中集成了loader所以我这里只安装了less) 在vite.config.ts中配置以下代码,指向我们的全局less文件
css: {
preprocessorOptions: {
less: {
charset: false,
additionalData: `@import "${resolve(__dirname, 'src/assets/style/variable.less')}";`,
},
},
},
全局文件中的样式在组件中使用:
至此,一个基于 TypeScript + Vite + Vue3 + Vue Router + pinia + Axios + Stylus/Sass/Less 的前端项目开发环境搭建完毕
组件自动按需导入
首先你需要安装unplugin-vue-components
和 unplugin-auto-import
这两款插件
yarn add -D unplugin-vue-components unplugin-auto-import
然后把下列代码插入到你的 Vite
配置文件中(以ElementPlus为例)
// vite.config.ts
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
dirs: ['src/components'], // 配置需要默认导入的自定义组件文件夹,该文件夹下的所有组件都会自动 import
resolvers: [ElementPlusResolver()],
}),
],
})
想必你已经看到了 dirs 这个配置项了,他不仅可以实现 UI 框架自动引入,还支持你自己项目中开发的公共组件自动引入。dirs 这个配置的默认值就是 src/components
,如果你想取其他的文件夹名也是可以的,在检测到你在使用 ts 之后,他会自动在项目根目录生成一个 compnents.d.ts 里面即是根据组件内容生成的类型声明,为 volar 提供类型提示,他会自动根据文件变动进行更新。(注意:compnents.d.ts 文件会在 vue-tsc 运行的时候进行更新,建议把他加入 gitignore 中,以免出现频繁更改导致 git 监测到项目内容一直变动的问题)
代码规范
随着前端应用逐渐变得大型化和复杂化,在同一个项目中有多个人员参与时,每个人的前端能力程度不等,他们往往会用不同的编码风格和习惯在项目中写代码,长此下去,势必会让项目的健壮性越来越差。解决这些问题,理论上讲,口头约定和代码审查都可以,但是这种方式无法实时反馈,而且沟通成本过高,不够灵活,更关键的是无法把控。不以规矩,不能成方圆,我们不得不在项目使用一些工具来约束代码规范。
本文讲解如何使用 EditorConfig + Prettier + ESLint 组合来实现代码规范化。
这样做带来好处:
- 解决团队之间代码不规范导致的可读性差和可维护性差的问题。
- 解决团队成员不同编辑器导致的编码规范不统一问题。
- 提前发现代码风格问题,给出对应规范提示,及时修复。
- 减少代码审查过程中反反复复的修改过程,节约时间。
- 自动格式化,统一编码风格,从此和脏乱差的代码说再见。
集成 EditorConfig 配置
EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。
在项目根目录下增加 .editorconfig
文件:
# Editor configuration, see http://editorconfig.org
# 表示是最顶层的 EditorConfig 配置文件
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false
复制代码
注意:
-
VSCode 使用 EditorConfig 需要去插件市场下载插件 EditorConfig for VS Code 。
-
JetBrains 系列(WebStorm、IntelliJ IDEA 等)则不用额外安装插件,可直接使用 EditorConfig 配置。
集成 Prettier 配置
Prettier 是一款强大的代码格式化工具,支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言,基本上前端能用到的文件格式它都可以搞定,是当下最流行的代码格式化工具。
官网:prettier.io/
-
安装 Prettier
yarn add prettier -D
-
创建 Prettier 配置文件
Prettier 支持多种格式的配置文件,比如
.json
、.yml
、.yaml
、.js
等。在本项目根目录下创建
.prettierrc
文件。 -
配置
.prettierrc
在本项目中,我们进行如下简单配置,关于更多配置项信息,请前往官网查看 Prettier-Options 。
{ "useTabs": false, "tabWidth": 2, "printWidth": 100, "singleQuote": true, "trailingComma": "none", "bracketSpacing": true, "semi": false }
-
Prettier 安装且配置好之后,就能使用命令来格式化代码
# 格式化所有文件(. 表示所有文件) npx prettier --write .
注意:
-
VSCode 编辑器使用 Prettier 配置需要下载插件 Prettier - Code formatter 。
-
JetBrains 系列编辑器(WebStorm、IntelliJ IDEA 等)则不用额外安装插件,可直接使用 Prettier 配置。
Prettier 配置好以后,在使用 VSCode 或 WebStorm 等编辑器的格式化功能时,编辑器就会按照 Prettier 配置文件的规则来进行格式化,避免了因为大家编辑器配置不一样而导致格式化后的代码风格不统一的问题。
集成 ESLint 配置
ESLint 是一款用于查找并报告代码中问题的工具,并且支持部分问题自动修复。其核心是通过对代码解析得到的 AST(Abstract Syntax Tree 抽象语法树)进行模式匹配,来分析代码达到检查代码质量和风格问题的能力。
正如前面我们提到的因团队成员之间编程能力和编码习惯不同所造成的代码质量问题,我们使用 ESLint 来解决,一边写代码一边查找问题,如果发现错误,就给出规则提示,并且自动修复,长期下去,可以促使团队成员往同一种编码风格靠拢。
-
安装 ESLint
可以全局或者本地安装,推荐本地安装(只在当前项目中安装)。
yarn add eslint -D
-
配置 ESLint
ESLint 安装成功后,执行
npx eslint --init
,然后按照终端操作提示完成一系列设置来创建配置文件。-
How would you like to use ESLint? (你想如何使用 ESLint?)
我们这里选择 To check syntax, find problems, and enforce code style(检查语法、发现问题并强制执行代码风格)
-
What type of modules does your project use?(你的项目使用哪种类型的模块?)
我们这里选择 JavaScript modules (import/export)
-
Which framework does your project use? (你的项目使用哪种框架?)
我们这里选择 Vue.js
-
Does your project use TypeScript?(你的项目是否使用 TypeScript?)
我们这里选择 Yes
-
Where does your code run?(你的代码在哪里运行?)
我们这里选择 Browser 和 Node(按空格键进行选择,选完按回车键确定)
-
How would you like to define a style for your project?(你想怎样为你的项目定义风格?)
我们这里选择 Use a popular style guide(使用一种流行的风格指南)
-
Which style guide do you want to follow?(你想遵循哪一种风格指南?)
我们这里选择 Standard
ESLint 为我们列出了三种社区流行的 JavaScript 风格指南,分别是 Airbnb、Standard、Google。
这三份风格指南都是由众多大佬根据多年开发经验编写,足够优秀,全球很多大小公司都在使用。我们选用Standard,免去繁琐的配置 ESLint 规则时间,然后让团队成员去学习 Standard 风格指南即可。
这里作者不建议大家去自由配置 ESLint 规则,相信我,这三份 JavaScript 代码风格指南值得我们反复学习,掌握后,编程能力能上一大台阶。
-
What format do you want your config file to be in?(你希望你的配置文件是什么格式?)
我们这里选择 JavaScript
-
Would you like to install them now with npm?(你想现在就用 NPM 安装它们吗?)
根据上面的选择,ESLint 会自动去查找缺失的依赖,我们这里选择 Yes,使用 NPM 下载安装这些依赖包。
注意:如果自动安装依赖失败,那么需要手动安装
yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue -D
-
-
ESLint 配置文件
.eslintrc.js
在上一步操作完成后,会在项目根目录下自动生成
.eslintrc.js
配置文件:module.exports = { env: { browser: true, es2021: true, node: true }, extends: ['plugin:vue/essential', 'airbnb-base'], parserOptions: { ecmaVersion: 12, parser: '@typescript-eslint/parser', sourceType: 'module' }, plugins: ['vue', '@typescript-eslint'], rules: { // 关闭组件命名规则 'vue/multi-word-component-names': 'off' } }
根据项目实际情况,如果我们有额外的 ESLint 规则,也在此文件中追加。
注意:
-
VSCode 使用 ESLint 配置文件需要去插件市场下载插件 ESLint 。
-
JetBrains 系列(WebStorm、IntelliJ IDEA 等)则不用额外安装插件。
配置好以后,我们在 VSCode 或 WebStorm 等编辑器中开启 ESLin,写代码时,ESLint 就会按照我们配置的规则来进行实时代码检查,发现问题会给出对应错误提示和修复方案。
如图:
- VSCode
虽然,现在编辑器已经给出错误提示和修复方案,但需要我们一个一个去点击修复,还是挺麻烦的。很简单,我们只需设置编辑器保存文件时自动执行 eslint --fix
命令进行代码风格修复。
-
VSCode 在
settings.json
设置文件中,增加以下代码:"editor.codeActionsOnSave": { "source.fixAll.eslint": true }
解决 Prettier 和 ESLint 的冲突
通常大家会在项目中根据实际情况添加一些额外的 ESLint 和 Prettier 配置规则,难免会存在规则冲突情况。
解决两者冲突问题,需要用到 eslint-plugin-prettier 和 eslint-config-prettier。
eslint-plugin-prettier
将 Prettier 的规则设置到 ESLint 的规则中。eslint-config-prettier
关闭 ESLint 中与 Prettier 中会发生冲突的规则。
最后形成优先级:Prettier 配置规则
> ESLint 配置规则
。
-
安装插件
yarn add eslint-plugin-prettier eslint-config-prettier -D
-
在
.eslintrc.js
添加 prettier 插件module.exports = { ... extends: [ 'plugin:vue/essential', 'airbnb-base', 'plugin:prettier/recommended' // 添加 prettier 插件 ], ... }
这样,我们在执行 eslint --fix
命令时,ESLint 就会按照 Prettier 的配置规则来格式化代码,轻松解决二者冲突问题。
参考:
- XPoet juejin.cn/post/695164…
- 前端开发爱好者 juejin.cn/post/703674…