vite 创建vue3项目

一、前言

由于在第一次创建项目的时候遇到了比较多的问题,因此记录一下创建vue3项目的过程以及遇到的一些问题

二、创建项目

1.环境准备

node:v18.17.1(更高版本也可,可用nvm切换node版本)

pnpm:9.1.4(更高版本也可)

2.初始化项目

安装pnpm指令

npm install -g pnpm 或者 npm i -g pnpm

创建vite项目以及初始化命令

pnpm create vite

初始化后根据提示输入

 //进入项目文件夹
 cd vite-vue-project

 //安装node_modules运行依赖
 pnpm install 或 pnpm i

 //启动项目
 pnpm run dev

三、项目配置

1.javascript代码检测工具配置(eslint)

1.1安装eslint

 npm i eslint@latest -D
 或
 pnpm add eslint@latest -D  /  pnpm install eslint@latest -D
 或
 yarn add eslint@latest -D

 latest是下载最新版本,可以替换成你想要下载的版本
 如:pnpm i eslint@8.8.0 -D
 可以下载8.8.0版本的eslint

1.2 初始化eslint

npx eslint --init

执行后会出现一下步骤






安装完成后 (在项目根目录会出现.eslintrc.cjs或.eslintrc.js文件)

如果没有则手动创建一个.eslintrc.cjs

若为.eslintrc.js需要改名为.eslintrc.cjs

1.3 安装vite-plugin-eslint

// 该包是用于配置vite运行的时候自动检测eslint规范,不符合页面会报错
pnpm add vite-plugin-eslint@latest -D
// 安装最新版eslint-plugin-vue
pnpm add eslint-plugin-vue@latest -D

配置vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import eslintPlugin from 'vite-plugin-eslint' //导入包

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    eslintPlugin({
      include: ['src/**/*.js', 'src/**/*.vue', 'src/*.js', 'src/*.vue']
    })
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

1.4 安装 eslint-parser (ESLint解析器)

pnpm add @babel/core -D // 某些代码需要调用 Babel 的 API 进行转码,就要使用@babel/core模块。
pnpm add  @babel/eslint-parser@latest -D

1.5 安装prettier (用于规范代码格式)

pnpm add  prettier -D
pnpm add prettier-eslint -D
pnpm add eslint-config-prettier  -D   // eslint兼容的插件
pnpm add eslint-plugin-prettier  -D   // eslint的prettier

1.6 配置prettier

在项目根目录创建文件 .prettierrc.cjs

// 在项目根目录创建文件 .prettierrc
// 以下配置视自己情况而定,并步是每个都需要的
module.exports = {
  tabWidth: 2,               // 使用4个空格缩进
  semi: false,               // 代码结尾是否加分号
  trailingComma: 'none',     // 代码末尾不需要逗号
  singleQuote: true,         // 是否使用单引号
  printWidth: 100,           // 超过多少字符强制换行
  arrowParens: 'avoid',      // 单个参数的箭头函数不加括号 x => x
  bracketSpacing: true,      // 对象大括号内两边是否加空格 { a:0 }

  endOfLine: 'auto',         // 文件换行格式 LF/CRLF
  useTabs: false,            // 不使用缩进符,而使用空格
  quoteProps: 'as-needed',   // 对象的key仅在必要时用引号
  jsxSingleQuote: false,     // jsx不使用单引号,而使用双引号
  jsxBracketSameLine: false, // jsx标签的反尖括号需要换行
  rangeStart: 0,             // 每个文件格式化的范围是文件的全部内容
  rangeEnd: Infinity,        // 结尾
  requirePragma: false,      // 不需要写文件开头的 @prettier
  insertPragma: false,       // 不需要自动在文件开头插入 @prettier
  proseWrap: 'preserve',     // 使用默认的折行标准
  htmlWhitespaceSensitivity: 'css'  // 根据显示样式决定html要不要折行
}

1.7配置配置 .eslintrc.cjs

module.exports = {
  "env": {
      "browser": true,
      "es2021": true,
      "node": true
  },
  "extends": [
      "eslint:recommended",         // 使用推荐的eslint
      'plugin:vue/vue3-recommended', // 使用插件支持vue3
       // 如果你没有安装第7步,以下两个包不要引入,否则报错 
      'plugin:prettier/recommended', 
      'eslint-config-prettier'
  ],
  "parserOptions": {
      "ecmaVersion": 13,
      "sourceType": "module",
      "ecmaFeatures": {
          "modules": true,
          'jsx': true
      },
      "requireConfigFile": false,
      "parser": '@babel/eslint-parser'
  },
  // eslint-plugin-vue 
  'plugins': [
      'vue',      // 引入vue的插件 vue <==> eslint-plugin-vue 
      // 这个包需要安装了第7步的三个包再引入
      'prettier' // 引入规范插件  prettier <==>  eslint-plugin-prettier
  ],
  'globals': {
      defineProps: 'readonly',
      defineEmits: 'readonly',
      defineExpose: 'readonly',
      withDefaults: 'readonly'
  },
  // 这里时配置规则的,自己看情况配置
  "rules": {
    "no-self-assign": "off",
      'semi': ['warn', 'never'],           // 禁止尾部使用分号
      'no-console': 'warn',                // 禁止出现console
      'no-debugger': 'warn',               // 禁止出现debugger
      'no-duplicate-case': 'warn',         // 禁止出现重复case
      'no-empty': 'warn',                  // 禁止出现空语句块
      'no-extra-parens': 'warn',           // 禁止不必要的括号
      'no-func-assign': 'warn',            // 禁止对Function声明重新赋值
      'no-unreachable': 'warn',            // 禁止出现[return|throw]之后的代码块
      'no-else-return': 'warn',            // 禁止if语句中return语句之后有else块
      'no-empty-function': 'warn',         // 禁止出现空的函数块
      'no-lone-blocks': 'warn',            // 禁用不必要的嵌套块
      'no-multi-spaces': 'warn',           // 禁止使用多个空格
      'no-redeclare': 'warn',              // 禁止多次声明同一变量
      'no-return-assign': 'warn',          // 禁止在return语句中使用赋值语句
      'no-return-await': 'warn',           // 禁用不必要的[return/await]
      'no-self-compare': 'warn',           // 禁止自身比较表达式
      'no-useless-catch': 'warn',          // 禁止不必要的catch子句
      'no-useless-return': 'warn',         // 禁止不必要的return语句
      'no-mixed-spaces-and-tabs': 'warn',  // 禁止空格和tab的混合缩进
      'no-multiple-empty-lines': 'warn',   // 禁止出现多行空行
      'no-trailing-spaces': 'warn',        // 禁止一行结束后面不要有空格
      'no-useless-call': 'warn',           // 禁止不必要的.call()和.apply()
      'no-var': 'warn',                    // 禁止出现var用let和const代替
      'no-delete-var': 'off',              // 允许出现delete变量的使用
      'no-shadow': 'off',                  // 允许变量声明与外层作用域的变量同名
      'dot-notation': 'warn',              // 要求尽可能地使用点号
      'default-case': 'warn',              // 要求switch语句中有default分支
      'eqeqeq': 'warn',                    // 要求使用 === 和 !==
      'curly': 'warn',                     // 要求所有控制语句使用一致的括号风格
      'space-before-blocks': 'warn',       // 要求在块之前使用一致的空格
      'space-in-parens': 'warn',           // 要求在圆括号内使用一致的空格
      'space-infix-ops': 'warn',           // 要求操作符周围有空格
      'space-unary-ops': 'warn',           // 要求在一元操作符前后使用一致的空格
      'switch-colon-spacing': 'warn',      // 要求在switch的冒号左右有空格
      'arrow-spacing': 'warn',             // 要求箭头函数的箭头前后使用一致的空格
      'array-bracket-spacing': 'warn',     // 要求数组方括号中使用一致的空格
      'brace-style': 'warn',               // 要求在代码块中使用一致的大括号风格
      'camelcase': 'warn',                 // 要求使用骆驼拼写法命名约定
      'indent': ['warn', 4],               // 要求使用JS一致缩进4个空格
      'max-depth': ['warn', 4],            // 要求可嵌套的块的最大深度4
      'max-statements': ['warn', 100],     // 要求函数块最多允许的的语句数量20
      'max-nested-callbacks': ['warn', 3], // 要求回调函数最大嵌套深度3
      'max-statements-per-line': ['warn', { max: 1 }],   // 要求每一行中所允许的最大语句数量
      "quotes": ["warn", "single", "avoid-escape"],      // 要求统一使用单引号符号
      "vue/require-default-prop": 0,                     // 关闭属性参数必须默认值
      "vue/singleline-html-element-content-newline": 0,  // 关闭单行元素必须换行符
      "vue/multiline-html-element-content-newline": 0,   // 关闭多行元素必须换行符
      // 要求每一行标签的最大属性不超五个
      'vue/max-attributes-per-line': ['warn', { singleline: 5 }],
      // 要求html标签的缩进为需要4个空格
      "vue/html-indent": ["warn", 4, {
          "attribute": 1,
          "baseIndent": 1,
          "closeBracket": 0,
          "alignAttributesVertically": true,
          "ignores": []
      }],
      // 取消关闭标签不能自闭合的限制设置
      "vue/html-self-closing": ["error", {              
          "html": {
              "void": "always",
              "normal": "never",
              "component": "always"
          },
          "svg": "always",
          "math": "always"
      }]   
  }
}

1.8配置VScode

安装“ESLint”插件 和 “Prettier code”插件
最后再重新安装依赖,防止有些依赖包降低或者升级带来的报错

pnpm i
 或
npm i

最后

// 配置vscode
// 打开:设置 -> 文本编辑器 -> 字体 -> 在 settings.json 中编辑

// settings.json文件
{
  // vscode默认启用了根据文件类型自动设置tabsize的选项
  "editor.detectIndentation": false,
  // 重新设定tabsize
  "editor.tabSize": 4,
  // 每次保存的时候自动格式化
  "editor.formatOnSave": true,
  // 每次保存的时候将代码按eslint格式进行修复
  "eslint.autoFixOnSave": true,
  // 添加vue支持
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autoFix": true
    }
  ],
  // #让prettier使用eslint的代码格式进行校验
  "prettier.eslintIntegration": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "eslint.codeActionsOnSave.rules": null
}

四、element-plus集成

1.导入element-plus指令

pnpm i element-plus
安装完成后在main.js中导入element-plus

//引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)

2.导入element-plus图标

pnpm i @element-plus/icons-vue

需要的页面导入对应的图标,下面就是Edit图标的导入

<script setup>
 import { Edit } from '@element-plus/icons-vue'
</script>

3.配置element-plus国际化,下面配置的是中文

// 引入element-plus国际化
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

const app = createApp(App)
app.use(ElementPlus, {
  location: zhCn // element-plus国际化配置
})

五、配置生产环境.env.production、测试环境.env.development

.env.production 生产环境加载

.env.development 测试开发环境加载

在文件里面配置如下

在.env文件

VUE_APP_NAME='vue测试名称'

.env.development文件:

NODE_ENV = development
VUE_APP_URL = 'developmentURL' //自定义变量  必须要以VUE_APP_开头定义

.env.production 文件:

NODE_ENV = production
VUE_APP_URL = 'productionURL' //自定义变量  必须要以VUE_APP_开头定义

下面我们就需要配置 package.json 添加如下字段

"scripts": {
    "build-development": "vue-tsc && vite build --mode development",
    "bulid:pro": "vue-tsc && vite build --mode production",
  },

六、封装Svg组件

1.安装 vite-plugin-svg-icons:

npm install vite-plugin-svg-icons -D

2.在 vite 配置文件中添加插件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import path from "path";
export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
      // 指定目录(svg存放目录)
      iconDirs: [path.resolve(process.cwd(), "src/assets/svgs")],
      // 使用 svg 图标的格式(name为图片名称)
      symbolId: "icon-[name]",
      //生成组件插入位置 只有两个值 boby-last | body-first
      inject: 'body-last'
    })
  ],
})

3.在main.ts文件中全局导入

import 'virtual:svg-icons-register';

4.封装svg组件,封装svg组件,可修改宽高和颜色

<template>
  <svg
      aria-hidden="true"
      :width="width"
      :height="height"
      :fill="color"
  >
      <use :xlink:href="`#icon-${name}` fill = "颜色"/>
  </svg>
</template>
<script setup lang="ts">
  defineProps<{
    name: string,
    width: string,
    height: string,
    color?: string
  }>();
</script>

5.使用

<template>
  <SvgIcon name="close" width="24" height="24"></SvgIcon>
  </template>
  <script setup>
  import SvgIcon from "@/components/svg-icon/svg-icon.vue";
</script>

七、mock接口(模拟接口)

1.安装依赖

pnpm install -D vite-plugin-mock mockjs

2.在vit.config.js配置文件启用插件

// mock插件提供方法
import { viteMockServe } from 'vite-plugin-mock'

export default defineConfig(({ command }) => {
  return {
    plugins: [
      viteMockServe({
        localEndabled: command === 'serve' // 保证开发阶段可以使用mock接口
      })
    ],
})


3.在根目录创建mock文件夹:去创建我们需要的mock数据与接口

例: 在mock文件夹内部创建一个user.js文件,内容如下

// 用户信息数据
// 此函数执行会返回一个数组,数组里面包含俩个用户信息
function createUserList() {
  return [
    {
      userId: 1,
      avatar: 'https://pic.cnblogs.com/avatar/1808605/20230206194007.png',
      username: 'munaiyi',
      password: '123456',
      desc: '平台管理员',
      roles: ['平台管理员'],
      buttons: ['cuser.detail'],
      routes: ['home'],
      token: 'Admin Token'
    },
    {
      userId: 1,
      avatar: 'https://c-ssl.dtstatic.com/uploads/item/202004/14/20200414210134_qbeyi.thumb.400_0.jpg',
      username: 'system',
      password: '123456',
      desc: '系统管理员',
      roles: ['系统管理员'],
      buttons: ['cuser.detail', 'cuser.user'],
      routes: ['home'],
      token: 'System Token'
    }
  ]
}

// 对外暴露一个数组:数组里面包含俩个接口
// 登录假的接口
// 获取用户信息假的接口
export default [
  // 用户登录接口
  {
    url: '/api/user/login', // 请求地址
    method: 'post', // 请求方式
    response: ({ body }) => {
      // 获取请求体带过来的用户名和密码
      const { username, password } = body
      // 调用获取用户信息函数,用户判断是否有此用户
      const checkUser = createUserList().find(item => item.username === username && item.password === password)

      // 没有用户返回失败信息
      if (!checkUser) {
        return { code: 201, data: { message: '账号或密码不正确' } }
      }

      // 如果有返回成功信息
      const { token } = checkUser
      return { code: 200, data: { token } }
    }
  },
  // 获取用户信息
  {
    url: '/api/user/info',
    method: 'get',
    response: request => {
      // 获取请求头携带token
      const token = request.headers.token
      // 查看用户信息师傅包含有此token用户
      const checkUser = createUserList().find(item => item.token === token)

      // / 没有用户返回失败信息
      if (!checkUser) {
        return { code: 201, data: { message: '获取用户信息失败' } }
      }
      // 如果有返回成功信息
      return { code: 200, data: { checkUser } }
    }
  }
]

八、axios二次封装

1.安装依赖

pnpm i axios

在开发项目的时候避免不了与后端进行交豆,因此我们需要使用axios插件实现发送网络请求。在开发项目的时候我们经常会把axios进行二次封装。

目的:

1:使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数)

2:使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理htp网络错误)

在根目录下创建utils/request.ts

error部分自行修改

// 进行axios的二次封装:使用请求与响应拦截器
import axios from 'axios'
import { ElMessage } from 'element-plus'
// 第一步: 利用axios对象的create方法,创建axios实例
const service = axios.create({
  // 基础路径
  baseURL: import.meta.env.VITE_APP_BASE_API, // 基础路径上带/api
  timeout: 5000 // 超时的时间设置
})

// 第二步: request 实例添加请求与响应拦截器

service.interceptors.request.use(config => {
  // 返回配置对象
  return config
})

// 第三步 :响应拦截器

service.interceptors.response.use(
  response => {
    // 成功回调
    // 简化数据
    return response.data
  },
  error => {
    // 失败的回调:处理http网络错误
    // 定义一个变量:存储网络错误的信息
    let message = ''
    // http状态码
    const status = error.response.status
    switch (status) {
      case 401:
        message = 'Token过期'
        break
      case 403:
        message = '无权访问'
        break
      case 404:
        message = '请求地址错误'
        break
      case 500:
        message = '服务器出现问题'
        break
      default:
        message = '网络出现问题'
        break
    }
    // 提示错误信息
    ElMessage({
      type: 'error',
      message
    })

    return Promise.reject(error)
  }
)
export default service

九、api接口统一管理

1.src文件夹下创建api文件夹

posted @ 2024-06-05 16:47  沐乃伊  阅读(23)  评论(0编辑  收藏  举报