vite-plugin-deploy-oss 2.0.0 → 3.0.1

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
@@ -48,6 +48,7 @@ export default {
48
48
 
49
49
  ## 说明
50
50
 
51
+ - 当前版本仅支持 ESM(`import`),不再提供 CommonJS(`require`)入口。
51
52
  - `open` 默认 `true`,建议通过环境变量控制开关(例如 `DEPLOY_OSS=1` 时再上传)。
52
53
  - `fancy` 默认 `true`,TTY 终端下会显示实时动效进度(速度、预计剩余、并发、当前文件)。
53
54
  - `failOnError` 默认 `true`,上传有失败会抛错,适合 CI 场景保证发布质量。
package/dist/index.js CHANGED
@@ -1,47 +1,37 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
1
  // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- default: () => vitePluginDeployOss
34
- });
35
- module.exports = __toCommonJS(index_exports);
36
- var import_ali_oss = __toESM(require("ali-oss"));
37
- var import_chalk = __toESM(require("chalk"));
38
- var import_delete_empty = __toESM(require("delete-empty"));
39
- var import_glob = require("glob");
40
- var import_promises = require("fs/promises");
41
- var import_node_path = require("path");
42
- var import_ora = __toESM(require("ora"));
43
- var import_vite = require("vite");
44
- var normalizeObjectKey = (targetDir, relativeFilePath) => (0, import_vite.normalizePath)(`${targetDir}/${relativeFilePath}`).replace(/\/{2,}/g, "/").replace(/^\/+/, "");
2
+ import oss from "ali-oss";
3
+ import chalk from "chalk";
4
+ import { globSync } from "glob";
5
+ import { readdir, rm, stat, unlink } from "fs/promises";
6
+ import { resolve } from "path";
7
+ import ora from "ora";
8
+ import { normalizePath } from "vite";
9
+ var GARBAGE_FILE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
10
+ var removeEmptyDirectories = async (rootDir) => {
11
+ const deletedDirectories = [];
12
+ const visit = async (dirPath) => {
13
+ const entries = await readdir(dirPath, { withFileTypes: true });
14
+ let hasNonEmptyContent = false;
15
+ for (const entry of entries) {
16
+ const entryPath = resolve(dirPath, entry.name);
17
+ if (entry.isDirectory()) {
18
+ const removed = await visit(entryPath);
19
+ if (!removed) hasNonEmptyContent = true;
20
+ continue;
21
+ }
22
+ if (!GARBAGE_FILE_REGEX.test(entry.name)) {
23
+ hasNonEmptyContent = true;
24
+ }
25
+ }
26
+ if (hasNonEmptyContent) return false;
27
+ await rm(dirPath, { recursive: true, force: true });
28
+ deletedDirectories.push(dirPath);
29
+ return true;
30
+ };
31
+ await visit(resolve(rootDir));
32
+ return deletedDirectories;
33
+ };
34
+ var normalizeObjectKey = (targetDir, relativeFilePath) => normalizePath(`${targetDir}/${relativeFilePath}`).replace(/\/{2,}/g, "/").replace(/^\/+/, "");
45
35
  var formatBytes = (bytes) => {
46
36
  if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
47
37
  const units = ["B", "KB", "MB", "GB", "TB"];
@@ -73,12 +63,12 @@ var buildCapsuleBar = (ratio, width = 30) => {
73
63
  const safeRatio = Math.max(0, Math.min(1, ratio));
74
64
  if (width <= 0) return "";
75
65
  if (safeRatio >= 1) {
76
- return import_chalk.default.green("\u2588".repeat(width));
66
+ return chalk.green("\u2588".repeat(width));
77
67
  }
78
68
  const pointerIndex = Math.min(width - 1, Math.floor(width * safeRatio));
79
- const done = pointerIndex > 0 ? import_chalk.default.green("\u2588".repeat(pointerIndex)) : "";
80
- const pointer = import_chalk.default.cyanBright("\u25B8");
81
- const pending = pointerIndex < width - 1 ? import_chalk.default.gray("\u2591".repeat(width - pointerIndex - 1)) : "";
69
+ const done = pointerIndex > 0 ? chalk.green("\u2588".repeat(pointerIndex)) : "";
70
+ const pointer = chalk.cyanBright("\u25B8");
71
+ const pending = pointerIndex < width - 1 ? chalk.gray("\u2591".repeat(width - pointerIndex - 1)) : "";
82
72
  return `${done}${pointer}${pending}`;
83
73
  };
84
74
  function vitePluginDeployOss(option) {
@@ -105,7 +95,7 @@ function vitePluginDeployOss(option) {
105
95
  } = option || {};
106
96
  let buildFailed = false;
107
97
  let upload = false;
108
- let outDir = (0, import_vite.normalizePath)((0, import_node_path.resolve)("dist"));
98
+ let outDir = normalizePath(resolve("dist"));
109
99
  let resolvedConfig = null;
110
100
  const useInteractiveOutput = fancy && Boolean(process.stdout?.isTTY) && Boolean(process.stderr?.isTTY) && !process.env.CI;
111
101
  const clearScreen = () => {
@@ -147,9 +137,9 @@ function vitePluginDeployOss(option) {
147
137
  if (result.res.status === 200) {
148
138
  if (autoDelete) {
149
139
  try {
150
- await (0, import_promises.unlink)(task.filePath);
140
+ await unlink(task.filePath);
151
141
  } catch (error) {
152
- console.warn(`${import_chalk.default.yellow("\u26A0")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${task.filePath}`);
142
+ console.warn(`${chalk.yellow("\u26A0")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${task.filePath}`);
153
143
  }
154
144
  }
155
145
  return { success: true, file: task.filePath, name: task.name, size: task.size, retries: attempt - 1 };
@@ -160,7 +150,7 @@ function vitePluginDeployOss(option) {
160
150
  if (attempt === maxRetries) {
161
151
  if (!silentLogs) {
162
152
  console.log(
163
- `${import_chalk.default.red("\u2717")} ${task.filePath} => ${error instanceof Error ? error.message : String(error)}`
153
+ `${chalk.red("\u2717")} ${task.filePath} => ${error instanceof Error ? error.message : String(error)}`
164
154
  );
165
155
  }
166
156
  return {
@@ -173,7 +163,7 @@ function vitePluginDeployOss(option) {
173
163
  };
174
164
  } else {
175
165
  if (!silentLogs) {
176
- console.log(`${import_chalk.default.yellow("\u26A0")} ${task.filePath} \u4E0A\u4F20\u5931\u8D25\uFF0C\u6B63\u5728\u91CD\u8BD5 (${attempt}/${maxRetries})...`);
166
+ console.log(`${chalk.yellow("\u26A0")} ${task.filePath} \u4E0A\u4F20\u5931\u8D25\uFF0C\u6B63\u5728\u91CD\u8BD5 (${attempt}/${maxRetries})...`);
177
167
  }
178
168
  await new Promise((resolve2) => setTimeout(resolve2, 1e3 * attempt));
179
169
  }
@@ -198,10 +188,10 @@ function vitePluginDeployOss(option) {
198
188
  let retries = 0;
199
189
  const taskCandidates = await Promise.all(
200
190
  files.map(async (relativeFilePath) => {
201
- const filePath = (0, import_vite.normalizePath)((0, import_node_path.resolve)(outDir, relativeFilePath));
191
+ const filePath = normalizePath(resolve(outDir, relativeFilePath));
202
192
  const name = normalizeObjectKey(uploadDir, relativeFilePath);
203
193
  try {
204
- const fileStats = await (0, import_promises.stat)(filePath);
194
+ const fileStats = await stat(filePath);
205
195
  return { task: { filePath, name, size: fileStats.size } };
206
196
  } catch (error) {
207
197
  return { task: null, error, filePath, name };
@@ -229,7 +219,7 @@ function vitePluginDeployOss(option) {
229
219
  const activeFiles = /* @__PURE__ */ new Set();
230
220
  const safeWindowSize = Math.max(1, Math.min(windowSize, tasks.length || 1));
231
221
  const silentLogs = Boolean(useInteractiveOutput);
232
- const spinner = useInteractiveOutput ? (0, import_ora.default)({ text: "\u51C6\u5907\u4E0A\u4F20...", spinner: "dots12" }).start() : null;
222
+ const spinner = useInteractiveOutput ? ora({ text: "\u51C6\u5907\u4E0A\u4F20...", spinner: "dots12" }).start() : null;
233
223
  const reportEvery = Math.max(1, Math.ceil(totalFiles / 10));
234
224
  let lastReportedCompleted = -1;
235
225
  const updateProgress = () => {
@@ -244,7 +234,7 @@ function vitePluginDeployOss(option) {
244
234
  if (completed === lastReportedCompleted) return;
245
235
  if (completed === totalFiles || completed % reportEvery === 0) {
246
236
  console.log(
247
- `${import_chalk.default.gray("\u8FDB\u5EA6:")} ${completed}/${totalFiles} (${percentage}%) | ${import_chalk.default.gray("\u6570\u636E:")} ${formatBytes(uploadedBytes)}/${formatBytes(totalBytes)} | ${import_chalk.default.gray("\u901F\u5EA6:")} ${formatBytes(speed)}/s`
237
+ `${chalk.gray("\u8FDB\u5EA6:")} ${completed}/${totalFiles} (${percentage}%) | ${chalk.gray("\u6570\u636E:")} ${formatBytes(uploadedBytes)}/${formatBytes(totalBytes)} | ${chalk.gray("\u901F\u5EA6:")} ${formatBytes(speed)}/s`
248
238
  );
249
239
  lastReportedCompleted = completed;
250
240
  }
@@ -252,10 +242,10 @@ function vitePluginDeployOss(option) {
252
242
  }
253
243
  const bar = buildCapsuleBar(progressRatio);
254
244
  const warnLine = retries > 0 || failed > 0 ? `
255
- ${import_chalk.default.yellow("\u91CD\u8BD5")}: ${retries} ${import_chalk.default.yellow("\u5931\u8D25")}: ${failed}` : "";
245
+ ${chalk.yellow("\u91CD\u8BD5")}: ${retries} ${chalk.yellow("\u5931\u8D25")}: ${failed}` : "";
256
246
  spinner.text = [
257
- `${import_chalk.default.cyan("\u6B63\u5728\u4E0A\u4F20:")} ${import_chalk.default.white(currentFile)}`,
258
- `${bar} ${import_chalk.default.bold(`${percentage}%`)} ${import_chalk.default.gray(`(${completed}/${totalFiles})`)} ${import_chalk.default.gray("|")} ${import_chalk.default.blue(formatBytes(uploadedBytes))}/${import_chalk.default.blue(formatBytes(totalBytes))} ${import_chalk.default.gray("|")} ${import_chalk.default.magenta(`${formatBytes(speed)}/s`)} ${import_chalk.default.gray("|")} \u9884\u8BA1 ${import_chalk.default.yellow(formatDuration(etaSeconds))}`
247
+ `${chalk.cyan("\u6B63\u5728\u4E0A\u4F20:")} ${chalk.white(currentFile)}`,
248
+ `${bar} ${chalk.bold(`${percentage}%`)} ${chalk.gray(`(${completed}/${totalFiles})`)} ${chalk.gray("|")} ${chalk.blue(formatBytes(uploadedBytes))}/${chalk.blue(formatBytes(totalBytes))} ${chalk.gray("|")} ${chalk.magenta(`${formatBytes(speed)}/s`)} ${chalk.gray("|")} \u9884\u8BA1 ${chalk.yellow(formatDuration(etaSeconds))}`
259
249
  ].join("\n");
260
250
  spinner.text += warnLine;
261
251
  };
@@ -292,11 +282,11 @@ ${import_chalk.default.yellow("\u91CD\u8BD5")}: ${retries} ${import_chalk.defau
292
282
  const successCount = results.filter((item) => item.success).length;
293
283
  const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
294
284
  spinner.succeed(
295
- `${import_chalk.default.green("\u4E0A\u4F20\u6210\u529F")} ${successCount} \u4E2A\u6587\u4EF6\u3002
296
- ${buildCapsuleBar(1)} 100% (${totalFiles}/${totalFiles}) ${import_chalk.default.gray("|")} \u901F\u5EA6 ${import_chalk.default.magenta(`${formatBytes(speed)}/s`)} ${import_chalk.default.gray("|")} \u8017\u65F6 ${import_chalk.default.yellow(formatDuration(elapsedSeconds))}`
285
+ `${chalk.green("\u4E0A\u4F20\u6210\u529F")} ${successCount} \u4E2A\u6587\u4EF6\u3002
286
+ ${buildCapsuleBar(1)} 100% (${totalFiles}/${totalFiles}) ${chalk.gray("|")} \u901F\u5EA6 ${chalk.magenta(`${formatBytes(speed)}/s`)} ${chalk.gray("|")} \u8017\u65F6 ${chalk.yellow(formatDuration(elapsedSeconds))}`
297
287
  );
298
288
  } else {
299
- console.log(`${import_chalk.default.green("\u2714")} \u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210 (${totalFiles}/${totalFiles})`);
289
+ console.log(`${chalk.green("\u2714")} \u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210 (${totalFiles}/${totalFiles})`);
300
290
  }
301
291
  return results;
302
292
  };
@@ -312,7 +302,7 @@ ${buildCapsuleBar(1)} 100% (${totalFiles}/${totalFiles}) ${import_chalk.default.
312
302
  clearScreen();
313
303
  const validationErrors = validateOptions();
314
304
  if (validationErrors.length > 0) {
315
- console.log(`${import_chalk.default.red("\u2717 \u914D\u7F6E\u9519\u8BEF:")}
305
+ console.log(`${chalk.red("\u2717 \u914D\u7F6E\u9519\u8BEF:")}
316
306
  ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
317
307
  return;
318
308
  }
@@ -322,7 +312,7 @@ ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
322
312
  },
323
313
  configResolved(config) {
324
314
  resolvedConfig = config;
325
- outDir = (0, import_vite.normalizePath)((0, import_node_path.resolve)(config.root, config.build.outDir));
315
+ outDir = normalizePath(resolve(config.root, config.build.outDir));
326
316
  },
327
317
  closeBundle: {
328
318
  sequential: true,
@@ -330,26 +320,26 @@ ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
330
320
  async handler() {
331
321
  if (!open || !upload || buildFailed || !resolvedConfig) return;
332
322
  const startTime = Date.now();
333
- const client = new import_ali_oss.default({ region, accessKeyId, accessKeySecret, secure, bucket, ...props });
334
- const files = (0, import_glob.globSync)("**/*", {
323
+ const client = new oss({ region, accessKeyId, accessKeySecret, secure, bucket, ...props });
324
+ const files = globSync("**/*", {
335
325
  cwd: outDir,
336
326
  nodir: true,
337
327
  ignore: Array.isArray(skip) ? skip : [skip]
338
- }).map((file) => (0, import_vite.normalizePath)(file));
328
+ }).map((file) => normalizePath(file));
339
329
  if (files.length === 0) {
340
- console.log(`${import_chalk.default.yellow("\u26A0 \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6")}`);
330
+ console.log(`${chalk.yellow("\u26A0 \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6")}`);
341
331
  return;
342
332
  }
343
333
  clearScreen();
344
- console.log(import_chalk.default.cyan(`
334
+ console.log(chalk.cyan(`
345
335
  \u{1F680} OSS \u90E8\u7F72\u5F00\u59CB
346
336
  `));
347
- console.log(`${import_chalk.default.gray("Bucket:")} ${import_chalk.default.green(bucket)}`);
348
- console.log(`${import_chalk.default.gray("Region:")} ${import_chalk.default.green(region)}`);
349
- console.log(`${import_chalk.default.gray("Source:")} ${import_chalk.default.yellow(outDir)}`);
350
- console.log(`${import_chalk.default.gray("Target:")} ${import_chalk.default.yellow(uploadDir)}`);
351
- if (alias) console.log(`${import_chalk.default.gray("Alias:")} ${import_chalk.default.green(alias)}`);
352
- console.log(`${import_chalk.default.gray("Files:")} ${import_chalk.default.blue(files.length)}
337
+ console.log(`${chalk.gray("Bucket:")} ${chalk.green(bucket)}`);
338
+ console.log(`${chalk.gray("Region:")} ${chalk.green(region)}`);
339
+ console.log(`${chalk.gray("Source:")} ${chalk.yellow(outDir)}`);
340
+ console.log(`${chalk.gray("Target:")} ${chalk.yellow(uploadDir)}`);
341
+ if (alias) console.log(`${chalk.gray("Alias:")} ${chalk.green(alias)}`);
342
+ console.log(`${chalk.gray("Files:")} ${chalk.blue(files.length)}
353
343
  `);
354
344
  try {
355
345
  const results = await uploadFilesInBatches(client, files, concurrency);
@@ -361,48 +351,48 @@ ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
361
351
  const retryCount = results.reduce((sum, result) => sum + result.retries, 0);
362
352
  const avgSpeed = durationSeconds > 0 ? uploadedBytes / durationSeconds : 0;
363
353
  clearScreen();
364
- console.log("\n" + import_chalk.default.gray("\u2500".repeat(40)) + "\n");
354
+ console.log("\n" + chalk.gray("\u2500".repeat(40)) + "\n");
365
355
  if (failedCount === 0) {
366
- console.log(`${import_chalk.default.green("\u{1F389} \u90E8\u7F72\u6210\u529F!")}`);
356
+ console.log(`${chalk.green("\u{1F389} \u90E8\u7F72\u6210\u529F!")}`);
367
357
  } else {
368
- console.log(`${import_chalk.default.yellow("\u26A0 \u90E8\u7F72\u5B8C\u6210\u4F46\u5B58\u5728\u9519\u8BEF")}`);
358
+ console.log(`${chalk.yellow("\u26A0 \u90E8\u7F72\u5B8C\u6210\u4F46\u5B58\u5728\u9519\u8BEF")}`);
369
359
  }
370
360
  console.log(`
371
- ${import_chalk.default.gray("\u7EDF\u8BA1:")}`);
372
- console.log(` ${import_chalk.default.green("\u2714")} \u6210\u529F: ${import_chalk.default.bold(successCount)}`);
361
+ ${chalk.gray("\u7EDF\u8BA1:")}`);
362
+ console.log(` ${chalk.green("\u2714")} \u6210\u529F: ${chalk.bold(successCount)}`);
373
363
  if (failedCount > 0) {
374
- console.log(` ${import_chalk.default.red("\u2717")} \u5931\u8D25: ${import_chalk.default.bold(failedCount)}`);
364
+ console.log(` ${chalk.red("\u2717")} \u5931\u8D25: ${chalk.bold(failedCount)}`);
375
365
  }
376
- console.log(` ${import_chalk.default.cyan("\u21C4")} \u91CD\u8BD5: ${import_chalk.default.bold(retryCount)}`);
377
- console.log(` ${import_chalk.default.blue("\u{1F4E6}")} \u6570\u636E: ${import_chalk.default.bold(formatBytes(uploadedBytes))}`);
378
- console.log(` ${import_chalk.default.magenta("\u26A1")} \u5E73\u5747\u901F\u5EA6: ${import_chalk.default.bold(`${formatBytes(avgSpeed)}/s`)}`);
379
- console.log(` ${import_chalk.default.blue("\u23F1")} \u8017\u65F6: ${import_chalk.default.bold(duration)}s`);
366
+ console.log(` ${chalk.cyan("\u21C4")} \u91CD\u8BD5: ${chalk.bold(retryCount)}`);
367
+ console.log(` ${chalk.blue("\u{1F4E6}")} \u6570\u636E: ${chalk.bold(formatBytes(uploadedBytes))}`);
368
+ console.log(` ${chalk.magenta("\u26A1")} \u5E73\u5747\u901F\u5EA6: ${chalk.bold(`${formatBytes(avgSpeed)}/s`)}`);
369
+ console.log(` ${chalk.blue("\u23F1")} \u8017\u65F6: ${chalk.bold(duration)}s`);
380
370
  console.log("");
381
371
  if (failedCount > 0) {
382
372
  const failedItems = results.filter((result) => !result.success);
383
373
  const previewCount = Math.min(5, failedItems.length);
384
- console.log(import_chalk.default.red("\u5931\u8D25\u660E\u7EC6:"));
374
+ console.log(chalk.red("\u5931\u8D25\u660E\u7EC6:"));
385
375
  for (let i = 0; i < previewCount; i++) {
386
376
  const item = failedItems[i];
387
377
  const reason = item.error?.message || "unknown error";
388
- console.log(` ${import_chalk.default.red("\u2022")} ${item.name} => ${reason}`);
378
+ console.log(` ${chalk.red("\u2022")} ${item.name} => ${reason}`);
389
379
  }
390
380
  if (failedItems.length > previewCount) {
391
- console.log(import_chalk.default.gray(` ... \u8FD8\u6709 ${failedItems.length - previewCount} \u4E2A\u5931\u8D25\u6587\u4EF6`));
381
+ console.log(chalk.gray(` ... \u8FD8\u6709 ${failedItems.length - previewCount} \u4E2A\u5931\u8D25\u6587\u4EF6`));
392
382
  }
393
383
  console.log("");
394
384
  }
395
385
  try {
396
- await (0, import_delete_empty.default)((0, import_node_path.resolve)(outDir));
386
+ await removeEmptyDirectories(outDir);
397
387
  } catch (error) {
398
- console.warn(`${import_chalk.default.yellow("\u26A0 \u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25:")} ${error}`);
388
+ console.warn(`${chalk.yellow("\u26A0 \u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25:")} ${error}`);
399
389
  }
400
390
  if (failedCount > 0 && failOnError) {
401
391
  throw new Error(`Failed to upload ${failedCount} of ${results.length} files`);
402
392
  }
403
393
  } catch (error) {
404
394
  console.log(`
405
- ${import_chalk.default.red("\u274C \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:")} ${error}
395
+ ${chalk.red("\u274C \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:")} ${error}
406
396
  `);
407
397
  if (failOnError) {
408
398
  throw error instanceof Error ? error : new Error(String(error));
@@ -412,3 +402,6 @@ ${import_chalk.default.red("\u274C \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9
412
402
  }
413
403
  };
414
404
  }
405
+ export {
406
+ vitePluginDeployOss as default
407
+ };
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "vite-plugin-deploy-oss",
3
- "version": "2.0.0",
3
+ "version": "3.0.1",
4
4
  "main": "./dist/index.js",
5
- "module": "./dist/index.mjs",
6
5
  "types": "./dist/index.d.ts",
7
- "type": "commonjs",
6
+ "type": "module",
8
7
  "homepage": "https://github.com/yulin96/vite-plugin-deploy-oss",
9
8
  "repository": {
10
9
  "type": "git",
@@ -15,14 +14,8 @@
15
14
  },
16
15
  "exports": {
17
16
  ".": {
18
- "import": {
19
- "types": "./dist/index.d.mts",
20
- "default": "./dist/index.mjs"
21
- },
22
- "require": {
23
- "types": "./dist/index.d.ts",
24
- "default": "./dist/index.js"
25
- }
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
26
19
  }
27
20
  },
28
21
  "keywords": [
@@ -39,8 +32,7 @@
39
32
  "description": "将dist目录下的文件上传到阿里云oss",
40
33
  "devDependencies": {
41
34
  "@types/ali-oss": "^6.23.3",
42
- "@types/delete-empty": "^3.0.5",
43
- "@types/node": "^22.19.11",
35
+ "@types/node": "^22.19.13",
44
36
  "tsup": "^8.5.1",
45
37
  "typescript": "^5.9.3"
46
38
  },
@@ -50,7 +42,6 @@
50
42
  "dependencies": {
51
43
  "ali-oss": "^6.23.0",
52
44
  "chalk": "^5.6.2",
53
- "delete-empty": "^3.0.0",
54
45
  "glob": "^13.0.6",
55
46
  "ora": "^9.3.0"
56
47
  },
package/dist/index.d.mts DELETED
@@ -1,26 +0,0 @@
1
- import oss from 'ali-oss';
2
- import { Plugin } from 'vite';
3
-
4
- interface vitePluginDeployOssOption extends Omit<oss.Options, 'accessKeyId' | 'accessKeySecret' | 'bucket' | 'region'> {
5
- configBase?: string;
6
- accessKeyId: string;
7
- accessKeySecret: string;
8
- region: string;
9
- secure?: boolean;
10
- bucket: string;
11
- overwrite?: boolean;
12
- uploadDir: string;
13
- alias?: string;
14
- autoDelete?: boolean;
15
- skip?: string | string[];
16
- open?: boolean;
17
- fancy?: boolean;
18
- noCache?: boolean;
19
- failOnError?: boolean;
20
- concurrency?: number;
21
- retryTimes?: number;
22
- multipartThreshold?: number;
23
- }
24
- declare function vitePluginDeployOss(option: vitePluginDeployOssOption): Plugin;
25
-
26
- export { vitePluginDeployOss as default, type vitePluginDeployOssOption };
package/dist/index.mjs DELETED
@@ -1,383 +0,0 @@
1
- // src/index.ts
2
- import oss from "ali-oss";
3
- import chalk from "chalk";
4
- import deleteEmpty from "delete-empty";
5
- import { globSync } from "glob";
6
- import { stat, unlink } from "fs/promises";
7
- import { resolve } from "path";
8
- import ora from "ora";
9
- import { normalizePath } from "vite";
10
- var normalizeObjectKey = (targetDir, relativeFilePath) => normalizePath(`${targetDir}/${relativeFilePath}`).replace(/\/{2,}/g, "/").replace(/^\/+/, "");
11
- var formatBytes = (bytes) => {
12
- if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
13
- const units = ["B", "KB", "MB", "GB", "TB"];
14
- let value = bytes;
15
- let unitIndex = 0;
16
- while (value >= 1024 && unitIndex < units.length - 1) {
17
- value /= 1024;
18
- unitIndex++;
19
- }
20
- const digits = value >= 100 || unitIndex === 0 ? 0 : 1;
21
- return `${value.toFixed(digits)} ${units[unitIndex]}`;
22
- };
23
- var formatDuration = (seconds) => {
24
- if (!Number.isFinite(seconds) || seconds < 0) return "--";
25
- const rounded = Math.round(seconds);
26
- const mins = Math.floor(rounded / 60);
27
- const secs = rounded % 60;
28
- if (mins === 0) return `${secs}s`;
29
- return `${mins}m${String(secs).padStart(2, "0")}s`;
30
- };
31
- var trimMiddle = (text, maxLength) => {
32
- if (text.length <= maxLength) return text;
33
- if (maxLength <= 10) return text.slice(0, maxLength);
34
- const leftLength = Math.floor((maxLength - 3) / 2);
35
- const rightLength = maxLength - 3 - leftLength;
36
- return `${text.slice(0, leftLength)}...${text.slice(-rightLength)}`;
37
- };
38
- var buildCapsuleBar = (ratio, width = 30) => {
39
- const safeRatio = Math.max(0, Math.min(1, ratio));
40
- if (width <= 0) return "";
41
- if (safeRatio >= 1) {
42
- return chalk.green("\u2588".repeat(width));
43
- }
44
- const pointerIndex = Math.min(width - 1, Math.floor(width * safeRatio));
45
- const done = pointerIndex > 0 ? chalk.green("\u2588".repeat(pointerIndex)) : "";
46
- const pointer = chalk.cyanBright("\u25B8");
47
- const pending = pointerIndex < width - 1 ? chalk.gray("\u2591".repeat(width - pointerIndex - 1)) : "";
48
- return `${done}${pointer}${pending}`;
49
- };
50
- function vitePluginDeployOss(option) {
51
- const {
52
- accessKeyId,
53
- accessKeySecret,
54
- region,
55
- bucket,
56
- configBase,
57
- skip = "**/index.html",
58
- uploadDir,
59
- overwrite = true,
60
- secure = true,
61
- autoDelete = false,
62
- alias,
63
- open = true,
64
- fancy = true,
65
- noCache = false,
66
- failOnError = true,
67
- concurrency = 5,
68
- retryTimes = 3,
69
- multipartThreshold = 10 * 1024 * 1024,
70
- ...props
71
- } = option || {};
72
- let buildFailed = false;
73
- let upload = false;
74
- let outDir = normalizePath(resolve("dist"));
75
- let resolvedConfig = null;
76
- const useInteractiveOutput = fancy && Boolean(process.stdout?.isTTY) && Boolean(process.stderr?.isTTY) && !process.env.CI;
77
- const clearScreen = () => {
78
- if (!useInteractiveOutput) return;
79
- process.stdout.write("\x1B[2J\x1B[0f");
80
- };
81
- const validateOptions = () => {
82
- const errors = [];
83
- if (!accessKeyId) errors.push("accessKeyId is required");
84
- if (!accessKeySecret) errors.push("accessKeySecret is required");
85
- if (!bucket) errors.push("bucket is required");
86
- if (!region) errors.push("region is required");
87
- if (!uploadDir) errors.push("uploadDir is required");
88
- if (!Number.isInteger(retryTimes) || retryTimes < 1) errors.push("retryTimes must be >= 1");
89
- if (!Number.isInteger(concurrency) || concurrency < 1) errors.push("concurrency must be >= 1");
90
- if (!Number.isFinite(multipartThreshold) || multipartThreshold <= 0)
91
- errors.push("multipartThreshold must be > 0");
92
- return errors;
93
- };
94
- const uploadFileWithRetry = async (client, task, silentLogs, maxRetries = retryTimes) => {
95
- const shouldUseMultipart = task.size >= multipartThreshold;
96
- const headers = {
97
- "x-oss-storage-class": "Standard",
98
- "x-oss-object-acl": "default",
99
- "Cache-Control": noCache ? "no-cache" : "public, max-age=86400, immutable",
100
- "x-oss-forbid-overwrite": overwrite ? "false" : "true"
101
- };
102
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
103
- try {
104
- const result = shouldUseMultipart ? await client.multipartUpload(task.name, task.filePath, {
105
- timeout: 6e5,
106
- partSize: 1024 * 1024,
107
- parallel: Math.max(1, Math.min(concurrency, 4)),
108
- headers
109
- }) : await client.put(task.name, task.filePath, {
110
- timeout: 6e5,
111
- headers
112
- });
113
- if (result.res.status === 200) {
114
- if (autoDelete) {
115
- try {
116
- await unlink(task.filePath);
117
- } catch (error) {
118
- console.warn(`${chalk.yellow("\u26A0")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${task.filePath}`);
119
- }
120
- }
121
- return { success: true, file: task.filePath, name: task.name, size: task.size, retries: attempt - 1 };
122
- } else {
123
- throw new Error(`Upload failed with status: ${result.res.status}`);
124
- }
125
- } catch (error) {
126
- if (attempt === maxRetries) {
127
- if (!silentLogs) {
128
- console.log(
129
- `${chalk.red("\u2717")} ${task.filePath} => ${error instanceof Error ? error.message : String(error)}`
130
- );
131
- }
132
- return {
133
- success: false,
134
- file: task.filePath,
135
- name: task.name,
136
- size: task.size,
137
- retries: attempt - 1,
138
- error
139
- };
140
- } else {
141
- if (!silentLogs) {
142
- console.log(`${chalk.yellow("\u26A0")} ${task.filePath} \u4E0A\u4F20\u5931\u8D25\uFF0C\u6B63\u5728\u91CD\u8BD5 (${attempt}/${maxRetries})...`);
143
- }
144
- await new Promise((resolve2) => setTimeout(resolve2, 1e3 * attempt));
145
- }
146
- }
147
- }
148
- return {
149
- success: false,
150
- file: task.filePath,
151
- name: task.name,
152
- size: task.size,
153
- retries: maxRetries,
154
- error: new Error("Max retries exceeded")
155
- };
156
- };
157
- const uploadFilesInBatches = async (client, files, windowSize = concurrency) => {
158
- const results = [];
159
- const totalFiles = files.length;
160
- const tasks = [];
161
- let completed = 0;
162
- let failed = 0;
163
- let uploadedBytes = 0;
164
- let retries = 0;
165
- const taskCandidates = await Promise.all(
166
- files.map(async (relativeFilePath) => {
167
- const filePath = normalizePath(resolve(outDir, relativeFilePath));
168
- const name = normalizeObjectKey(uploadDir, relativeFilePath);
169
- try {
170
- const fileStats = await stat(filePath);
171
- return { task: { filePath, name, size: fileStats.size } };
172
- } catch (error) {
173
- return { task: null, error, filePath, name };
174
- }
175
- })
176
- );
177
- for (const candidate of taskCandidates) {
178
- if (candidate.task) {
179
- tasks.push(candidate.task);
180
- } else {
181
- failed++;
182
- completed++;
183
- results.push({
184
- success: false,
185
- file: candidate.filePath,
186
- name: candidate.name,
187
- size: 0,
188
- retries: 0,
189
- error: candidate.error
190
- });
191
- }
192
- }
193
- const totalBytes = tasks.reduce((sum, task) => sum + task.size, 0);
194
- const startAt = Date.now();
195
- const activeFiles = /* @__PURE__ */ new Set();
196
- const safeWindowSize = Math.max(1, Math.min(windowSize, tasks.length || 1));
197
- const silentLogs = Boolean(useInteractiveOutput);
198
- const spinner = useInteractiveOutput ? ora({ text: "\u51C6\u5907\u4E0A\u4F20...", spinner: "dots12" }).start() : null;
199
- const reportEvery = Math.max(1, Math.ceil(totalFiles / 10));
200
- let lastReportedCompleted = -1;
201
- const updateProgress = () => {
202
- const progressRatio = totalFiles > 0 ? completed / totalFiles : 1;
203
- const percentage = Math.round(progressRatio * 100);
204
- const elapsedSeconds = (Date.now() - startAt) / 1e3;
205
- const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
206
- const etaSeconds = speed > 0 ? Math.max(0, (totalBytes - uploadedBytes) / speed) : 0;
207
- const activeList = Array.from(activeFiles);
208
- const currentFile = activeList.length > 0 ? trimMiddle(activeList[activeList.length - 1], 86) : "-";
209
- if (!spinner) {
210
- if (completed === lastReportedCompleted) return;
211
- if (completed === totalFiles || completed % reportEvery === 0) {
212
- console.log(
213
- `${chalk.gray("\u8FDB\u5EA6:")} ${completed}/${totalFiles} (${percentage}%) | ${chalk.gray("\u6570\u636E:")} ${formatBytes(uploadedBytes)}/${formatBytes(totalBytes)} | ${chalk.gray("\u901F\u5EA6:")} ${formatBytes(speed)}/s`
214
- );
215
- lastReportedCompleted = completed;
216
- }
217
- return;
218
- }
219
- const bar = buildCapsuleBar(progressRatio);
220
- const warnLine = retries > 0 || failed > 0 ? `
221
- ${chalk.yellow("\u91CD\u8BD5")}: ${retries} ${chalk.yellow("\u5931\u8D25")}: ${failed}` : "";
222
- spinner.text = [
223
- `${chalk.cyan("\u6B63\u5728\u4E0A\u4F20:")} ${chalk.white(currentFile)}`,
224
- `${bar} ${chalk.bold(`${percentage}%`)} ${chalk.gray(`(${completed}/${totalFiles})`)} ${chalk.gray("|")} ${chalk.blue(formatBytes(uploadedBytes))}/${chalk.blue(formatBytes(totalBytes))} ${chalk.gray("|")} ${chalk.magenta(`${formatBytes(speed)}/s`)} ${chalk.gray("|")} \u9884\u8BA1 ${chalk.yellow(formatDuration(etaSeconds))}`
225
- ].join("\n");
226
- spinner.text += warnLine;
227
- };
228
- const refreshTimer = spinner ? setInterval(updateProgress, 120) : null;
229
- let currentIndex = 0;
230
- const worker = async () => {
231
- while (true) {
232
- const index = currentIndex++;
233
- if (index >= tasks.length) return;
234
- const task = tasks[index];
235
- activeFiles.add(task.name);
236
- updateProgress();
237
- const result = await uploadFileWithRetry(client, task, silentLogs);
238
- completed++;
239
- retries += result.retries;
240
- if (result.success) {
241
- uploadedBytes += result.size;
242
- } else {
243
- failed++;
244
- }
245
- results.push(result);
246
- activeFiles.delete(task.name);
247
- updateProgress();
248
- }
249
- };
250
- updateProgress();
251
- try {
252
- await Promise.all(Array.from({ length: safeWindowSize }, () => worker()));
253
- } finally {
254
- if (refreshTimer) clearInterval(refreshTimer);
255
- }
256
- if (spinner) {
257
- const elapsedSeconds = (Date.now() - startAt) / 1e3;
258
- const successCount = results.filter((item) => item.success).length;
259
- const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
260
- spinner.succeed(
261
- `${chalk.green("\u4E0A\u4F20\u6210\u529F")} ${successCount} \u4E2A\u6587\u4EF6\u3002
262
- ${buildCapsuleBar(1)} 100% (${totalFiles}/${totalFiles}) ${chalk.gray("|")} \u901F\u5EA6 ${chalk.magenta(`${formatBytes(speed)}/s`)} ${chalk.gray("|")} \u8017\u65F6 ${chalk.yellow(formatDuration(elapsedSeconds))}`
263
- );
264
- } else {
265
- console.log(`${chalk.green("\u2714")} \u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210 (${totalFiles}/${totalFiles})`);
266
- }
267
- return results;
268
- };
269
- return {
270
- name: "vite-plugin-deploy-oss",
271
- apply: "build",
272
- enforce: "post",
273
- buildEnd(error) {
274
- if (error) buildFailed = true;
275
- },
276
- config(config) {
277
- if (!open || buildFailed) return;
278
- clearScreen();
279
- const validationErrors = validateOptions();
280
- if (validationErrors.length > 0) {
281
- console.log(`${chalk.red("\u2717 \u914D\u7F6E\u9519\u8BEF:")}
282
- ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
283
- return;
284
- }
285
- upload = true;
286
- config.base = configBase || config.base;
287
- return config;
288
- },
289
- configResolved(config) {
290
- resolvedConfig = config;
291
- outDir = normalizePath(resolve(config.root, config.build.outDir));
292
- },
293
- closeBundle: {
294
- sequential: true,
295
- order: "post",
296
- async handler() {
297
- if (!open || !upload || buildFailed || !resolvedConfig) return;
298
- const startTime = Date.now();
299
- const client = new oss({ region, accessKeyId, accessKeySecret, secure, bucket, ...props });
300
- const files = globSync("**/*", {
301
- cwd: outDir,
302
- nodir: true,
303
- ignore: Array.isArray(skip) ? skip : [skip]
304
- }).map((file) => normalizePath(file));
305
- if (files.length === 0) {
306
- console.log(`${chalk.yellow("\u26A0 \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6")}`);
307
- return;
308
- }
309
- clearScreen();
310
- console.log(chalk.cyan(`
311
- \u{1F680} OSS \u90E8\u7F72\u5F00\u59CB
312
- `));
313
- console.log(`${chalk.gray("Bucket:")} ${chalk.green(bucket)}`);
314
- console.log(`${chalk.gray("Region:")} ${chalk.green(region)}`);
315
- console.log(`${chalk.gray("Source:")} ${chalk.yellow(outDir)}`);
316
- console.log(`${chalk.gray("Target:")} ${chalk.yellow(uploadDir)}`);
317
- if (alias) console.log(`${chalk.gray("Alias:")} ${chalk.green(alias)}`);
318
- console.log(`${chalk.gray("Files:")} ${chalk.blue(files.length)}
319
- `);
320
- try {
321
- const results = await uploadFilesInBatches(client, files, concurrency);
322
- const successCount = results.filter((r) => r.success).length;
323
- const failedCount = results.length - successCount;
324
- const durationSeconds = (Date.now() - startTime) / 1e3;
325
- const duration = durationSeconds.toFixed(2);
326
- const uploadedBytes = results.reduce((sum, result) => result.success ? sum + result.size : sum, 0);
327
- const retryCount = results.reduce((sum, result) => sum + result.retries, 0);
328
- const avgSpeed = durationSeconds > 0 ? uploadedBytes / durationSeconds : 0;
329
- clearScreen();
330
- console.log("\n" + chalk.gray("\u2500".repeat(40)) + "\n");
331
- if (failedCount === 0) {
332
- console.log(`${chalk.green("\u{1F389} \u90E8\u7F72\u6210\u529F!")}`);
333
- } else {
334
- console.log(`${chalk.yellow("\u26A0 \u90E8\u7F72\u5B8C\u6210\u4F46\u5B58\u5728\u9519\u8BEF")}`);
335
- }
336
- console.log(`
337
- ${chalk.gray("\u7EDF\u8BA1:")}`);
338
- console.log(` ${chalk.green("\u2714")} \u6210\u529F: ${chalk.bold(successCount)}`);
339
- if (failedCount > 0) {
340
- console.log(` ${chalk.red("\u2717")} \u5931\u8D25: ${chalk.bold(failedCount)}`);
341
- }
342
- console.log(` ${chalk.cyan("\u21C4")} \u91CD\u8BD5: ${chalk.bold(retryCount)}`);
343
- console.log(` ${chalk.blue("\u{1F4E6}")} \u6570\u636E: ${chalk.bold(formatBytes(uploadedBytes))}`);
344
- console.log(` ${chalk.magenta("\u26A1")} \u5E73\u5747\u901F\u5EA6: ${chalk.bold(`${formatBytes(avgSpeed)}/s`)}`);
345
- console.log(` ${chalk.blue("\u23F1")} \u8017\u65F6: ${chalk.bold(duration)}s`);
346
- console.log("");
347
- if (failedCount > 0) {
348
- const failedItems = results.filter((result) => !result.success);
349
- const previewCount = Math.min(5, failedItems.length);
350
- console.log(chalk.red("\u5931\u8D25\u660E\u7EC6:"));
351
- for (let i = 0; i < previewCount; i++) {
352
- const item = failedItems[i];
353
- const reason = item.error?.message || "unknown error";
354
- console.log(` ${chalk.red("\u2022")} ${item.name} => ${reason}`);
355
- }
356
- if (failedItems.length > previewCount) {
357
- console.log(chalk.gray(` ... \u8FD8\u6709 ${failedItems.length - previewCount} \u4E2A\u5931\u8D25\u6587\u4EF6`));
358
- }
359
- console.log("");
360
- }
361
- try {
362
- await deleteEmpty(resolve(outDir));
363
- } catch (error) {
364
- console.warn(`${chalk.yellow("\u26A0 \u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25:")} ${error}`);
365
- }
366
- if (failedCount > 0 && failOnError) {
367
- throw new Error(`Failed to upload ${failedCount} of ${results.length} files`);
368
- }
369
- } catch (error) {
370
- console.log(`
371
- ${chalk.red("\u274C \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:")} ${error}
372
- `);
373
- if (failOnError) {
374
- throw error instanceof Error ? error : new Error(String(error));
375
- }
376
- }
377
- }
378
- }
379
- };
380
- }
381
- export {
382
- vitePluginDeployOss as default
383
- };