【Vue3+Ts+Vite】使用Vite与TS构建Vue3项目

简介: 🔈今天学习一下如何初始化一个 Vue3 + Ts + Vite 的项目🔊与时俱进 开始用全新的技术。本文包含以下内容:基础框架的搭建,别名配置,vue-router配置,pinia配置,axios配置,ESLint配置。

Vue3+Ts+Vite

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

🔉学习地址:开始 {#getting-started} | Vite中文网 (vitejs.cn)

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

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

安装

# 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
// 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']
    }
})
// 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

# Vue-Router 4+ 版本支持 Vue3
npm install vue-router@4
  • 新建 目录/文件夹 src/router/index.ts
// 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 }
// 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");
<!-- App.vue -->
<!-- 记得在App.vue中添加 router-view -->
<router-view></router-view>

Pinia

npm install pinia
  • 新建 目录/文件 src/store/index.ts
// 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: {

    }
})
// 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

npm insall axios
  • 新建 目录/文件 src/utils/request.ts src/api/xxx.ts
// 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
// 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进行代码规范 保存就更改 看起来就舒服多了
# 安装
# 指定一下版本号 不然会有很多不兼容以及奇奇怪怪的问题
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 配置文件 手动添加即可
  • 写入以下代码
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 写好的代码开箱即用
# 克隆项目
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
关注我查看更多前端技术文章
相关文章
|
16天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
37 7
|
17天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
39 3
|
16天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
36 1
|
16天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
37 1
|
6天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
6天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
6天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
6天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
5天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
7天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。