uni-cdn-uploader

将 uniapp + vue3 + ts 小程序的静态资源自动上传到 CDN,并在构建时替换路径
182
Install
npm install uni-cdn-uploader
Latest Version:1.0.0
Vue:3
License:MIT
Last Updated:Sep 18, 2026
Links: npm
Maintainer: jikeszhang

uni-cdn-uploader

将 uniapp + Vue3 + TypeScript 小程序的静态资源自动上传到 CDN(支持火山引擎 TOS、七牛云 Kodo、阿里云 OSS、腾讯云 COS),并在构建时自动替换路径,大幅减小小程序包体积。

工作原理

┌─────────────┐     ┌──────────────┐     ┌───────────────┐     ┌─────────────┐
│  uni-cdn    │────▶│  上传到 CDN   │────▶│ 生成 cdn-map  │────▶│  Vite 构建  │
│  upload     │     │  (带缓存)     │     │   .json       │     │  替换路径   │
└─────────────┘     └──────────────┘     └───────────────┘     └─────────────┘
  1. 上传阶段:扫描 src/static/ 下的图片资源,上传到 CDN(火山引擎 TOS / 七牛云 Kodo / 阿里云 OSS / 腾讯云 COS),生成本地路径 → CDN URL 的映射表
  2. 构建阶段:Vite 插件在打包时自动将 .wxml / .wxss / .js 中的 /static/xxx 替换为 CDN URL
  3. 清理阶段:构建完成后自动删除产物中已上传到 CDN 的 static 文件,只保留 tabBar 图标等必要文件

安装

npm install uni-cdn-uploader --save-dev

快速开始

1. 初始化配置

npx uni-cdn init                     # 火山引擎 TOS(默认)
npx uni-cdn init --provider qiniu    # 七牛云 Kodo
npx uni-cdn init --provider aliyun   # 阿里云 OSS
npx uni-cdn init --provider tencent  # 腾讯云 COS

会在项目根目录生成 uni-cdn.config.ts(以下为 TOS 示例,七牛/阿里云/腾讯云示例见「配置项说明」):

import type { UniCdnConfig } from 'uni-cdn-uploader'

const config: UniCdnConfig = {
  provider: 'tos',
  cdn: {
    accessKeyId: process.env.VITE_TOS_ACCESS_KEY!,
    secretAccessKey: process.env.VITE_TOS_SECRET_KEY!,
    region: process.env.VITE_TOS_REGION!,
    bucket: process.env.VITE_TOS_BUCKET!,
    baseUrl: process.env.VITE_TOS_BASE_URL!,
  },
}

export default config

2. 配置环境变量

运行 npx uni-cdn init 会自动生成专门的配置文件 .env.uni-cdn(与项目的 .env.local 分离,已含每项的获取指引),你也可以手动创建。各变量的获取方式(火山引擎):

变量 获取方式
VITE_TOS_ACCESS_KEY 火山引擎控制台 →「访问控制 IAM」→「API 访问密钥」→ 新建密钥得到 AK
VITE_TOS_SECRET_KEY 与 AK 同时生成的 SK
VITE_TOS_REGION Bucket 所在地域,如 cn-beijing / cn-shanghai / cn-guangzhou
VITE_TOS_BUCKET 「对象存储 TOS」中创建的 Bucket 名称
VITE_TOS_BASE_URL 为 Bucket 绑定的 CDN 域名(如 https://cdn.example.com),也可临时用 TOS 默认域名 https://{bucket}.tos-{region}.volces.com
VITE_TOS_ACCESS_KEY=你的AccessKeyId
VITE_TOS_SECRET_KEY=你的SecretAccessKey
VITE_TOS_REGION=cn-beijing
VITE_TOS_BUCKET=你的bucket名
VITE_TOS_BASE_URL=https://cdn.example.com

七牛云用户改用以下变量(获取方式:七牛控制台 →「个人中心」→「密钥管理」):

变量 获取方式
VITE_QINIU_ACCESS_KEY 七牛「个人中心」→「密钥管理」中的 AccessKey
VITE_QINIU_SECRET_KEY 与 AK 同时生成的 SecretKey
VITE_QINIU_BUCKET 「对象存储 Kodo」中创建的空间名称
VITE_QINIU_REGION 空间创建时所在存储区域(z0 华东 / z1 华北 / z2 华南 / na0 北美 / as0 新加坡等,默认 z0)
VITE_QINIU_BASE_URL 为空间绑定的 CDN 域名(如 https://cdn.example.com)

阿里云用户改用以下变量(获取方式:阿里云控制台 →「访问控制 RAM」→ AccessKey):

变量 获取方式
VITE_ALIYUN_ACCESS_KEY_ID RAM 用户 / 主账号的 AccessKeyId
VITE_ALIYUN_ACCESS_KEY_SECRET 与 AK 同时生成的 AccessKeySecret
VITE_ALIYUN_REGION Bucket 所在地域,如 oss-cn-hangzhou / oss-cn-shanghai / oss-cn-beijing
VITE_ALIYUN_BUCKET 「对象存储 OSS」中创建的 Bucket 名称
VITE_ALIYUN_BASE_URL 为 Bucket 绑定的 CDN 域名(如 https://cdn.example.com)

腾讯云用户改用以下变量(获取方式:腾讯云控制台 →「访问管理」→「API 密钥管理」):

变量 获取方式
VITE_TENCENT_SECRET_ID 「API 密钥管理」中的 SecretId
VITE_TENCENT_SECRET_KEY 与 SecretId 同时生成的 SecretKey
VITE_TENCENT_REGION 存储桶所属地域,如 ap-guangzhou / ap-shanghai / ap-beijing
VITE_TENCENT_BUCKET 存储桶名称({名称}-{APPID} 格式,如 static-img-1250000000)
VITE_TENCENT_BASE_URL 为存储桶绑定的 CDN 域名(如 https://cdn.example.com)

⚠️ .env.uni-cdn 包含密钥,请务必加入 .gitignore。

3. 上传静态资源

npx uni-cdn upload
  • 首次上传会扫描所有匹配的图片文件
  • 再次上传会自动跳过内容未变化的文件(基于文件内容 hash 缓存,避免 CI / git checkout 后 mtime 变化导致误判)

提示:.cdn-cache.json 与 cdn-map.json 是运行时产物,建议加入项目 .gitignore。

如需清除缓存、强制全量重新上传(例如想重新推送所有资源到 CDN),运行:

npx uni-cdn clean   # 删除 .cdn-cache.json 与 cdn-map.json

清除后再次运行 npx uni-cdn upload 即可全量重传。

4. 在 vite.config.ts 中注册插件

import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { cdnReplacePlugin } from 'uni-cdn-uploader'

export default defineConfig({
  plugins: [
    uni(),
    cdnReplacePlugin({
      // 微信小程序产物目录
      outputDir: 'dist/build/mp-weixin',
      // 支付宝小程序改成:
      // outputDir: 'dist/build/mp-alipay',

      // 保留 tabBar 图标不上传、不删除
      keepDirs: ['icon/tabBar'],
    }),
  ],
})

5. 正常构建小程序

npm run build:mp-weixin

构建完成后,你会看到:

  • 所有 /static/xxx.png 已被替换为 CDN URL
  • dist/build/mp-weixin/static/ 中多余文件已自动清理

配置项说明

provider 支持 'tos'(火山引擎)、'qiniu'(七牛云)、'aliyun'(阿里云 OSS)与 'tencent'(腾讯云 COS),四者的 cdn 字段不同。

TOS(火山引擎)

cdn: {
  accessKeyId: '...',
  secretAccessKey: '...',
  region: 'cn-beijing',
  bucket: '...',
  baseUrl: 'https://cdn.example.com',
}
配置项 类型 说明
cdn.accessKeyId string TOS AccessKeyId
cdn.secretAccessKey string TOS SecretAccessKey
cdn.region string 地域,如 cn-beijing
cdn.bucket string Bucket 名称
cdn.baseUrl string CDN 访问域名

七牛云 Kodo

cdn: {
  accessKey: '...',
  secretKey: '...',
  bucket: '...',
  region: 'z0',   // 可选,默认 z0 华东
  baseUrl: 'https://cdn.example.com',
}
配置项 类型 默认值 说明
cdn.accessKey string 必填 七牛 AccessKey
cdn.secretKey string 必填 七牛 SecretKey
cdn.bucket string 必填 空间(Bucket)名称
cdn.region QiniuRegion 'z0' 存储区域,决定上传域名(见下表)
cdn.baseUrl string 必填 CDN 访问域名

七牛存储区域代号(region):

代号 区域
z0 华东-浙江(默认)
cn-east-2 华东-浙江2
z1 华北-河北
z2 华南-广东
na0 北美-洛杉矶
as0 亚太-新加坡(原东南亚)
ap-southeast-2 亚太-河内
ap-southeast-3 亚太-胡志明

阿里云 OSS

cdn: {
  accessKeyId: '...',
  accessKeySecret: '...',
  region: 'oss-cn-hangzhou',
  bucket: '...',
  baseUrl: 'https://cdn.example.com',
}
配置项 类型 说明
cdn.accessKeyId string 阿里云 AccessKeyId
cdn.accessKeySecret string 阿里云 AccessKeySecret
cdn.region string 地域(endpoint 后缀),如 oss-cn-hangzhou / oss-cn-shanghai / oss-cn-beijing
cdn.bucket string Bucket 名称
cdn.baseUrl string CDN 访问域名

腾讯云 COS

cdn: {
  secretId: '...',
  secretKey: '...',
  region: 'ap-guangzhou',
  bucket: 'static-img-1250000000',   // {名称}-{APPID} 格式
  baseUrl: 'https://cdn.example.com',
}
配置项 类型 说明
cdn.secretId string 腾讯云 SecretId
cdn.secretKey string 腾讯云 SecretKey
cdn.region string 存储桶地域,如 ap-guangzhou / ap-shanghai / ap-beijing
cdn.bucket string 存储桶名称({名称}-{APPID} 格式)
cdn.baseUrl string CDN 访问域名

通用配置

配置项 类型 默认值 说明
localDir string 'src/static' 本地静态资源目录
cdnPrefix string 'static/' CDN 上的路径前缀
excludeDirs string[] ['icon/tabBar'] 排除上传的目录
extensions string[] ['.png', '.jpg', '.jpeg', '.gif', '.webp'] 上传的文件类型
keepDirs string[] ['icon/tabBar'] 构建后保留的 static 子目录

插件选项说明

除 fileExtensions 外,mapFile / outputDir / keepDirs 未在插件选项中指定时,会自动从 uni-cdn.config.ts 中读取(优先级:插件选项 > 配置文件 > 内置默认)。推荐只在配置文件中维护一份,插件选项仅用于个别覆盖。

选项 类型 默认值 说明
mapFile string 'cdn-map.json' 映射表文件路径
outputDir string 'dist/build/mp-weixin' 构建产物目录
keepDirs string[] ['icon/tabBar'] 保留不删除的目录
fileExtensions string[] ['.wxml', '.wxss', '.js', '.xml', '.acss', '.axml'] 需要替换路径的文件类型
autoUpload boolean false 构建前自动上传静态资源(等价于先跑 uni-cdn upload),适用于 HBuilderX 发行等无法手动执行 upload 的场景
replaceInDev boolean false dev 运行模式也执行「上传 + 替换 + 清理」(默认仅发行模式生效),适用于 HBuilderX「运行到小程序模拟器」等 dev 场景

自动上传(autoUpload)与 dev 模式(replaceInDev)

默认插件只在「发行模式」(production)生效。手动跑 uni-cdn upload + 发行构建是基本用法;开启下面两个选项可实现全自动。

autoUpload:构建前自动上传

开启后,每次构建开始前会自动执行一次上传(等价于先跑 uni-cdn upload,有 hash 缓存,未变化的文件会秒过),无需再手动跑命令。命令行 npm run build:mp-weixin 与 HBuilderX「发行」都会触发:

cdnReplacePlugin({
  outputDir: 'dist/build/mp-weixin',   // 构建产物目录
  keepDirs: ['icon/tabBar'],           // 保留不上传的目录(如 tabBar 图标)
  autoUpload: true,                    // 构建前自动上传静态资源到 CDN
})
replaceInDev:打 dev 包时也上传 + 替换

默认插件只在发行模式生效,dev(运行模式)不触发——这是刻意的:开发调试时图片应走本地以便即时预览。若需要打 dev 包时也自动上传并替换,额外开启 replaceInDev: true。

命令行的 npm run dev:mp-weixin、HBuilderX 的「运行到小程序模拟器」都属于 dev 模式,开启后两者都会自动上传 + 替换。

注意:HBuilderX 项目的「运行」与「发行」产物目录不同(unpackage/dist/dev/ 与 unpackage/dist/build/),需按构建模式切换 outputDir(mode 由构建器自动传入,无需手动判断):

export default (command, mode) => {
  const isProd = mode === 'production'   // 发行=production,运行=development,自动传入
  return {
    plugins: [
      cdnReplacePlugin({
        // 运行(dev)与发行(build)的产物目录不同,按模式自动切换
        outputDir: isProd
          ? 'unpackage/dist/build/mp-weixin'   // 发行产物目录
          : 'unpackage/dist/dev/mp-weixin',    // 运行(dev)产物目录
        keepDirs: ['icon/tabBar'],             // 保留不上传的目录(如 tabBar 图标)
        autoUpload: true,                      // 构建前自动上传
        replaceInDev: true,                    // dev 运行模式也上传+替换(打 dev 包也走 CDN)
      }),
    ],
  }
}

⚠️ 开启 replaceInDev 后,dev 调试时图片将走 CDN 加载(网络图片),CDN 或网络不可用会影响本地调试。

常见问题

Q: 为什么 tabBar 图标不上传 CDN? A: 微信/支付宝小程序的 tabBar 图标要求放在本地,不支持 CDN 路径,所以默认排除。

Q: 上传后代码里的路径没被替换? A: 确保:1) 已执行 uni-cdn upload 生成了 cdn-map.json;2) 是在 production 模式下构建;3) 路径写法和映射表中的 key 一致(以 /static/ 开头)。

Q: 如何支持支付宝小程序? A: 将插件的 outputDir 改为 dist/build/mp-alipay,fileExtensions 已经默认包含 .xml 和 .acss。

Q: Windows PowerShell 提示「无法加载 npx.ps1,因为在此系统上禁止运行脚本」? A: 这是 PowerShell 默认执行策略(Restricted)拦截了 npm 的 .ps1 启动脚本,与工具本身无关。以当前用户身份执行一次即可解决:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

或者改用 cmd / Git Bash 执行命令(命令用法完全相同)。

License

MIT

Related Packages

@uni-ku/root

借助 Vite 模拟出虚拟的全局组件,解决 Uniapp 无法使用全局共享组件问题

44,742 174
@uni-ku/bundle-optimizer

uni-app 分包优化插件化实现

36,524 123
vite-plugin-cdn2

A Vite plugin that allowed you replace module with CDN

22,904 80
@uni-helper/vite-plugin-uni-components

适用于 uni-app (Vue3) 的 unplugin-vue-components,按需自动导入组件

82,851 44
@vinxi/vite-plugin-inspect

Inspect the intermediate state of Vite plugins

8,820 1,699

Version History

Version Released License
1.0.0 MIT