Vue3 + Vite + Element Plus project construction (full)

1 Introduction

This article uses Vue3 + Vite + Element Plus + Vue Router + Pinia + Typescript to build the project

2 Project initialization

npm init vue@latest

insert image description here

It is recommended to use pnpm, if pnpm is not installed, you can use npm

cd vue-project
pnpm i
pnpm dev

insert image description here

3 code style processing

  • Change the file type of .prettierrc.json to .prettierrc.js, and replace the file content with:
module.exports = {
    
    
  singleQuote: true, // 使用单引号
  semi: false, // 行尾不需要有分号
  trailingComma: 'none', // 行尾不需要有逗号
  endOfLine: 'auto', // 换行符使用 lf
  printWidth: 100 // 一行最多 100 字符
}
  • .eslintrc.cjs adds rules to resolve conflicts between eslint and prettier
rules: {
    
    
  'prettier/prettier': [
    'warn',
    {
    
    
      singleQuote: true,
      trailingComma: false
    }
  ]
}

4 Dependency installation

  • Functional dependencies
pnpm i element-plus axios
  • Automatically import related dependencies
pnpm i unplugin-auto-import unplugin-vue-components unplugin-icons -D

5 Automatic import

vite.config.ts file add the following:
insert image description here

Add "types" to tsconfig.json file includes to avoid ts error找不到名称“ref”

"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "types"]

6 Route interception

router/index.ts file add the following:

// 路由拦截
router.beforeEach((to, from, next) => {
    
    
  const token: string | null = getUser('token')
  // 已经登录过请求 login 界面会直接回到首页
  if (token) {
    
    
    to.path === '/login' ? next('/') : next()
    return
  }
  // 请求需要权限的界面,会转到 login 界面
  if (to.meta.requireAuth) {
    
    
    next({
    
    
      path: '/login',
      replace: true
    })
    return
  }
  next()
})

7 Add environment variable configuration file

  • Add a new .env.development file in the root directory
# 开发环境

# 配置文件路径
VITE_PUBLIC_PATH = /

# 接口代理
VITE_PROXY_DOMAIN = /api

# 后端地址
VITE_PROXY_DOMAIN_REAL = http://192.168.60.66:8000
  • Add a new .env.production file in the root directory
# 生产环境

# 项目打包路径
VITE_PUBLIC_PATH = ./

# 后端地址
VITE_PROXY_DOMAIN_REAL = /api

8 axios package

Add utils/http/index.ts file

import axios from 'axios'
import type {
    
     AxiosError, AxiosResponse } from 'axios'
import router from '@/router'

enum Msgs {
    
    
  '操作成功' = 200,
  '无权操作' = 401,
  '系统内部错误' = 500
}

// 避免多个接口401弹出多个弹框
let isRefreshing = false

const {
    
     DEV, VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL } = import.meta.env
// 创建http实例
const instance = axios.create({
    
    
  baseURL: DEV ? VITE_PROXY_DOMAIN : VITE_PROXY_DOMAIN_REAL,
  timeout: 2000,
  headers: {
    
    
    'Content-Type': 'application/json;charset=UTF-8'
  }
})

// 添加请求拦截器
instance.interceptors.request.use((config) => {
    
    
  config.headers = config.headers || {
    
    }
  // const token = getToken()
  // if (token) {
    
    
  //   config.headers['User-Token'] = token
  // }
  return config
})

// 添加响应拦截器
instance.interceptors.response.use(
  (res: AxiosResponse) => res,
  (err: AxiosError) => {
    
    
    const {
    
     response } = err
    if (!response) return Promise.reject(err)
    const errCodes = [401, 403, 500]
    const code = response.status
    if (errCodes.includes(response.status)) {
    
    
      // removeUserInfo()
      ElMessageBox({
    
    
        message: Msgs[code],
        title: '提示'
      })
        .then(() => {
    
    
          router.push('Login')
        })
        .finally(() => (isRefreshing = false))
      return Promise.reject(err)
    }
    ElMessage(Msgs[code] || '请求失败')
    return Promise.reject(err)
  }
)

const http = {
    
    
  get: (url = '', params = {
    
    }) => instance.get(url, {
    
     params }),
  post: (url = '', data = {
    
    }, config = {
    
    }) => instance.post(url, data, config),
  put: (url = '', data = {
    
    }) => instance.put(url, data),
  delete: (url = '', data = {
    
    }) => instance.delete(url, data),
  patch: (url = '', data = {
    
    }) => instance.patch(url, data)
}

export default http

use:

import http from '@/utils/http'

http.get('user').then((res) => {
    
    
  console.log(res)
})

9 Startup and production packaging configuration

Modify the vite.config.ts file

import {
    
     fileURLToPath, URL } from 'node:url'
import {
    
     loadEnv, ConfigEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite' // 自动导入
import Components from 'unplugin-vue-components/vite' // 组件注册
import {
    
     ElementPlusResolver } from 'unplugin-vue-components/resolvers' // elementPlus
import Icons from 'unplugin-icons/vite' // icon相关
import IconsResolver from 'unplugin-icons/resolver' // icon相关

export default ({
    
     mode }: ConfigEnv) => {
    
    
  const {
    
     VITE_PUBLIC_PATH, VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL } = loadEnv(
    mode,
    process.cwd()
  )
  return {
    
    
    base: VITE_PUBLIC_PATH, //打包路径
    plugins: [
      vue(),
      AutoImport({
    
    
        imports: ['vue', 'vue-router'],
        dts: fileURLToPath(new URL('./types/auto-imports.d.ts', import.meta.url)),
        resolvers: [
          ElementPlusResolver(),
          // 自动导入图标组件
          IconsResolver({
    
    
            prefix: 'Icon'
          })
        ]
      }),
      Components({
    
    
        dirs: ['src/views', 'src/layout', 'src/components'],
        dts: fileURLToPath(new URL('./types/components.d.ts', import.meta.url)),
        resolvers: [
          ElementPlusResolver(),
          IconsResolver({
    
    
            enabledCollections: ['ep'] // 重点
          })
        ]
      }),
      Icons({
    
    
        autoInstall: true
      })
    ],
    resolve: {
    
    
      alias: {
    
    
        '@': fileURLToPath(new URL('./src', import.meta.url))
      }
    },
    // 启动服务配置
    server: {
    
    
      host: '0.0.0.0',
      port: 8000,
      open: false,
      https: false,
      proxy: {
    
    
        [VITE_PROXY_DOMAIN]: {
    
    
          target: VITE_PROXY_DOMAIN_REAL,
          changeOrigin: true,
          rewrite: (path: string) => path.replace(/^\/api/, '')
        }
      }
    },
    // 生产环境打包配置
    build: {
    
    
      minify: 'terser',
      terserOptions: {
    
    
        compress: {
    
    
          drop_console: true,
          drop_debugger: true
        }
      },
      rollupOptions: {
    
    
        output: {
    
    
          chunkFileNames: 'js/[name]-[hash].js',
          entryFileNames: 'js/[name]-[hash].js',
          manualChunks(id: string | string[]) {
    
    
            if (id.includes('node_modules')) {
    
    
              const arr = id.toString().split('node_modules/')
              return arr[arr.length - 1].split('/')[0].toString()
            }
          }
        }
      }
    }
  }
}

10 Extremely fast construction

Use the yana-cli scaffolding, which provides a vue3 template and has built all the above content
insert image description here

npm i yana-cli
yana-cli create

Guess you like

Origin blog.csdn.net/weixin_36757282/article/details/130521812