🚀 vite-upload-assets-oss
A powerful Vite plugin that automatically uploads media assets to multiple cloud storage providers (OSS, COS, S3, OBS) and replaces references with CDN URLs. Perfect for optimizing your web applications with seamless multi-cloud asset management.
一个强大的Vite插件,自动将媒体资源上传到多个云存储提供商(阿里云OSS、腾讯云COS、AWS S3、华为云OBS)并替换代码中的引用为CDN URL,支持多种资源引入方式和多云存储架构。
✨ 特性
- 🌐 多云存储 - 支持阿里云OSS、腾讯云COS、AWS S3、华为云OBS
- 🎯 智能识别 - 自动识别各种媒体资源引入方式
- 🚀 去重上传 - 基于文件哈希的智能去重机制
- ⚡ 并发控制 - 可配置的并发上传数量,防止云服务限流
- 💾 本地缓存 - 避免重复上传相同文件,加速构建
- 🔧 开发友好 - 开发模式可跳过上传,不影响开发体验
- 📊 详细日志 - 上传进度和状态实时可视化
- 🛡️ 错误恢复 - 上传失败时自动回退到本地路径
- 🎨 路径自定义 - 灵活的云存储路径模板配置
- 🔄 向后兼容 - 完全兼容现有OSS配置,无需修改现有代码
📦 安装
npm install vite-upload-assets-oss --save-dev
或使用其他包管理器:
# yarn
yarn add -D vite-upload-assets-oss
# pnpm
pnpm add -D vite-upload-assets-oss
🌐 支持的云存储提供商
提供商 | 配置类型 | SDK依赖 | 说明 |
---|---|---|---|
阿里云OSS | OSSConfig |
ali-oss |
支持全部功能,主要维护 |
腾讯云COS | COSConfig |
cos-nodejs-sdk-v5 |
完整支持 |
AWS S3 | S3Config |
aws-sdk |
兼容S3协议的所有服务 |
华为云OBS | OBSConfig |
esdk-obs-nodejs |
完整支持 |
💡 提示: 插件会自动检测配置类型并加载相应的云存储SDK。为了减少包体积,SDK作为可选依赖安装,只需要安装您使用的云服务对应的SDK。
🚀 快速开始
0. 安装云存储SDK
根据你使用的云服务安装对应的SDK:
# 阿里云OSS
npm install ali-oss
# 腾讯云COS
npm install cos-nodejs-sdk-v5
# AWS S3
npm install aws-sdk
# 华为云OBS
npm install esdk-obs-nodejs
1. 基础配置
在 vite.config.ts
中添加插件:
import { defineConfig } from 'vite'
import { createViteCloudPlugin } from 'vite-upload-assets-oss'
export default defineConfig({
plugins: [
// 阿里云OSS配置
createViteCloudPlugin({
provider: 'oss',
oss: {
accessKeyId: 'your-access-key-id',
accessKeySecret: 'your-access-key-secret',
bucket: 'your-bucket-name',
region: 'oss-cn-hangzhou'
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'mp4', 'webm'],
publicPath: 'https://your-cdn-domain.com/',
dev: false
})
// 或者使用腾讯云COS
createViteCloudPlugin({
provider: 'cos',
cos: {
secretId: 'your-secret-id',
secretKey: 'your-secret-key',
bucket: 'your-bucket-name',
region: 'ap-beijing'
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg'],
publicPath: 'https://your-cos-domain.com/'
})
// 或者使用AWS S3
createViteCloudPlugin({
provider: 's3',
s3: {
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
bucket: 'your-bucket-name',
region: 'us-west-2'
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg'],
publicPath: 'https://your-s3-domain.com/'
})
// 或者使用华为云OBS
createViteCloudPlugin({
provider: 'obs',
obs: {
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
bucket: 'your-bucket-name',
endpoint: 'obs.cn-north-4.myhuaweicloud.com'
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg'],
publicPath: 'https://your-obs-domain.com/'
})
]
})
💡 向后兼容: 你仍然可以使用
createViteOSSPlugin
函数名,它是createViteCloudPlugin
的别名。
2. 环境变量配置(推荐)
创建 .env
文件:
VITE_OSS_ACCESS_KEY_ID=your-access-key-id
VITE_OSS_ACCESS_KEY_SECRET=your-access-key-secret
VITE_OSS_BUCKET=your-bucket-name
VITE_OSS_REGION=oss-cn-hangzhou
VITE_CDN_URL=https://your-cdn-domain.com/
更新配置:
export default defineConfig({
plugins: [
createViteOSSPlugin({
oss: {
accessKeyId: process.env.VITE_OSS_ACCESS_KEY_ID!,
accessKeySecret: process.env.VITE_OSS_ACCESS_KEY_SECRET!,
bucket: process.env.VITE_OSS_BUCKET!,
region: process.env.VITE_OSS_REGION!
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'mp4', 'webm'],
publicPath: process.env.VITE_CDN_URL!,
dev: false
})
]
})
🎪 支持的资源引入方式
插件支持以下四种主要的资源引入方式:
1. ES模块直接导入
import logoUrl from './assets/logo.png'
import bannerImage from '../images/banner.jpg'
// 构建后自动变为:
// logoUrl = 'https://cdn.example.com/assets/abc123ef.png'
// bannerImage = 'https://cdn.example.com/assets/def456gh.jpg'
2. 动态URL构造
// 静态路径
const imageUrl = new URL('./assets/image.png', import.meta.url).href
// 动态路径
function getImageUrl(name) {
return new URL(`./assets/${name}.jpg`, import.meta.url).href
}
3. CSS中的url()引用
.hero {
background-image: url('./assets/hero-bg.jpg');
}
.icon::before {
content: url('../images/icon.svg');
}
4. 模板中的资源引用
<template>
<div>
<img :src="logoUrl" alt="Logo" />
<video :src="videoUrl" controls></video>
<audio :src="audioUrl" controls></audio>
</div>
</template>
⚙️ 配置选项
多云存储完整配置示例
阿里云OSS配置
createViteCloudPlugin({
provider: 'oss',
oss: {
accessKeyId: 'your-access-key-id',
accessKeySecret: 'your-access-key-secret',
bucket: 'your-bucket-name',
region: 'oss-cn-hangzhou',
endpoint: 'oss-cn-hangzhou.aliyuncs.com', // 可选
secure: true, // 可选,默认true
timeout: 60000 // 可选,超时时间
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'mp4', 'webm'],
publicPath: 'https://your-cdn-domain.com/',
prefix: 'assets/[hash:8].[ext]',
maxConcurrency: 3,
cache: true,
cacheFile: '.oss-cache.json',
verbose: true
})
腾讯云COS配置
createViteCloudPlugin({
provider: 'cos',
cos: {
secretId: 'your-secret-id',
secretKey: 'your-secret-key',
bucket: 'your-bucket-name',
region: 'ap-beijing',
protocol: 'https', // 可选,默认https
domain: 'your-custom-domain.com', // 可选,自定义域名
timeout: 60000 // 可选
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'],
publicPath: 'https://your-cos-domain.com/',
prefix: 'assets/[hash:8].[ext]',
maxConcurrency: 3,
cache: true,
cacheFile: '.cos-cache.json',
verbose: true
})
AWS S3配置
createViteCloudPlugin({
provider: 's3',
s3: {
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
bucket: 'your-bucket-name',
region: 'us-west-2',
endpoint: 'https://s3.amazonaws.com', // 可选,自定义endpoint
s3ForcePathStyle: false, // 可选,路径风格
signatureVersion: 'v4', // 可选,签名版本
timeout: 60000 // 可选
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'],
publicPath: 'https://your-s3-domain.com/',
prefix: 'assets/[hash:8].[ext]',
maxConcurrency: 3,
cache: true,
cacheFile: '.s3-cache.json',
verbose: true
})
华为云OBS配置
createViteCloudPlugin({
provider: 'obs',
obs: {
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
bucket: 'your-bucket-name',
endpoint: 'obs.cn-north-4.myhuaweicloud.com',
signature: 'v4', // 可选,签名版本
timeout: 60000 // 可选
},
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'],
publicPath: 'https://your-obs-domain.com/',
prefix: 'assets/[hash:8].[ext]',
maxConcurrency: 3,
cache: true,
cacheFile: '.obs-cache.json',
verbose: true
})
配置项详细说明
通用配置选项
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
provider |
'oss' | 'cos' | 's3' | 'obs' |
- | 云存储提供商类型,必需 |
include |
string[] |
- | 需要上传的文件扩展名列表,必需 |
exclude |
string[] |
[] |
排除上传的文件扩展名列表 |
publicPath |
string |
- | CDN访问域名,必需 |
prefix |
string |
'assets/[hash:8].[ext]' |
云存储文件路径模板 |
minSize |
number |
0 |
最小上传文件大小(字节) |
maxConcurrency |
number |
3 |
最大并发上传数 |
dev |
boolean |
false |
开发模式是否跳过上传 |
verbose |
boolean |
false |
是否显示详细日志 |
cache |
boolean |
true |
是否启用本地缓存 |
cacheFile |
string |
'.[provider]-cache.json' |
缓存文件路径 |
云存储特定配置
阿里云OSS配置 (OSSConfig
)
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
accessKeyId |
string |
- | AccessKey ID,必需 |
accessKeySecret |
string |
- | AccessKey Secret,必需 |
bucket |
string |
- | 存储桶名称,必需 |
region |
string |
- | 地域,必需 |
endpoint |
string |
可选 | 自定义endpoint |
secure |
boolean |
true |
是否使用HTTPS |
timeout |
number |
60000 |
超时时间(毫秒) |
腾讯云COS配置 (COSConfig
)
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
secretId |
string |
- | Secret ID,必需 |
secretKey |
string |
- | Secret Key,必需 |
bucket |
string |
- | 存储桶名称,必需 |
region |
string |
- | 地域,必需 |
protocol |
'http' | 'https' |
'https' |
协议类型 |
domain |
string |
可选 | 自定义域名 |
timeout |
number |
60000 |
超时时间(毫秒) |
AWS S3配置 (S3Config
)
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
accessKeyId |
string |
- | Access Key ID,必需 |
secretAccessKey |
string |
- | Secret Access Key,必需 |
bucket |
string |
- | 存储桶名称,必需 |
region |
string |
- | 地域,必需 |
endpoint |
string |
可选 | 自定义endpoint |
s3ForcePathStyle |
boolean |
false |
强制路径风格 |
signatureVersion |
string |
'v4' |
签名版本 |
timeout |
number |
60000 |
超时时间(毫秒) |
华为云OBS配置 (OBSConfig
)
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
accessKeyId |
string |
- | Access Key ID,必需 |
secretAccessKey |
string |
- | Secret Access Key,必需 |
bucket |
string |
- | 存储桶名称,必需 |
endpoint |
string |
- | OBS服务endpoint,必需 |
signature |
string |
'v4' |
签名版本 |
timeout |
number |
60000 |
超时时间(毫秒) |
📋 使用流程
开发阶段
- 配置插件 - 在
vite.config.ts
中添加插件配置 - 正常开发 - 使用相对路径引入资源,插件在开发模式下不会上传
- 本地预览 - 资源通过本地路径访问,确保开发体验
构建阶段
- 资源扫描 - 插件扫描代码中所有媒体资源引用
- 智能去重 - 基于文件哈希计算,相同内容的文件只上传一次
- 并发上传 - 按配置的并发数同时上传到OSS
- 引用替换 - 将代码中的本地路径替换为CDN URL
- 生成构建 - 输出优化后的生产版本
构建命令
# 开发模式(不上传OSS)
npm run dev
# 生产构建(自动上传OSS)
npm run build
# 预览构建结果
npm run preview
📊 构建日志示例
启用 verbose: true
后的构建输出:
阿里云OSS:
$ npm run build
✓ Connected to OSS bucket: my-bucket
📦 Starting upload 8 assets to OSS
✓ Uploaded logo.png 12.3 KB
✓ Cached banner.jpg 45.7 KB
✓ Uploaded video.mp4 2.1 MB
📊 OSS Upload Summary:
Total: 8 files (3.2 MB)
Uploaded: 3 files
Cached: 2 files
Failed: 0 files
腾讯云COS:
$ npm run build
✓ Connected to COS bucket: my-bucket
📦 Starting upload 8 assets to COS
✓ Uploaded logo.png 12.3 KB
✓ Cached banner.jpg 45.7 KB
✓ Uploaded video.mp4 2.1 MB
📊 COS Upload Summary:
Total: 8 files (3.2 MB)
Uploaded: 3 files
Cached: 2 files
Failed: 0 files
AWS S3:
$ npm run build
✓ Connected to S3 bucket: my-bucket
📦 Starting upload 8 assets to S3
✓ Uploaded logo.png 12.3 KB
✓ Cached banner.jpg 45.7 KB
✓ Uploaded video.mp4 2.1 MB
📊 S3 Upload Summary:
Total: 8 files (3.2 MB)
Uploaded: 3 files
Cached: 2 files
Failed: 0 files
🔧 高级用法
自定义路径模板
createViteOSSPlugin({
// 按日期组织文件
prefix: 'assets/[YYYY]/[MM]/[hash:8].[ext]',
// 按文件类型分类
prefix: '[type]/[hash:8].[ext]', // images/abc123ef.png, videos/def456gh.mp4
// 保留原始文件名
prefix: 'static/[name]-[hash:8].[ext]'
})
条件性配置
import { defineConfig } from 'vite'
export default defineConfig(({ command, mode }) => {
const isProduction = command === 'build'
return {
plugins: [
...(isProduction ? [
createViteCloudPlugin({
// 只在生产构建时启用
provider: 'oss',
oss: { /* config */ },
include: ['png', 'jpg'],
publicPath: 'https://cdn.example.com/'
})
] : [])
]
}
})
多环境配置
// 不同环境使用不同云存储配置
const getCloudConfig = () => {
if (process.env.NODE_ENV === 'production') {
return {
provider: 'oss' as const,
oss: {
accessKeyId: process.env.PROD_OSS_ACCESS_KEY_ID!,
accessKeySecret: process.env.PROD_OSS_ACCESS_KEY_SECRET!,
bucket: 'prod-bucket',
region: 'oss-cn-hangzhou'
},
publicPath: 'https://cdn.example.com/'
}
} else if (process.env.NODE_ENV === 'staging') {
return {
provider: 'cos' as const,
cos: {
secretId: process.env.STAGING_COS_SECRET_ID!,
secretKey: process.env.STAGING_COS_SECRET_KEY!,
bucket: 'staging-bucket',
region: 'ap-beijing'
},
publicPath: 'https://staging-cdn.example.com/'
}
}
return null
}
const cloudConfig = getCloudConfig()
if (cloudConfig) {
plugins.push(createViteCloudPlugin(cloudConfig))
}
云服务商切换
// 根据环境变量动态选择云存储提供商
const provider = process.env.VITE_CLOUD_PROVIDER as 'oss' | 'cos' | 's3' | 'obs'
const cloudConfigs = {
oss: {
provider: 'oss' as const,
oss: {
accessKeyId: process.env.VITE_OSS_ACCESS_KEY_ID!,
accessKeySecret: process.env.VITE_OSS_ACCESS_KEY_SECRET!,
bucket: process.env.VITE_OSS_BUCKET!,
region: process.env.VITE_OSS_REGION!
},
publicPath: process.env.VITE_OSS_PUBLIC_PATH!
},
cos: {
provider: 'cos' as const,
cos: {
secretId: process.env.VITE_COS_SECRET_ID!,
secretKey: process.env.VITE_COS_SECRET_KEY!,
bucket: process.env.VITE_COS_BUCKET!,
region: process.env.VITE_COS_REGION!
},
publicPath: process.env.VITE_COS_PUBLIC_PATH!
}
// ... 其他配置
}
const config = cloudConfigs[provider]
if (config) {
plugins.push(createViteCloudPlugin({
...config,
include: ['png', 'jpg', 'jpeg', 'gif', 'svg']
}))
}
🐛 故障排除
常见问题
1. 云存储认证失败
Error: Upload failed: Forbidden / AccessDenied
解决方案:
- 阿里云OSS: 检查AccessKey ID和Secret是否正确,确认存储桶权限
- 腾讯云COS: 验证Secret ID和Key,检查存储桶和地域配置
- AWS S3: 确认Access Key和Secret Key,检查IAM权限设置
- 华为云OBS: 验证Access Key和Secret,确认endpoint配置正确
2. 找不到存储桶
Error: No such bucket / BucketNotFound
解决方案:
- 确认存储桶名称拼写正确
- 检查存储桶是否在指定的地域中
- 验证存储桶是否已创建且可访问
3. SDK未安装
Error: Failed to initialize [Provider] SDK. Please install: npm install [sdk-name]
解决方案:
- 根据错误提示安装对应的SDK
- 确认SDK版本与插件兼容性
4. 资源未上传
Warning: Asset not processed
解决方案:
- 确认文件扩展名在
include
列表中 - 检查文件大小是否超过
minSize
限制 - 查看是否被
exclude
规则排除 - 验证
provider
配置是否正确
5. 路径解析错误
Error: Cannot resolve asset path
解决方案:
- 检查相对路径是否正确
- 确认文件确实存在
- 验证Vite alias配置
6. 开发模式资源404
解决方案:
- 确保
dev: false
配置正确 - 检查public目录设置
- 验证开发服务器静态资源配置
调试技巧
启用详细日志:
createViteCloudPlugin({ verbose: true, // ... 其他配置 })
检查缓存文件:
`
bash查看缓存内容 (根据provider不同)
cat .oss-cache.json # OSS cat .cos-cache.json # COS cat .s3-cache.json # S3 cat .obs-cache.json # OBS
清除缓存重新上传
rm .*-cache.json
3. **构建分析**:
```bash
# 分析构建输出
npm run build -- --debug
# 检查生成文件
ls -la dist/
🤝 贡献指南
欢迎贡献代码!请遵循以下步骤:
- Fork 项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature
) - 提交更改 (
git commit -m 'Add some AmazingFeature'
) - 推送到分支 (
git push origin feature/AmazingFeature
) - 开启 Pull Request
开发环境设置
# 克隆项目
git clone https://github.com/zhangnuli/vite-upload-assets-oss.git
cd vite-upload-assets-oss
# 安装依赖
npm install
# 构建插件
npm run build
# 运行示例项目
cd example
npm install
npm run dev
📄 许可证
本项目采用 MIT 许可证。
🙏 致谢
English
✨ Features
- 🎯 Auto Detection: Automatically identifies various media asset import methods
- 🚀 Smart Upload: Hash-based deduplication upload mechanism
- ⚡ Concurrent Control: Configurable concurrent upload limits
- 💾 Local Caching: Avoids re-uploading identical files
- 🔧 Dev Friendly: Skip uploads in development mode
- 📊 Detailed Logging: Visual upload progress and status reporting
- 🛡️ Error Recovery: Automatic fallback to local paths on upload failure
- 🎨 Path Customization: Flexible OSS path template configuration
📦 Installation
npm install vite-upload-assets-oss --save-dev
# or
yarn add vite-upload-assets-oss -D
# or
pnpm add vite-upload-assets-oss -D
🚀 Quick Start
Basic Usage
// vite.config.ts
import { defineConfig } from 'vite'
import { createViteOSSPlugin } from 'vite-upload-assets-oss'
export default defineConfig({
plugins: [
createViteOSSPlugin({
oss: {
accessKeyId: 'your-access-key-id',
accessKeySecret: 'your-access-key-secret',
bucket: 'your-bucket-name',
region: 'oss-cn-hangzhou'
},
publicPath: 'https://your-cdn-domain.com/',
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'mp4', 'mp3'],
prefix: 'assets/[hash:8].[ext]'
})
]
})
Environment Variables (Recommended)
# .env.local
VITE_OSS_ACCESS_KEY_ID=your_access_key_id
VITE_OSS_ACCESS_KEY_SECRET=your_access_key_secret
VITE_OSS_BUCKET=your_bucket_name
VITE_OSS_REGION=oss-cn-hangzhou
VITE_CDN_URL=https://your-cdn-domain.com/
export default defineConfig({
plugins: [
createViteOSSPlugin({
oss: {
accessKeyId: process.env.VITE_OSS_ACCESS_KEY_ID!,
accessKeySecret: process.env.VITE_OSS_ACCESS_KEY_SECRET!,
bucket: process.env.VITE_OSS_BUCKET!,
region: process.env.VITE_OSS_REGION!
},
publicPath: process.env.VITE_CDN_URL!,
include: ['png', 'jpg', 'jpeg', 'gif', 'svg', 'mp4', 'webm', 'wav', 'mp3'],
exclude: ['ico'], // Exclude favicon
prefix: 'assets/[hash:8].[ext]',
minSize: 1024, // Only upload files larger than 1KB
maxConcurrency: 3,
dev: false, // Skip upload in development mode
verbose: true, // Show detailed logs
cache: true,
cacheFile: '.oss-cache.json'
})
]
})
🎪 Supported Import Methods
The plugin automatically detects and processes these import patterns:
1. ES Module Import
import logo from './assets/logo.png'
import banner from '../images/banner.jpg'
2. Dynamic URL Construction
const imageUrl = new URL('./assets/image.png', import.meta.url).href
function getDynamicImage(name) {
return new URL(`./assets/${name}.jpg`, import.meta.url).href
}
3. CSS url() References
.hero {
background: url('./assets/hero-bg.jpg');
}
4. Template Asset References
<template>
<img :src="logoUrl" alt="Logo" />
<video :src="videoUrl" controls></video>
</template>
⚙️ Configuration Options
Option | Type | Default | Description |
---|---|---|---|
oss |
OSSConfig |
Required | Alibaba Cloud OSS configuration |
publicPath |
string |
Required | CDN domain URL |
include |
string[] |
Required | File extensions to process |
exclude |
string[] |
[] |
File extensions to exclude |
prefix |
string |
'assets/[hash:8].[ext]' |
Upload path template |
minSize |
number |
0 |
Minimum file size in bytes |
maxConcurrency |
number |
3 |
Maximum concurrent uploads |
dev |
boolean |
false |
Enable upload in development mode |
verbose |
boolean |
false |
Show detailed logs |
cache |
boolean |
true |
Enable local caching |
cacheFile |
string |
'.oss-cache.json' |
Cache file path |
Path Template Variables
[name]
- Original filename without extension[ext]
- File extension[hash]
- File content hash (MD5)[hash:8]
- First 8 characters of hash
Example: 'assets/[hash:8].[ext]'
→ 'assets/a1b2c3d4.jpg'
📊 Build Process
When you run npm run build
, the plugin will:
- Scan all media asset references in your code
- Calculate MD5 hashes for deduplication
- Upload assets concurrently to OSS
- Replace all references with CDN URLs
- Generate optimized production build
🔧 Troubleshooting
Common Issues
1. "AccessDenied" Error
- Check your AccessKey ID and Secret
- Verify bucket permissions
- Ensure the RAM user has OSS write permissions
2. "No such bucket" Error
- Verify bucket name is correct
- Check if bucket exists in the specified region
3. Assets not uploading
- Check file extensions are in
include
list - Verify files meet
minSize
requirement - Enable
verbose
logging for detailed information
🤝 Contributing
Contributions are welcome! Please read our Contributing Guide for details.
📄 License
MIT License - see the LICENSE file for details.
Star ⭐ this repo if it helped you!
如果这个插件对您有帮助,请给项目一个⭐!