vite-plugin-deploy-oss 3.2.1 → 3.3.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.d.ts +31 -3
- package/dist/index.js +269 -162
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import oss from 'ali-oss';
|
|
2
1
|
import { Plugin } from 'vite';
|
|
2
|
+
import oss from 'ali-oss';
|
|
3
3
|
|
|
4
4
|
interface ManifestOption {
|
|
5
5
|
fileName?: string;
|
|
6
6
|
}
|
|
7
|
+
type ManifestConfig = boolean | ManifestOption | undefined;
|
|
7
8
|
interface vitePluginDeployOssOption extends Omit<oss.Options, 'accessKeyId' | 'accessKeySecret' | 'bucket' | 'region'> {
|
|
8
9
|
configBase?: string;
|
|
9
10
|
accessKeyId: string;
|
|
@@ -23,8 +24,35 @@ interface vitePluginDeployOssOption extends Omit<oss.Options, 'accessKeyId' | 'a
|
|
|
23
24
|
concurrency?: number;
|
|
24
25
|
retryTimes?: number;
|
|
25
26
|
multipartThreshold?: number;
|
|
26
|
-
manifest?:
|
|
27
|
+
manifest?: ManifestConfig;
|
|
28
|
+
}
|
|
29
|
+
interface UploadResult {
|
|
30
|
+
success: boolean;
|
|
31
|
+
file: string;
|
|
32
|
+
relativeFilePath: string;
|
|
33
|
+
name: string;
|
|
34
|
+
size: number;
|
|
35
|
+
retries: number;
|
|
36
|
+
error?: Error;
|
|
37
|
+
}
|
|
38
|
+
interface UploadTask {
|
|
39
|
+
filePath: string;
|
|
40
|
+
relativeFilePath: string;
|
|
41
|
+
name: string;
|
|
42
|
+
size: number;
|
|
43
|
+
cacheControl?: string;
|
|
27
44
|
}
|
|
45
|
+
interface ManifestFileItem {
|
|
46
|
+
file: string;
|
|
47
|
+
key: string;
|
|
48
|
+
url: string;
|
|
49
|
+
md5: string;
|
|
50
|
+
}
|
|
51
|
+
interface ManifestPayload {
|
|
52
|
+
version: number;
|
|
53
|
+
files: ManifestFileItem[];
|
|
54
|
+
}
|
|
55
|
+
|
|
28
56
|
declare function vitePluginDeployOss(option: vitePluginDeployOssOption): Plugin;
|
|
29
57
|
|
|
30
|
-
export { vitePluginDeployOss as default, type vitePluginDeployOssOption };
|
|
58
|
+
export { type ManifestConfig, type ManifestFileItem, type ManifestOption, type ManifestPayload, type UploadResult, type UploadTask, vitePluginDeployOss as default, type vitePluginDeployOssOption };
|
package/dist/index.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import oss from "ali-oss";
|
|
3
|
-
import
|
|
3
|
+
import chalk3 from "chalk";
|
|
4
|
+
import cliProgress from "cli-progress";
|
|
4
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
|
|
5
11
|
import { createHash } from "crypto";
|
|
6
12
|
import { createReadStream } from "fs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import { normalizePath } from "vite";
|
|
13
|
+
import { readdir, rm } from "fs/promises";
|
|
14
|
+
import { resolve } from "path";
|
|
15
|
+
var GARBAGE_FILE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
|
|
11
16
|
var getFileMd5 = (filePath) => {
|
|
12
|
-
return new Promise((
|
|
17
|
+
return new Promise((resolvePromise, reject) => {
|
|
13
18
|
const hash = createHash("md5");
|
|
14
19
|
const stream = createReadStream(filePath);
|
|
15
20
|
stream.on("error", (err) => reject(err));
|
|
16
21
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
17
|
-
stream.on("end", () =>
|
|
22
|
+
stream.on("end", () => resolvePromise(hash.digest("hex")));
|
|
18
23
|
});
|
|
19
24
|
};
|
|
20
|
-
var GARBAGE_FILE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
|
|
21
|
-
var DEFAULT_MANIFEST_FILE_NAME = "oss-manifest.json";
|
|
22
25
|
var removeEmptyDirectories = async (rootDir) => {
|
|
23
26
|
const deletedDirectories = [];
|
|
24
27
|
const visit = async (dirPath) => {
|
|
@@ -43,9 +46,53 @@ var removeEmptyDirectories = async (rootDir) => {
|
|
|
43
46
|
await visit(resolve(rootDir));
|
|
44
47
|
return deletedDirectories;
|
|
45
48
|
};
|
|
46
|
-
|
|
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);
|
|
47
94
|
var normalizeManifestFileName = (fileName) => {
|
|
48
|
-
const normalized =
|
|
95
|
+
const normalized = normalizePathSegments(fileName || DEFAULT_MANIFEST_FILE_NAME);
|
|
49
96
|
return normalized || DEFAULT_MANIFEST_FILE_NAME;
|
|
50
97
|
};
|
|
51
98
|
var resolveManifestFileName = (manifest) => {
|
|
@@ -53,46 +100,16 @@ var resolveManifestFileName = (manifest) => {
|
|
|
53
100
|
if (manifest === true) return DEFAULT_MANIFEST_FILE_NAME;
|
|
54
101
|
return normalizeManifestFileName(manifest.fileName);
|
|
55
102
|
};
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
const protocolSeparatorIndex = normalized.indexOf("://");
|
|
59
|
-
if (protocolSeparatorIndex >= 0) {
|
|
60
|
-
const pathIndex = normalized.indexOf("/", protocolSeparatorIndex + 3);
|
|
61
|
-
if (pathIndex < 0) return normalized;
|
|
62
|
-
return `${normalized.slice(0, pathIndex)}${normalized.slice(pathIndex).replace(/\/{2,}/g, "/")}`;
|
|
63
|
-
}
|
|
64
|
-
if (normalized.startsWith("//")) {
|
|
65
|
-
const pathIndex = normalized.indexOf("/", 2);
|
|
66
|
-
if (pathIndex < 0) return normalized;
|
|
67
|
-
return `${normalized.slice(0, pathIndex)}${normalized.slice(pathIndex).replace(/\/{2,}/g, "/")}`;
|
|
68
|
-
}
|
|
69
|
-
return normalized.replace(/\/{2,}/g, "/");
|
|
70
|
-
};
|
|
71
|
-
var encodeUrlPath = (path) => encodeURI(path.replace(/^\/+/, ""));
|
|
72
|
-
var joinUrlPath = (base, path) => `${normalizeUrlBase(base).replace(/\/+$/, "")}/${encodeUrlPath(path)}`;
|
|
103
|
+
var encodeUrlPath = (path) => encodeURI(normalizePathSegments(path));
|
|
104
|
+
var joinUrlPath = (base, path) => `${normalizeUrlLikeBase(base).replace(/\/+$/, "")}/${encodeUrlPath(path)}`;
|
|
73
105
|
var resolveUploadedFileUrl = (relativeFilePath, objectKey, configBase, alias) => {
|
|
74
106
|
if (configBase) return joinUrlPath(configBase, relativeFilePath);
|
|
75
107
|
if (alias) return joinUrlPath(alias, objectKey);
|
|
76
108
|
return objectKey;
|
|
77
109
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
successfulResults.map(async (result) => {
|
|
82
|
-
const md5 = await getFileMd5(result.file);
|
|
83
|
-
return {
|
|
84
|
-
file: result.relativeFilePath,
|
|
85
|
-
key: result.name,
|
|
86
|
-
url: resolveUploadedFileUrl(result.relativeFilePath, result.name, configBase, alias),
|
|
87
|
-
md5
|
|
88
|
-
};
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
return {
|
|
92
|
-
version: Date.now(),
|
|
93
|
-
files
|
|
94
|
-
};
|
|
95
|
-
};
|
|
110
|
+
|
|
111
|
+
// src/utils/progress.ts
|
|
112
|
+
import chalk from "chalk";
|
|
96
113
|
var formatBytes = (bytes) => {
|
|
97
114
|
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
98
115
|
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
@@ -113,24 +130,84 @@ var formatDuration = (seconds) => {
|
|
|
113
130
|
if (mins === 0) return `${secs}s`;
|
|
114
131
|
return `${mins}m${String(secs).padStart(2, "0")}s`;
|
|
115
132
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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"
|
|
122
144
|
};
|
|
123
|
-
var
|
|
124
|
-
|
|
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) => {
|
|
125
149
|
if (width <= 0) return "";
|
|
126
|
-
|
|
127
|
-
|
|
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" })));
|
|
128
173
|
}
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
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 getLogSymbol = (tone) => {
|
|
183
|
+
switch (tone) {
|
|
184
|
+
case "success":
|
|
185
|
+
return logSymbols.success;
|
|
186
|
+
case "warning":
|
|
187
|
+
return logSymbols.warning;
|
|
188
|
+
case "danger":
|
|
189
|
+
return logSymbols.error;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/index.ts
|
|
194
|
+
var createManifestPayload = async (results, configBase, alias) => {
|
|
195
|
+
const successfulResults = results.filter((result) => result.success);
|
|
196
|
+
const files = await Promise.all(
|
|
197
|
+
successfulResults.map(async (result) => {
|
|
198
|
+
const md5 = await getFileMd5(result.file);
|
|
199
|
+
return {
|
|
200
|
+
file: result.relativeFilePath,
|
|
201
|
+
key: result.name,
|
|
202
|
+
url: resolveUploadedFileUrl(result.relativeFilePath, result.name, configBase, alias),
|
|
203
|
+
md5
|
|
204
|
+
};
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
return {
|
|
208
|
+
version: Date.now(),
|
|
209
|
+
files
|
|
210
|
+
};
|
|
134
211
|
};
|
|
135
212
|
function vitePluginDeployOss(option) {
|
|
136
213
|
const {
|
|
@@ -155,12 +232,15 @@ function vitePluginDeployOss(option) {
|
|
|
155
232
|
manifest = false,
|
|
156
233
|
...props
|
|
157
234
|
} = option || {};
|
|
235
|
+
const normalizedUploadDir = normalizePathSegments(uploadDir);
|
|
236
|
+
const normalizedConfigBase = configBase ? ensureTrailingSlash(normalizeUrlLikeBase(configBase)) : void 0;
|
|
237
|
+
const normalizedAlias = alias ? normalizeUrlLikeBase(alias) : void 0;
|
|
158
238
|
let buildFailed = false;
|
|
159
239
|
let upload = false;
|
|
160
|
-
let outDir = normalizePath(
|
|
240
|
+
let outDir = normalizePath(resolve2("dist"));
|
|
161
241
|
let resolvedConfig = null;
|
|
162
242
|
const useInteractiveOutput = fancy && Boolean(process.stdout?.isTTY) && Boolean(process.stderr?.isTTY) && !process.env.CI;
|
|
163
|
-
const
|
|
243
|
+
const clearViewport = () => {
|
|
164
244
|
if (!useInteractiveOutput) return;
|
|
165
245
|
process.stdout.write("\x1B[2J\x1B[0f");
|
|
166
246
|
};
|
|
@@ -173,8 +253,7 @@ function vitePluginDeployOss(option) {
|
|
|
173
253
|
if (!uploadDir) errors.push("uploadDir is required");
|
|
174
254
|
if (!Number.isInteger(retryTimes) || retryTimes < 1) errors.push("retryTimes must be >= 1");
|
|
175
255
|
if (!Number.isInteger(concurrency) || concurrency < 1) errors.push("concurrency must be >= 1");
|
|
176
|
-
if (!Number.isFinite(multipartThreshold) || multipartThreshold <= 0)
|
|
177
|
-
errors.push("multipartThreshold must be > 0");
|
|
256
|
+
if (!Number.isFinite(multipartThreshold) || multipartThreshold <= 0) errors.push("multipartThreshold must be > 0");
|
|
178
257
|
return errors;
|
|
179
258
|
};
|
|
180
259
|
const uploadSingleTask = async (client, task) => uploadFileWithRetry(client, task, false);
|
|
@@ -202,7 +281,9 @@ function vitePluginDeployOss(option) {
|
|
|
202
281
|
try {
|
|
203
282
|
await unlink(task.filePath);
|
|
204
283
|
} catch (error) {
|
|
205
|
-
console.warn(
|
|
284
|
+
console.warn(
|
|
285
|
+
`${getLogSymbol("warning")} \u5220\u9664\u672C\u5730\u6587\u4EF6\u5931\u8D25: ${truncateTerminalText(task.relativeFilePath, 18)}`
|
|
286
|
+
);
|
|
206
287
|
}
|
|
207
288
|
}
|
|
208
289
|
return {
|
|
@@ -219,9 +300,8 @@ function vitePluginDeployOss(option) {
|
|
|
219
300
|
} catch (error) {
|
|
220
301
|
if (attempt === maxRetries) {
|
|
221
302
|
if (!silentLogs) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
);
|
|
303
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
304
|
+
console.log(`${getLogSymbol("danger")} ${truncateTerminalText(task.relativeFilePath, 18)} ${reason}`);
|
|
225
305
|
}
|
|
226
306
|
return {
|
|
227
307
|
success: false,
|
|
@@ -234,9 +314,11 @@ function vitePluginDeployOss(option) {
|
|
|
234
314
|
};
|
|
235
315
|
} else {
|
|
236
316
|
if (!silentLogs) {
|
|
237
|
-
console.log(
|
|
317
|
+
console.log(
|
|
318
|
+
`${getLogSymbol("warning")} ${truncateTerminalText(task.relativeFilePath, 18)} \u6B63\u5728\u91CD\u8BD5 (${attempt}/${maxRetries})`
|
|
319
|
+
);
|
|
238
320
|
}
|
|
239
|
-
await new Promise((
|
|
321
|
+
await new Promise((resolve3) => setTimeout(resolve3, 1e3 * attempt));
|
|
240
322
|
}
|
|
241
323
|
}
|
|
242
324
|
}
|
|
@@ -260,8 +342,8 @@ function vitePluginDeployOss(option) {
|
|
|
260
342
|
let retries = 0;
|
|
261
343
|
const taskCandidates = await Promise.all(
|
|
262
344
|
files.map(async (relativeFilePath) => {
|
|
263
|
-
const filePath = normalizePath(
|
|
264
|
-
const name = normalizeObjectKey(
|
|
345
|
+
const filePath = normalizePath(resolve2(outDir, relativeFilePath));
|
|
346
|
+
const name = normalizeObjectKey(normalizedUploadDir, relativeFilePath);
|
|
265
347
|
try {
|
|
266
348
|
const fileStats = await stat(filePath);
|
|
267
349
|
return { task: { filePath, relativeFilePath, name, size: fileStats.size } };
|
|
@@ -289,47 +371,58 @@ function vitePluginDeployOss(option) {
|
|
|
289
371
|
}
|
|
290
372
|
const totalBytes = tasks.reduce((sum, task) => sum + task.size, 0);
|
|
291
373
|
const startAt = Date.now();
|
|
292
|
-
const activeFiles = /* @__PURE__ */ new Set();
|
|
293
374
|
const safeWindowSize = Math.max(1, Math.min(windowSize, tasks.length || 1));
|
|
294
375
|
const silentLogs = Boolean(useInteractiveOutput);
|
|
295
|
-
const
|
|
296
|
-
|
|
376
|
+
const progressBar = useInteractiveOutput ? new cliProgress.SingleBar({
|
|
377
|
+
hideCursor: true,
|
|
378
|
+
clearOnComplete: true,
|
|
379
|
+
stopOnComplete: true,
|
|
380
|
+
barsize: 18,
|
|
381
|
+
barCompleteChar: "\u2588",
|
|
382
|
+
barIncompleteChar: "\u2591",
|
|
383
|
+
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`
|
|
384
|
+
}) : null;
|
|
385
|
+
const reportEvery = Math.max(1, Math.ceil(totalFiles / 6));
|
|
297
386
|
let lastReportedCompleted = -1;
|
|
387
|
+
if (progressBar) {
|
|
388
|
+
progressBar.start(totalFiles, 0, {
|
|
389
|
+
speed: formatBytes(0),
|
|
390
|
+
elapsed: "0"
|
|
391
|
+
});
|
|
392
|
+
}
|
|
298
393
|
const updateProgress = () => {
|
|
299
|
-
const progressRatio = totalFiles > 0 ? completed / totalFiles : 1;
|
|
300
|
-
const percentage = Math.round(progressRatio * 100);
|
|
301
394
|
const elapsedSeconds = (Date.now() - startAt) / 1e3;
|
|
302
395
|
const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
396
|
+
if (!progressBar) {
|
|
397
|
+
const progressRatio = totalFiles > 0 ? completed / totalFiles : 1;
|
|
398
|
+
const percentage = Math.round(progressRatio * 100);
|
|
399
|
+
if (completed === 0 && totalFiles > 0) return;
|
|
307
400
|
if (completed === lastReportedCompleted) return;
|
|
308
401
|
if (completed === totalFiles || completed % reportEvery === 0) {
|
|
309
402
|
console.log(
|
|
310
|
-
`${
|
|
403
|
+
`${chalk3.gray("\u4E0A\u4F20\u8FDB\u5EA6")} ${renderInlineStats([
|
|
404
|
+
chalk3.bold(`${completed}/${totalFiles}`),
|
|
405
|
+
`${percentage}%`,
|
|
406
|
+
`${formatBytes(uploadedBytes)}/${formatBytes(totalBytes)}`,
|
|
407
|
+
`${formatBytes(speed)}/s`
|
|
408
|
+
])}`
|
|
311
409
|
);
|
|
312
410
|
lastReportedCompleted = completed;
|
|
313
411
|
}
|
|
314
412
|
return;
|
|
315
413
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
`${chalk.cyan("\u6B63\u5728\u4E0A\u4F20:")} ${chalk.white(currentFile)}`,
|
|
321
|
-
`${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))}`
|
|
322
|
-
].join("\n");
|
|
323
|
-
spinner.text += warnLine;
|
|
414
|
+
progressBar.update(completed, {
|
|
415
|
+
speed: chalk3.magenta(formatBytes(speed)),
|
|
416
|
+
elapsed: formatDuration(elapsedSeconds).replace(/s$/, "")
|
|
417
|
+
});
|
|
324
418
|
};
|
|
325
|
-
const refreshTimer =
|
|
419
|
+
const refreshTimer = progressBar ? setInterval(updateProgress, 120) : null;
|
|
326
420
|
let currentIndex = 0;
|
|
327
421
|
const worker = async () => {
|
|
328
422
|
while (true) {
|
|
329
423
|
const index = currentIndex++;
|
|
330
424
|
if (index >= tasks.length) return;
|
|
331
425
|
const task = tasks[index];
|
|
332
|
-
activeFiles.add(task.name);
|
|
333
426
|
updateProgress();
|
|
334
427
|
const result = await uploadFileWithRetry(client, task, silentLogs);
|
|
335
428
|
completed++;
|
|
@@ -340,7 +433,6 @@ ${chalk.yellow("\u91CD\u8BD5")}: ${retries} ${chalk.yellow("\u5931\u8D25")}: ${
|
|
|
340
433
|
failed++;
|
|
341
434
|
}
|
|
342
435
|
results.push(result);
|
|
343
|
-
activeFiles.delete(task.name);
|
|
344
436
|
updateProgress();
|
|
345
437
|
}
|
|
346
438
|
};
|
|
@@ -350,16 +442,16 @@ ${chalk.yellow("\u91CD\u8BD5")}: ${retries} ${chalk.yellow("\u5931\u8D25")}: ${
|
|
|
350
442
|
} finally {
|
|
351
443
|
if (refreshTimer) clearInterval(refreshTimer);
|
|
352
444
|
}
|
|
353
|
-
if (
|
|
445
|
+
if (progressBar) {
|
|
354
446
|
const elapsedSeconds = (Date.now() - startAt) / 1e3;
|
|
355
|
-
const successCount = results.filter((item) => item.success).length;
|
|
356
447
|
const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
);
|
|
448
|
+
progressBar.update(totalFiles, {
|
|
449
|
+
speed: chalk3.magenta(formatBytes(speed)),
|
|
450
|
+
elapsed: formatDuration(elapsedSeconds).replace(/s$/, "")
|
|
451
|
+
});
|
|
452
|
+
progressBar.stop();
|
|
361
453
|
} else {
|
|
362
|
-
console.log(`${
|
|
454
|
+
console.log(`${getLogSymbol("success")} \u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210 (${totalFiles}/${totalFiles})`);
|
|
363
455
|
}
|
|
364
456
|
return results;
|
|
365
457
|
};
|
|
@@ -372,20 +464,19 @@ ${buildCapsuleBar(1)} 100% (${totalFiles}/${totalFiles}) ${chalk.gray("|")} \u90
|
|
|
372
464
|
},
|
|
373
465
|
config(config) {
|
|
374
466
|
if (!open || buildFailed) return;
|
|
375
|
-
clearScreen();
|
|
376
467
|
const validationErrors = validateOptions();
|
|
377
468
|
if (validationErrors.length > 0) {
|
|
378
|
-
console.log(`${
|
|
469
|
+
console.log(`${chalk3.red("\u2717 \u914D\u7F6E\u9519\u8BEF:")}
|
|
379
470
|
${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
|
|
380
471
|
return;
|
|
381
472
|
}
|
|
382
473
|
upload = true;
|
|
383
|
-
config.base =
|
|
474
|
+
config.base = normalizedConfigBase || config.base;
|
|
384
475
|
return config;
|
|
385
476
|
},
|
|
386
477
|
configResolved(config) {
|
|
387
478
|
resolvedConfig = config;
|
|
388
|
-
outDir = normalizePath(
|
|
479
|
+
outDir = normalizePath(resolve2(config.root, config.build.outDir));
|
|
389
480
|
},
|
|
390
481
|
closeBundle: {
|
|
391
482
|
sequential: true,
|
|
@@ -401,69 +492,49 @@ ${validationErrors.map((err) => ` - ${err}`).join("\n")}`);
|
|
|
401
492
|
ignore: Array.isArray(skip) ? skip : [skip]
|
|
402
493
|
}).map((file) => normalizePath(file)).filter((file) => file !== manifestFileName);
|
|
403
494
|
if (files.length === 0) {
|
|
404
|
-
console.log(`${
|
|
495
|
+
console.log(`${getLogSymbol("warning")} \u6CA1\u6709\u627E\u5230\u9700\u8981\u4E0A\u4F20\u7684\u6587\u4EF6`);
|
|
405
496
|
return;
|
|
406
497
|
}
|
|
407
|
-
|
|
408
|
-
console.log(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
`
|
|
498
|
+
clearViewport();
|
|
499
|
+
console.log(
|
|
500
|
+
renderPanel(
|
|
501
|
+
"\u51C6\u5907\u90E8\u7F72",
|
|
502
|
+
[
|
|
503
|
+
{ label: "\u4F4D\u7F6E:", value: chalk3.green(`${bucket} \xB7 ${region}`) },
|
|
504
|
+
{
|
|
505
|
+
label: "\u76EE\u6807:",
|
|
506
|
+
value: chalk3.yellow(
|
|
507
|
+
truncateTerminalText(
|
|
508
|
+
normalizedAlias ? `${normalizedUploadDir || "/"} \xB7 ${normalizedAlias}` : normalizedUploadDir || "/",
|
|
509
|
+
18
|
|
510
|
+
)
|
|
511
|
+
)
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
label: "\u6587\u4EF6:",
|
|
515
|
+
value: chalk3.blue(`${files.length} \u4E2A \xB7 ${truncateTerminalText(outDir, 30)}`)
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
"info"
|
|
519
|
+
)
|
|
520
|
+
);
|
|
418
521
|
try {
|
|
419
522
|
const results = await uploadFilesInBatches(client, files, concurrency);
|
|
420
523
|
const successCount = results.filter((r) => r.success).length;
|
|
421
524
|
const failedCount = results.length - successCount;
|
|
422
525
|
const durationSeconds = (Date.now() - startTime) / 1e3;
|
|
423
|
-
const duration = durationSeconds.toFixed(2);
|
|
424
526
|
const uploadedBytes = results.reduce((sum, result) => result.success ? sum + result.size : sum, 0);
|
|
425
527
|
const retryCount = results.reduce((sum, result) => sum + result.retries, 0);
|
|
426
528
|
const avgSpeed = durationSeconds > 0 ? uploadedBytes / durationSeconds : 0;
|
|
427
|
-
|
|
428
|
-
console.log("\n" + chalk.gray("\u2500".repeat(40)) + "\n");
|
|
429
|
-
if (failedCount === 0) {
|
|
430
|
-
console.log(`${chalk.green("\u{1F389} \u90E8\u7F72\u6210\u529F!")}`);
|
|
431
|
-
} else {
|
|
432
|
-
console.log(`${chalk.yellow("\u26A0 \u90E8\u7F72\u5B8C\u6210\u4F46\u5B58\u5728\u9519\u8BEF")}`);
|
|
433
|
-
}
|
|
434
|
-
console.log(`
|
|
435
|
-
${chalk.gray("\u7EDF\u8BA1:")}`);
|
|
436
|
-
console.log(` ${chalk.green("\u2714")} \u6210\u529F: ${chalk.bold(successCount)}`);
|
|
437
|
-
if (failedCount > 0) {
|
|
438
|
-
console.log(` ${chalk.red("\u2717")} \u5931\u8D25: ${chalk.bold(failedCount)}`);
|
|
439
|
-
}
|
|
440
|
-
console.log(` ${chalk.cyan("\u21C4")} \u91CD\u8BD5: ${chalk.bold(retryCount)}`);
|
|
441
|
-
console.log(` ${chalk.blue("\u{1F4E6}")} \u6570\u636E: ${chalk.bold(formatBytes(uploadedBytes))}`);
|
|
442
|
-
console.log(` ${chalk.magenta("\u26A1")} \u5E73\u5747\u901F\u5EA6: ${chalk.bold(`${formatBytes(avgSpeed)}/s`)}`);
|
|
443
|
-
console.log(` ${chalk.blue("\u23F1")} \u8017\u65F6: ${chalk.bold(duration)}s`);
|
|
444
|
-
console.log("");
|
|
445
|
-
if (failedCount > 0) {
|
|
446
|
-
const failedItems = results.filter((result) => !result.success);
|
|
447
|
-
const previewCount = Math.min(5, failedItems.length);
|
|
448
|
-
console.log(chalk.red("\u5931\u8D25\u660E\u7EC6:"));
|
|
449
|
-
for (let i = 0; i < previewCount; i++) {
|
|
450
|
-
const item = failedItems[i];
|
|
451
|
-
const reason = item.error?.message || "unknown error";
|
|
452
|
-
console.log(` ${chalk.red("\u2022")} ${item.name} => ${reason}`);
|
|
453
|
-
}
|
|
454
|
-
if (failedItems.length > previewCount) {
|
|
455
|
-
console.log(chalk.gray(` ... \u8FD8\u6709 ${failedItems.length - previewCount} \u4E2A\u5931\u8D25\u6587\u4EF6`));
|
|
456
|
-
}
|
|
457
|
-
console.log("");
|
|
458
|
-
}
|
|
529
|
+
let manifestSummary = null;
|
|
459
530
|
if (manifestFileName) {
|
|
460
531
|
const manifestRelativeFilePath = manifestFileName;
|
|
461
|
-
const manifestFilePath = normalizePath(
|
|
462
|
-
const manifestObjectKey = normalizeObjectKey(
|
|
532
|
+
const manifestFilePath = normalizePath(resolve2(outDir, manifestRelativeFilePath));
|
|
533
|
+
const manifestObjectKey = normalizeObjectKey(normalizedUploadDir, manifestRelativeFilePath);
|
|
463
534
|
await mkdir(dirname(manifestFilePath), { recursive: true });
|
|
464
535
|
await writeFile(
|
|
465
536
|
manifestFilePath,
|
|
466
|
-
JSON.stringify(await createManifestPayload(results,
|
|
537
|
+
JSON.stringify(await createManifestPayload(results, normalizedConfigBase, normalizedAlias), null, 2),
|
|
467
538
|
"utf8"
|
|
468
539
|
);
|
|
469
540
|
const manifestStats = await stat(manifestFilePath);
|
|
@@ -480,26 +551,62 @@ ${chalk.gray("\u7EDF\u8BA1:")}`);
|
|
|
480
551
|
const manifestUrl = resolveUploadedFileUrl(
|
|
481
552
|
manifestRelativeFilePath,
|
|
482
553
|
manifestObjectKey,
|
|
483
|
-
|
|
484
|
-
|
|
554
|
+
normalizedConfigBase,
|
|
555
|
+
normalizedAlias
|
|
485
556
|
);
|
|
486
|
-
|
|
487
|
-
console.log(` ${chalk.gray("File:")} ${chalk.yellow(manifestFilePath)}`);
|
|
488
|
-
console.log(` ${chalk.gray("Target:")} ${chalk.yellow(manifestObjectKey)}`);
|
|
489
|
-
console.log(` ${chalk.gray("URL:")} ${chalk.green(manifestUrl)}`);
|
|
490
|
-
console.log("");
|
|
557
|
+
manifestSummary = truncateTerminalText(manifestUrl || manifestObjectKey, 20);
|
|
491
558
|
}
|
|
492
559
|
try {
|
|
493
560
|
await removeEmptyDirectories(outDir);
|
|
494
561
|
} catch (error) {
|
|
495
|
-
console.warn(`${
|
|
562
|
+
console.warn(`${getLogSymbol("warning")} \u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25: ${error}`);
|
|
496
563
|
}
|
|
564
|
+
const resultRows = [
|
|
565
|
+
{
|
|
566
|
+
label: "\u7ED3\u679C:",
|
|
567
|
+
value: failedCount === 0 ? chalk3.green(`${successCount}/${results.length} \u5168\u90E8\u6210\u529F`) : chalk3.yellow(`\u6210\u529F ${successCount} \u4E2A\uFF0C\u5931\u8D25 ${failedCount} \u4E2A`)
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
label: "\u7EDF\u8BA1:",
|
|
571
|
+
value: renderInlineStats([
|
|
572
|
+
`${retryCount} \u6B21\u91CD\u8BD5`,
|
|
573
|
+
formatBytes(uploadedBytes),
|
|
574
|
+
`${formatBytes(avgSpeed)}/s`,
|
|
575
|
+
formatDuration(durationSeconds)
|
|
576
|
+
])
|
|
577
|
+
},
|
|
578
|
+
...manifestSummary ? [{ label: "\u6E05\u5355:", value: chalk3.cyan(manifestSummary) }] : []
|
|
579
|
+
];
|
|
580
|
+
if (failedCount > 0) {
|
|
581
|
+
const failedItems = results.filter((result) => !result.success).slice(0, 2);
|
|
582
|
+
resultRows.push(
|
|
583
|
+
...failedItems.map((item, index) => ({
|
|
584
|
+
label: `\u5931\u8D25 ${index + 1}`,
|
|
585
|
+
value: chalk3.red(
|
|
586
|
+
`${truncateTerminalText(item.name, 26)} \xB7 ${truncateTerminalText(item.error?.message || "unknown error", 22)}`
|
|
587
|
+
)
|
|
588
|
+
}))
|
|
589
|
+
);
|
|
590
|
+
if (failedCount > failedItems.length) {
|
|
591
|
+
resultRows.push({
|
|
592
|
+
label: "\u5176\u4F59",
|
|
593
|
+
value: chalk3.gray(`\u8FD8\u6709 ${failedCount - failedItems.length} \u4E2A\u5931\u8D25\u9879\u672A\u5C55\u5F00`)
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
console.log(
|
|
598
|
+
renderPanel(
|
|
599
|
+
failedCount === 0 ? `${getLogSymbol("success")} \u90E8\u7F72\u5B8C\u6210` : `${getLogSymbol("warning")} \u90E8\u7F72\u5B8C\u6210`,
|
|
600
|
+
resultRows,
|
|
601
|
+
failedCount === 0 ? "success" : "warning"
|
|
602
|
+
)
|
|
603
|
+
);
|
|
497
604
|
if (failedCount > 0 && failOnError) {
|
|
498
605
|
throw new Error(`Failed to upload ${failedCount} of ${results.length} files`);
|
|
499
606
|
}
|
|
500
607
|
} catch (error) {
|
|
501
608
|
console.log(`
|
|
502
|
-
${
|
|
609
|
+
${getLogSymbol("danger")} \u4E0A\u4F20\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF: ${error}
|
|
503
610
|
`);
|
|
504
611
|
if (failOnError) {
|
|
505
612
|
throw error instanceof Error ? error : new Error(String(error));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-deploy-oss",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -40,10 +40,14 @@
|
|
|
40
40
|
"vite": "^6.0.3 || ^7 || ^8"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@types/cli-progress": "^3.11.6",
|
|
43
44
|
"ali-oss": "^6.23.0",
|
|
44
45
|
"chalk": "^5.6.2",
|
|
46
|
+
"cli-progress": "^3.12.0",
|
|
47
|
+
"cli-truncate": "^5.2.0",
|
|
45
48
|
"glob": "^13.0.6",
|
|
46
|
-
"
|
|
49
|
+
"log-symbols": "^7.0.1",
|
|
50
|
+
"string-width": "^8.2.0"
|
|
47
51
|
},
|
|
48
52
|
"scripts": {
|
|
49
53
|
"build": "tsup",
|