一:创建项目 github完整配置地址
使用vite官网命令安装
pnpm create vite my-vue-ts --template vue-ts
cd my-vue-ts
pnpm install
pnpm dev
tsconfig.json中新增 "allowJs": true, // 允许项目中使用js,对于不习惯使用ts的可以在项目中使用js
二:新增.env文件 修改package.json scripts命令
新增 .env.dev .env.beta .env.prod 文件,文件内容如下,每个文件域名应该不一样,用以请求配置axios时区分不同的环境域名 更多环境配置参考官网
VUE_APP_BASE_API = 'http://127.0.0.1:8080/'
package.json 中scripts下配置如下命令
"serve:dev": "vite --mode dev",
"serve:beta": "vite --mode beta",
"serve:prod": "vite --mode prod",
"build:dev": "vite build --mode dev",
"build:beta": "vite build --mode beta",
"build:prod": "vite build --mode prod",
三:vite.config.js 配置
1.常用配置 vite官网地址
安装依赖:pnpm add @types/node -D
vite.config.js配置如下:
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
}
})
2.配置plugins
2.1 vue,vueJsx插件配置
安装依赖
pnpm add @vitejs/plugin-vue
pnpm add @vitejs/plugin-vue-jsx
vite.config.js 配置如下:
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
}
})
tips:配置vueJsx时需要加上
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
写个jsx测试下
components/helloJsx.jsx
import { defineComponent } from 'vue'
export default defineComponent({ render() { return <div>Test jsx</div> }})
App.vue中引入:
tips:引入时没加后缀,是因为常用配置中配置了extensions:[".jsx",''.vue"],在配置数组中的引入时都可以不加后缀
<script setup lang="ts">
import HelloWorld from './components/HelloWorld'
import helloJsx from './components/helloJsx'
</script>
<template>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
<helloJsx />
</template>
2.2配置AutoImport(按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API)和Components(Vue的按需组件自动导入。)
安装依赖
pnpm add unplugin-auto-import - D
pnpm add unplugin-vue-components - D
vite.config.js 配置如下:
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
AutoImport({ // 按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API。具有 TypeScript 支持。
imports: [
'vue',
],
dts: 'auto-imports.d.ts', // 生成文件的位置
}),
Components({ // Vue的按需组件自动导入。
dts: 'components.d.ts', // 生成文件的位置
}),
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
}
})
AutoImport里面现在就配置了一个vue,现在跟vue相关的api就不用自己去导入了,比如上面jsx文件中的defineComponent
import { defineComponent } from 'vue'
export default defineComponent({ render() { return <div>Test jsx</div> }})
现在只需要写成
export default defineComponent({ render() { return <div>Test jsx</div> }})
dts配置了输出文件的位置,当你执行pnpm dev 时会在你的项目下新建auto-imports.d.ts和components.d.ts
在这两个文件中你能看到它自动帮你引入了的api和组件,比如defineComponent在auto-imports.d.ts中如下导入:
const defineComponent: typeof import('vue')['defineComponent']
Components插件会默认帮我们导入src/components下的组件 比如HelloWorld在components.d.ts导入如下:
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
如果不想导入可以配置下只需要导入的目录:dirs
Components({ // Vue的按需组件自动导入。
dirs: ['library/components'],
dts: 'components.d.ts', // 生成文件的位置
}),
2.2.1 配合ElementPlus 按需导入使用
安装依赖
pnpm add element-plus
vite.config.js 配置如下:
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
AutoImport({ // 按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API。具有 TypeScript 支持。
imports: [
'vue',
],
resolvers: [ElementPlusResolver()],
dts: 'auto-imports.d.ts', // 生成文件的位置
}),
Components({ // Vue的按需组件自动导入。
dirs: ['library/components'],
resolvers: [ElementPlusResolver()],
dts: 'components.d.ts', // 生成文件的位置
}),
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
}
})
unplugin-vue-components 提供了ElementPlusResolver 来按需导入具体可以参考 element-pluss官网
2.3 配置vite-plugin-svg-icons和remixicon,导入自定义svg和remixicon图标库配合使用
安装依赖
pnpm add vite-plugin-svg-icons
pnpm add remixicon
vite.config.js 配置如下:
main.ts中先引入以下代码,不引入不现实svg图标
main.ts
import 'virtual:svg-icons-register' // 引入svg
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
AutoImport({ // 按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API。具有 TypeScript 支持。
imports: [
'vue',
],
resolvers: [ElementPlusResolver({ importStyle: false })],
dts: 'auto-imports.d.ts', // 生成文件的位置
}),
Components({ // Vue的按需组件自动导入。
dirs: ['library/components'],
resolvers: [ElementPlusResolver()],
dts: 'components.d.ts', // 生成文件的位置
}),
createSvgIconsPlugin({ // svg 导入
iconDirs: [resolve('src/icons/svg')],
symbolId: 'icon-[name]',
}),
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
}
})
createSvgIconsPlugin:
iconDirs:需要导入的自定义个svg图标目录
symbolId: 'icon-[name]' 给图标增加前缀icon
2.3.1写个icon的通用组件
<template>
<img v-if="isExternal" class="img-icon" :src="icon" />
<svg v-else-if="isCustomSvg" aria-hidden="true" :class="svgClass">
<use :xlink:href="'#icon-' + icon" />
</svg>
<!-- 内置svg雪碧图较大,对性能要求苛刻的用户请勿使用isDefaultSvg属性 -->
<svg v-else-if="isDefaultSvg" class="vab-icon">
<use :xlink:href="remixIconPath + '#ri-' + icon" />
</svg>
<i
v-else
aria-hidden="true"
:class="{
['ri-' + icon]: true,
}"
/>
</template>
<script>
import 'remixicon/fonts/remixicon.css'
import { isExternal } from '@/utils/validate'
// import { computed } from 'vue'
export default {
name: 'VabIcon',
props: {
icon: {
type: String,
required: true,
},
// 是否使用自定义图标
isCustomSvg: {
type: Boolean,
default: false,
},
// 是否使用本地库Remix图标
isDefaultSvg: {
type: Boolean,
default: false,
},
className: {
type: String,
default: '',
},
},
setup(props) {
const svgClass = computed(() => {
if (props.className) return `vab-icon ${props.className}`
else return 'vab-icon'
})
return {
svgClass,
isExternal: isExternal(props.icon),
remixIconPath: import.meta.glob(
'remixicon/fonts/remixicon.symbol.svg',
{ eager: true }
),
}
},
}
</script>
<style lang="scss" scoped>
.img-icon {
display: inline-block;
width: 2em;
height: 2em;
vertical-align: middle;
}
.vab-icon {
display: inline-block;
width: 16px;
height: 16px;
margin: 0 auto;
overflow: hidden;
vertical-align: middle;
fill: currentColor;
}
[class*='ri'] {
display: inline-block;
font-size: 16px;
text-align: center;
vertical-align: -3.5px;
}
</style>
validate.ts
/**
* @description 判读是否为外链
* @param path
* @returns {boolean}
*/
export function isExternal(path: string) {
return /^(https?:|mailto:|tel:|\/\/)/.test(path)
}
使用:main.ts中全局注册组件
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import vabIcon from '@/components/VabIcon'
import 'virtual:svg-icons-register' // 引入svg
const app = createApp(App)
app.component('vabIcon',vabIcon)
app.mount('#app')
使用自己的svg图标
自己找个svg图标复制到 src/icons/svg 目录下,isCustomSvg表示使用自己导入的svg标志
项目中直接使用: <vabIcon icon="404" isCustomSvg />
使用remixicon图标库的图标 图标库地址
复制图标名字直接使用:<vab-icon icon="arrow-left-up-line" />
2.4 配置eslintPlugin
安装依赖
pnpm add eslint -D
vue,vite相关插件
pnpm add eslint-plugin-vue -D Vue.js的官方ESLint插件。
pnpm add vite-plugin-eslint -D vite的ESLint插件。
ts相关插件:
pnpm add @typescript-eslint/eslint-plugin -D
pnpm add @typescript-eslint/parser -D
pnpm add @vue/eslint-config-typescript -D
prettier相关插件:
pnpm add eslint-config-prettier -D
pnpm add eslint-plugin-prettier -D
vite.config.js 配置如下:
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { visualizer } from 'rollup-plugin-visualizer'
import eslintPlugin from 'vite-plugin-eslint'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
AutoImport({ // 按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API。具有 TypeScript 支持。
imports: [
'vue',
],
resolvers: [ElementPlusResolver({ importStyle: false })],
dts: 'auto-imports.d.ts', // 生成文件的位置
}),
Components({ // Vue的按需组件自动导入。
dirs: ['library/components'],
resolvers: [ElementPlusResolver()],
dts: 'components.d.ts', // 生成文件的位置
}),
createSvgIconsPlugin({ // svg 导入
iconDirs: [resolve('src/icons/svg')],
symbolId: 'icon-[name]',
}),
eslintPlugin({ // eslint 校验
include: [
'src/**/*.js',
'src/**/*.ts',
'src/**/*.vue',
'src/**/*.jsx',
'src/**/*.tsx',
'src/*.js',
'src/*.vue',
],
}),
visualizer({ // 可视化并分析Rollup包,以查看哪些模块占用了空间。
// 必须放在最后一个
filename: 'stats.html',
open: true,
gzipSize: true,
sourcemap: true,
}),
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
optimizeDeps: {
include: [
'axios',
'element-plus',
'lodash',
'echarts',
'pinia',
'qs',
],
exclude: [],
},
build: {
outDir: 'dist',
assetsDir: 'assets',
cssCodeSplit: true,
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'static/js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
manualChunks: {
vue: ['vue'],
vueRouter: ['vue-router'],
qs: ['qs'],
axios: ['axios'],
lodash: ['lodash'],
echarts: ['echarts'],
elementUi: ['element-plus'],
},
},
},
// 关闭文件计算
// reportCompressedSize: false,
sourcemap: command === 'serve',
// chunkSizeWarningLimit: 1500 // 消除打包大小超过500kb警告
},
}
})
eslintPlugin({ // eslint 校验
include: [
'src//.js',
'src//.ts',
'src//.vue',
'src//.jsx',
'src//.tsx',
'src/.js',
'src/*.vue',
],
}),
配置需要校验的文件
.eslintrc.cjs如下
规则参考 https://eslint.nodejs.cn/docs/latest/rules/
eslint-plugin-vue https://eslint.vuejs.org/rules/first-attribute-linebreak.html
typescript-eslint https://typescript-eslint.io/rules/
module.exports = {
root: true,
env: {
node: true,
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'@vue/typescript/recommended',
],
parser: 'vue-eslint-parser',
parserOptions: {
parser: {
ecmaVersion: 12,
js: 'espree',
ts: '@typescript-eslint/parser',
'<template>': 'espree',
},
sourceType: 'module',
ecmaFeatures: {
jsx: true,
tsx: true,
},
warnOnUnsupportedTypeScriptVersion: false,
},
// 规则参考 https://eslint.nodejs.cn/docs/latest/rules/
// eslint-plugin-vue https://eslint.vuejs.org/rules/first-attribute-linebreak.html
//typescript-eslint https://typescript-eslint.io/rules/
rules: {
'no-undef': 'off',
'no-console': 'off',
'no-debugger': 'off',
'prefer-rest-params': 'off',
'vue/no-reserved-component-names': 'off',
'vue/one-component-per-file': 'off',
'prefer-const': 'off',
'vue/require-prop-types': 'off',
'vue/require-explicit-emits': 'off',
'vue/multi-word-component-names':'off',
'@typescript-eslint/no-explicit-any': 'off'
},
}
.eslintignore如下
auto-imports.d.ts
components.d.ts
node_modules
src/assets
src/icons
public
dist
tsconfig.json如下:
tsconfig.json中新增 "allowJs": true, // 允许项目中使用js,对于不习惯使用ts的可以在项目中使用js
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"allowJs": true, // 允许项目中使用js
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
/* paths */
"paths": {
"~/*": ["*"],
"@/*": ["./src/*"],
"/#/*": ["./types/*"],
},
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/components/helloJsx.jsx"],
"references": [{ "path": "./tsconfig.node.json" }]
}
jsconfig.json 如下:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"baseUrl": "./",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"paths": {
"~/*": ["*"],
"@/*": ["src/*"],
"/#/*": ["types/*"],
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"exclude": ["node_modules", "dist"]
}
2.5 配置rollup-plugin-visualizer 可视化并分析Rollup包,以查看哪些模块占用了空间。
安装依赖
pnpm add rollup-plugin-visualizer -D
vite.config.js 配置如下:
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig(({ command, mode }) => {
return {
base: './', // 开发或生产环境服务的公共基础路径。
server: {
host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
port: 5173,
},
envPrefix: 'VUE_', // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
resolve: {
alias: { // 配置别名
'~': resolve(__dirname, '.'),
'@': resolve(__dirname, 'src'),
'/#': resolve(__dirname, 'types'),
},
extensions: [ // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
'.mjs',
'.js',
'.mts',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue',
],
},
plugins: [
vue(), // 支持 vue
vueJsx(), // 支持 jsx tsx
AutoImport({ // 按需自动导入 Vite、Webpack、Rspack、Rollup 和 esbuild 的 API。具有 TypeScript 支持。
imports: [
'vue',
],
resolvers: [ElementPlusResolver({ importStyle: false })],
dts: 'auto-imports.d.ts', // 生成文件的位置
}),
Components({ // Vue的按需组件自动导入。
dirs: ['library/components'],
resolvers: [ElementPlusResolver()],
dts: 'components.d.ts', // 生成文件的位置
}),
createSvgIconsPlugin({ // svg 导入
iconDirs: [resolve('src/icons/svg')],
symbolId: 'icon-[name]',
}),
visualizer({ // 可视化并分析Rollup包,以查看哪些模块占用了空间。
// 必须放在最后一个
filename: 'stats.html', //输出文件名
open: true,
gzipSize: true,
sourcemap: true,
}),
],
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
}
})
visualizer({ // 可视化并分析Rollup包,以查看哪些模块占用了空间。
// 必须放在最后一个
filename: 'stats.html', //输出文件名
open: true,
gzipSize: true,
sourcemap: true,
})
现在运行 pnpm build:serve 就会自动生成stats.html,就可以分析各个包的大小
3.配置optimizeDeps
optimizeDeps: {
include: [
'axios',
'element-plus',
'lodash',
'echarts',
'pinia',
'qs',
],
exclude: [],
},
配置include预购建 vite官网
4.配置build
build: {
outDir: 'dist',
assetsDir: 'assets',
cssCodeSplit: true,
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'static/js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
manualChunks: {
vue: ['vue'],
vueRouter: ['vue-router'],
qs: ['qs'],
axios: ['axios'],
lodash: ['lodash'],
echarts: ['echarts'],
elementUi: ['element-plus'],
},
},
},
// 关闭文件计算
// reportCompressedSize: false,
sourcemap: command === 'serve',
// chunkSizeWarningLimit: 1500 // 消除打包大小超过500kb警告
},
配置如下代码会在打包的dist/static下面生成js,png,css,svg等格式的文件夹单独存放
chunkFileNames: 'static/js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'static/js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
配置如下代码会把包含在里面的包,打包时生成单独的文件, vueRouter: ['vue-router'],前面的名字可以自己随便取,后面的文件要跟package.json中的一致
manualChunks: {
vue: ['vue'],
vueRouter: ['vue-router'],
qs: ['qs'],
axios: ['axios'],
lodash: ['lodash'],
echarts: ['echarts'],
elementUi: ['element-plus'],
},
(四)配置pinia
安装依赖:
pnpm add pinia
新建以下文件:
src/store/index.ts
import {createPinia} from 'pinia'
import { App } from 'vue'
const pinia = createPinia()
export function setupStore(app: App<Element>) {
app.use(pinia)
}
export default pinia
src/store/modules/acl.ts
import { defineStore } from 'pinia'
export const useAclStore = defineStore('acl', {
state: () => ({
admin: false,
role: '2312',
}),
getters: {
getAdmin: (state) => state.admin,
getRole: (state) => state.role,
},
actions: {
setFull(admin: boolean) {
this.admin = admin
},
},
})
main.ts中引入
import { createApp } from 'vue'
import { setupStore } from './store/index'
import './style.css'
import App from './App.vue'
const app = createApp(App)
setupStore(app)
app.mount('#app')
helloWord.vue中使用
<script setup lang="ts">
import { useAclStore } from '../store/modules/acl'
const { getRole } = useAclStore()
defineProps<{ msg: string }>()
</script>
<template>
{{getRole}}
<vabIcon
icon="404"
is-custom-svg
/>
<vab-icon icon="lock-password-line" />
<vab-icon icon="arrow-right-up-line" />
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
(五)配置router
安装依赖:
pnpm add vue-router
新建以下文件:
src/router/index.ts
import type { RouteRecordRaw } from 'vue-router'
import type { VabRouteRecord } from '/#/router'
import type { App } from 'vue'
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router'
export const constantRoutes: VabRouteRecord[] = [
{
path: '/home',
name: 'Home',
component: () => import('@/views/Home/index.vue'),
meta: {
title:'Home'
},
},
{
path: '/404',
name: '404',
component: () => import('@/views/404.vue'),
meta: {
title:'404'
},
},
]
const publicPath = ''
const isHashRouterMode = true
const router = createRouter({
history: isHashRouterMode
? createWebHashHistory(publicPath)
: createWebHistory(publicPath),
routes: constantRoutes as RouteRecordRaw[],
})
export function setupRouter(app: App<Element>) {
app.use(router)
return router
}
export default router
我这里新建了2个路由home和404,你们需要根据自己需求新建路由
跟目录下新建types,项目中用到了ts需要定义接口(interface)
types/router.d.ts
import type { RouteRecordRaw } from 'vue-router'
/**
* 路由记录
*/
declare interface VabRouteRecord
extends Omit<RouteRecordRaw, 'name' | 'meta' | 'children'> {
name: string
meta: VabRouteMeta
children?: VabRouteRecord[]
}
declare interface VabRouteMeta {
// 菜单、面包屑、多标签页显示的名称
title?: string
}
main.ts引入
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { setupStore } from '@/store'
import { setupRouter } from '@/router'
import vabIcon from '@/components/VabIcon'
import 'virtual:svg-icons-register' // 引入svg
const app = createApp(App)
app.component('VabIcon',vabIcon)
setupStore(app)
setupRouter(app)
app.mount('#app')
现在还需要修改App.vue,加上router-view组件,具体的可以根据自己项目结构修改
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</template>
现在启动项目就可以输入路由访问了:http://10.1.40.62:5173/#/home
现在只是一个路由的基础配置,后续我会加上erp后台权限管理的逻辑
(六)配置axios
安装依赖:
pnpm add axios
新建以下文件:
src/utils/request.ts
import axios from 'axios'
/**
* axios请求拦截器配置
* @param config
* @returns {any}
*/
const requestConf: any = (config: any): any => {
const token = '' // 从自己保存的token位置获取token
if (token) config.headers['token'] = `${token}`
return config
}
/**
* axios响应拦截器
* @param config 请求配置
* @param data response数据
* @param status HTTP status
* @param statusText HTTP status text
* @returns {Promise<*|*>}
*/
const handleData = async (res: any): Promise<any | any> => {
const { data, config } = res
if (config.export) return data //导出
const { code } = data.heads
switch (code) {
case 200:
return data.body
case 4001:
break
case 403:
break
default:
return Promise.reject(data)
break
}
}
/**
* @description axios初始化
*/
const instance = axios.create({
baseURL: import.meta.env.VUE_APP_BASE_API,
timeout: 60000,
withCredentials: true,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
})
/**
* @description axios请求拦截器
*/
instance.interceptors.request.use(requestConf, (error) => {
return Promise.reject(error)
})
/**
* @description axios响应拦截器
*/
instance.interceptors.response.use(
(response) => handleData(response),
(error) => {
//这里可以写提示错误信息的逻辑
return Promise.reject(error)
}
)
export default instance
请求拦截和响应拦截里面具体逻辑需要根据自己的具体业务来
axios配置好了,下面就可以写接口了:
src/api/home.ts
import request from '@/utils/request'
export const getHomeInfo = (data:any) => {
return request({
url: '/home/info',
method: 'post',
data,
})
}
组件中引入使用
<script setup lang="ts">
import {getHomeInfo} from '@/api/home'
const getInfo = async ()=>{
const data = await getHomeInfo({})
console.log(data)
}
onMounted(() => {
getInfo()
})
</script>
(七)配置lint-staged 和 husky
安装依赖:
pnpm add husky -D
pnpm add lint-staged -D
pnpm add @commitlint/cli -D
pnpm add @commitlint/config-conventional -D
修改package.josn:
{
"name": "my-vue3-ts-template",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"serve:dev": "vite --mode dev",
"serve:beta": "vite --mode beta",
"serve:prod": "vite --mode prod",
"build:dev": "vite build --mode dev",
"build:beta": "vite build --mode beta",
"build:prod": "vite build --mode prod",
"lint": "eslint --fix --ext .js,.ts,.jsx,.tsx,.vue src",
"preview": "vite preview",
"prepare": "husky install"
},
"dependencies": {
"@vitejs/plugin-vue-jsx": "^3.0.2",
"axios": "^1.5.0",
"element-plus": "^2.3.12",
"pinia": "^2.1.6",
"remixicon": "^3.5.0",
"vite-plugin-svg-icons": "^2.0.1",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"@types/node": "^20.5.7",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"@vitejs/plugin-vue": "^4.3.4",
"@vue/eslint-config-typescript": "^11.0.3",
"eslint": "^8.48.0",
"eslint-plugin-vue": "^9.17.0",
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.66.1",
"typescript": "^5.0.2",
"unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.5",
"vite-plugin-eslint": "^1.8.1",
"vue-tsc": "^1.8.5"
},
"lint-staged": {
"*.{js,cjs,jsx,tsx,vue}": [
"eslint --fix --ext .js,.vue src"
]
}
}
新增lint-staged配置和 "prepare": "husky install"
lint-staged下是通过eslint来校验的,需要先配置eslint,参考上面eslint配置
跟目录下新增.commitlintrc.cjs
// https://github.com/conventional-changelog/commitlint/#what-is-commitlint
module.exports = {
extends: ['@commitlint/config-conventional']
}
运行 pnpm install 通过配置的 脚本 "prepare": "husky install"
会自动在跟目录下新增.husky文件夹
生成好后在.husky文件夹下面新增commit-msg 和 pre-commit 分别如下:
commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm lint
pre-commit下我是直接运行 pnpm lint 命令来在提交时做校验
好了,现在可以按照commitlint规则来提交代码了