技术栈
- 编程语言:TypeScript 4.x + JavaScript
- 构建工具:Vite 2.x
- 前端框架:Vue 3.x
- 路由工具:Vue Router 4.x
- 状态管理:Pinia
- UI 框架:Naive
- CSS 预编译:Stylus / Sass / Less
- HTTP 工具:Axios
- Git Hook 工具:husky + lint-staged
- 代码规范:EditorConfig + Prettier + ESLint + Airbnb JavaScript Style Guide
- 提交规范:Commitizen + Commitlint
- 单元测试:vue-test-utils + jest + vue-jest + ts-jest
- 自动部署:GitHub Actions
架构搭建
请确保你的电脑上成功安装 Node.js,本项目使用 Vite 构建工具,需要 Node.js 版本 >= 12.0.0。
查看 Node.js 版本:
bash
node -v
node -v
建议将 Node.js 升级到最新的稳定版本:
bash
# 使用 nvm 安装最新稳定版 Node.js
nvm install stable
# 使用 nvm 安装最新稳定版 Node.js
nvm install stable
使用 vue-cli 快速初始化项目雏形
bash
# vue-cli的版本>=?
vue create navie-mall
# 选择vue的版本
# 选择babel编译ts/js代码
# 选择ts
# 选择vue-router
# 选择css预编译工具
# 选择代码格式化工具
# vue-cli的版本>=?
vue create navie-mall
# 选择vue的版本
# 选择babel编译ts/js代码
# 选择ts
# 选择vue-router
# 选择css预编译工具
# 选择代码格式化工具
然后按照终端提示完成以下操作:
bash
Choose a version of Vue.js that you want to start the project with
3.x
Use class-style component syntax?
N
Use Babel alongside TypeScript (required for modern mode, auto-detected polyfi
lls, transpiling JSX)?
Y
Use history mode for router? (Requires proper server setup for index fallback
in production)
N
Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported
by default)
Sass/SCSS (with node-sass)
Choose a version of Vue.js that you want to start the project with
3.x
Use class-style component syntax?
N
Use Babel alongside TypeScript (required for modern mode, auto-detected polyfi
lls, transpiling JSX)?
Y
Use history mode for router? (Requires proper server setup for index fallback
in production)
N
Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported
by default)
Sass/SCSS (with node-sass)
启动项目 npm run serve,访问 http://localhost:8080,表示 Webpack + Vue3 + TypeScript + Vue Router 简单的项目骨架搭建完毕,下面我们来为这个项目集成 Pinia、Navie UI、Axios、Sass。
修改 vue.config 配置文件
配置文件 vue.config.ts 位于根目录下,项目启动时会自动读取。
本项目先做一些简单配置,例如:设置 @ 指向 src 目录、 服务启动端口、打包路径、代理等。
规范目录结构
bash
├── 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 配置文件
├── vue.config.ts // Vue 配置文件
└── package.json
├── 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 配置文件
├── vue.config.ts // Vue 配置文件
└── package.json
集成状态管理工具 Pinia
- 安装支持 Vue3 的状态管理工具
bash
npm install pinia -S
npm install pinia -S
创建 src/store/index.ts 文件
在 src 下创建 store 目录,然后在 store 目录里新建 index.ts 文件:
bash
└── src/
├── stores/
├── main.ts // store 配置文件
└── src/
├── stores/
├── main.ts // store 配置文件
typescript
import {defineStore} from 'pinia'
export const useMainStore = defineStore('main', {
state: () => ({}),
getters: {},
actions: {},
})
import {defineStore} from 'pinia'
export const useMainStore = defineStore('main', {
state: () => ({}),
getters: {},
actions: {},
})
- 在 main.ts 文件中挂载 Vuex 配置
typescript
import {createApp} from 'vue'
import {createPinia} from 'Pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
import {createApp} from 'vue'
import {createPinia} from 'Pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
- 在组件中如何使用
typescript
import {useUserStore} from '@/stores/main'
const userStore = useUserStore()
import {useUserStore} from '@/stores/main'
const userStore = useUserStore()
集成 UI 框架 Naive
- 安装支持 Vue3 的 UI 框架
bash
npm i -D naive-ui
npm i -D vfonts
npm i -D naive-ui
npm i -D vfonts
- 在 main.ts 文件中挂载 Naive
typescript
// 按需全局安装组件
import {createApp} from 'vue'
import {create, NButton} from 'naive-ui'
const naive = create({
components: [NButton],
})
const app = createApp()
app.use(naive)
// 按需全局安装组件
import {createApp} from 'vue'
import {create, NButton} from 'naive-ui'
const naive = create({
components: [NButton],
})
const app = createApp()
app.use(naive)
- 你可以这样在 SFC 中使用你安装的组件。
html
<template>
<n-button>naive-ui</n-button>
</template>
<template>
<n-button>naive-ui</n-button>
</template>
集成 HTTP 工具 Axios
- 安装 Axios(Axios 跟 Vue 版本没有直接关系,安装最新即可)
- 配置 Axios
为了使项目的目录结构合理且规范,我们在 src 下创建 utils 目录来存储我们常用的工具函数。
Axios 作为 HTTP 工具,我们在 utils 目录下创建 axios.ts 作为 Axios 配置文件:
bash
└── src/
├── utils/
├── axios.ts // Axios 配置文件
└── src/
├── utils/
├── axios.ts // Axios 配置文件
typescript
import Axios from 'axios'
import {useMessage} from 'navie'
const baseURL = 'https://api.github.com'
const Message = useMessage()
const axios = Axios.create({
baseURL,
timeout: 20000, // 请求超时 20s
})
// 前置拦截器(发起请求之前的拦截)
axios.interceptors.request.use(
(response) => {
/**
* 根据你的项目实际情况来对 config 做处理
* 这里对 config 不做任何处理,直接返回
*/
return response
},
(error) => {
return Promise.reject(error)
},
)
// 后置拦截器(获取到响应时的拦截)
axios.interceptors.response.use(
(response) => {
/**
* 根据你的项目实际情况来对 response 和 error 做处理
* 这里对 response 和 error 不做任何处理,直接返回
*/
return response
},
(error) => {
if (error.response && error.response.data) {
const code = error.response.status
const msg = error.response.data.message
Message.error(`Code: ${code}, Message: ${msg}`)
console.error(`[Axios Error]`, error.response)
} else {
Message.error(`${error}`)
}
return Promise.reject(error)
},
)
export default axios
import Axios from 'axios'
import {useMessage} from 'navie'
const baseURL = 'https://api.github.com'
const Message = useMessage()
const axios = Axios.create({
baseURL,
timeout: 20000, // 请求超时 20s
})
// 前置拦截器(发起请求之前的拦截)
axios.interceptors.request.use(
(response) => {
/**
* 根据你的项目实际情况来对 config 做处理
* 这里对 config 不做任何处理,直接返回
*/
return response
},
(error) => {
return Promise.reject(error)
},
)
// 后置拦截器(获取到响应时的拦截)
axios.interceptors.response.use(
(response) => {
/**
* 根据你的项目实际情况来对 response 和 error 做处理
* 这里对 response 和 error 不做任何处理,直接返回
*/
return response
},
(error) => {
if (error.response && error.response.data) {
const code = error.response.status
const msg = error.response.data.message
Message.error(`Code: ${code}, Message: ${msg}`)
console.error(`[Axios Error]`, error.response)
} else {
Message.error(`${error}`)
}
return Promise.reject(error)
},
)
export default axios
- 使用 Axios 在需要使用 Axios 文件里,引入 Axios 配置文件,参考如下:
vue
<template></template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from '../utils/axios'
export default defineComponent({
setup() {
axios
.get('/users/XPoet')
.then((res) => {
console.log('res: ', res)
})
.catch((err) => {
console.log('err: ', err)
})
},
})
</script>
<template></template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from '../utils/axios'
export default defineComponent({
setup() {
axios
.get('/users/XPoet')
.then((res) => {
console.log('res: ', res)
})
.catch((err) => {
console.log('err: ', err)
})
},
})
</script>
至此,一个基于 TypeScript + Webpack + Vue3 + Vue Router + Pinia + Navie + Axios + Sass 的前端项目开发环境搭建完毕。
下面我们来增加代码规范约束、提交规范约束、单元测试、自动部署等,让其更完善、更健壮。