@coocon/next-s3-cdn
v0.1.0
Published
Next.js plugin to upload static assets to S3-compatible CDN (Tencent COS, Alibaba OSS, AWS S3, MinIO, etc.)
Maintainers
Readme
next-s3-cdn
Next.js 静态资源自动上传至 S3 兼容 CDN 的插件。
支持腾讯云 COS、阿里云 OSS、AWS S3、MinIO 等所有 S3 兼容的对象存储服务。
安装
npm install next-s3-cdn快速开始
// next.config.ts
import { withS3CDN } from 'next-s3-cdn'
export default withS3CDN({
accessKeyId: process.env.CDN_ACCESS_KEY_ID!,
secretAccessKey: process.env.CDN_SECRET_ACCESS_KEY!,
bucket: 'my-bucket-1250000000',
region: 'ap-guangzhou',
endpoint: 'https://cos.ap-guangzhou.myqcloud.com',
cdnUrl: 'https://cdn.example.com',
})({
// 原有 next.config 配置
reactStrictMode: true,
})运行 next build 时,插件会自动:
- 设置
assetPrefix指向 CDN 地址 - 构建完成后上传
.next/static/和public/目录到对象存储
配置项
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| accessKeyId | string | ✅ | — | S3 Access Key ID |
| secretAccessKey | string | ✅ | — | S3 Secret Access Key |
| bucket | string | ✅ | — | 存储桶名称 |
| region | string | ✅ | — | 存储区域 |
| endpoint | string | ✅ | — | S3 兼容端点 URL |
| cdnUrl | string | ✅ | — | CDN 加速域名 |
| prefix | string | — | '' | 对象键前缀 |
| concurrency | number | — | 20 | 并发上传数 |
| cacheControl | string | — | 'public, max-age=31536000, immutable' | Cache-Control 响应头 |
| uploadStatic | boolean | — | true | 是否上传 .next/static |
| uploadPublic | boolean | — | true | 是否上传 public/ |
| exclude | RegExp[] | — | [] | 排除文件匹配规则 |
| skipUpload | boolean | — | false | 跳过上传 |
| forcePathStyle | boolean | — | false | 使用 path-style URL |
| enableLog | boolean | — | true | 打印上传日志 |
各服务商配置示例
腾讯云 COS
withS3CDN({
accessKeyId: process.env.COS_SECRET_ID!,
secretAccessKey: process.env.COS_SECRET_KEY!,
bucket: 'my-bucket-1250000000',
region: 'ap-guangzhou',
endpoint: 'https://cos.ap-guangzhou.myqcloud.com',
cdnUrl: 'https://cdn.example.com',
})阿里云 OSS
withS3CDN({
accessKeyId: process.env.OSS_ACCESS_KEY_ID!,
secretAccessKey: process.env.OSS_ACCESS_KEY_SECRET!,
bucket: 'my-bucket',
region: 'oss-cn-hangzhou',
endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
cdnUrl: 'https://cdn.example.com',
forcePathStyle: true,
})AWS S3
withS3CDN({
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
bucket: 'my-bucket',
region: 'us-east-1',
endpoint: 'https://s3.us-east-1.amazonaws.com',
cdnUrl: 'https://d111111abcdef8.cloudfront.net',
})MinIO (自建)
withS3CDN({
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
bucket: 'static-assets',
region: 'us-east-1',
endpoint: 'http://localhost:9000',
cdnUrl: 'http://localhost:9000/static-assets',
forcePathStyle: true,
})上传映射规则
| 本地路径 | S3 Key (无 prefix) | S3 Key (prefix: v1) |
|----------|--------------------|-----------------------|
| .next/static/chunks/main.js | _next/static/chunks/main.js | v1/_next/static/chunks/main.js |
| .next/static/css/app.css | _next/static/css/app.css | v1/_next/static/css/app.css |
| public/favicon.ico | favicon.ico | v1/favicon.ico |
| public/images/logo.png | images/logo.png | v1/images/logo.png |
环境变量建议
CDN_ACCESS_KEY_ID=your-access-key-id
CDN_SECRET_ACCESS_KEY=your-secret-access-key⚠️ 不要将密钥硬编码到代码中,始终通过环境变量注入。
高级用法
排除特定文件
withS3CDN({
// ...
exclude: [/\.map$/, /\.DS_Store/],
})仅上传 JS/CSS (不上传 public)
withS3CDN({
// ...
uploadPublic: false,
})编程式调用
import { scanFiles, uploadFiles } from 'next-s3-cdn'
const files = scanFiles({
distDir: '/path/to/.next',
publicDir: '/path/to/public',
prefix: '',
uploadStatic: true,
uploadPublic: true,
exclude: [],
})
const result = await uploadFiles(files, {
accessKeyId: '...',
secretAccessKey: '...',
bucket: 'my-bucket',
region: 'ap-guangzhou',
endpoint: 'https://cos.ap-guangzhou.myqcloud.com',
forcePathStyle: false,
concurrency: 20,
cacheControl: 'public, max-age=31536000, immutable',
enableLog: true,
})
console.log(`Uploaded ${result.uploaded}/${result.total} files`)工作原理
withS3CDN()包装 Next.js 配置,注入assetPrefix指向 CDN 域名- 注册 Webpack 插件,在客户端构建完成后自动触发上传
- 扫描
.next/static/和public/目录 - 通过 S3 协议并发上传文件,附带正确的 Content-Type 和 Cache-Control 头
- 上传失败不会中断构建,仅输出警告日志
兼容性
- Next.js ≥ 13.0.0
- Node.js ≥ 18.0.0
License
MIT
