vite-plugin-deploy-oss 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,6 +39,9 @@ export default {
39
39
  // 默认 true:有上传失败时抛错并让构建失败
40
40
  failOnError: true,
41
41
 
42
+ // 生成并上传 OSS 汇总文件
43
+ manifest: true,
44
+
42
45
  // 修改打包后的资源路径
43
46
  configBase: `https://oss.eventnet.cn/H5/zz/test/`,
44
47
  }),
@@ -52,3 +55,20 @@ export default {
52
55
  - `open` 默认 `true`,建议通过环境变量控制开关(例如 `DEPLOY_OSS=1` 时再上传)。
53
56
  - `fancy` 默认 `true`,TTY 终端下会显示实时动效进度(速度、预计剩余、并发、当前文件)。
54
57
  - `failOnError` 默认 `true`,上传有失败会抛错,适合 CI 场景保证发布质量。
58
+ - `manifest` 默认关闭。开启后会在构建目录生成并上传 `oss-manifest.json`。
59
+ - `manifest: true` 时默认文件名为 `oss-manifest.json`,也支持 `manifest: { fileName: 'meta/oss-manifest.json' }` 自定义路径。
60
+ - `oss-manifest.json` 仅包含本次成功上传的文件,不包含汇总文件自身。
61
+ - `oss-manifest.json` 内容示例:
62
+
63
+ ```json
64
+ {
65
+ "version": 1742467200000,
66
+ "files": [
67
+ {
68
+ "file": "assets/index-abc123.js",
69
+ "key": "H5/zz/test/assets/index-abc123.js",
70
+ "url": "https://oss.eventnet.cn/H5/zz/test/assets/index-abc123.js"
71
+ }
72
+ ]
73
+ }
74
+ ```
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import oss from 'ali-oss';
2
2
  import { Plugin } from 'vite';
3
3
 
4
+ interface ManifestOption {
5
+ fileName?: string;
6
+ }
4
7
  interface vitePluginDeployOssOption extends Omit<oss.Options, 'accessKeyId' | 'accessKeySecret' | 'bucket' | 'region'> {
5
8
  configBase?: string;
6
9
  accessKeyId: string;
@@ -20,6 +23,7 @@ interface vitePluginDeployOssOption extends Omit<oss.Options, 'accessKeyId' | 'a
20
23
  concurrency?: number;
21
24
  retryTimes?: number;
22
25
  multipartThreshold?: number;
26
+ manifest?: boolean | ManifestOption;
23
27
  }
24
28
  declare function vitePluginDeployOss(option: vitePluginDeployOssOption): Plugin;
25
29
 
package/dist/index.js CHANGED
@@ -2,11 +2,12 @@
2
2
  import oss from "ali-oss";
3
3
  import chalk from "chalk";
4
4
  import { globSync } from "glob";
5
- import { readdir, rm, stat, unlink } from "fs/promises";
6
- import { resolve } from "path";
5
+ import { mkdir, readdir, rm, stat, unlink, writeFile } from "fs/promises";
6
+ import { dirname, resolve } from "path";
7
7
  import ora from "ora";
8
8
  import { normalizePath } from "vite";
9
9
  var GARBAGE_FILE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
10
+ var DEFAULT_MANIFEST_FILE_NAME = "oss-manifest.json";
10
11
  var removeEmptyDirectories = async (rootDir) => {
11
12
  const deletedDirectories = [];
12
13
  const visit = async (dirPath) => {
@@ -32,6 +33,45 @@ var removeEmptyDirectories = async (rootDir) => {
32
33
  return deletedDirectories;
33
34
  };
34
35
  var normalizeObjectKey = (targetDir, relativeFilePath) => normalizePath(`${targetDir}/${relativeFilePath}`).replace(/\/{2,}/g, "/").replace(/^\/+/, "");
36
+ var normalizeManifestFileName = (fileName) => {
37
+ const normalized = normalizePath(fileName || DEFAULT_MANIFEST_FILE_NAME).replace(/^\/+/, "").replace(/\/{2,}/g, "/");
38
+ return normalized || DEFAULT_MANIFEST_FILE_NAME;
39
+ };
40
+ var resolveManifestFileName = (manifest) => {
41
+ if (!manifest) return null;
42
+ if (manifest === true) return DEFAULT_MANIFEST_FILE_NAME;
43
+ return normalizeManifestFileName(manifest.fileName);
44
+ };
45
+ var normalizeUrlBase = (base) => {
46
+ const normalized = base.replace(/\\/g, "/");
47
+ const protocolSeparatorIndex = normalized.indexOf("://");
48
+ if (protocolSeparatorIndex >= 0) {
49
+ const pathIndex = normalized.indexOf("/", protocolSeparatorIndex + 3);
50
+ if (pathIndex < 0) return normalized;
51
+ return `${normalized.slice(0, pathIndex)}${normalized.slice(pathIndex).replace(/\/{2,}/g, "/")}`;
52
+ }
53
+ if (normalized.startsWith("//")) {
54
+ const pathIndex = normalized.indexOf("/", 2);
55
+ if (pathIndex < 0) return normalized;
56
+ return `${normalized.slice(0, pathIndex)}${normalized.slice(pathIndex).replace(/\/{2,}/g, "/")}`;
57
+ }
58
+ return normalized.replace(/\/{2,}/g, "/");
59
+ };
60
+ var encodeUrlPath = (path) => encodeURI(path.replace(/^\/+/, ""));
61
+ var joinUrlPath = (base, path) => `${normalizeUrlBase(base).replace(/\/+$/, "")}/${encodeUrlPath(path)}`;
62
+ var resolveUploadedFileUrl = (relativeFilePath, objectKey, configBase, alias) => {
63
+ if (configBase) return joinUrlPath(configBase, relativeFilePath);
64
+ if (alias) return joinUrlPath(alias, objectKey);
65
+ return objectKey;
66
+ };
67
+ var createManifestPayload = (results, configBase, alias) => ({
68
+ version: Date.now(),
69
+ files: results.filter((result) => result.success).map((result) => ({
70
+ file: result.relativeFilePath,
71
+ key: result.name,
72
+ url: resolveUploadedFileUrl(result.relativeFilePath, result.name, configBase, alias)
73
+ }))
74
+ });
35
75
  var formatBytes = (bytes) => {
36
76
  if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
37
77
  const units = ["B", "KB", "MB", "GB", "TB"];
@@ -91,6 +131,7 @@ function vitePluginDeployOss(option) {
91
131
  concurrency = 5,
92
132
  retryTimes = 3,
93
133
  multipartThreshold = 10 * 1024 * 1024,
134
+ manifest = false,
94
135
  ...props
95
136
  } = option || {};
96
137
  let buildFailed = false;
@@ -115,12 +156,13 @@ function vitePluginDeployOss(option) {
115
156
  errors.push("multipartThreshold must be > 0");
116
157
  return errors;
117
158
  };
159
+ const uploadSingleTask = async (client, task) => uploadFileWithRetry(client, task, false);
118
160
  const uploadFileWithRetry = async (client, task, silentLogs, maxRetries = retryTimes) => {
119
161
  const shouldUseMultipart = task.size >= multipartThreshold;
120
162
  const headers = {
121
163
  "x-oss-storage-class": "Standard",
122
164
  "x-oss-object-acl": "default",
123
- "Cache-Control": noCache ? "no-cache" : "public, max-age=86400, immutable",
165
+ "Cache-Control": task.cacheControl || (noCache ? "no-cache" : "public, max-age=86400, immutable"),
124
166
  "x-oss-forbid-overwrite": overwrite ? "false" : "true"
125
167
  };
126
168
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
@@ -142,7 +184,14 @@ function vitePluginDeployOss(option) {
142
184
  console.warn(`${chalk.yellow("\u26A0")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${task.filePath}`);
143
185
  }
144
186
  }
145
- return { success: true, file: task.filePath, name: task.name, size: task.size, retries: attempt - 1 };
187
+ return {
188
+ success: true,
189
+ file: task.filePath,
190
+ relativeFilePath: task.relativeFilePath,
191
+ name: task.name,
192
+ size: task.size,
193
+ retries: attempt - 1
194
+ };
146
195
  } else {
147
196
  throw new Error(`Upload failed with status: ${result.res.status}`);
148
197
  }
@@ -156,6 +205,7 @@ function vitePluginDeployOss(option) {
156
205
  return {
157
206
  success: false,
158
207
  file: task.filePath,
208
+ relativeFilePath: task.relativeFilePath,
159
209
  name: task.name,
160
210
  size: task.size,
161
211
  retries: attempt - 1,
@@ -172,6 +222,7 @@ function vitePluginDeployOss(option) {
172
222
  return {
173
223
  success: false,
174
224
  file: task.filePath,
225
+ relativeFilePath: task.relativeFilePath,
175
226
  name: task.name,
176
227
  size: task.size,
177
228
  retries: maxRetries,
@@ -192,9 +243,9 @@ function vitePluginDeployOss(option) {
192
243
  const name = normalizeObjectKey(uploadDir, relativeFilePath);
193
244
  try {
194
245
  const fileStats = await stat(filePath);
195
- return { task: { filePath, name, size: fileStats.size } };
246
+ return { task: { filePath, relativeFilePath, name, size: fileStats.size } };
196
247
  } catch (error) {
197
- return { task: null, error, filePath, name };
248
+ return { task: null, error, filePath, relativeFilePath, name };
198
249
  }
199
250
  })
200
251
  );
@@ -207,6 +258,7 @@ function vitePluginDeployOss(option) {
207
258
  results.push({
208
259
  success: false,
209
260
  file: candidate.filePath,
261
+ relativeFilePath: candidate.relativeFilePath,
210
262
  name: candidate.name,
211
263
  size: 0,
212
264
  retries: 0,
@@ -321,11 +373,12 @@ ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
321
373
  if (!open || !upload || buildFailed || !resolvedConfig) return;
322
374
  const startTime = Date.now();
323
375
  const client = new oss({ region, accessKeyId, accessKeySecret, secure, bucket, ...props });
376
+ const manifestFileName = resolveManifestFileName(manifest);
324
377
  const files = globSync("**/*", {
325
378
  cwd: outDir,
326
379
  nodir: true,
327
380
  ignore: Array.isArray(skip) ? skip : [skip]
328
- }).map((file) => normalizePath(file));
381
+ }).map((file) => normalizePath(file)).filter((file) => file !== manifestFileName);
329
382
  if (files.length === 0) {
330
383
  console.log(`${chalk.yellow("\u26A0 \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6")}`);
331
384
  return;
@@ -382,6 +435,39 @@ ${chalk.gray("\u7EDF\u8BA1:")}`);
382
435
  }
383
436
  console.log("");
384
437
  }
438
+ if (manifestFileName) {
439
+ const manifestRelativeFilePath = manifestFileName;
440
+ const manifestFilePath = normalizePath(resolve(outDir, manifestRelativeFilePath));
441
+ const manifestObjectKey = normalizeObjectKey(uploadDir, manifestRelativeFilePath);
442
+ await mkdir(dirname(manifestFilePath), { recursive: true });
443
+ await writeFile(
444
+ manifestFilePath,
445
+ JSON.stringify(createManifestPayload(results, configBase, alias), null, 2),
446
+ "utf8"
447
+ );
448
+ const manifestStats = await stat(manifestFilePath);
449
+ const manifestResult = await uploadSingleTask(client, {
450
+ filePath: manifestFilePath,
451
+ relativeFilePath: manifestRelativeFilePath,
452
+ name: manifestObjectKey,
453
+ size: manifestStats.size,
454
+ cacheControl: "no-cache"
455
+ });
456
+ if (!manifestResult.success) {
457
+ throw manifestResult.error || new Error(`Failed to upload manifest: ${manifestRelativeFilePath}`);
458
+ }
459
+ const manifestUrl = resolveUploadedFileUrl(
460
+ manifestRelativeFilePath,
461
+ manifestObjectKey,
462
+ configBase,
463
+ alias
464
+ );
465
+ console.log(chalk.cyan("Manifest:"));
466
+ console.log(` ${chalk.gray("File:")} ${chalk.yellow(manifestFilePath)}`);
467
+ console.log(` ${chalk.gray("Target:")} ${chalk.yellow(manifestObjectKey)}`);
468
+ console.log(` ${chalk.gray("URL:")} ${chalk.green(manifestUrl)}`);
469
+ console.log("");
470
+ }
385
471
  try {
386
472
  await removeEmptyDirectories(outDir);
387
473
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-deploy-oss",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",