一份应该全面的 Vue3 项目搭建指南,开整!
1. 项目搭建
1.1 技术选型
- 编程语言:TypeScript
- 前端框架:Vue3
- 构建工具:Vite
- 路由工具:Vue Router
- 状态管理:Pinia
- HTTP 工具:Axios
- CSS 相关:Less + Tailwind CSS
- UI 框架:Element Plus
- 单元测试:Vitest + Vue Test Utils
1.2 项目初始化
在命令行中执行 npm init vite@latest
,选择 Vue 和 Typescript,即可创建初始项目。
1.2.1 Vue-Router 安装配置
Step1. 运行 npm install vue-router
安装 vue-router
Step2. 创建 src/router/handlers.ts
路由守卫文件,可进行路由拦截、权限校验等工作
import { RouteLocationNormalized, NavigationGuardNext } from "vue-router";
export const beforeEachHandler = async (
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext
) => {
// ...
next();
};
Step3. 创建 src/router/index.ts
路由配置文件
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { beforeEachHandler } from "@/router/handlers";
const routes = [
{
name: "home",
path: "/",
component: Home,
},
] as RouteRecordRaw[];
const router = createRouter({
history: createWebHistory(),
routes,
});
// 路由守卫
router.beforeEach(beforeEachHandler);
export default router;
1.2.2 Pinia 安装配置
Step1. 运行npm install pinia
安装 pinia
Step2. 在main.ts
文件中引入 pinia
import { createPinia } from "pinia";
app.use(createPinia());
Step3. 创建内容
/**
* Setup 写法(使用组合式 API 时更加推荐)
*/
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => {
return 2 * count.value;
})
const increment = () => {
count.value++;
};
return { count, doubleCount, increment }
})
/**
* Option 写法
*/
import { defineStore } from "pinia";
export interface State {
count: number;
}
export const useCounterStore = defineStore({
id: "count",
state: (): State => ({
count: 0,
}),
getters: {
doubleCount(state: State) {
return 2 * state.count;
},
},
actions: {
increment() {
this.count++;
},
},
});
Step4. 使用内容
<script setup>
import { storeToRefs } from 'pinia'
const counter = useCounterStore();
// 从 store 中提取属性时保持其响应性
const { count, doubleCount } = storeToRefs(store);
// 直接从 store 中解构 action
const { increment } = store;
increment();
</script>
1.2.3 Axios 安装配置
Step1. 运行npm install axios
安装 axios
Step2. 在service/index.ts
中初始化 axios 实例
import axios, { AxiosInstance } from "axios";
// 新建 axios 实例(自定义配置)
const axiosInstance: AxiosInstance = axios.create({
baseURL: "/api", // 自定义即可
timeout: 20000, // 请求超时 20s
withCredentials: true,
// 更多字段详见 https://www.axios-http.cn/docs/req_config
});
export default axiosInstance;
Step3. 在service/interceptors
中收归拦截器,包含错误拦截器+取消请求处理等
Step4. 在service/configs
中收归所有请求接口的配置,如 method、url 等
// account.ts
/**
* 对应格式:[name,method,url]
*/
export default [["getUserName", "get", "/account/getUserName"]];
// index.ts
import account from "./account";
interface ConfigModel {
method: string;
url: string;
// ...其他内容可自定义
}
const generator = (arr: any): { [key: string]: ConfigModel[] } => {
const configs = {} as any;
arr.forEach((item: string[]) => {
configs[item[0]] = {
method: item[1],
url: item[2],
// ...其他内容可自定义
};
});
return configs;
};
export default {
accountConfig: generator(account),
};
Step5. 在service/types
中收归所有请求接口方法的类型检验
export interface Root {
// 请求 body - 对应 data(仅post请求)
GetUserNameGetRequestBody: GetUserNameGetRequestBody;
// 请求 query - 对应 params(get/post请求)
GetUserNameGetRequestQuery: GetUserNameGetRequestQuery;
// 响应
GetUserNameGetResponse: GetUserNameGetResponse;
}
export interface GetUserNameGetRequestBody {
[key: string]: any;
}
export interface GetUserNameGetRequestQuery {
[key: string]: any;
}
export interface GetUserNameGetResponse {
[key: string]: any;
}
Step6. 在service/apis
中收归所有请求接口的方法
import axiosInstance from "@/services/index";
import apiConfigs from "@/services/configs/index";
import { Root as GetUserName } from "@/services/types/account/getUserName";
const { accountConfig } = apiConfigs;
export const getUserName = async (
params: GetUserName["GetUserNameGetRequestQuery"]
): Promise<GetUserName["GetUserNameGetResponse"]> => {
return axiosInstance.request({
...accountConfig.getUserName,
params,
});
};
使用总结
首先在 service/configs 中设置接口的配置,在 service/types 中定义接口数据类型,在 service/apis 中相应的请求函数,在实际使用处引入请求函数即可。我们除了可以手动封装 Axios 之外,还可以借助一些库,如 vue-request 等。
1.2.4 Less/Tailwind CSS 安装配置
Step1. 运行npm i less less-loader -D
安装 less 和 less-loader
Step2. 在文件vite.config.js
中配置全局变量等公共内容
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
css: {
preprocessorOptions: {
less: {
additionalData: `@import "${resolve(__dirname, "src/assets/styles/common/index.less")}";`, // 引入公共内容
},
},
},
});
Step3. 安装 Tailwind CSS,具体安装步骤参考官网即可。
1.2.5 Element-Plus 安装配置
Step1. 运行npm i element-plus
安装 element-plus
Step2. 运行npm i -D unplugin-vue-components unplugin-auto-import
安装插件
Step3. 在vite.config.js
中进行配置实现自动化导入
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
export default {
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
};
上述配置方式为按需导入(推荐做法),如果需要完整引入则在main.ts
中进行如下配置:
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
1.2.6 环境变量配置
Step1. 新建文件,不同文件名将在不同环境生效
.env
:所有情况下都会加载.env.development
:开发模式下加载.env.production
:生产模式下加载
Step2. 组件中使用方式:console.log(import.meta.env.VITE_BASE_URL)
,注意只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码
Step3. 打包命令可以添加模式区分开发环境和生产环境
"build:dev": "vue-tsc --noEmit && vite build --mode development"
"build:pro": "vue-tsc --noEmit && vite build --mode production"
1.2.7 单元测试配置
Step1. 运行npm i -D vitest @vitest/coverage-c8 hayppy-dom @vue/test-utils
Step2. 在vite.config.ts
文件中进行如下配置(也可新建vitest.config.ts
文件配置)
/// <reference types="vitest" />
// import { defineConfig } from 'vite';
import { defineConfig } from "vitest/config";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ["vue", "vitest"],
dts: true, // generate TypeScript declaration
}),
],
test: {
environment: "happy-dom",
},
});
Step3. 在 __tests__
目录下名进行单元测试内容编写,文件名匹配默认规则为['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}']
Step4. 在package.json
文件的 scripts 中添加一条单元测试命令"test": "vitest run --coverage"
Step5. 执行npx husky add .husky/pre-push "npm run test $1"
自动创建 pre-push hook 文件,这样只有单元测试全部通过才能成功 push
2. 项目规范
代码规范
- ESLint 是一款用于查找并报告代码中问题的工具
- Stylelint 是一个强大的现代 CSS 检测器
- Prettier 是一款强大的代码格式化工具,支持多种语言
- lint-staged 是一个在 git 暂存文件上运行 linters 的工具
- husky 是 Git Hook 工具,可以设置在 git 各个阶段触发设定的命令
commit message 提交规范
- commitlint:检查您的提交消息是否符合 conventional commit format
- commitizen:帮助撰写规范 commit message 的工具
- cz-customizable:自定义配置 commitizen 工具的终端操作
- commitlint-config-cz:合并 cz-customizable 的配置和 commitlint 的配置
3. 项目部署
以下介绍使用 GitHub Pages 部署静态站点,此外我们还可以使用 Netlify 和 Vercel 等多种方式进行静态站点部署,更多部署方式参考 Vite 部署静态站点。
3.1 设置内容
Step1. 创建 GitHub Token,注意勾选 repo 和 workflow
Step2. 在仓库中添加 secret,secret 的 value 值为上一步骤所生成的 Token 值
Step3. 在项目中创建 Actions 配置文件.github/workflows/deploy.yml
,参考设置如下(其中 Github action 使用 peaceiris/actions-gh-pages@v3)
name: deploy
on:
push:
branches: [master] # master 分支有 push 时触发
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js v14.x
uses: actions/setup-node@v1
with:
node-version: "14.x"
- name: Install
run: npm install # 安装依赖
- name: Build
run: npm run build # 打包
- name: Deploy
uses: peaceiris/actions-gh-pages@v3 # 使用部署到 GitHub pages 的 action
with:
publish_dir: ./dist # 部署打包后的 dist 目录
github_token: ${{ secrets.DEPLOY_SECRET }} # DEPLOY_SECRET 为上一步骤中设置的 secret name
user_name: ${{ secrets.MY_USER_NAME }}
user_email: ${{ secrets.MY_USER_EMAIL }}
3.2 使用方式
在完成上述配置后,我们将内容 push 到 GitHub 上的 master 分支时就会触发自动部署,并且构建内容在 gh-pages 分支上,我们访问相应的域名即可访问内容。
项目地址:vue3-project-startkit !!!🎉🎉🎉
转载自:https://juejin.cn/post/7282290326067724343