vite-plugin-deploy-oss 3.4.2 → 3.5.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/dist/index.js CHANGED
@@ -1,502 +1,20 @@
1
- // src/index.ts
2
- import oss from "ali-oss";
3
- import chalk3 from "chalk";
4
- import cliProgress from "cli-progress";
5
- import { globSync } from "glob";
6
- import { mkdir, stat, unlink, writeFile } from "fs/promises";
7
- import { dirname, resolve as resolve2 } from "path";
8
- import { normalizePath } from "vite";
9
-
10
- // src/utils/file.ts
11
- import { createHash } from "crypto";
12
- import { createReadStream } from "fs";
13
- import { readdir, rm } from "fs/promises";
14
- import { resolve } from "path";
15
- var GARBAGE_FILE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
16
- var getFileMd5 = (filePath) => {
17
- return new Promise((resolvePromise, reject) => {
18
- const hash = createHash("md5");
19
- const stream = createReadStream(filePath);
20
- stream.on("error", (err) => reject(err));
21
- stream.on("data", (chunk) => hash.update(chunk));
22
- stream.on("end", () => resolvePromise(hash.digest("hex")));
23
- });
24
- };
25
- var removeEmptyDirectories = async (rootDir) => {
26
- const deletedDirectories = [];
27
- const visit = async (dirPath) => {
28
- const entries = await readdir(dirPath, { withFileTypes: true });
29
- let hasNonEmptyContent = false;
30
- for (const entry of entries) {
31
- const entryPath = resolve(dirPath, entry.name);
32
- if (entry.isDirectory()) {
33
- const removed = await visit(entryPath);
34
- if (!removed) hasNonEmptyContent = true;
35
- continue;
36
- }
37
- if (!GARBAGE_FILE_REGEX.test(entry.name)) {
38
- hasNonEmptyContent = true;
39
- }
40
- }
41
- if (hasNonEmptyContent) return false;
42
- await rm(dirPath, { recursive: true, force: true });
43
- deletedDirectories.push(dirPath);
44
- return true;
45
- };
46
- await visit(resolve(rootDir));
47
- return deletedDirectories;
48
- };
49
-
50
- // src/utils/path.ts
51
- var DEFAULT_MANIFEST_FILE_NAME = "oss-manifest.json";
52
- var normalizeSlash = (value) => value.replace(/\\/g, "/").trim();
53
- var normalizePathSegments = (...values) => values.filter((value) => Boolean(value)).flatMap((value) => normalizeSlash(value).split("/")).filter(Boolean).join("/");
54
- var splitUrlLikeBase = (value) => {
55
- const normalized = normalizeSlash(value);
56
- const protocolMatch = normalized.match(/^([a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]+)(.*)$/);
57
- if (protocolMatch) {
58
- return {
59
- prefix: protocolMatch[1],
60
- path: protocolMatch[2] || ""
61
- };
62
- }
63
- const protocolRelativeMatch = normalized.match(/^(\/\/[^/]+)(.*)$/);
64
- if (protocolRelativeMatch) {
65
- return {
66
- prefix: protocolRelativeMatch[1],
67
- path: protocolRelativeMatch[2] || ""
68
- };
69
- }
70
- if (normalized.startsWith("/")) {
71
- return {
72
- prefix: "/",
73
- path: normalized
74
- };
75
- }
76
- return {
77
- prefix: "",
78
- path: normalized
79
- };
80
- };
81
- var normalizeUrlLikeBase = (base) => {
82
- const { prefix, path } = splitUrlLikeBase(base);
83
- const normalizedPath = normalizePathSegments(path);
84
- if (!prefix) return normalizedPath;
85
- if (!normalizedPath) return prefix;
86
- if (prefix === "/") return `/${normalizedPath}`;
87
- return `${prefix}/${normalizedPath}`;
88
- };
89
- var ensureTrailingSlash = (value) => {
90
- if (!value || value.endsWith("/")) return value;
91
- return `${value}/`;
92
- };
93
- var normalizeObjectKey = (targetDir, relativeFilePath) => normalizePathSegments(targetDir, relativeFilePath);
94
- var normalizeManifestFileName = (fileName) => {
95
- const normalized = normalizePathSegments(fileName || DEFAULT_MANIFEST_FILE_NAME);
96
- return normalized || DEFAULT_MANIFEST_FILE_NAME;
97
- };
98
- var resolveManifestFileName = (manifest) => {
99
- if (!manifest) return null;
100
- if (manifest === true) return DEFAULT_MANIFEST_FILE_NAME;
101
- return normalizeManifestFileName(manifest.fileName);
102
- };
103
- var encodeUrlPath = (path) => encodeURI(normalizePathSegments(path));
104
- var joinUrlPath = (base, path) => `${normalizeUrlLikeBase(base).replace(/\/+$/, "")}/${encodeUrlPath(path)}`;
105
- var resolveUploadedFileUrl = (relativeFilePath, objectKey, configBase, alias) => {
106
- if (configBase) return joinUrlPath(configBase, relativeFilePath);
107
- if (alias) return joinUrlPath(alias, objectKey);
108
- return objectKey;
109
- };
110
-
111
- // src/utils/progress.ts
112
- import chalk from "chalk";
113
- var formatBytes = (bytes) => {
114
- if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
115
- const units = ["B", "KB", "MB", "GB", "TB"];
116
- let value = bytes;
117
- let unitIndex = 0;
118
- while (value >= 1024 && unitIndex < units.length - 1) {
119
- value /= 1024;
120
- unitIndex++;
121
- }
122
- const digits = value >= 100 || unitIndex === 0 ? 0 : 1;
123
- return `${value.toFixed(digits)} ${units[unitIndex]}`;
124
- };
125
- var formatDuration = (seconds) => {
126
- if (!Number.isFinite(seconds) || seconds < 0) return "--";
127
- const rounded = Math.round(seconds);
128
- const mins = Math.floor(rounded / 60);
129
- const secs = rounded % 60;
130
- if (mins === 0) return `${secs}s`;
131
- return `${mins}m${String(secs).padStart(2, "0")}s`;
132
- };
133
-
134
- // src/utils/terminal.ts
135
- import chalk2 from "chalk";
136
- import cliTruncate from "cli-truncate";
137
- import logSymbols from "log-symbols";
138
- import stringWidth from "string-width";
139
- var panelBorderColor = {
140
- info: "cyan",
141
- success: "green",
142
- warning: "yellow",
143
- danger: "red"
144
- };
145
- var getTerminalWidth = () => process.stdout?.columns || 100;
146
- var getPanelInnerWidth = () => Math.max(46, Math.min(84, getTerminalWidth() - 4));
147
- var padVisual = (text, width) => `${text}${" ".repeat(Math.max(0, width - stringWidth(text)))}`;
148
- var fitVisual = (text, width) => {
149
- if (width <= 0) return "";
150
- return padVisual(cliTruncate(text, width, { position: "middle" }), width);
151
- };
152
- var truncateTerminalText = (text, reservedWidth = 26) => {
153
- const maxWidth = Math.max(24, Math.min(88, getTerminalWidth() - reservedWidth));
154
- return cliTruncate(text, maxWidth, { position: "middle" });
155
- };
156
- var renderPanel = (title, rows, tone = "info", footer) => {
157
- const color = chalk2[panelBorderColor[tone]];
158
- const innerWidth = getPanelInnerWidth();
159
- const labelWidth = rows.length > 0 ? Math.max(...rows.map((row) => stringWidth(row.label))) : 0;
160
- const contentLines = [chalk2.bold(cliTruncate(title, innerWidth, { position: "end" }))];
161
- if (rows.length > 0) {
162
- contentLines.push("");
163
- for (const row of rows) {
164
- const paddedLabel = padVisual(row.label, labelWidth);
165
- const prefix = `${paddedLabel} `;
166
- const availableValueWidth = Math.max(8, innerWidth - stringWidth(prefix));
167
- contentLines.push(`${chalk2.gray(prefix)}${fitVisual(row.value, availableValueWidth)}`);
168
- }
169
- }
170
- if (footer) {
171
- contentLines.push("");
172
- contentLines.push(chalk2.gray(cliTruncate(footer, innerWidth, { position: "middle" })));
173
- }
174
- const top = color(`\u256D${"\u2500".repeat(innerWidth + 2)}\u256E`);
175
- const bottom = color(`\u2570${"\u2500".repeat(innerWidth + 2)}\u256F`);
176
- const body = contentLines.map((line) => `${color("\u2502")} ${fitVisual(line, innerWidth)} ${color("\u2502")}`).join("\n");
177
- return `${top}
178
- ${body}
179
- ${bottom}`;
180
- };
181
- var renderInlineStats = (items) => items.filter(Boolean).join(chalk2.gray(" \xB7 "));
182
- var getPanelDot = (tone = "success") => {
183
- switch (tone) {
184
- case "info":
185
- return chalk2.green("\u25CF");
186
- case "success":
187
- return chalk2.green("\u25CF");
188
- case "warning":
189
- return chalk2.yellow("\u25CF");
190
- case "danger":
191
- return chalk2.red("\u25CF");
192
- }
193
- };
194
- var getLogSymbol = (tone) => {
195
- switch (tone) {
196
- case "success":
197
- return logSymbols.success;
198
- case "warning":
199
- return logSymbols.warning;
200
- case "danger":
201
- return logSymbols.error;
202
- }
203
- };
1
+ import {
2
+ deployOss,
3
+ ensureTrailingSlash,
4
+ normalizeSlash,
5
+ normalizeUrlLikeBase
6
+ } from "./chunk-6D7VVVXN.js";
204
7
 
205
8
  // src/index.ts
206
- var formatTimingDuration = (durationMs) => {
207
- if (durationMs < 1e3) return `${durationMs}ms`;
208
- const seconds = durationMs / 1e3;
209
- return `${seconds.toFixed(seconds >= 10 ? 1 : 2)}s`;
210
- };
211
- var renderDebugPanel = (entries) => {
212
- const rows = entries.map((entry) => ({
213
- label: `${entry.label}:`,
214
- value: chalk3.cyan(
215
- entry.detail ? `${formatTimingDuration(entry.durationMs)} \xB7 ${truncateTerminalText(entry.detail, 24)}` : formatTimingDuration(entry.durationMs)
216
- )
217
- }));
218
- return renderPanel(`${getPanelDot("success")} \u8C03\u8BD5\u8017\u65F6`, rows, "info");
219
- };
220
- var createManifestPayload = async (results, configBase, alias) => {
221
- const successfulResults = results.filter((result) => result.success);
222
- const files = await Promise.all(
223
- successfulResults.map(async (result) => {
224
- const md5 = await getFileMd5(result.file);
225
- return {
226
- file: result.relativeFilePath,
227
- key: result.name,
228
- url: resolveUploadedFileUrl(result.relativeFilePath, result.name, configBase, alias),
229
- md5
230
- };
231
- })
232
- );
233
- return {
234
- version: Date.now(),
235
- files
236
- };
237
- };
9
+ import { resolve } from "path";
10
+ var defineDeployConfig = (option) => option;
238
11
  function vitePluginDeployOss(option) {
239
- const {
240
- accessKeyId,
241
- accessKeySecret,
242
- region,
243
- bucket,
244
- configBase,
245
- skip = "**/index.html",
246
- uploadDir,
247
- overwrite = true,
248
- secure = true,
249
- autoDelete = false,
250
- alias,
251
- open = true,
252
- debug = false,
253
- fancy = true,
254
- noCache = false,
255
- failOnError = true,
256
- concurrency = 5,
257
- retryTimes = 3,
258
- multipartThreshold = 10 * 1024 * 1024,
259
- manifest = false,
260
- ...props
261
- } = option || {};
262
- const normalizedUploadDir = normalizePathSegments(uploadDir);
263
- const normalizedConfigBase = configBase ? ensureTrailingSlash(normalizeUrlLikeBase(configBase)) : void 0;
264
- const normalizedAlias = alias ? normalizeUrlLikeBase(alias) : void 0;
265
- const manifestFileName = resolveManifestFileName(manifest);
266
- const effectiveAutoDelete = manifestFileName ? false : autoDelete;
267
- const effectiveSkip = manifestFileName ? [] : Array.isArray(skip) ? skip : [skip];
12
+ const { open = true, configBase } = option || {};
268
13
  let buildFailed = false;
269
14
  let upload = false;
270
- let outDir = normalizePath(resolve2("dist"));
15
+ let outDir = normalizeSlash(resolve("dist"));
271
16
  let resolvedConfig = null;
272
- const useInteractiveOutput = fancy && Boolean(process.stdout?.isTTY) && Boolean(process.stderr?.isTTY) && !process.env.CI;
273
- const clearViewport = () => {
274
- if (!useInteractiveOutput) return;
275
- process.stdout.write("\x1B[2J\x1B[0f");
276
- };
277
- const validateOptions = () => {
278
- const errors = [];
279
- if (!accessKeyId) errors.push("accessKeyId is required");
280
- if (!accessKeySecret) errors.push("accessKeySecret is required");
281
- if (!bucket) errors.push("bucket is required");
282
- if (!region) errors.push("region is required");
283
- if (!uploadDir) errors.push("uploadDir is required");
284
- if (!Number.isInteger(retryTimes) || retryTimes < 1) errors.push("retryTimes must be >= 1");
285
- if (!Number.isInteger(concurrency) || concurrency < 1) errors.push("concurrency must be >= 1");
286
- if (!Number.isFinite(multipartThreshold) || multipartThreshold <= 0) errors.push("multipartThreshold must be > 0");
287
- return errors;
288
- };
289
- const uploadSingleTask = async (client, task) => uploadFileWithRetry(client, task, false);
290
- const uploadFileWithRetry = async (client, task, silentLogs, maxRetries = retryTimes) => {
291
- const shouldUseMultipart = task.size >= multipartThreshold;
292
- const headers = {
293
- "x-oss-storage-class": "Standard",
294
- "x-oss-object-acl": "default",
295
- "Cache-Control": task.cacheControl || (noCache || task.name.endsWith(".html") ? "no-cache" : "public, max-age=86400, immutable"),
296
- "x-oss-forbid-overwrite": overwrite ? "false" : "true"
297
- };
298
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
299
- try {
300
- const result = shouldUseMultipart ? await client.multipartUpload(task.name, task.filePath, {
301
- timeout: 6e5,
302
- partSize: 1024 * 1024,
303
- parallel: Math.max(1, Math.min(concurrency, 4)),
304
- headers
305
- }) : await client.put(task.name, task.filePath, {
306
- timeout: 6e5,
307
- headers
308
- });
309
- if (result.res.status === 200) {
310
- if (effectiveAutoDelete) {
311
- try {
312
- await unlink(task.filePath);
313
- } catch (error) {
314
- console.warn(
315
- `${getLogSymbol("warning")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${truncateTerminalText(task.relativeFilePath, 18)}`
316
- );
317
- }
318
- }
319
- return {
320
- success: true,
321
- file: task.filePath,
322
- relativeFilePath: task.relativeFilePath,
323
- name: task.name,
324
- size: task.size,
325
- retries: attempt - 1
326
- };
327
- } else {
328
- throw new Error(`Upload failed with status: ${result.res.status}`);
329
- }
330
- } catch (error) {
331
- if (attempt === maxRetries) {
332
- if (!silentLogs) {
333
- const reason = error instanceof Error ? error.message : String(error);
334
- console.log(`${getLogSymbol("danger")} ${truncateTerminalText(task.relativeFilePath, 18)} ${reason}`);
335
- }
336
- return {
337
- success: false,
338
- file: task.filePath,
339
- relativeFilePath: task.relativeFilePath,
340
- name: task.name,
341
- size: task.size,
342
- retries: attempt - 1,
343
- error
344
- };
345
- } else {
346
- if (!silentLogs) {
347
- console.log(
348
- `${getLogSymbol("warning")} ${truncateTerminalText(task.relativeFilePath, 18)} \u6B63\u5728\u91CD\u8BD5 (${attempt}/${maxRetries})`
349
- );
350
- }
351
- await new Promise((resolve3) => setTimeout(resolve3, 1e3 * attempt));
352
- }
353
- }
354
- }
355
- return {
356
- success: false,
357
- file: task.filePath,
358
- relativeFilePath: task.relativeFilePath,
359
- name: task.name,
360
- size: task.size,
361
- retries: maxRetries,
362
- error: new Error("Max retries exceeded")
363
- };
364
- };
365
- const uploadFilesInBatches = async (client, files, windowSize = concurrency) => {
366
- const results = [];
367
- const debugEntries = [];
368
- const totalFiles = files.length;
369
- const tasks = [];
370
- let completed = 0;
371
- let failed = 0;
372
- let uploadedBytes = 0;
373
- let retries = 0;
374
- const taskPrepareStartedAt = Date.now();
375
- const taskCandidates = await Promise.all(
376
- files.map(async (relativeFilePath) => {
377
- const filePath = normalizePath(resolve2(outDir, relativeFilePath));
378
- const name = normalizeObjectKey(normalizedUploadDir, relativeFilePath);
379
- try {
380
- const fileStats = await stat(filePath);
381
- return { task: { filePath, relativeFilePath, name, size: fileStats.size } };
382
- } catch (error) {
383
- return { task: null, error, filePath, relativeFilePath, name };
384
- }
385
- })
386
- );
387
- debugEntries.push({
388
- label: "\u751F\u6210\u4E0A\u4F20\u4EFB\u52A1",
389
- durationMs: Date.now() - taskPrepareStartedAt,
390
- detail: `${files.length} \u4E2A\u6587\u4EF6`
391
- });
392
- for (const candidate of taskCandidates) {
393
- if (candidate.task) {
394
- tasks.push(candidate.task);
395
- } else {
396
- failed++;
397
- completed++;
398
- results.push({
399
- success: false,
400
- file: candidate.filePath,
401
- relativeFilePath: candidate.relativeFilePath,
402
- name: candidate.name,
403
- size: 0,
404
- retries: 0,
405
- error: candidate.error
406
- });
407
- }
408
- }
409
- const totalBytes = tasks.reduce((sum, task) => sum + task.size, 0);
410
- const startAt = Date.now();
411
- const safeWindowSize = Math.max(1, Math.min(windowSize, tasks.length || 1));
412
- const silentLogs = Boolean(useInteractiveOutput);
413
- const progressBar = useInteractiveOutput ? new cliProgress.SingleBar({
414
- hideCursor: true,
415
- clearOnComplete: true,
416
- stopOnComplete: true,
417
- barsize: 18,
418
- barCompleteChar: "\u2588",
419
- barIncompleteChar: "\u2591",
420
- format: `${chalk3.gray("\u4E0A\u4F20")} ${chalk3.bold("{percentage}%")} ${chalk3.cyan("{bar}")} ${chalk3.gray("\xB7")} ${chalk3.magenta("{speed}/s")} ${chalk3.gray("\xB7")} ${chalk3.gray("{elapsed}")}s`
421
- }) : null;
422
- const reportEvery = Math.max(1, Math.ceil(totalFiles / 6));
423
- let lastReportedCompleted = -1;
424
- if (progressBar) {
425
- progressBar.start(totalFiles, 0, {
426
- speed: formatBytes(0),
427
- elapsed: "0"
428
- });
429
- }
430
- const updateProgress = () => {
431
- const elapsedSeconds = (Date.now() - startAt) / 1e3;
432
- const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
433
- if (!progressBar) {
434
- const progressRatio = totalFiles > 0 ? completed / totalFiles : 1;
435
- const percentage = Math.round(progressRatio * 100);
436
- if (completed === 0 && totalFiles > 0) return;
437
- if (completed === lastReportedCompleted) return;
438
- if (completed === totalFiles || completed % reportEvery === 0) {
439
- console.log(
440
- `${chalk3.gray("\u4E0A\u4F20\u8FDB\u5EA6")} ${renderInlineStats([
441
- chalk3.bold(`${completed}/${totalFiles}`),
442
- `${percentage}%`,
443
- `${formatBytes(uploadedBytes)}/${formatBytes(totalBytes)}`,
444
- `${formatBytes(speed)}/s`
445
- ])}`
446
- );
447
- lastReportedCompleted = completed;
448
- }
449
- return;
450
- }
451
- progressBar.update(completed, {
452
- speed: chalk3.magenta(formatBytes(speed)),
453
- elapsed: formatDuration(elapsedSeconds).replace(/s$/, "")
454
- });
455
- };
456
- const refreshTimer = progressBar ? setInterval(updateProgress, 120) : null;
457
- let currentIndex = 0;
458
- const worker = async () => {
459
- while (true) {
460
- const index = currentIndex++;
461
- if (index >= tasks.length) return;
462
- const task = tasks[index];
463
- updateProgress();
464
- const result = await uploadFileWithRetry(client, task, silentLogs);
465
- completed++;
466
- retries += result.retries;
467
- if (result.success) {
468
- uploadedBytes += result.size;
469
- } else {
470
- failed++;
471
- }
472
- results.push(result);
473
- updateProgress();
474
- }
475
- };
476
- updateProgress();
477
- try {
478
- await Promise.all(Array.from({ length: safeWindowSize }, () => worker()));
479
- } finally {
480
- if (refreshTimer) clearInterval(refreshTimer);
481
- }
482
- if (progressBar) {
483
- const elapsedSeconds = (Date.now() - startAt) / 1e3;
484
- const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
485
- progressBar.update(totalFiles, {
486
- speed: chalk3.magenta(formatBytes(speed)),
487
- elapsed: formatDuration(elapsedSeconds).replace(/s$/, "")
488
- });
489
- progressBar.stop();
490
- } else {
491
- console.log(`${getLogSymbol("success")} \u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210 (${totalFiles}/${totalFiles})`);
492
- }
493
- debugEntries.push({
494
- label: "\u4E0A\u4F20\u6587\u4EF6",
495
- durationMs: Date.now() - startAt,
496
- detail: `${tasks.length} \u4E2A\u6210\u529F\u5019\u9009 \xB7 \u5E76\u53D1 ${safeWindowSize}`
497
- });
498
- return { results, debugEntries };
499
- };
17
+ const normalizedConfigBase = configBase ? ensureTrailingSlash(normalizeUrlLikeBase(configBase)) : void 0;
500
18
  return {
501
19
  name: "vite-plugin-deploy-oss",
502
20
  apply: "build",
@@ -506,204 +24,30 @@ function vitePluginDeployOss(option) {
506
24
  },
507
25
  config(config) {
508
26
  if (!open || buildFailed) return;
509
- const validationErrors = validateOptions();
510
- if (validationErrors.length > 0) {
511
- throw new Error(`vite-plugin-deploy-oss \u914D\u7F6E\u9519\u8BEF:
512
- ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
513
- }
514
27
  upload = true;
515
28
  config.base = normalizedConfigBase || config.base;
516
29
  return config;
517
30
  },
518
31
  configResolved(config) {
519
32
  resolvedConfig = config;
520
- outDir = normalizePath(resolve2(config.root, config.build.outDir));
33
+ outDir = normalizeSlash(resolve(config.root, config.build.outDir));
521
34
  },
522
35
  closeBundle: {
523
36
  sequential: true,
524
37
  order: "post",
525
38
  async handler() {
526
39
  if (!open || !upload || buildFailed || !resolvedConfig) return;
527
- const startTime = Date.now();
528
- const debugEntries = [];
529
- const client = new oss({ region, accessKeyId, accessKeySecret, secure, bucket, ...props });
530
- const collectFilesStartedAt = Date.now();
531
- const files = globSync("**/*", {
532
- cwd: outDir,
533
- nodir: true,
534
- ignore: effectiveSkip
535
- }).map((file) => normalizePath(file)).filter((file) => file !== manifestFileName);
536
- debugEntries.push({
537
- label: "\u626B\u63CF\u672C\u5730\u6587\u4EF6",
538
- durationMs: Date.now() - collectFilesStartedAt,
539
- detail: `${files.length} \u4E2A\u6587\u4EF6`
40
+ await deployOss({
41
+ ...option,
42
+ configBase: normalizedConfigBase,
43
+ outDir
540
44
  });
541
- if (files.length === 0) {
542
- console.log(`${getLogSymbol("warning")} \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6`);
543
- return;
544
- }
545
- clearViewport();
546
- console.log(
547
- renderPanel(
548
- `${getPanelDot("success")} \u51C6\u5907\u90E8\u7F72`,
549
- [
550
- { label: "\u4F4D\u7F6E:", value: chalk3.green(`${bucket} \xB7 ${region}`) },
551
- {
552
- label: "\u76EE\u6807:",
553
- value: chalk3.yellow(
554
- truncateTerminalText(
555
- normalizedAlias ? `${normalizedUploadDir || "/"} \xB7 ${normalizedAlias}` : normalizedUploadDir || "/",
556
- 18
557
- )
558
- )
559
- },
560
- {
561
- label: "\u6587\u4EF6:",
562
- value: chalk3.blue(`${files.length} \u4E2A \xB7 ${truncateTerminalText(outDir, 30)}`)
563
- }
564
- ],
565
- "info"
566
- )
567
- );
568
- try {
569
- const uploadExecution = await uploadFilesInBatches(client, files, concurrency);
570
- const { results, debugEntries: uploadDebugEntries } = uploadExecution;
571
- if (debug) {
572
- debugEntries.push(...uploadDebugEntries);
573
- }
574
- const successCount = results.filter((r) => r.success).length;
575
- const failedCount = results.length - successCount;
576
- const durationSeconds = (Date.now() - startTime) / 1e3;
577
- const uploadedBytes = results.reduce((sum, result) => result.success ? sum + result.size : sum, 0);
578
- const retryCount = results.reduce((sum, result) => sum + result.retries, 0);
579
- const avgSpeed = durationSeconds > 0 ? uploadedBytes / durationSeconds : 0;
580
- let manifestSummary = null;
581
- if (manifestFileName) {
582
- const manifestRelativeFilePath = manifestFileName;
583
- const manifestFilePath = normalizePath(resolve2(outDir, manifestRelativeFilePath));
584
- const manifestObjectKey = normalizeObjectKey(normalizedUploadDir, manifestRelativeFilePath);
585
- const manifestStartedAt = Date.now();
586
- await mkdir(dirname(manifestFilePath), { recursive: true });
587
- await writeFile(
588
- manifestFilePath,
589
- JSON.stringify(await createManifestPayload(results, normalizedConfigBase, normalizedAlias), null, 2),
590
- "utf8"
591
- );
592
- if (debug) {
593
- debugEntries.push({
594
- label: "\u751F\u6210\u6E05\u5355\u6587\u4EF6",
595
- durationMs: Date.now() - manifestStartedAt,
596
- detail: manifestRelativeFilePath
597
- });
598
- }
599
- const manifestStats = await stat(manifestFilePath);
600
- const manifestUploadStartedAt = Date.now();
601
- const manifestResult = await uploadSingleTask(client, {
602
- filePath: manifestFilePath,
603
- relativeFilePath: manifestRelativeFilePath,
604
- name: manifestObjectKey,
605
- size: manifestStats.size,
606
- cacheControl: "no-cache, no-store, must-revalidate"
607
- });
608
- if (!manifestResult.success) {
609
- throw manifestResult.error || new Error(`Failed to upload manifest: ${manifestRelativeFilePath}`);
610
- }
611
- if (debug) {
612
- debugEntries.push({
613
- label: "\u4E0A\u4F20\u6E05\u5355\u6587\u4EF6",
614
- durationMs: Date.now() - manifestUploadStartedAt,
615
- detail: manifestRelativeFilePath
616
- });
617
- }
618
- const manifestUrl = resolveUploadedFileUrl(
619
- manifestRelativeFilePath,
620
- manifestObjectKey,
621
- normalizedConfigBase,
622
- normalizedAlias
623
- );
624
- manifestSummary = truncateTerminalText(manifestUrl || manifestObjectKey, 20);
625
- }
626
- try {
627
- const cleanupStartedAt = Date.now();
628
- await removeEmptyDirectories(outDir);
629
- if (debug) {
630
- debugEntries.push({
631
- label: "\u6E05\u7406\u7A7A\u76EE\u5F55",
632
- durationMs: Date.now() - cleanupStartedAt
633
- });
634
- }
635
- } catch (error) {
636
- console.warn(`${getLogSymbol("warning")} \u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25: ${error}`);
637
- }
638
- const resultRows = [
639
- {
640
- label: "\u7ED3\u679C:",
641
- value: failedCount === 0 ? chalk3.green(`${successCount}/${results.length} \u5168\u90E8\u6210\u529F`) : chalk3.yellow(`\u6210\u529F ${successCount} \u4E2A\uFF0C\u5931\u8D25 ${failedCount} \u4E2A`)
642
- },
643
- {
644
- label: "\u7EDF\u8BA1:",
645
- value: renderInlineStats([
646
- `${retryCount} \u6B21\u91CD\u8BD5`,
647
- formatBytes(uploadedBytes),
648
- `${formatBytes(avgSpeed)}/s`,
649
- formatDuration(durationSeconds)
650
- ])
651
- },
652
- ...manifestSummary ? [{ label: "\u6E05\u5355:", value: chalk3.cyan(manifestSummary) }] : []
653
- ];
654
- if (failedCount > 0) {
655
- const failedItems = results.filter((result) => !result.success).slice(0, 2);
656
- resultRows.push(
657
- ...failedItems.map((item, index) => ({
658
- label: `\u5931\u8D25 ${index + 1}`,
659
- value: chalk3.red(
660
- `${truncateTerminalText(item.name, 26)} \xB7 ${truncateTerminalText(item.error?.message || "unknown error", 22)}`
661
- )
662
- }))
663
- );
664
- if (failedCount > failedItems.length) {
665
- resultRows.push({
666
- label: "\u5176\u4F59",
667
- value: chalk3.gray(`\u8FD8\u6709 ${failedCount - failedItems.length} \u4E2A\u5931\u8D25\u9879\u672A\u5C55\u5F00`)
668
- });
669
- }
670
- }
671
- console.log(
672
- renderPanel(
673
- failedCount === 0 ? `${getPanelDot("success")} \u90E8\u7F72\u5B8C\u6210` : `${getPanelDot("warning")} \u90E8\u7F72\u5B8C\u6210`,
674
- resultRows,
675
- failedCount === 0 ? "success" : "warning"
676
- )
677
- );
678
- if (debug) {
679
- debugEntries.push({
680
- label: "\u603B\u8017\u65F6",
681
- durationMs: Date.now() - startTime
682
- });
683
- console.log(renderDebugPanel(debugEntries));
684
- }
685
- if (failedCount > 0 && failOnError) {
686
- throw new Error(`Failed to upload ${failedCount} of ${results.length} files`);
687
- }
688
- } catch (error) {
689
- console.log(`
690
- ${getLogSymbol("danger")} \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF: ${error}
691
- `);
692
- if (debug && debugEntries.length > 0) {
693
- debugEntries.push({
694
- label: "\u5931\u8D25\u524D\u8017\u65F6",
695
- durationMs: Date.now() - startTime
696
- });
697
- console.log(renderDebugPanel(debugEntries));
698
- }
699
- if (failOnError) {
700
- throw error instanceof Error ? error : new Error(String(error));
701
- }
702
- }
703
45
  }
704
46
  }
705
47
  };
706
48
  }
707
49
  export {
708
- vitePluginDeployOss as default
50
+ vitePluginDeployOss as default,
51
+ defineDeployConfig,
52
+ deployOss
709
53
  };