Loading...
Loading...
Compare original and translation side by side
Platform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
平台: 仅支持Web。移动端演示使用Expo搭配Metro打包工具,请查看expo-sdk技能。
pnpm add -D vitepnpm add -D vitevite.config.tspnpm add -D @vitejs/plugin-react.envpnpm vitepnpm vite buildpnpm vite previewvite.config.tspnpm add -D @vitejs/plugin-react.envpnpm vitepnpm vite buildpnpm vite previewimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
},
build: {
outDir: 'dist'
}
});import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
},
build: {
outDir: 'dist'
}
});import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@types': path.resolve(__dirname, './src/types')
}
}
});{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@types': path.resolve(__dirname, './src/types')
}
}
});{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
// Babel plugins for React (optional)
babel: {
plugins: [
// Add custom babel plugins here
]
}
})
]
});@vitejs/plugin-reactimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
// React的Babel插件(可选)
babel: {
plugins: [
// 在此添加自定义Babel插件
]
}
})
]
});@vitejs/plugin-reactimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC plugins
plugins: [
// Add SWC plugins here
]
})
]
});import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC插件
plugins: [
// 在此添加SWC插件
]
})
]
});undefinedundefined
**CRITICAL**: All env vars must start with `VITE_` to be exposed to client code.
**重要提示:** 所有环境变量必须以`VITE_`开头才能在客户端代码中访问。// ✅ Accessing env vars in code
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE; // 'development' | 'production'
// Type-safe env vars
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
readonly VITE_API_URL: string;
readonly VITE_API_VERSION: string;
readonly VITE_DEBUG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// ❌ NEVER commit secrets to .env files
// Use .env.local for API keys and credentials// ✅ 在代码中访问环境变量
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE; // 'development' | 'production'
// 类型安全的环境变量
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
readonly VITE_API_URL: string;
readonly VITE_API_VERSION: string;
readonly VITE_DEBUG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// ❌ 绝对不要将密钥提交到.env文件中
// 使用.env.local存储API密钥和凭证import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// Load env file based on mode
const env = loadEnv(mode, process.cwd(), '');
return {
define: {
// Expose non-VITE_ prefixed vars
__APP_VERSION__: JSON.stringify(env.npm_package_version)
},
server: {
port: Number(env.PORT) || 5173
}
};
});import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// 根据模式加载对应环境文件
const env = loadEnv(mode, process.cwd(), '');
return {
define: {
// 暴露非VITE_前缀的变量
__APP_VERSION__: JSON.stringify(env.npm_package_version)
},
server: {
port: Number(env.PORT) || 5173
}
};
});export default defineConfig({
server: {
port: 5173,
strictPort: true, // Exit if port is already in use
open: true, // Open browser on server start
cors: true, // Enable CORS
// Hot Module Replacement
hmr: {
overlay: true // Show error overlay
},
// File watching
watch: {
// Ignore dotfiles
ignored: ['**/.*']
}
}
});export default defineConfig({
server: {
port: 5173,
strictPort: true, // 如果端口已被占用则退出
open: true, // 服务器启动时自动打开浏览器
cors: true, // 启用CORS
// 热模块替换
hmr: {
overlay: true // 显示错误覆盖层
},
// 文件监听
watch: {
// 忽略点文件
ignored: ['**/.*']
}
}
});export default defineConfig({
server: {
proxy: {
// Proxy API requests to backend
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// WebSocket proxy
'/ws': {
target: 'ws://localhost:3000',
ws: true
},
// Multiple backends
'/v1': {
target: 'http://localhost:3001',
changeOrigin: true
},
'/v2': {
target: 'http://localhost:3002',
changeOrigin: true
}
}
}
});export default defineConfig({
server: {
proxy: {
// 将API请求代理到后端
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// WebSocket代理
'/ws': {
target: 'ws://localhost:3000',
ws: true
},
// 多后端代理
'/v1': {
target: 'http://localhost:3001',
changeOrigin: true
},
'/v2': {
target: 'http://localhost:3002',
changeOrigin: true
}
}
}
});import { defineConfig } from 'vite';
import fs from 'node:fs';
export default defineConfig({
server: {
https: {
key: fs.readFileSync('./.cert/key.pem'),
cert: fs.readFileSync('./.cert/cert.pem')
}
}
});import { defineConfig } from 'vite';
import fs from 'node:fs';
export default defineConfig({
server: {
https: {
key: fs.readFileSync('./.cert/key.pem'),
cert: fs.readFileSync('./.cert/cert.pem')
}
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
// Manual chunk splitting
manualChunks: {
// Vendor chunks
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion'],
// Feature-based chunks
'dashboard': ['./src/components/views/DashboardView.tsx'],
'reports': ['./src/components/views/ReportsView.tsx']
},
// Asset file naming
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
// Chunk size warnings
chunkSizeWarningLimit: 500, // KB
// Minification
minify: 'esbuild', // 'terser' | 'esbuild'
// Source maps
sourcemap: true, // or 'inline' | 'hidden'
// Target browsers
target: 'esnext', // or 'es2015', 'es2020', etc.
// CSS code splitting
cssCodeSplit: true
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
// 手动分割Chunk
manualChunks: {
// 第三方依赖Chunk
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion'],
// 基于功能的Chunk
'dashboard': ['./src/components/views/DashboardView.tsx'],
'reports': ['./src/components/views/ReportsView.tsx']
},
// 资源文件命名
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
// Chunk大小警告阈值
chunkSizeWarningLimit: 500, // KB
// 代码压缩
minify: 'esbuild', // 可选值:'terser' | 'esbuild'
// 源映射
sourcemap: true, // 可选值:'inline' | 'hidden'
// 目标浏览器
target: 'esnext', // 可选值:'es2015', 'es2020'等
// CSS代码分割
cssCodeSplit: true
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// All node_modules in vendor chunk
if (id.includes('node_modules')) {
// Split large vendors
if (id.includes('framer-motion')) {
return 'vendor-animation';
}
if (id.includes('react') || id.includes('react-dom')) {
return 'vendor-react';
}
return 'vendor';
}
// Component-based splitting
if (id.includes('/components/views/')) {
const viewName = id.split('/components/views/')[1].split('.')[0];
return `view-${viewName.toLowerCase()}`;
}
}
}
}
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 所有node_modules内容放入vendor chunk
if (id.includes('node_modules')) {
// 分割大型依赖
if (id.includes('framer-motion')) {
return 'vendor-animation';
}
if (id.includes('react') || id.includes('react-dom')) {
return 'vendor-react';
}
return 'vendor';
}
// 基于组件的分割
if (id.includes('/components/views/')) {
const viewName = id.split('/components/views/')[1].split('.')[0];
return `view-${viewName.toLowerCase()}`;
}
}
}
}
}
});import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';
// Install: pnpm add -D vite-plugin-compression2
export default defineConfig({
plugins: [
// Gzip compression
compression({
algorithm: 'gzip',
include: /\.(js|css|html|svg)$/
}),
// Brotli compression
compression({
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg)$/
})
],
build: {
// esbuild is faster, terser produces smaller output
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // Remove console.log in production
drop_debugger: true
}
}
}
});import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';
// 安装:pnpm add -D vite-plugin-compression2
export default defineConfig({
plugins: [
// Gzip压缩
compression({
algorithm: 'gzip',
include: /\.(js|css|html|svg)$/
}),
// Brotli压缩
compression({
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg)$/
})
],
build: {
// esbuild速度更快,terser生成的输出体积更小
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 生产环境移除console.log
drop_debugger: true
}
}
}
});// vite.config.ts
export default defineConfig({
css: {
postcss: './postcss.config.js',
// CSS modules configuration
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local'
},
// Preprocessor options
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
});// postcss.config.js
export default {
plugins: {
'tailwindcss': {},
'autoprefixer': {}
}
};// vite.config.ts
export default defineConfig({
css: {
postcss: './postcss.config.js',
// CSS Modules配置
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local'
},
// 预处理器选项
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
});// postcss.config.js
export default {
plugins: {
'tailwindcss': {},
'autoprefixer': {}
}
};export default defineConfig({
build: {
cssCodeSplit: true, // Split CSS per chunk
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
// Organize CSS files
if (assetInfo.name?.endsWith('.css')) {
return 'css/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});export default defineConfig({
build: {
cssCodeSplit: true, // 按Chunk分割CSS
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
// 整理CSS文件
if (assetInfo.name?.endsWith('.css')) {
return 'css/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});// Importing assets (returns URL string)
import logo from './assets/logo.png';
import styles from './styles.module.css';
// Explicit URL imports
import assetUrl from './asset.png?url';
// Raw content import
import rawSvg from './icon.svg?raw';
// Worker import
import Worker from './worker?worker';
// JSON import
import data from './data.json';// 导入资源(返回URL字符串)
import logo from './assets/logo.png';
import styles from './styles.module.css';
// 显式URL导入
import assetUrl from './asset.png?url';
// 原始内容导入
import rawSvg from './icon.svg?raw';
// Worker导入
import Worker from './worker?worker';
// JSON导入
import data from './data.json';/public
/images
logo.svg
/fonts
custom-font.woff2
favicon.ico// Public assets are served at root and NOT processed
// Reference with absolute path
<img src="/images/logo.svg" alt="Logo" />
// ❌ Don't import from public
// import logo from '/public/images/logo.svg'; // Wrong!
// ✅ Import from src/assets for processing
import logo from '@/assets/logo.svg'; // Correct/public
/images
logo.svg
/fonts
custom-font.woff2
favicon.ico// 公共目录下的资源会被部署到根路径且不经过处理
// 使用绝对路径引用
<img src="/images/logo.svg" alt="Logo" />
// ❌ 不要从public目录导入
// import logo from '/public/images/logo.svg'; // 错误!
// ✅ 从src/assets导入以进行处理
import logo from '@/assets/logo.svg'; // 正确export default defineConfig({
// Public base path
base: '/', // or '/my-app/' for subdirectory hosting
publicDir: 'public', // Default
build: {
assetsDir: 'assets', // Output directory for assets
assetsInlineLimit: 4096, // Inline assets < 4kb as base64
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
// Organize by file type
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});export default defineConfig({
// 公共基础路径
base: '/', // 子目录部署时使用'/my-app/'
publicDir: 'public', // 默认值
build: {
assetsDir: 'assets', // 资源输出目录
assetsInlineLimit: 4096, // 小于4kb的资源会被内联为base64
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
// 按文件类型整理
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});export default defineConfig({
preview: {
port: 4173,
strictPort: true,
open: true,
// Proxy config (same as dev server)
proxy: {
'/api': 'http://localhost:3000'
},
// CORS
cors: true,
// Headers
headers: {
'Cache-Control': 'public, max-age=31536000'
}
}
});undefinedexport default defineConfig({
preview: {
port: 4173,
strictPort: true,
open: true,
// 代理配置(与开发服务器相同)
proxy: {
'/api': 'http://localhost:3000'
},
// CORS
cors: true,
// 请求头
headers: {
'Cache-Control': 'public, max-age=31536000'
}
}
});undefinedundefinedundefinedimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compression } from 'vite-plugin-compression2';
import path from 'node:path';
export default defineConfig(({ mode }) => {
const isDev = mode === 'development';
return {
plugins: [
react(),
// Compression for production (requires vite-plugin-compression2)
!isDev && compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
!isDev && compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ })
].filter(Boolean),
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@types': path.resolve(__dirname, './src/types')
}
},
server: {
port: 5173,
strictPort: true,
open: true,
hmr: {
overlay: true
},
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: !isDev,
minify: isDev ? false : 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion']
},
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
},
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
chunkSizeWarningLimit: 500
},
preview: {
port: 4173,
strictPort: true,
open: true
}
};
});import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compression } from 'vite-plugin-compression2';
import path from 'node:path';
export default defineConfig(({ mode }) => {
const isDev = mode === 'development';
return {
plugins: [
react(),
// 生产环境启用压缩(需要vite-plugin-compression2)
!isDev && compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
!isDev && compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ })
].filter(Boolean),
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@types': path.resolve(__dirname, './src/types')
}
},
server: {
port: 5173,
strictPort: true,
open: true,
hmr: {
overlay: true
},
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: !isDev,
minify: isDev ? false : 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion']
},
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
},
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
chunkSizeWarningLimit: 500
},
preview: {
port: 4173,
strictPort: true,
open: true
}
};
});undefinedundefined
**Build analysis:**
```bash
**构建分析:**
```bash
**Preview testing:**
```bash
**预览测试:**
```bash
**Environment validation:**
```typescript
// Add runtime checks for required env vars
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL is required');
}
**环境变量验证:**
```typescriptundefined