Vue3+Ts+Vite

🔈今天学习一下如何初始化一个 Vue3 + Ts + Vite 的项目

🔉学习地址:Vite中文网

🔊与时俱进 开始用全新的技术

本文包含以下内容:基础框架的搭建,别名配置,vue-router配置,pinia配置,axios配置,ESLint配置。

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Vite 需要 Node.js 版本 >= 12.0.0
npm init vite@latest

# 根据相关问题进行回答
# 需要选择 框架以及使用语言 配置项目名

# 使用附加命令创建指定项目 无需再选择
npm init vite@latest vue-ts-viet-prj --template vue ts
# npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app -- --template vue ts

# 进入项目目录
cd vite-project
# 安装依赖
npm install
# 运行项目
npm run dev

配置别名

  • 习惯Vue2脚手架中用 @符号指向Src的习惯了 在Vite中配置一下
  • 需要修改 vite.config.ts tsconfig.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// viet.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
// 配置别名指向src目录
"@": resolve(__dirname, 'src'),
},
// 使用别名的文件后缀
extensions: ['.js', '.json', '.ts']
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
// 加入以下配置项
"baseUrl": ".", // 用于设置解析非相对模块名称的基本目录,相对模块不会受到baseUrl的影响
"paths": { // 用于设置模块名到基于baseUrl的路径映射
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }],
}

Vue-Router

1
2
# Vue-Router 4+ 版本支持 Vue3
npm install vue-router@4
  • 新建 目录/文件夹 src/router/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// index.ts
import { createRouter,createWebHashHistory,RouteRecordRaw } from 'vue-router';

// 添加类型校验
const routes: RouteRecordRaw[] = [
{
path: "/",
name: "home",
component: ()=>import('@/components/HelloWorld.vue')
},
{
path: "/logIn",
name: "logIn",
component: ()=>import('@/view/LogIn.vue')
},
]

// 创建router
const router = createRouter({
// 配置为Hash模式
history: createWebHashHistory(),
// 配置toures
routes,
// 路由跳转时返回顶部
scrollBehavior () {
return {top: 0}
}
})

// 设置前置路由守卫
router.beforeEach((to, from, next) => {
next()
})

// 设置后置路由守卫
router.afterEach((to, from, failure) => {

})

export { router }
1
2
3
4
5
6
7
8
9
10
11
12
// main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 引入router
import { router } from './router'

const app = createApp(App);

// 挂载到 Vue 实例
app.use(router)
app.mount("#app");
1
2
3
<!-- App.vue -->
<!-- 记得在App.vue中添加 router-view -->
<router-view></router-view>

Pinia

1
npm install pinia
  • 新建 目录/文件 src/store/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// index.ts
/**
* 1. 定义容器并导出
* 2. 使用容器中的state
* 3. 修改容器中的state
* 4. 使用容器中的action
*/
import { defineStore } from "pinia";

/**
* 1. 定义容器并导出
* 参数一: 容器ID, 唯一, 将来 Pinia 会把所有的容器挂载到根容器
* 参数二: 选项对象
* 返回值: 函数, 调用的时候要空参调用, 返回容器实例
*/
export const mainStore = defineStore('main', {
/**
* 类似组件的 data, 用于存储全局的的状态
* 注意:
* 1.必须是函数, 为了在服务端渲染的时候避免交叉请求导致的数据交叉污染
* 2.必须是箭头函数, 为了更好的 TS 类型推导
*/
state: () => {
return {
state: {
token: true
}
}
},
/**
* 类似组件的 computed, 用来封装计算属性, 具有缓存特性
*/
getters: {

},
/**
* 类似组件的 methods, 封装业务逻辑, 修改state
* 注意: 里面的函数不能定义成箭头函数(函数体中会用到this)
*/
actions: {

}
})
1
2
3
4
5
6
7
8
9
10
11
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
// 创建 Pinia 实例
const pinia = createPinia()
// 创建 Vue 实例
const app = createApp(App)
// 挂载到 Vue 根实例
app.use(pinia)
app.mount('#app')

Axios

1
npm insall axios
  • 新建 目录/文件 src/utils/request.ts src/api/xxx.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// request.ts

import axios from 'axios'
// 导入pinia
import { mainStore } from '@/store'
const store = mainStore()

// 创建axios
const $http = axios.create({
//设置默认请求地址
baseURL: 'http://localhost:8080',
//设置请求超时时间
timeout:5000,
//设置请求头
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
})


// 请求拦截器
$http.interceptors.request.use(config => {
// 验证 token
const token = store.state.token;
if (config.headers!= undefined) config.headers.Authorization = token
return config;
},error => {
return Promise.reject(error);
})

//响应拦截
$http.interceptors.response.use(res => {

// 状态码为200正常返回
if (res.status === 200) {
return Promise.resolve(res);
} else {
return Promise.reject(res);
}
}, error => {
return Promise.reject(error);
})

// 导出封装的axios
export default $http
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// api/user.ts
import request from "@/utils/request"

export function login(data: object) {
return request({
url: '/user/login',
method: 'post',
data
})
}

export function getInfo(token: object) {
return request({
url: '/user/info',
method: 'get',
params: { token }
})
}

export function logout() {
return request({
url: '/user/logout',
method: 'post'
})
}

ESLint

参考文章在 Vue3 + Vite + TS 项目中配置 ESLint,让 VSCode 编辑器自动修复错误 - 知乎 (zhihu.com)

  • 使用ESLint进行代码规范 保存就更改 看起来就舒服多了
1
2
3
# 安装
# 指定一下版本号 不然会有很多不兼容以及奇奇怪怪的问题
npm install eslint@7.2.0 eslint-plugin-vue@7.20.0 vue-eslint-parser @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-airbnb-base@14.2.1 eslint-plugin-import -D
  • 添加 .eslintrc.js 配置文件 手动添加即可
  • 写入以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
module.exports = {
root: true,
globals: {
defineEmits: 'readonly',
defineProps: 'readonly',
},
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended',
'airbnb-base',
],
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
},
rules: {
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 debugger
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 console
'no-bitwise': 'off', // 禁用按位运算符
'no-tabs': 'off', // 禁用 tab
'array-element-newline': ['error', 'consistent'], // 强制数组元素间出现换行
indent: [
'error',
2,
{ MemberExpression: 0, SwitchCase: 1, ignoredNodes: ['TemplateLiteral'] },
], // 强制使用一致的缩进
quotes: ['error', 'single'], // 强制使用一致的反勾号、双引号或单引号
'comma-dangle': ['error', 'always-multiline'], // 要求或禁止末尾逗号
'object-curly-spacing': ['error', 'always'], // 强制在大括号中使用一致的空格
'max-len': ['error', 120], // 强制一行的最大长度
'no-new': 'off', // 禁止使用 new 以避免产生副作用
'linebreak-style': 'off', // 强制使用一致的换行风格
'import/extensions': 'off', // 确保在导入路径中统一使用文件扩展名
'eol-last': 'off', // 要求或禁止文件末尾存在空行
'no-shadow': 'off', // 禁止变量声明与外层作用域的变量同名
'no-unused-vars': 'warn', // 禁止出现未使用过的变量
'import/no-cycle': 'off', // 禁止一个模块导入一个有依赖路径的模块回到自己身上
'arrow-parens': 'off', // 要求箭头函数的参数使用圆括号
semi: ['error', 'never'], // 要求或禁止使用分号代替 ASI
eqeqeq: 'off', // 要求使用 === 和 !==
'no-param-reassign': 'off', // 禁止对 function 的参数进行重新赋值
'import/prefer-default-export': 'off', // 如果模块只输入一个名字,则倾向于默认输出
'no-use-before-define': 'off', // 禁止在变量定义之前使用它们,则倾向于默认输出
'no-continue': 'off', // 禁用 continue 语句
'prefer-destructuring': 'off', // 优先使用数组和对象解构
'no-plusplus': 'off', // 禁用一元操作符 ++ 和 --
'prefer-const': 'warn', // 要求使用 const 声明那些声明后不再被修改的变量
'global-require': 'off', // 要求 require() 出现在顶层模块作用域中
'no-prototype-builtins': 'off', // 禁止直接调用 Object.prototypes 的内置属性
'consistent-return': 'off', // 要求 return 语句要么总是指定返回的值,要么不指定
'one-var-declaration-per-line': 'off', // 要求或禁止在变量声明周围换行
'one-var': 'off', // 强制函数中的变量要么一起声明要么分开声明
'import/named': 'off', // 确保命名导入与远程文件中的命名导出相对应
'object-curly-newline': 'off', // 强制大括号内换行符的一致性
'default-case': 'off', // 要求 switch 语句中有 default 分支
'no-trailing-spaces': 'off', // 禁用行尾空格
'func-names': 'off', // 要求或禁止使用命名的 function 表达式
radix: 'off', // 强制在 parseInt() 使用基数参数
'no-unused-expressions': 'off', // 禁止出现未使用过的表达式
'no-underscore-dangle': 'off', // 禁止标识符中有悬空下划线
'no-nested-ternary': 'off', // 禁用嵌套的三元表达式
'no-restricted-syntax': 'off', // 禁用特定的语法
'no-await-in-loop': 'off', // 禁止在循环中出现 await
'import/no-extraneous-dependencies': 'off', // 禁止使用外部包
'import/no-unresolved': 'off', // 确保导入指向一个可以解析的文件/模块
'template-curly-spacing': ['error', 'always'], // 要求或禁止模板字符串中的嵌入表达式周围空格的使用
'@typescript-eslint/no-var-requires': 'off', // 除import语句外,禁止使用require语句
'@typescript-eslint/no-empty-function': 'off', // 不允许空函数
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'guard-for-in': 'off', // 要求 for-in 循环中有一个 if 语句
'class-methods-use-this': 'off', // 强制类方法使用 this
'vue/html-indent': ['error', 2], // 在<template>中强制一致缩进
'vue/html-self-closing': 'off', // 执行自闭合的风格
'vue/max-attributes-per-line': [ // 强制每行属性的最大数量
'warn',
{
singleline: {
max: 3,
allowFirstLine: true,
},
multiline: {
max: 1,
allowFirstLine: false,
},
},
],
'vue/singleline-html-element-content-newline': 'off', // 要求单行元素的内容前后有一个换行符
}
}
  • 不同IDE设置ESLint方法不同
  • 大家自行查找即可

WebStorm:WebStorm 2021.1 使用 ESLint自动格式化代码_程序员鱼丸的博客-CSDN博客_webstorm代码格式化插件

VsCode:VsCode 如何配置Eslint - 掘金 (juejin.cn)

  • 配置完真的舒服多了😀

懒人必备

  • 不想自己配置的话 直接 clone 写好的代码开箱即用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 克隆项目
git clone https://gitee.com/lonelysnowman/vue3-vite-ts-template.git

# 进入项目目录
cd vue3-vite-ts-template

# 安装依赖
npm install

# 淘宝镜像加速下载
npm install --registry=https://registry.npm.taobao.org

# 启动服务
npm run dev

关注我查看更多前端技术文章