weapp-ide-cli 3.1.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,51 +1,104 @@
1
1
  # weapp-ide-cli
2
2
 
3
- 微信开发者工具的命令行(v2) 的一个二次封装的包裹实现,来让开发者更加方便的使用微信开发者工具。
3
+ `weapp-ide-cli` 是对「微信开发者工具」官方命令行的增强封装,提供更友好的参数体验、路径兼容与配置管理能力,帮助你在本地与持续集成环境中高效调用工具链。
4
4
 
5
- > 要使用命令行,注意首先需要在开发者工具的设置 -> 安全设置中开启服务端口。
5
+ > 开始前请在微信开发者工具中打开「设置 安全设置 → 服务端口」。
6
6
 
7
- ## 快速安装
7
+ ## 功能亮点
8
+
9
+ - 自动识别或记忆微信开发者工具 `cli` 所在位置,避免反复输入路径。
10
+ - 为 `-p / --project`、`--qr-output` 等选项自动补全绝对路径,默认使用当前工作目录。
11
+ - 使用与官方指令完全一致的调用方式,便于在脚本中无缝迁移。
12
+ - 支持 macOS、Windows 以及安装了社区版工具的 Linux 桌面环境。
13
+
14
+ ## 安装
8
15
 
9
16
  ```sh
10
- npm i -g weapp-ide-cli
11
- # or
17
+ # 使用 pnpm
18
+ pnpm add -g weapp-ide-cli
19
+
20
+ # 或使用 npm
21
+ npm install -g weapp-ide-cli
22
+
23
+ # 或使用 yarn
12
24
  yarn global add weapp-ide-cli
13
25
  ```
14
26
 
15
- ### 执行命令
27
+ ## 快速开始
16
28
 
17
29
  ```sh
18
- weapp open
19
- # 等价
20
- weapp-ide-cli open
21
-
22
- # 在当前命令行所在位置,打开微信开发者工具
30
+ # 打开微信开发者工具(项目目录为当前终端所在位置)
23
31
  weapp open -p
24
- # 等价
25
- weapp open --project
26
32
 
27
- # 在相对的路径,打开微信开发者工具
28
- # 比如 uni-app 就可以在项目目录执行
29
- weapp open -p dist/dev/mp-weixin
30
- # 工具会把相对路径转化为绝对路径,然后打开(绝对路径不转化)
33
+ # 启动并加载指定项目
34
+ weapp open --project ./dist/dev/mp-weixin
35
+
36
+ # 执行预览、上传等官方支持的命令
37
+ weapp preview
38
+ weapp upload --project ./dist/build/mp-weixin
31
39
  ```
32
40
 
33
- ## 常用命令
41
+ `weapp` 与 `weapp-ide-cli` 等价,选择任一前缀即可。
42
+
43
+ ## 常用命令速查
44
+
45
+ | 命令 | 说明 |
46
+ | ----------------------------------------------- | ------------------------------------ |
47
+ | `weapp login` | 在终端扫码登录账号 |
48
+ | `weapp open -p [path]` | 启动工具并打开项目(默认为当前路径) |
49
+ | `weapp preview --project <path>` | 生成预览二维码 |
50
+ | `weapp upload --project <path> --version <ver>` | 上传小程序代码 |
51
+ | `weapp quit` | 关闭微信开发者工具 |
52
+
53
+ 更多原生命令与参数请参考官方文档:<https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html>
54
+
55
+ ## 路径与参数兼容
56
+
57
+ - `-p` 会被自动替换为 `--project`,并且相对路径会解析为绝对路径。
58
+ - `--qr-output`、`--result-output`、`--info-output` 及其短选项在缺省值时会默认指向当前工作目录。
59
+ - 如果未显式提供路径参数,CLI 会自动注入当前终端所在目录,方便脚本化调用。
60
+
61
+ ## 配置 CLI 所在位置
62
+
63
+ 执行一次互动式配置即可持久化工具路径:
64
+
65
+ ```sh
66
+ weapp config
67
+ ```
68
+
69
+ 配置数据保存在用户目录:
70
+
71
+ - macOS / Linux:`~/.weapp-ide-cli/config.json`
72
+ - Windows:`C:\Users\<用户名>\.weapp-ide-cli\config.json`
73
+
74
+ 可以直接编辑该文件或重新运行 `weapp config` 来更新路径。当配置文件缺失或留空时,CLI 会尝试按系统默认安装位置自动寻找。
75
+
76
+ ## 平台支持与限制
77
+
78
+ | 平台 | 支持情况 | 默认查找路径 |
79
+ | --------------- | ------------- | ---------------------------------------------------------- |
80
+ | macOS | ✅ | `/Applications/wechatwebdevtools.app/Contents/MacOS/cli` |
81
+ | Windows | ✅ | `C:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat` |
82
+ | Linux(社区版) | ⚠️ 需手动安装 | 通过 `PATH` 搜索 `wechat-devtools-cli` |
83
+
84
+ 若所属平台未检测到 CLI,请使用 `weapp config` 指定安装位置。
85
+
86
+ ## 在脚本或 CI 中使用
34
87
 
35
- 1. `weapp login` 在命令行进行微信扫码登录
36
- 2. `weapp open -p` 启动工具进行调试开发
37
- 3. `weapp preview` 开始预览
38
- 4. `weapp upload` 上传代码
39
- 5. `weapp quit` 关闭开发者工具
88
+ 1. 确保执行环境已安装微信开发者工具并开启服务端口。
89
+ 2. 首次运行前可通过 `weapp config` 写入 CLI 路径,也可在 CI 中直接向 `~/.weapp-ide-cli/config.json` 写入。
90
+ 3. 在自动化流程中建议加上 `--qr-output`、`--result-output` 等参数,以便收集产物或日志。
40
91
 
41
- ### 自定义配置
92
+ ## 常见问题
42
93
 
43
- `weapp config` 可以对微信开发者工具的 `cli` 目录进行配置,而配置文件就存放在用户的 `${homedir}/.weapp-ide-cli/config.json` 中,您可以随时进行更改。
94
+ - **命令执行后无反应**:请确认微信开发者工具已开启服务端口,并尝试重新登录或升级工具版本。
95
+ - **提示未找到 CLI**:检查配置文件中的路径是否真实存在,可使用绝对路径避免解析误差。
96
+ - **Linux 环境报错**:需安装社区版工具并将 `wechat-devtools-cli` 加入 `PATH`,否则只能手动指定路径。
44
97
 
45
- > 比如 windows 存放位置就在 `C:\Users\${你的用户名}\.weapp-ide-cli/config.json`
98
+ ## 贡献
46
99
 
47
- ### 更多命令
100
+ 欢迎通过 Issues 或 Pull Request 提交优化建议,开发前请阅读仓库根目录的 `CONTRIBUTING.md`。
48
101
 
49
- 这个工具本质是一个 `cli` 二次处理工具,所以绝大部分命令都是透传的。
102
+ ## 许可证
50
103
 
51
- 全部的命令请查看 <https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html>
104
+ MIT
@@ -0,0 +1,302 @@
1
+ // src/utils/path.ts
2
+ import process from "process";
3
+ import path from "pathe";
4
+ function resolvePath(filePath) {
5
+ if (path.isAbsolute(filePath)) {
6
+ return filePath;
7
+ }
8
+ return path.resolve(process.cwd(), filePath);
9
+ }
10
+
11
+ // src/config/paths.ts
12
+ import os from "os";
13
+ import path2 from "pathe";
14
+ var homedir = os.homedir();
15
+ var defaultCustomConfigDirPath = path2.join(homedir, ".weapp-ide-cli");
16
+ var defaultCustomConfigFilePath = path2.join(
17
+ defaultCustomConfigDirPath,
18
+ "config.json"
19
+ );
20
+
21
+ // src/config/custom.ts
22
+ import fs from "fs-extra";
23
+ var JSON_OPTIONS = {
24
+ encoding: "utf8",
25
+ spaces: 2
26
+ };
27
+ async function createCustomConfig(params) {
28
+ const trimmedCliPath = params.cliPath.trim();
29
+ if (!trimmedCliPath) {
30
+ throw new Error("cliPath cannot be empty");
31
+ }
32
+ const normalizedCliPath = resolvePath(trimmedCliPath);
33
+ await fs.ensureDir(defaultCustomConfigDirPath);
34
+ await fs.writeJSON(
35
+ defaultCustomConfigFilePath,
36
+ {
37
+ cliPath: normalizedCliPath
38
+ },
39
+ JSON_OPTIONS
40
+ );
41
+ return normalizedCliPath;
42
+ }
43
+
44
+ // src/logger.ts
45
+ import logger from "@weapp-core/logger";
46
+ var logger_default = logger;
47
+
48
+ // src/cli/prompt.ts
49
+ import { stdin as input, stdout as output } from "process";
50
+ import { createInterface } from "readline/promises";
51
+ import fs2 from "fs-extra";
52
+ async function promptForCliPath() {
53
+ const rl = createInterface({ input, output });
54
+ try {
55
+ logger_default.log("\u8BF7\u8BBE\u7F6E\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177 CLI \u7684\u8DEF\u5F84");
56
+ logger_default.log("> \u63D0\u793A\uFF1A\u547D\u4EE4\u884C\u5DE5\u5177\u9ED8\u8BA4\u6240\u5728\u4F4D\u7F6E\uFF1A");
57
+ logger_default.log("- MacOS: <\u5B89\u88C5\u8DEF\u5F84>/Contents/MacOS/cli");
58
+ logger_default.log("- Windows: <\u5B89\u88C5\u8DEF\u5F84>/cli.bat");
59
+ logger_default.log("- Linux: <\u5B89\u88C5\u8DEF\u5F84>/files/bin/bin/wechat-devtools-cli");
60
+ const cliPath = (await rl.question("\u8BF7\u8F93\u5165\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177 CLI \u8DEF\u5F84\uFF1A")).trim();
61
+ if (!cliPath) {
62
+ logger_default.error("\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u53D6\u6D88\u672C\u6B21\u914D\u7F6E\u3002");
63
+ return null;
64
+ }
65
+ try {
66
+ const normalizedPath = await createCustomConfig({ cliPath });
67
+ logger_default.log(`\u5168\u5C40\u914D\u7F6E\u5B58\u50A8\u4F4D\u7F6E\uFF1A${defaultCustomConfigFilePath}`);
68
+ if (!await fs2.pathExists(normalizedPath)) {
69
+ logger_default.warn("\u5728\u5F53\u524D\u8DEF\u5F84\u672A\u627E\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u786E\u8BA4\u8DEF\u5F84\u662F\u5426\u6B63\u786E\u3002");
70
+ }
71
+ return normalizedPath;
72
+ } catch (error) {
73
+ const reason = error instanceof Error ? error.message : String(error);
74
+ logger_default.error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25\uFF1A${reason}`);
75
+ return null;
76
+ }
77
+ } finally {
78
+ rl.close();
79
+ }
80
+ }
81
+
82
+ // src/runtime/platform.ts
83
+ import os2 from "os";
84
+ import process2 from "process";
85
+ import fs3 from "fs-extra";
86
+ import path3 from "pathe";
87
+ var SupportedPlatformsMap = {
88
+ Windows_NT: "Windows_NT",
89
+ Darwin: "Darwin",
90
+ Linux: "Linux"
91
+ };
92
+ function isOperatingSystemSupported(osName = os2.type()) {
93
+ return osName === SupportedPlatformsMap.Windows_NT || osName === SupportedPlatformsMap.Darwin || osName === SupportedPlatformsMap.Linux;
94
+ }
95
+ var operatingSystemName = os2.type();
96
+ function createLinuxCliResolver() {
97
+ let resolvedPath;
98
+ let attempted = false;
99
+ let pending = null;
100
+ return async () => {
101
+ if (attempted) {
102
+ return resolvedPath;
103
+ }
104
+ if (!pending) {
105
+ pending = (async () => {
106
+ try {
107
+ const envPath = await getFirstBinaryPath("wechat-devtools-cli");
108
+ if (envPath) {
109
+ resolvedPath = envPath;
110
+ }
111
+ } catch (error) {
112
+ const reason = error instanceof Error ? error.message : String(error);
113
+ logger_default.warn(`\u83B7\u53D6 Linux wechat-devtools-cli \u8DEF\u5F84\u5931\u8D25\uFF1A${reason}`);
114
+ } finally {
115
+ attempted = true;
116
+ }
117
+ return resolvedPath;
118
+ })();
119
+ }
120
+ return pending;
121
+ };
122
+ }
123
+ var linuxCliResolver = createLinuxCliResolver();
124
+ var WINDOWS_DEFAULT_CLI = "C:\\Program Files (x86)\\Tencent\\\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177\\cli.bat";
125
+ var DARWIN_DEFAULT_CLI = "/Applications/wechatwebdevtools.app/Contents/MacOS/cli";
126
+ var cliPathResolvers = {
127
+ [SupportedPlatformsMap.Windows_NT]: async () => WINDOWS_DEFAULT_CLI,
128
+ [SupportedPlatformsMap.Darwin]: async () => DARWIN_DEFAULT_CLI,
129
+ [SupportedPlatformsMap.Linux]: linuxCliResolver
130
+ };
131
+ async function getDefaultCliPath(targetOs = operatingSystemName) {
132
+ if (!isOperatingSystemSupported(targetOs)) {
133
+ return void 0;
134
+ }
135
+ const resolver = cliPathResolvers[targetOs];
136
+ const resolvedPath = await resolver();
137
+ return resolvedPath;
138
+ }
139
+ async function getFirstBinaryPath(command) {
140
+ const envPath = process2.env.PATH || "";
141
+ const pathDirs = envPath.split(path3.delimiter);
142
+ for (const dir of pathDirs) {
143
+ const fullPath = path3.join(dir, command);
144
+ try {
145
+ await fs3.access(fullPath, fs3.constants.X_OK);
146
+ return fullPath;
147
+ } catch {
148
+ continue;
149
+ }
150
+ }
151
+ return void 0;
152
+ }
153
+
154
+ // src/config/resolver.ts
155
+ import fs4 from "fs-extra";
156
+ async function getConfig() {
157
+ if (await fs4.pathExists(defaultCustomConfigFilePath)) {
158
+ try {
159
+ const config = await fs4.readJSON(defaultCustomConfigFilePath);
160
+ const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
161
+ if (cliPath) {
162
+ logger_default.log("> \u5168\u5C40\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF1A", defaultCustomConfigFilePath);
163
+ logger_default.log("> \u81EA\u5B9A\u4E49 CLI \u8DEF\u5F84\uFF1A", cliPath);
164
+ return {
165
+ cliPath,
166
+ source: "custom"
167
+ };
168
+ }
169
+ logger_default.warn("\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u7F3A\u5C11\u6709\u6548\u7684 CLI \u8DEF\u5F84\uFF0C\u5C06\u5C1D\u8BD5\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u5F84\u3002");
170
+ } catch (error) {
171
+ const reason = error instanceof Error ? error.message : String(error);
172
+ logger_default.warn(`\u89E3\u6790\u81EA\u5B9A\u4E49\u914D\u7F6E\u5931\u8D25\uFF0C\u5C06\u5C1D\u8BD5\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u5F84\u3002\u539F\u56E0\uFF1A${reason}`);
173
+ }
174
+ }
175
+ const fallbackPath = await getDefaultCliPath();
176
+ if (fallbackPath) {
177
+ return {
178
+ cliPath: fallbackPath,
179
+ source: "default"
180
+ };
181
+ }
182
+ return {
183
+ cliPath: "",
184
+ source: "missing"
185
+ };
186
+ }
187
+
188
+ // src/cli/resolver.ts
189
+ import fs5 from "fs-extra";
190
+ async function resolveCliPath() {
191
+ const config = await getConfig();
192
+ if (!config.cliPath) {
193
+ return { cliPath: null, source: config.source };
194
+ }
195
+ const exists = await fs5.pathExists(config.cliPath);
196
+ return {
197
+ cliPath: exists ? config.cliPath : null,
198
+ source: config.source
199
+ };
200
+ }
201
+
202
+ // src/utils/argv.ts
203
+ import process3 from "process";
204
+ function ensurePathArgument(argv, optionIndex) {
205
+ const paramIdx = optionIndex + 1;
206
+ const param = argv[paramIdx];
207
+ if (param && !param.startsWith("-")) {
208
+ argv[paramIdx] = resolvePath(param);
209
+ } else {
210
+ argv.splice(paramIdx, 0, process3.cwd());
211
+ }
212
+ return argv;
213
+ }
214
+ function transformArgv(argv, transforms) {
215
+ return transforms.reduce((current, transform) => transform(current), [
216
+ ...argv
217
+ ]);
218
+ }
219
+ function createAlias(entry) {
220
+ return (input2) => {
221
+ const argv = [...input2];
222
+ let optionIndex = argv.indexOf(entry.find);
223
+ if (optionIndex > -1) {
224
+ argv.splice(optionIndex, 1, entry.replacement);
225
+ } else {
226
+ optionIndex = argv.indexOf(entry.replacement);
227
+ }
228
+ if (optionIndex === -1) {
229
+ return argv;
230
+ }
231
+ return ensurePathArgument(argv, optionIndex);
232
+ };
233
+ }
234
+ function createPathCompat(option) {
235
+ return (input2) => {
236
+ const argv = [...input2];
237
+ const optionIndex = argv.indexOf(option);
238
+ if (optionIndex === -1) {
239
+ return argv;
240
+ }
241
+ return ensurePathArgument(argv, optionIndex);
242
+ };
243
+ }
244
+
245
+ // src/utils/exec.ts
246
+ import process4 from "process";
247
+ async function execute(cliPath, argv) {
248
+ const { execa } = await import("execa");
249
+ const task = execa(cliPath, argv);
250
+ task?.stdout?.pipe(process4.stdout);
251
+ await task;
252
+ }
253
+
254
+ // src/cli/run.ts
255
+ var ARG_TRANSFORMS = [
256
+ createAlias({ find: "-p", replacement: "--project" }),
257
+ createPathCompat("--result-output"),
258
+ createPathCompat("-r"),
259
+ createPathCompat("--qr-output"),
260
+ createPathCompat("-o"),
261
+ createPathCompat("--info-output"),
262
+ createPathCompat("-i")
263
+ ];
264
+ async function parse(argv) {
265
+ if (!isOperatingSystemSupported(operatingSystemName)) {
266
+ logger_default.log(`\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177\u4E0D\u652F\u6301\u5F53\u524D\u5E73\u53F0\uFF1A${operatingSystemName} !`);
267
+ return;
268
+ }
269
+ if (argv[0] === "config") {
270
+ await promptForCliPath();
271
+ return;
272
+ }
273
+ const { cliPath, source } = await resolveCliPath();
274
+ if (!cliPath) {
275
+ const message = source === "custom" ? "\u5728\u5F53\u524D\u81EA\u5B9A\u4E49\u8DEF\u5F84\u4E2D\u672A\u627E\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u91CD\u65B0\u6307\u5B9A\u8DEF\u5F84\u3002" : "\u672A\u68C0\u6D4B\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u6267\u884C `weapp-ide-cli config` \u6307\u5B9A\u8DEF\u5F84\u3002";
276
+ logger_default.log(message);
277
+ await promptForCliPath();
278
+ return;
279
+ }
280
+ const formattedArgv = transformArgv(argv, ARG_TRANSFORMS);
281
+ await execute(cliPath, formattedArgv);
282
+ }
283
+
284
+ export {
285
+ resolvePath,
286
+ defaultCustomConfigDirPath,
287
+ defaultCustomConfigFilePath,
288
+ createCustomConfig,
289
+ logger_default,
290
+ promptForCliPath,
291
+ SupportedPlatformsMap,
292
+ isOperatingSystemSupported,
293
+ operatingSystemName,
294
+ getDefaultCliPath,
295
+ getConfig,
296
+ resolveCliPath,
297
+ transformArgv,
298
+ createAlias,
299
+ createPathCompat,
300
+ execute,
301
+ parse
302
+ };