@ruan-cat/vercel-deploy-tool 0.12.2 → 1.1.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 ADDED
@@ -0,0 +1,566 @@
1
+ // src/config/define-config.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+
6
+ // src/config/loader.ts
7
+ import { loadConfig as c12LoadConfig } from "c12";
8
+ import { consola } from "consola";
9
+ import { isUndefined } from "lodash-es";
10
+ import { config as dotenvxConfig } from "@dotenvx/dotenvx";
11
+ import { printFormat } from "@ruan-cat/utils";
12
+ var CONFIG_NAME = "vercel-deploy-tool";
13
+ var DEFAULT_CONFIG = {
14
+ vercelProjectName: "",
15
+ vercelToken: "",
16
+ vercelOrgId: "",
17
+ vercelProjectId: "",
18
+ deployTargets: []
19
+ };
20
+ async function loadConfig() {
21
+ consola.start("\u5F00\u59CB\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6 vercel-deploy-tool.config.* ...");
22
+ const envPath = process.env.VERCEL_DEPLOY_TOOL_ENV_PATH;
23
+ if (envPath) {
24
+ dotenvxConfig({ path: envPath });
25
+ consola.info(`\u5DF2\u4ECE VERCEL_DEPLOY_TOOL_ENV_PATH \u52A0\u8F7D dotenv: ${envPath}`);
26
+ }
27
+ let config;
28
+ const loaded = await c12LoadConfig({
29
+ cwd: process.cwd(),
30
+ name: CONFIG_NAME,
31
+ dotenv: true,
32
+ defaults: DEFAULT_CONFIG
33
+ });
34
+ config = loaded.config;
35
+ const vercelOrgId = process.env.VERCEL_ORG_ID;
36
+ const vercelProjectId = process.env.VERCEL_PROJECT_ID;
37
+ const vercelToken = process.env.VERCEL_TOKEN;
38
+ if (!isUndefined(vercelOrgId)) {
39
+ config.vercelOrgId = vercelOrgId;
40
+ }
41
+ if (!isUndefined(vercelProjectId)) {
42
+ config.vercelProjectId = vercelProjectId;
43
+ }
44
+ if (!isUndefined(vercelToken)) {
45
+ config.vercelToken = vercelToken;
46
+ }
47
+ consola.success("\u914D\u7F6E\u52A0\u8F7D\u5B8C\u6210");
48
+ consola.box(printFormat(config));
49
+ return config;
50
+ }
51
+ var cachedConfigPromise = null;
52
+ async function getConfig() {
53
+ if (!cachedConfigPromise) {
54
+ cachedConfigPromise = loadConfig();
55
+ }
56
+ return cachedConfigPromise;
57
+ }
58
+
59
+ // src/core/tasks/index.ts
60
+ import fs4 from "fs";
61
+ import { resolve as resolve5 } from "path";
62
+ import { consola as consola9 } from "consola";
63
+
64
+ // src/core/executor.ts
65
+ import task from "tasuku";
66
+ async function executeSequential(title, tasks) {
67
+ const results = [];
68
+ for (const t of tasks) {
69
+ const result = await task(t.name, t.fn);
70
+ results.push(result.result);
71
+ }
72
+ return results;
73
+ }
74
+
75
+ // src/utils/type-guards.ts
76
+ function isDeployTargetBase(target) {
77
+ return target.type === "static";
78
+ }
79
+ function isDeployTargetWithUserCommands(target) {
80
+ return target.type === "userCommands";
81
+ }
82
+ function getIsCopyDist(target) {
83
+ return target.isCopyDist ?? true;
84
+ }
85
+ function isNeedVercelBuild(target) {
86
+ return target.isNeedVercelBuild ?? true;
87
+ }
88
+
89
+ // src/utils/vercel-null-config.ts
90
+ var VERCEL_NULL_CONFIG = {
91
+ framework: null,
92
+ buildCommand: null,
93
+ installCommand: null,
94
+ outputDirectory: null,
95
+ devCommand: null,
96
+ public: false,
97
+ /**
98
+ * 部署后提供干净的链接
99
+ * @see https://vercel.com/docs/projects/project-configuration#cleanurls
100
+ *
101
+ * @description
102
+ * 暂无效果
103
+ *
104
+ * 目前在 build-output-api 中,实现cleanUrls需要手动地写入配置文件
105
+ *
106
+ * 成本较大,目前不做投入。
107
+ */
108
+ cleanUrls: true,
109
+ git: {
110
+ deploymentEnabled: {
111
+ main: false
112
+ }
113
+ }
114
+ };
115
+ var VERCEL_NULL_CONFIG_PATH = "./vercel.null.def.json";
116
+ var VERCEL_OUTPUT_STATIC = ".vercel/output/static";
117
+
118
+ // src/core/tasks/link.ts
119
+ import fs from "fs";
120
+ import { resolve } from "path";
121
+ import { spawnSync } from "child_process";
122
+ import { concat } from "lodash-es";
123
+ import { consola as consola2 } from "consola";
124
+
125
+ // src/core/vercel.ts
126
+ function getVercelProjectNameArg(config) {
127
+ return ["--project", config.vercelProjectName];
128
+ }
129
+ function getVercelScopeArg(config) {
130
+ return ["--scope", config.vercelOrgId];
131
+ }
132
+ function getVercelTokenArg(config) {
133
+ return ["--token", config.vercelToken];
134
+ }
135
+ function getVercelLocalConfigArg() {
136
+ return ["--local-config", VERCEL_NULL_CONFIG_PATH];
137
+ }
138
+ function getTargetCWDArg(target) {
139
+ return ["--cwd", target.targetCWD];
140
+ }
141
+ function createVercelSpawnOptions(stdoutMode = "inherit") {
142
+ const base = {
143
+ encoding: "utf8",
144
+ shell: process.platform === "win32"
145
+ };
146
+ if (stdoutMode === "pipe") {
147
+ return { ...base, stdio: ["inherit", "pipe", "inherit"] };
148
+ }
149
+ return { ...base, stdio: "inherit" };
150
+ }
151
+
152
+ // src/core/tasks/link.ts
153
+ function createLinkTask(config, target) {
154
+ return {
155
+ name: `Link: ${target.targetCWD}`,
156
+ fn: async () => {
157
+ const targetPath = resolve(target.targetCWD);
158
+ if (!fs.existsSync(targetPath)) {
159
+ const err = new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6784\u5EFA: ${target.targetCWD}`);
160
+ consola2.error(err.message);
161
+ throw err;
162
+ }
163
+ const args = concat(
164
+ ["link"],
165
+ ["--yes"],
166
+ getTargetCWDArg(target),
167
+ getVercelProjectNameArg(config),
168
+ getVercelTokenArg(config)
169
+ );
170
+ consola2.start(`\u5F00\u59CB link \u4EFB\u52A1: ${target.targetCWD}`);
171
+ const result = spawnSync("vercel", args, createVercelSpawnOptions());
172
+ if (result.error) {
173
+ consola2.error(`link \u4EFB\u52A1\u5931\u8D25: ${target.targetCWD}`);
174
+ throw result.error;
175
+ }
176
+ consola2.success(`\u5B8C\u6210 link \u4EFB\u52A1: ${target.targetCWD}`);
177
+ return result.stdout;
178
+ }
179
+ };
180
+ }
181
+
182
+ // src/core/tasks/build.ts
183
+ import fs2 from "fs";
184
+ import { resolve as resolve2 } from "path";
185
+ import { spawnSync as spawnSync2 } from "child_process";
186
+ import { concat as concat2 } from "lodash-es";
187
+ import { consola as consola3 } from "consola";
188
+ function createBuildTask(config, target) {
189
+ return {
190
+ name: `Build: ${target.targetCWD}`,
191
+ fn: async () => {
192
+ const targetPath = resolve2(target.targetCWD);
193
+ if (!fs2.existsSync(targetPath)) {
194
+ const err = new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6784\u5EFA: ${target.targetCWD}`);
195
+ consola3.error(err.message);
196
+ throw err;
197
+ }
198
+ const args = concat2(
199
+ ["build"],
200
+ ["--yes"],
201
+ ["--prod"],
202
+ getTargetCWDArg(target),
203
+ getVercelLocalConfigArg(),
204
+ getVercelTokenArg(config)
205
+ );
206
+ consola3.start(`\u5F00\u59CB build \u4EFB\u52A1: ${target.targetCWD}`);
207
+ const result = spawnSync2("vercel", args, createVercelSpawnOptions());
208
+ if (result.error) {
209
+ consola3.error(`build \u4EFB\u52A1\u5931\u8D25: ${target.targetCWD}`);
210
+ throw result.error;
211
+ }
212
+ consola3.success(`\u5B8C\u6210 build \u4EFB\u52A1: ${target.targetCWD}`);
213
+ return result.stdout;
214
+ }
215
+ };
216
+ }
217
+
218
+ // src/core/tasks/after-build.ts
219
+ import { spawnSync as spawnSync3 } from "child_process";
220
+ import { consola as consola4 } from "consola";
221
+ import { isUndefined as isUndefined2, isEmpty } from "lodash-es";
222
+ function createAfterBuildTasks(config) {
223
+ const afterBuildTasks = config.afterBuildTasks;
224
+ if (isUndefined2(afterBuildTasks) || isEmpty(afterBuildTasks)) {
225
+ return [
226
+ {
227
+ name: "AfterBuild: \u65E0\u4EFB\u52A1",
228
+ fn: async () => {
229
+ consola4.warn("\u5F53\u524D\u6CA1\u6709\u6709\u610F\u4E49\u7684 afterBuildTasks \u4EFB\u52A1\u914D\u7F6E");
230
+ return void 0;
231
+ }
232
+ }
233
+ ];
234
+ }
235
+ return afterBuildTasks.map((command) => ({
236
+ name: `AfterBuild: ${command}`,
237
+ fn: async () => {
238
+ consola4.start(`\u5F00\u59CB afterBuild \u4EFB\u52A1: ${command}`);
239
+ const result = spawnSync3(command, [], {
240
+ encoding: "utf-8",
241
+ stdio: "inherit",
242
+ shell: true
243
+ });
244
+ if (result.error) {
245
+ consola4.error(`afterBuild \u4EFB\u52A1\u5931\u8D25: ${command}`);
246
+ throw result.error;
247
+ }
248
+ consola4.success(`\u5B8C\u6210 afterBuild \u4EFB\u52A1: ${command}`);
249
+ return result.stdout;
250
+ }
251
+ }));
252
+ }
253
+
254
+ // src/core/tasks/user-commands.ts
255
+ import { spawnSync as spawnSync4 } from "child_process";
256
+ import { consola as consola5 } from "consola";
257
+ function createUserCommandTasks(target) {
258
+ return target.userCommands.map((command) => ({
259
+ name: `UserCommand: ${command}`,
260
+ fn: async () => {
261
+ consola5.start(`\u5F00\u59CB\u7528\u6237\u547D\u4EE4\u4EFB\u52A1: ${command}`);
262
+ const result = spawnSync4(command, [], {
263
+ encoding: "utf-8",
264
+ stdio: "inherit",
265
+ shell: true
266
+ });
267
+ if (result.error) {
268
+ consola5.error(`\u7528\u6237\u547D\u4EE4\u4EFB\u52A1\u5931\u8D25: ${command}`);
269
+ throw result.error;
270
+ }
271
+ consola5.success(`\u5B8C\u6210\u7528\u6237\u547D\u4EE4\u4EFB\u52A1: ${command}`);
272
+ return result.stdout;
273
+ }
274
+ }));
275
+ }
276
+
277
+ // src/core/tasks/copy-dist.ts
278
+ import { resolve as resolve3 } from "path";
279
+ import { rmSync, mkdirSync, cpSync } from "fs";
280
+ import { consola as consola6 } from "consola";
281
+ function createCopyDistTasks(target) {
282
+ const targetCWD = target.targetCWD;
283
+ const outputDirectory = target.outputDirectory;
284
+ function joinPath(dir) {
285
+ return resolve3(process.cwd(), targetCWD, dir);
286
+ }
287
+ const pathVercelOutputStatic = joinPath(VERCEL_OUTPUT_STATIC);
288
+ const pathOutputDirectory = joinPath(outputDirectory);
289
+ return [
290
+ {
291
+ name: `\u5220\u9664\u76EE\u5F55: ${pathVercelOutputStatic}`,
292
+ fn: async () => {
293
+ consola6.start(`\u5F00\u59CB\u5220\u9664\u6587\u4EF6\u4EFB\u52A1: ${pathVercelOutputStatic}`);
294
+ rmSync(pathVercelOutputStatic, { recursive: true, force: true });
295
+ consola6.success(`\u5220\u9664\u8BE5\u8DEF\u5F84\u7684\u6587\u4EF6: ${pathVercelOutputStatic}`);
296
+ }
297
+ },
298
+ {
299
+ name: `\u521B\u5EFA\u76EE\u5F55: ${pathVercelOutputStatic}`,
300
+ fn: async () => {
301
+ consola6.start(`\u5F00\u59CB\u521B\u5EFA\u6587\u4EF6\u5939\u4EFB\u52A1: ${pathVercelOutputStatic}`);
302
+ mkdirSync(pathVercelOutputStatic, { recursive: true });
303
+ consola6.success(`\u521B\u5EFA\u7684\u65B0\u76EE\u5F55\u4E3A: ${pathVercelOutputStatic}`);
304
+ }
305
+ },
306
+ {
307
+ name: `\u590D\u5236\u6587\u4EF6: ${pathOutputDirectory} -> ${pathVercelOutputStatic}`,
308
+ fn: async () => {
309
+ consola6.start(`\u5F00\u59CB\u6587\u4EF6\u590D\u5236\u4EFB\u52A1`);
310
+ consola6.info(`\u4ECE ${pathOutputDirectory} \u5F00\u59CB`);
311
+ consola6.info(`\u590D\u5236\u5230 ${pathVercelOutputStatic} \u5185`);
312
+ cpSync(pathOutputDirectory, pathVercelOutputStatic, { recursive: true });
313
+ consola6.success(`\u5B8C\u6210\u6587\u4EF6\u590D\u5236\u4EFB\u52A1`);
314
+ }
315
+ }
316
+ ];
317
+ }
318
+
319
+ // src/core/tasks/deploy.ts
320
+ import fs3 from "fs";
321
+ import { resolve as resolve4 } from "path";
322
+ import { spawnSync as spawnSync5 } from "child_process";
323
+ import { concat as concat3 } from "lodash-es";
324
+ import { consola as consola7 } from "consola";
325
+ function createDeployTask(config, target) {
326
+ return {
327
+ name: `Deploy: ${target.targetCWD}`,
328
+ fn: async () => {
329
+ const targetPath = resolve4(target.targetCWD);
330
+ if (!fs3.existsSync(targetPath)) {
331
+ const err = new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6784\u5EFA: ${target.targetCWD}`);
332
+ consola7.error(err.message);
333
+ throw err;
334
+ }
335
+ const args = concat3(
336
+ ["deploy"],
337
+ ["--yes"],
338
+ ["--prebuilt"],
339
+ ["--prod"],
340
+ getTargetCWDArg(target),
341
+ getVercelTokenArg(config)
342
+ );
343
+ consola7.start(`\u5F00\u59CB\u90E8\u7F72\u4EFB\u52A1: ${target.targetCWD}`);
344
+ const result = spawnSync5("vercel", args, createVercelSpawnOptions("pipe"));
345
+ if (result.error) {
346
+ consola7.error(`\u90E8\u7F72\u5931\u8D25\u4E86: ${target.targetCWD}`);
347
+ consola7.error(result.error);
348
+ throw result.error;
349
+ }
350
+ const vercelUrl = result.stdout.toString().trim();
351
+ consola7.success(`\u5B8C\u6210\u90E8\u7F72\u4EFB\u52A1\uFF0C\u751F\u6210\u7684url\u4E3A:`);
352
+ consola7.box(vercelUrl);
353
+ return vercelUrl;
354
+ }
355
+ };
356
+ }
357
+
358
+ // src/core/tasks/alias.ts
359
+ import { spawnSync as spawnSync6 } from "child_process";
360
+ import { concat as concat4 } from "lodash-es";
361
+ import { consola as consola8 } from "consola";
362
+ function createAliasTask(config, vercelUrl, userUrl) {
363
+ return {
364
+ name: `Alias: ${userUrl}`,
365
+ fn: async () => {
366
+ const args = concat4(["alias", "set", vercelUrl, userUrl], getVercelTokenArg(config), getVercelScopeArg(config));
367
+ consola8.start(`\u5F00\u59CB\u522B\u540D\u4EFB\u52A1: ${userUrl}`);
368
+ const result = spawnSync6("vercel", args, createVercelSpawnOptions());
369
+ if (result.error) {
370
+ consola8.error(`\u522B\u540D\u4EFB\u52A1\u5931\u8D25: ${userUrl}`);
371
+ throw result.error;
372
+ }
373
+ consola8.success(`\u5B8C\u6210\u522B\u540D\u4EFB\u52A1\uFF0C\u53EF\u7528\u7684\u522B\u540D\u5730\u5740\u4E3A:`);
374
+ consola8.box(`https://${userUrl}`);
375
+ return result.stdout;
376
+ }
377
+ };
378
+ }
379
+
380
+ // src/core/tasks/index.ts
381
+ async function generateVercelNullConfig() {
382
+ fs4.writeFileSync(VERCEL_NULL_CONFIG_PATH, JSON.stringify(VERCEL_NULL_CONFIG, null, 2));
383
+ consola9.success(`\u751F\u6210 Vercel \u7A7A\u914D\u7F6E\u6587\u4EF6: ${VERCEL_NULL_CONFIG_PATH}`);
384
+ }
385
+ async function executeDeploymentWorkflow(config) {
386
+ await generateVercelNullConfig();
387
+ const { deployTargets } = config;
388
+ const availableTargets = deployTargets.filter((target) => {
389
+ const targetPath = resolve5(target.targetCWD);
390
+ if (!fs4.existsSync(targetPath)) {
391
+ consola9.warn(`\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u5DF2\u8DF3\u8FC7: ${target.targetCWD}`);
392
+ return false;
393
+ }
394
+ return true;
395
+ });
396
+ if (availableTargets.length === 0) {
397
+ consola9.error("\u6CA1\u6709\u53EF\u7528\u7684\u90E8\u7F72\u76EE\u6807\uFF0C\u8BF7\u5148\u6784\u5EFA\u4EA7\u7269");
398
+ return;
399
+ }
400
+ await task("Vercel \u90E8\u7F72\u5DE5\u4F5C\u6D41", async ({ task: task2 }) => {
401
+ await task2("1. Link \u9879\u76EE", async () => {
402
+ const linkTasks = availableTargets.map((target) => createLinkTask(config, target));
403
+ await task2.group((task3) => linkTasks.map((t) => task3(t.name, t.fn)));
404
+ });
405
+ await task2("2. \u6784\u5EFA\u9879\u76EE", async () => {
406
+ const buildTasks = availableTargets.filter(isNeedVercelBuild).map((target) => createBuildTask(config, target));
407
+ if (buildTasks.length === 0) {
408
+ consola9.warn("\u6CA1\u6709\u9700\u8981\u6267\u884C build \u7684\u76EE\u6807");
409
+ return;
410
+ }
411
+ await task2.group((task3) => buildTasks.map((t) => task3(t.name, t.fn)));
412
+ });
413
+ await task2("3. \u6267\u884C AfterBuild \u4EFB\u52A1", async () => {
414
+ const afterBuildTasks = createAfterBuildTasks(config);
415
+ await executeSequential("AfterBuild", afterBuildTasks);
416
+ });
417
+ await task2("4. \u6267\u884C\u7528\u6237\u547D\u4EE4\u4E0E\u6587\u4EF6\u590D\u5236", async () => {
418
+ const targetTasks = availableTargets.map((target) => ({
419
+ name: `\u5904\u7406\u76EE\u6807: ${target.targetCWD}`,
420
+ fn: async () => {
421
+ if (!isDeployTargetWithUserCommands(target)) {
422
+ consola9.warn(`\u76EE\u6807 ${target.targetCWD} \u4E0D\u5C5E\u4E8E userCommands \u7C7B\u578B`);
423
+ return;
424
+ }
425
+ const userCommandTasks = createUserCommandTasks(target);
426
+ await executeSequential(`UserCommands: ${target.targetCWD}`, userCommandTasks);
427
+ if (getIsCopyDist(target)) {
428
+ const copyDistTasks = createCopyDistTasks(target);
429
+ await executeSequential(`CopyDist: ${target.targetCWD}`, copyDistTasks);
430
+ } else {
431
+ consola9.warn(`\u76EE\u6807 ${target.targetCWD} \u4E0D\u9700\u8981\u590D\u5236\u6587\u4EF6`);
432
+ }
433
+ }
434
+ }));
435
+ await task2.group((task3) => targetTasks.map((t) => task3(t.name, t.fn)));
436
+ });
437
+ await task2("5. \u90E8\u7F72\u4E0E\u8BBE\u7F6E\u522B\u540D", async () => {
438
+ const deployAliasTasks = availableTargets.map((target) => ({
439
+ name: `\u90E8\u7F72\u4E0E\u522B\u540D: ${target.targetCWD}`,
440
+ fn: async () => {
441
+ const deployTask = createDeployTask(config, target);
442
+ const deployResult = await task2(deployTask.name, deployTask.fn);
443
+ const vercelUrl = deployResult.result;
444
+ if (target.url && target.url.length > 0) {
445
+ const aliasTasks = target.url.map((userUrl) => createAliasTask(config, vercelUrl, userUrl));
446
+ await task2.group((task3) => aliasTasks.map((t) => task3(t.name, t.fn)));
447
+ } else {
448
+ consola9.warn(`\u76EE\u6807 ${target.targetCWD} \u6CA1\u6709\u914D\u7F6E\u522B\u540D`);
449
+ }
450
+ }
451
+ }));
452
+ await task2.group((task3) => deployAliasTasks.map((t) => task3(t.name, t.fn)));
453
+ });
454
+ });
455
+ consola9.success("\u{1F389} Vercel \u90E8\u7F72\u5DE5\u4F5C\u6D41\u5B8C\u6210\uFF01");
456
+ }
457
+
458
+ // src/commands/deploy.ts
459
+ import { Command } from "commander";
460
+ import { consola as consola10 } from "consola";
461
+ import { config as dotenvxConfig2 } from "@dotenvx/dotenvx";
462
+ function createDeployCommand() {
463
+ const command = new Command("deploy");
464
+ command.description("\u90E8\u7F72\u9879\u76EE\u5230 Vercel").option("--env-path <path>", "\u6307\u5B9A dotenv \u6587\u4EF6\u8DEF\u5F84\uFF0C\u7528\u4E8E\u8986\u76D6\u9ED8\u8BA4\u73AF\u5883\u53D8\u91CF").action(async (options) => {
465
+ try {
466
+ if (options?.envPath) {
467
+ process.env.VERCEL_DEPLOY_TOOL_ENV_PATH = options.envPath;
468
+ dotenvxConfig2({ path: options.envPath });
469
+ consola10.info(`\u5DF2\u4ECE --env-path \u52A0\u8F7D\u73AF\u5883\u53D8\u91CF: ${options.envPath}`);
470
+ }
471
+ consola10.start("\u5F00\u59CB\u52A0\u8F7D\u914D\u7F6E...");
472
+ const config = await loadConfig();
473
+ consola10.start("\u5F00\u59CB\u6267\u884C\u90E8\u7F72\u5DE5\u4F5C\u6D41...");
474
+ await executeDeploymentWorkflow(config);
475
+ consola10.success("\u90E8\u7F72\u5B8C\u6210\uFF01");
476
+ } catch (error) {
477
+ consola10.error("\u90E8\u7F72\u5931\u8D25:");
478
+ consola10.error(error);
479
+ process.exit(1);
480
+ }
481
+ });
482
+ return command;
483
+ }
484
+
485
+ // src/commands/init.ts
486
+ import { Command as Command2 } from "commander";
487
+ import { readFileSync, writeFileSync, existsSync } from "fs";
488
+ import { join, dirname } from "path";
489
+ import { fileURLToPath } from "url";
490
+ import { consola as consola11 } from "consola";
491
+ var __filename2 = fileURLToPath(import.meta.url);
492
+ var __dirname2 = dirname(__filename2);
493
+ function createInitCommand() {
494
+ const command = new Command2("init");
495
+ command.description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").option("-f, --force", "\u5F3A\u5236\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u6587\u4EF6").action((options) => {
496
+ const cwd = process.cwd();
497
+ const configFile = "vercel-deploy-tool.config.ts";
498
+ const targetPath = join(cwd, configFile);
499
+ if (existsSync(targetPath) && !options.force) {
500
+ consola11.warn(`\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728: ${configFile}`);
501
+ consola11.info("\u4F7F\u7528 --force \u9009\u9879\u53EF\u4EE5\u8986\u76D6");
502
+ return;
503
+ }
504
+ const templatePath = join(__dirname2, "..", "templates", configFile);
505
+ if (!existsSync(templatePath)) {
506
+ consola11.error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${templatePath}`);
507
+ consola11.error("\u8BF7\u786E\u4FDD @ruan-cat/vercel-deploy-tool \u5305\u5DF2\u6B63\u786E\u5B89\u88C5");
508
+ process.exit(1);
509
+ }
510
+ const content = readFileSync(templatePath, "utf-8");
511
+ writeFileSync(targetPath, content, "utf-8");
512
+ consola11.success(`\u5DF2\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6: ${configFile}`);
513
+ const pkgPath = join(cwd, "package.json");
514
+ if (existsSync(pkgPath)) {
515
+ try {
516
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
517
+ if (!pkg.scripts) pkg.scripts = {};
518
+ pkg.scripts["deploy-vercel"] = "vercel-deploy-tool deploy";
519
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
520
+ consola11.success('\u5DF2\u6DFB\u52A0\u811A\u672C: "deploy-vercel"');
521
+ } catch (error) {
522
+ consola11.warn("\u66F4\u65B0 package.json \u5931\u8D25:", error);
523
+ }
524
+ }
525
+ consola11.box(`\u{1F389} \u521D\u59CB\u5316\u5B8C\u6210\uFF01
526
+
527
+ \u521B\u5EFA\u7684\u6587\u4EF6:
528
+ \u2022 ${configFile} - Vercel \u90E8\u7F72\u914D\u7F6E\u6587\u4EF6
529
+
530
+ \u6DFB\u52A0\u7684\u811A\u672C:
531
+ \u2022 deploy-vercel: vercel-deploy-tool deploy
532
+
533
+ \u4E0B\u4E00\u6B65:
534
+ 1. \u7F16\u8F91 ${configFile} \u586B\u5199\u4F60\u7684\u914D\u7F6E
535
+ 2. \u786E\u4FDD\u73AF\u5883\u53D8\u91CF\u5DF2\u8BBE\u7F6E:
536
+ - VERCEL_TOKEN
537
+ - VERCEL_ORG_ID
538
+ - VERCEL_PROJECT_ID
539
+ 3. \u8FD0\u884C\u90E8\u7F72:
540
+ pnpm run deploy-vercel`);
541
+ });
542
+ return command;
543
+ }
544
+ export {
545
+ VERCEL_NULL_CONFIG,
546
+ VERCEL_NULL_CONFIG_PATH,
547
+ VERCEL_OUTPUT_STATIC,
548
+ createDeployCommand,
549
+ createInitCommand,
550
+ defineConfig,
551
+ executeDeploymentWorkflow,
552
+ getConfig,
553
+ getIsCopyDist,
554
+ isDeployTargetBase,
555
+ isDeployTargetWithUserCommands,
556
+ isNeedVercelBuild,
557
+ loadConfig
558
+ };
559
+ /**
560
+ * @ruan-cat/vercel-deploy-tool
561
+ * @description
562
+ * Vercel 部署工具 - 支持 monorepo 的自动化部署
563
+ *
564
+ * @author ruan-cat
565
+ * @license MIT
566
+ */
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@ruan-cat/vercel-deploy-tool",
3
- "version": "0.12.2",
3
+ "version": "1.1.0",
4
4
  "description": "阮喵喵自用的vercel部署工具,用于实现复杂项目的部署。",
5
5
  "type": "module",
6
- "main": "./src/index.ts",
7
- "types": "./src/index.ts",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "homepage": "https://vercel-deploy-tool.ruancat6312.top",
9
9
  "bugs": {
10
10
  "url": "https://github.com/ruan-cat/monorepo/issues"
@@ -14,10 +14,15 @@
14
14
  "url": "git+https://github.com/ruan-cat/monorepo.git",
15
15
  "directory": "packages/vercel-deploy-tool"
16
16
  },
17
+ "bin": {
18
+ "vercel-deploy-tool": "./dist/cli.js",
19
+ "vdt": "./dist/cli.js",
20
+ "@ruan-cat/vercel-deploy-tool": "./dist/cli.js"
21
+ },
17
22
  "exports": {
18
23
  ".": {
19
- "import": "./src/index.ts",
20
- "types": "./src/index.ts"
24
+ "import": "./dist/index.js",
25
+ "types": "./dist/index.d.ts"
21
26
  },
22
27
  "./src/*": "./src/*"
23
28
  },
@@ -57,6 +62,7 @@
57
62
  "lodash-es": "^4.17.21",
58
63
  "pathe": "^2.0.3",
59
64
  "rimraf": "^6.1.0",
65
+ "tasuku": "^2.0.4",
60
66
  "vercel": "^41.7.8",
61
67
  "@ruan-cat/utils": "^4.18.0"
62
68
  },
@@ -70,11 +76,13 @@
70
76
  "@ruan-cat/vitepress-preset-config": "^2.12.2"
71
77
  },
72
78
  "scripts": {
79
+ "build": "tsup",
73
80
  "docs:dev": "vitepress dev src/docs",
74
81
  "build:docs": "vitepress build src/docs",
75
82
  "prebuild": "automd",
83
+ "test:cli": "node dist/cli.js deploy",
76
84
  "test:prod": "node ./dist/index.js",
77
- "test:dev": "tsx ./src/index.ts --env-path=.env.test",
85
+ "test:dev": "tsx ./src/cli.ts deploy",
78
86
  "test:config": "dotenvx run -f .env.test -f .env.test-2 -- tsx ./tests/config.test.ts"
79
87
  }
80
88
  }
package/src/cli.ts ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+ import path from "node:path";
6
+ import { Command } from "commander";
7
+ import { createDeployCommand } from "./commands/deploy";
8
+ import { createInitCommand } from "./commands/init";
9
+
10
+ // 获取当前文件的目录
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ // 读取 package.json 获取版本号
15
+ const packageJsonPath = path.join(__dirname, "..", "package.json");
16
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
17
+ const { version } = packageJson;
18
+
19
+ // 创建主程序
20
+ const program = new Command();
21
+
22
+ // 设置程序基本信息
23
+ program.name("vercel-deploy-tool").description("Vercel 部署工具 - 支持 monorepo 的自动化部署").version(version);
24
+
25
+ // 注册所有子命令
26
+ program.addCommand(createDeployCommand());
27
+ program.addCommand(createInitCommand());
28
+
29
+ // 自定义帮助信息
30
+ program.on("--help", () => {
31
+ console.log("");
32
+ console.log("使用示例 / Usage Examples:");
33
+ console.log("");
34
+ console.log(" # 初始化配置文件");
35
+ console.log(" vercel-deploy-tool init");
36
+ console.log(" vdt init");
37
+ console.log("");
38
+ console.log(" # 部署项目");
39
+ console.log(" vercel-deploy-tool deploy");
40
+ console.log(" vdt deploy");
41
+ console.log("");
42
+ console.log(" # 查看帮助");
43
+ console.log(" vercel-deploy-tool --help");
44
+ console.log(" vdt --help");
45
+ console.log("");
46
+ console.log("环境变量 / Environment Variables:");
47
+ console.log(" VERCEL_TOKEN - Vercel API Token");
48
+ console.log(" VERCEL_ORG_ID - Vercel 组织 ID");
49
+ console.log(" VERCEL_PROJECT_ID - Vercel 项目 ID");
50
+ console.log("");
51
+ });
52
+
53
+ async function main() {
54
+ // 解析命令行参数(异步,确保子命令的 async action 被执行并正确传递异常)
55
+ await program.parseAsync();
56
+ }
57
+
58
+ main().catch((error) => {
59
+ console.error(error);
60
+ process.exit(1);
61
+ });