vite-plugin-oss 第一次Vite插件开发历程

1,726 阅读7分钟

近期一直在对公司的项目做优化,其中一环是将项目部署方式由Nginx改为OSS部署。需要将打包好的项目文件目录上传到阿里云OSS。

项目原先是VUE2+TS开发的,打包工具用的也是webpack。将webpack打包好的文件目录上传到OSS的webpack插件社区很容易就找到了。比如webpack-aliyun-oss,这里不做赘述,需要的小伙伴自行搜索。

一、开发Vite插件的初衷

由于这项目原先是VUE2+TS+webpack开发的。现在我已经重构了一个VUE3+TS+Vite的新项目。

好家伙!!?在社区溜了一圈,发现“将项目打包好的文件目录上传到OSS”的Vite插件不超过5个?相关MD文档不完善,且只有最基本的上传更新功能,与本人项目的需要不是很符合。

一直想参与开源,或是自己写点东西发布到NPM上去,可惜没有找到合适的需求去做。

正好。VUE3、Vite的生态相对而言还是有所欠缺,蹭波热度?造个轮子试试~~

二、明确需求

  • 将Vite打包好的文件目录上传到阿里云OSS
  • 如何读取需要上传的文件目录?(glob)
  • 如何上传到阿里OSS?(ali-oss)
  • 何时上传?(打包完成,输出bundle完成后)
  • 显示上传进度,文件路径、链接等?
  • 上传之后文件目录是否需要清空等。

三、准备工作

1、注册NPM账号,绑定邮箱。

这个我之前有注册过,但是没有绑定邮箱。这给我在后面进行npm publish发布的时候埋了一个坑。一直没能顺利发布,找了好长时间的问题。。。一直给我报NPM 403错误。

各位小伙伴注册完一定要记得绑定验证邮箱!!!

2、查阅Vite插件API的相关文档

由于是第一次接触Vite插件的开发,并不了解它的相关API和生命周期钩子函数等,完全不知道从哪开始入手(emo...)。只能去Git上面翻阅人家的源码,看下入口文件如何编写,这里不做赘述,下面会有写到。 Vite插件API官方文档

四、正文

1、开发工作

新建一个文件夹,文件夹名称为你的要发布的包名。取名的时候最好是去NPM官网搜一下你要发布的包名,因为包名是唯一性的。

1.1、初始化package.json

npm init

1.2、安装相关依赖库

有幸之前学习和使用过node.js。知道一些基本常用工具库。这里简单介绍一下各个依赖的作用。

  • glob 获取目录下文件路径,返回一个路径数组。
  • colors 控制台输入文案样式库。
  • ali-oss 阿里OSS SDK。
  • vite 用于引入Vite插件API 在对node工具库的选择的时候,最初我是用globby(glob的加强版)、kolorist(与colors类似)、ora(进度条)这些库,发现与Vite并不兼容,引入打包过程中会报错,原因是:Vite只允许使用import的方式引入对象,而globby、kolorist似乎并不是ESM模块,也可能是我使用的版本不对,或是没有配置balel,欢迎各位大佬指点~~

具体配置如下:

{
  "name": "vite-plugin-oss",
  "version": "1.1.2",
  "description": "将打包好的文件目录上传到阿里云OSS",
  "author": "jae <494595074@qq.com>",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "repository": {
    "type": "git",
    "url": "https://github.com/jaelam0214/vite-plugin-oss.git"
  },
  "scripts": {
    "dev": "vite",
    "build": "node_modules/.bin/tsc --newLine lf -d"
  },
  "keywords": [
    "vite",
    "plugin",
    "oss"
  ],
  "engines": {
    "node": ">=14"
  },
  "license": "MIT",
  "devDependencies": {
    "@types/ali-oss": "^6.16.2",
    "@types/glob": "^7.2.0",
    "@types/node": "^16.11.7",
    "@typescript-eslint/eslint-plugin": "^5.4.0",
    "@typescript-eslint/parser": "^5.4.0",
    "typescript": "^4.4.4",
    "vite-plugin-inspect": "^0.3.10"
  },
  "dependencies": {
    "ali-oss": "^6.16.0",
    "colors": "^1.4.0",
    "glob": "^7.2.0",
    "vite": "^2.6.14"
  }
}

1.3、入口文件index.ts

由于排版问题,这部分代码做了删减,文末有git地址~

const assetUploaderPlugin = (options: PluginOptions): Plugin => {
  const oss = new OSS({
    region: options.region,
    accessKeyId: options.accessKeyId,
    accessKeySecret: options.accessKeySecret,
    bucket: options.bucket
  })
  
  return {
    name: 'vite-plugin-oss',
    // 在解析 Vite 配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它也很有用。
    configResolved: async (config) => {
      // 获取需要上传的文件目录路径
      outputPath = path.resolve(slash(config.build.outDir))
    },
    // 打包完成后执行上传
    closeBundle: async () => {
      // 获取需要上传的文件目录路径的所有文件的路径列表
      const files = await glob.sync(from)
      console.log(`需要更新上传的文件目录${files}`)

      if (files.length) {
        try {
          await upload(files, true, outputPath)
        } catch (err: any) {
          console.log(red(err))
        }
      } else {
        verbose && console.log(red(`no files to be uploaded`))
      }
    }
  }
}
export default assetUploaderPlugin

这里最初遇到了一个问题,最开始把 upload() 更新方法放到了 configResolved() 钩子中,发现:此时打包构建工作还未完成,获取不到指定的文件目录。查阅Rollup文档,又尝试了 buildEnd() 钩子,发现还是一样的问题。最终实验 closeBundle() 钩子可行。

2、源码打包

执行

npm run build

将src下的文件编译打包输出到dist目录。目的:使外部项目能顺利通过import引入该插件。

image.png

这里遇到一个坑,使用tsup插件进行打包输出时,.dist/index.js并没有导出assetUploaderPlugin对象,导致外部安装该插件后无法顺利使用。 最后还是选用了tsc命令进行编译。

3、NPM发布

登录NPM

npm login

输入账号,密码、邮箱后,执行

npm pubilsh

记得一定要去NPM官网看下邮箱是否验证成功。登录后,如果没绑定验证邮箱,在网站页面顶部会有黄色警告框!

五、总结

vite-plugin-oss插件的使用配置说明 git源码npm地址

vite-plugin-oss

一个可以将打包好的文件目录上传到阿里OSS的vite(version>=2.6.0)插件。

Install 安装

npm i vite-plugin-oss -D

Options 配置参数

  • region: 必传。阿里云上传区域
  • accessKeyId: 必传。阿里云的授权accessKeyId
  • accessKeySecret: 必传。阿里云的授权accessKeySecret
  • bucket: 必传。上传到哪个bucket
  • from: 必传。上传哪些文件,支持类似gulp.src的glob方法,如'./build/**', 为glob字符串。
  • dist: 上传到oss哪个目录下,默认为oss根目录。可作为路径前缀使用。
  • timeout: oss超时设置,默认为30秒(30000)
  • overwrite: 是否覆盖oss同名文件。默认true。
  • verbose: 是否显示上传日志,默认为true。
  • deletOrigin: 上传完成是否删除原文件,默认false。
  • deleteEmptyDir: 如果某个目录下的文件都上传过了,是否删除此目录。deleteOrigin为true时候生效。默认false。
  • setOssPath: 自定义每个文件上传路径。接收参数为当前文件路径。不传,或者所传函数返回false则按默认方式上传。
  • test: 测试,仅查看文件和上传路径,但是不执行上传操作。默认false。
  • quitWpOnError: 出错是否中断打包。默认false。
  • version: 版本号。默认为''。
  • setVersion: 设置线上的版本号的方法。一般为axios请求方法,需同时配置version。

注意: accessKeyId, accessKeySecret 很重要,注意保密!!!

Basic Exapmle 基本例子

// vite.config.js
import { defineConfig } from 'vite'
import VitePluginOss from 'vite-plugin-oss'

export default defineConfig({
  plugins: [
    VitePluginOss({
      from: './dist/**', // 上传那个文件或文件夹
      dist: "/test",  // 需要上传到oss上的给定文件目录
      region: 'oss-xx-xx-1',
      accessKeyId: 'xxxxxxxxxxxx',
      accessKeySecret: 'xxxxxxxxxxxx',
      bucket: 'xxxxxxxxx',
      test: true, // 测试,可以在进行测试看上传路径是否正确, 打开后只会显示上传路径并不会真正上传。默认false
      // 因为文件标识符 "\"  和 "/" 的区别 不进行 setOssPath配置,上传的文件夹就会拼到文件名上, 丢失了文件目录,所以需要对setOssPath 配置。
      setOssPath: filePath => {
        let index = filePath.lastIndexOf("dist")
        let Path = filePath.substring(index + 4, filePath.length)
        return Path.replace(/\\/g, "/")
      },
    })
  ],
});

Custom Exapmle 指定环境(模式)下使用例子

该例子为在执行 npm run build:oss 时引入插件

1.在项目根目录下增加环境配置文件 .env.oss

NODE_ENV = oss

2.package.json 增加打包命令-oss模式。

"build:oss": "vue-tsc --noEmit && vite build --mode oss"

{
  "scripts": {
    "dev": "vite",
    "build:prod": "vue-tsc --noEmit && vite build",
    "build:oss": "vue-tsc --noEmit && vite build --mode oss",
  },
}

vite.config.js 按需引入

import { defineConfig } from 'vite'
import VitePluginOss from 'vite-plugin-oss'

export default ({ mode }) => {
  const plugins = []  // 可将其他插件放入该数组
  if (mode === 'oss') { // 仅oss模式下引入
    plugins.push(VitePluginOss({
      from: './dist/**', // 上传那个文件或文件夹
      dist: "/test",  // 需要上传到oss上的给定文件目录
      region: 'oss-xx-xx-1',
      accessKeyId: 'xxxxxxxxxxxx',
      accessKeySecret: 'xxxxxxxxxxxx',
      bucket: 'xxxxxxxxx',
      test: true, // 测试,可以在进行测试看上传路径是否正确, 打开后只会显示上传路径并不会真正上传。默认false
      // 因为文件标识符 "\"  和 "/" 的区别 不进行 setOssPath配置,上传的文件夹就会拼到文件名上, 丢失了文件目录,所以需要对setOssPath 配置。
      setOssPath: filePath => {
        // some operations to filePath
        let index = filePath.lastIndexOf("dist")
        let Path = filePath.substring(index + 4, filePath.length)
        return Path.replace(/\\/g, "/")
      },
    }))
  }
  return defineConfig({
    base: mode === 'oss' ? './' : '/',
    plugins: plugins,
}

后续计划

  • 优化代码结构
  • 集成七牛云OSS等其他SDK
  • 优化控制台输出日志
  • ...