前言:一切都始于一个简单的需求
时间回到几个月前,某个阳光明媚的下午,我正在开发一个Vue项目。项目里有很多图片和视频资源,每次构建后都要手动上传到阿里云OSS,然后替换HTML里的路径...
"卧槽,这也太麻烦了!"我看着一堆需要手动处理的静态资源,内心是崩溃的。😩
作为一个懒惰的程序员(这是褒义词),我的第一反应是:网上肯定有现成的解决方案!
结果搜了一圈,要么是webpack的插件不支持Vite,要么就是功能太简陋。最要命的是,大部分插件都只支持单一的云存储服务商。
"算了,自己写一个吧!就一个简单的OSS上传插件,能有多难?"
哈哈哈,现在回想起来,当时的我真是太天真了... 😅
第一阶段:初生牛犊不怕虎(v1.0.0诞生记)
第一个版本:简单粗暴
我的想法很简单:
- 在Vite构建过程中拦截静态资源
- 上传到阿里云OSS
- 替换引用路径为CDN地址
javascript
// 最初的代码,现在看起来好幼稚
function uploadToOSS(file) {
const client = new OSS({ /* 配置 */ })
client.put(fileName, fileContent)
return `https://cdn.example.com/${fileName}`
}
用了两天时间,写出了一个基础版本。测试了一下,能用!心情大好!
第一次发布的激动
bash
npm init
npm publish
看到控制台显示 + vite-upload-assets-oss@1.0.0
,那种成就感简直了!我竟然发布了自己的第一个npm包!🎉
虽然功能很简陋,但至少能解决我自己的问题。
继续优化:发现缓存的必要性
插件发布后,我自己用着用着,发现了一个问题:每次构建都要重新上传所有文件,太慢了!
"这也太浪费时间了,加个缓存吧!"
于是我加了一个简单的缓存机制,发布了v1.0.1:
javascript
// v1.0.1 加了简单缓存
const cache = new Map()
if (cache.has(filePath)) {
return cache.get(filePath) // 直接返回之前的URL
}
新的想法:为什么不支持多云存储?
v1.0.1发布后,我继续在其他项目中使用这个插件。用着用着,我突然想到:
"现在只支持阿里云OSS,要是哪天我想用腾讯云COS怎么办?或者AWS S3?"
然后我就开始YY:"要不做个通用的多云存储插件?这样不管用哪家的服务都不用换插件了!"
我开始意识到,这个小项目可能要往大了做... 🤔
第二阶段:野心膨胀(多云存储的诱惑)
决定支持多云:一个"简单"的想法
既然想到了多云存储,我就开始规划:"支持多云存储应该不难吧,就是多加几个API调用而已。先加个腾讯云COS,再加个AWS S3..."
天哪,我当时怎么这么天真... 😂
第一次重构:发现问题大了
当我开始添加腾讯云COS支持时,发现了一个严重问题:
javascript
// 阿里云OSS
const result = await client.put(objectName, stream)
// 腾讯云COS
cos.putObject({
Bucket: 'bucket-name',
Region: 'region',
Key: 'object-name',
Body: buffer
}, callback)
这两个API完全不一样!如果继续用if-else,代码会变成灾难...
设计模式救命:抽象基类
经过一番思考,我决定重构整个架构,引入抽象基类:
typescript
abstract class CloudStorageProvider {
abstract initialize(): Promise<void>
abstract uploadFile(asset: AssetInfo, content: Buffer): Promise<UploadResult>
// 其他通用方法...
}
class OSSProvider extends CloudStorageProvider {
// OSS specific implementation
}
class COSProvider extends CloudStorageProvider {
// COS specific implementation
}
这次重构花了我整整一周时间!但重构完成后,添加新的云存储提供商就变得简单多了。
v1.1.0:多云存储版本诞生
经过两周的开发和测试,v1.1.0终于发布了!
bash
npm publish
看到 + vite-upload-assets-oss@1.1.0
的那一刻,我激动得差点跳起来!从单一OSS到支持4家云存储,这个跨越太大了!
功能完成的成就感
v1.1.0发布后,我看着这个支持4家云存储的插件,心里满满的成就感!
从单一的OSS支持到现在的多云架构,这个跨越真的不小。最重要的是,现在我可以随时切换云存储服务商了,不用担心被某一家绑定!🥳
第三阶段:自己给自己找活干(VSCode扩展的诞生)
一个突然冒出来的想法
就在我以为项目已经完成时,我突然想到一个问题:
"我自己用这个插件的时候,每次都要翻文档看配置参数,好麻烦啊...要是有个可视化界面就好了!"
然后我就开始YY:如果做个VSCode扩展,点点鼠标就能配置,岂不是很酷?🤔
第一次接触VSCode扩展开发
作为一个后端程序员,我对前端UI开发并不熟悉,更别说VSCode扩展了。但既然自己有需求,那就试试吧!
javascript
// 我的第一个VSCode扩展代码
function activate(context) {
console.log('Hello VSCode Extension!')
}
从Hello World开始,我开始了VSCode扩展开发的学习之路。
WebView:一个全新的世界
VSCode扩展的WebView让我眼前一亮!可以用HTML/CSS/JS来构建界面,但又运行在VSCode的环境中。
html
<!-- 我的第一个WebView界面 -->
<div>
<h1>Vite Cloud Uploader 配置</h1>
<select id="provider">
<option value="oss">阿里云 OSS</option>
<option value="cos">腾讯云 COS</option>
<option value="s3">AWS S3</option>
<option value="obs">华为云 OBS</option>
</select>
</div>
虽然简陋,但能工作!
通信机制:最大的技术挑战
VSCode扩展和WebView之间的通信,成了我遇到的最大技术挑战。
javascript
// WebView 发消息给扩展
vscode.postMessage({
command: 'testConnection',
config: configData
})
// 扩展接收消息
panel.webview.onDidReceiveMessage(message => {
if (message.command === 'testConnection') {
// 处理测试连接
}
})
为了确保消息的可靠传递,我设计了一套完整的消息管理系统,包括消息队列、超时处理、错误重试等机制。
配置同步:打通两个世界
最复杂的功能是配置同步:VSCode扩展的配置要能同步到Vite配置文件中。
typescript
// 解析 vite.config.js 中的插件配置
const configMatches = [
/createViteCloudPlugin\(\s*({[\s\S]*?})\s*\)/,
/uploadOss\(\s*({[\s\S]*?})\s*\)/
]
用正则表达式解析JavaScript代码,这个过程充满了挑战和意外!
v0.1.0:VSCode扩展首发
经过一个月的开发,VSCode扩展终于完成了!
bash
vsce package
vsce publish
看到自己的扩展出现在VSCode市场上,那种成就感无以言表!🚀
第四阶段:完整生态的形成
两个项目的完美配合
现在我有了:
- vite-upload-assets-oss@1.1.0:功能强大的Vite插件
- vscode-vite-cloud-uploader@0.1.0:直观的可视化界面
两个项目完美配合,形成了一个完整的解决方案!
完整解决方案的形成
现在我拥有了一个完整的多云存储解决方案:
- 强大的Vite插件:支持4家主流云存储,智能缓存,并发上传
- 直观的VSCode扩展:可视化配置界面,一键测试连接,配置同步
两个项目配合使用,真正实现了"点点鼠标就能搞定资源上传"的目标!
踩坑大全:那些让我崩溃的瞬间 😭
坑1:alert()被禁用
javascript
// 在VSCode WebView中不能用alert()
alert('测试成功!') // ❌ 被安全策略阻止
解决方案:自己实现DOM-based的消息提示系统
javascript
class MessageUI {
static show(message, type) {
const div = document.createElement('div')
div.className = `message-${type}`
div.textContent = message
document.body.appendChild(div)
}
}
坑2:异步处理的地狱
javascript
// 最开始的回调地狱
uploadFile(file, (err, result) => {
if (err) {
handleError(err, (err2) => {
if (err2) {
// 又套了一层...
}
})
}
})
解决方案:全面拥抱async/await
javascript
try {
const result = await uploadFile(file)
console.log('上传成功!', result)
} catch (error) {
console.error('上传失败:', error)
}
坑3:配置解析的复杂性
用户的Vite配置千奇百怪:
javascript
// 各种写法都有
createViteCloudPlugin({ provider: 'oss' })
createViteCloudPlugin(Object.assign({}, config))
const plugin = createViteCloudPlugin(dynamicConfig)
解决方案:写了十几个正则表达式,覆盖各种情况 😅
坑4:跨平台路径问题
javascript
// Windows: C:\Users\xxx\project
// Linux: /home/xxx/project
// macOS: /Users/xxx/project
解决方案:使用Node.js的path模块统一处理
项目现状
整个项目从构思到实现,完全是按照我自己的想法和需求来做的。每一个功能都是为了解决实际遇到的问题,每一次优化都是为了让自己用得更爽!
结语:感谢这段神奇的旅程
回头看这几个月的开发历程,真的是一段神奇的旅程。从一个简单的需求开始,最终发展成了一个完整的解决方案。
这个过程中:
- 😫 有过崩溃的debug时刻
- 🤔 有过迷茫的架构重构
- 😤 有过和自己需求的纠结
- 🎉 也有过功能上线的狂欢
- 🥳 更有过项目完成的激动
如果你正好需要多云存储的解决方案,欢迎试用我的项目:
- npm包 :
npm install vite-upload-assets-oss
- VSCode扩展:搜索"Vite Cloud Uploader"
- GitHub :github.com/zhangnuli/v...