編輯 vite.config.ts
文件:
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { resolve } from 'path';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
base: env.VITE_BASE_URL || '/',
// 路徑別名
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@pages': resolve(__dirname, 'src/pages'),
'@utils': resolve(__dirname, 'src/utils'),
'@api': resolve(__dirname, 'src/api'),
'@store': resolve(__dirname, 'src/store'),
},
},
// 插件配置
plugins: [
vue(),
vueJsx(),
],
// 開(kāi)發(fā)服務(wù)器配置
server: {
port: 3002,
host: '0.0.0.0',
open: true,
cors: true,
// 代理配置
proxy: {
'/api': {
target: env.VITE_API_BASE_URL || 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
// 依賴(lài)優(yōu)化
optimizeDeps: {
include: [
'vue',
'vue-router',
'pinia',
'tdesign-vue-next',
'echarts',
'lodash',
'dayjs',
'axios',
],
},
};
});
export default defineConfig({
// ... 其他配置
build: {
// 輸出目錄
outDir: 'dist',
// 靜態(tài)資源目錄
assetsDir: 'assets',
// 資源內聯(lián)閾值
assetsInlineLimit: 4096,
// 啟用CSS代碼分割
cssCodeSplit: true,
// 生產(chǎn)環(huán)境移除console和debugger
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
// 代碼分割配置
rollupOptions: {
output: {
// 手動(dòng)分包
manualChunks: {
// Vue相關(guān)
vue: ['vue', 'vue-router', 'pinia'],
// UI組件庫
tdesign: ['tdesign-vue-next', 'tdesign-icons-vue-next'],
// 圖表庫
charts: ['echarts'],
// 工具庫
utils: ['lodash', 'dayjs', 'axios'],
// 國際化
i18n: ['vue-i18n'],
},
// 資源文件命名
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(assetInfo.name)) {
return `media/[name]-[hash].${ext}`;
}
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/i.test(assetInfo.name)) {
return `images/[name]-[hash].${ext}`;
}
if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(assetInfo.name)) {
return `fonts/[name]-[hash].${ext}`;
}
return `assets/[name]-[hash].${ext}`;
},
},
},
// 生產(chǎn)環(huán)境不生成source map
sourcemap: false,
// 構建目標
target: 'es2015',
// 警告閾值
chunkSizeWarningLimit: 1000,
},
});
編輯 tsconfig.json
文件:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"useDefineForClassFields": true,
// 路徑映射
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@pages/*": ["src/pages/*"],
"@utils/*": ["src/utils/*"],
"@api/*": ["src/api/*"],
"@store/*": ["src/store/*"]
},
// 類(lèi)型檢查選項
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules",
"dist"
]
}
創(chuàng )建不同環(huán)境的配置文件:
# .env.development
NODE_ENV = development
VITE_APP_TITLE = 開(kāi)發(fā)環(huán)境
VITE_BASE_URL = /
VITE_API_BASE_URL = http://localhost:3000
VITE_API_URL_PREFIX = /api
VITE_USE_MOCK = true
VITE_ENABLE_ANALYZE = false
# .env.test
NODE_ENV = test
VITE_APP_TITLE = 測試環(huán)境
VITE_BASE_URL = /
VITE_API_BASE_URL = https://test-api.example.com
VITE_API_URL_PREFIX = /api
VITE_USE_MOCK = false
VITE_ENABLE_ANALYZE = false
# .env.production
NODE_ENV = production
VITE_APP_TITLE = 生產(chǎn)環(huán)境
VITE_BASE_URL = /
VITE_API_BASE_URL = https://api.example.com
VITE_API_URL_PREFIX = /api
VITE_USE_MOCK = false
VITE_ENABLE_ANALYZE = false
在 package.json
中添加構建腳本:
{
"scripts": {
"dev": "vite --mode development",
"build": "vue-tsc --noEmit && vite build --mode production",
"build:test": "vue-tsc --noEmit && vite build --mode test",
"build:analyze": "VITE_ENABLE_ANALYZE=true vite build --mode production",
"preview": "vite preview",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.ts,.tsx --max-warnings 0",
"lint:fix": "eslint . --ext .vue,.js,.jsx,.ts,.tsx --max-warnings 0 --fix"
}
}
安裝和配置性能優(yōu)化插件:
npm install --save-dev vite-plugin-compression rollup-plugin-visualizer
// vite.config.ts
import { defineConfig } from 'vite';
import compression from 'vite-plugin-compression';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
// ... 其他插件
// Gzip壓縮
compression({
algorithm: 'gzip',
ext: '.gz',
}),
// Brotli壓縮
compression({
algorithm: 'brotliCompress',
ext: '.br',
}),
// 打包分析
process.env.VITE_ENABLE_ANALYZE && visualizer({
filename: 'dist/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}),
].filter(Boolean),
});
export default defineConfig({
css: {
// CSS預處理器配置
preprocessorOptions: {
less: {
modifyVars: {
hack: `true; @import (reference) "${resolve('src/style/variables.less')}";`,
},
math: 'strict',
javascriptEnabled: true,
},
},
// PostCSS配置
postcss: {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
},
},
});
export default defineConfig({
build: {
// 啟用構建緩存
rollupOptions: {
cache: true,
},
},
// 依賴(lài)預構建緩存
optimizeDeps: {
force: false, // 強制重新預構建
},
});
如果是多頁(yè)面應用:
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
admin: resolve(__dirname, 'admin.html'),
},
},
},
});
添加構建時(shí)間監控:
// vite.config.ts
export default defineConfig({
plugins: [
{
name: 'build-time',
buildStart() {
this.buildStartTime = Date.now();
},
buildEnd() {
const buildTime = Date.now() - this.buildStartTime;
console.log(`構建耗時(shí): ${buildTime}ms`);
},
},
],
});