从零开始的开发一个vite插件:一个程序员的"意外"之旅 🚀

前言:一切都始于一个简单的需求

时间回到几个月前,某个阳光明媚的下午,我正在开发一个Vue项目。项目里有很多图片和视频资源,每次构建后都要手动上传到阿里云OSS,然后替换HTML里的路径...

"卧槽,这也太麻烦了!"我看着一堆需要手动处理的静态资源,内心是崩溃的。😩

作为一个懒惰的程序员(这是褒义词),我的第一反应是:网上肯定有现成的解决方案!

结果搜了一圈,要么是webpack的插件不支持Vite,要么就是功能太简陋。最要命的是,大部分插件都只支持单一的云存储服务商。

"算了,自己写一个吧!就一个简单的OSS上传插件,能有多难?"

哈哈哈,现在回想起来,当时的我真是太天真了... 😅

第一阶段:初生牛犊不怕虎(v1.0.0诞生记)

第一个版本:简单粗暴

我的想法很简单:

  1. 在Vite构建过程中拦截静态资源
  2. 上传到阿里云OSS
  3. 替换引用路径为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"
  • GitHubgithub.com/zhangnuli/v...
相关推荐
vivo互联网技术6 分钟前
EMNLP 2025|vivo 等提出 DiMo-GUI:模态分治+动态聚焦,GUI 智能体推理时扩展的新范式
前端·人工智能·agent
本末倒置18323 分钟前
Svelte邪修的JSDoc,到底是个啥?
前端·javascript·面试
李明卫杭州28 分钟前
CSS中的background-clip详解
前端·javascript
林太白34 分钟前
Vite+React+ts项目搭建(十分钟搭建个最新版React19项目吧)
前端·后端·react.js
Mr. Cao code35 分钟前
Nginx与Apache:Web服务器性能大比拼
运维·服务器·前端·nginx·apache
中微子1 小时前
用 ECharts + React 打造环形饼图:从 0 到 1 入门
前端
彭于晏爱编程1 小时前
密码的,YOU不能不知道的Next.jsSSR(服务端渲染)
前端·javascript·react.js
再学一点就睡1 小时前
手撕前端常用 7 种设计模式:从原理到实战,附完整代码案例
前端·设计模式
龙在天1 小时前
vue3如何封装统一的弹窗
前端
一枚前端小能手1 小时前
🚀 应用出了问题你都不知道,别着急我来帮你
前端·监控