weapp-vite 6.13.3 → 6.14.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 +20 -1
- package/dist/auto-import-components/resolvers.d.mts +1 -1
- package/dist/auto-routes.d.mts +1 -1
- package/dist/auto-routes.mjs +1 -1
- package/dist/cli.mjs +591 -192
- package/dist/config-DJjSbpNX.mjs +6 -0
- package/dist/{config-Dec415jY.d.mts → config-bkgtM4wZ.d.mts} +8 -2
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +2 -6
- package/dist/{createContext-3UhoQl2A.mjs → createContext-BolxgJjC.mjs} +953 -844
- package/dist/docs/README.md +20 -1
- package/dist/docs/ai-workflows.md +17 -1
- package/dist/docs/mcp.md +33 -2
- package/dist/file-DgJb3pIf.mjs +2 -0
- package/dist/{file-BAUXs16l.mjs → file-Ej-4GoYg.mjs} +3 -19
- package/dist/getInstance-CVtFkrEA.mjs +2 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +4 -4
- package/dist/json-D0HkutE0.mjs +33 -0
- package/dist/json.d.mts +1 -1
- package/dist/json.mjs +1 -32
- package/dist/mcp-DRlj32v4.mjs +39 -0
- package/dist/mcp.d.mts +1 -1
- package/dist/mcp.mjs +1 -38
- package/dist/runtime.d.mts +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/types.d.mts +3 -3
- package/package.json +11 -11
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- /package/dist/{index-CUFOUU8V.d.mts → index-hN5mdpQ_.d.mts} +0 -0
- /package/dist/{logger-gutcwWKE.mjs → logger-CgxdNjvb.mjs} +0 -0
- /package/dist/{routes-o20IHwXa.d.mts → routes-DiEBrMtj.d.mts} +0 -0
- /package/dist/{runtime-CpQutkhu.d.mts → runtime-58wbbRDf.d.mts} +0 -0
- /package/dist/{runtime-gyZnAGCZ.mjs → runtime-tVnzZwtl.mjs} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import { r as logger_default, t as colors } from "./logger-
|
|
3
|
-
import {
|
|
4
|
-
import { resolveWeappMcpConfig, startWeappViteMcpServer } from "./mcp.mjs";
|
|
1
|
+
import { S as isPathInside, _ as DEFAULT_MP_PLATFORM, b as resolveMiniPlatform, c as createSharedBuildConfig, d as resolveWeappConfigFile, f as checkRuntime, g as createCjsConfigLoadError, h as parseCommentJson, l as SHARED_CHUNK_VIRTUAL_PREFIX, m as loadViteConfigFile, n as syncProjectSupportFiles, p as getProjectConfigFileName, r as syncManagedTsconfigBootstrapFiles, s as formatBytes, t as createCompilerContext, v as getDefaultIdeProjectRoot, x as shouldPassPlatformArgToIdeOpen, y as normalizeMiniPlatform } from "./createContext-BolxgJjC.mjs";
|
|
2
|
+
import { r as logger_default, t as colors } from "./logger-CgxdNjvb.mjs";
|
|
3
|
+
import { m as VERSION } from "./file-Ej-4GoYg.mjs";
|
|
4
|
+
import { a as resolveWeappMcpConfig, o as startWeappViteMcpServer } from "./mcp-DRlj32v4.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
|
-
import { defu } from "@weapp-core/shared";
|
|
6
|
+
import { defu, fs } from "@weapp-core/shared";
|
|
7
7
|
import path, { posix } from "pathe";
|
|
8
|
-
import fs from "fs-extra";
|
|
9
8
|
import process from "node:process";
|
|
10
9
|
import fs$1 from "node:fs/promises";
|
|
11
10
|
import { build, createServer } from "vite";
|
|
@@ -15,10 +14,11 @@ import fs$2 from "node:fs";
|
|
|
15
14
|
import { cac } from "cac";
|
|
16
15
|
import { resolveCommand } from "package-manager-detector/commands";
|
|
17
16
|
import { promisify } from "node:util";
|
|
18
|
-
import { formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getConfig, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, parse, startForwardConsole, waitForRetryKeypress } from "weapp-ide-cli";
|
|
17
|
+
import { closeSharedMiniProgram, connectOpenedAutomator, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getConfig, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, parse, startForwardConsole, takeScreenshot, waitForRetryKeypress } from "weapp-ide-cli";
|
|
19
18
|
import { generateJs, generateJson, generateWxml, generateWxss } from "@weapp-core/schematics";
|
|
20
19
|
import { determineAgent } from "@vercel/detect-agent";
|
|
21
20
|
import { initConfig } from "@weapp-core/init";
|
|
21
|
+
import { emitKeypressEvents } from "node:readline";
|
|
22
22
|
//#region src/analyze/subpackages/classifier.ts
|
|
23
23
|
const VIRTUAL_MODULE_INDICATOR = "\0";
|
|
24
24
|
const VIRTUAL_PREFIX = `${SHARED_CHUNK_VIRTUAL_PREFIX}/`;
|
|
@@ -857,6 +857,14 @@ function registerAnalyzeCommand(cli) {
|
|
|
857
857
|
});
|
|
858
858
|
}
|
|
859
859
|
//#endregion
|
|
860
|
+
//#region src/cli/formatDuration.ts
|
|
861
|
+
/**
|
|
862
|
+
* 将毫秒耗时格式化为适合 CLI 展示的文本。
|
|
863
|
+
*/
|
|
864
|
+
function formatDuration(durationMs) {
|
|
865
|
+
return `${durationMs}ms`;
|
|
866
|
+
}
|
|
867
|
+
//#endregion
|
|
860
868
|
//#region src/cli/logBuildAppFinish.ts
|
|
861
869
|
let logBuildAppFinishOnlyShowOnce = false;
|
|
862
870
|
function collectServerUrls(webServer) {
|
|
@@ -942,6 +950,27 @@ function logBuildPackageSizeReport(options) {
|
|
|
942
950
|
//#endregion
|
|
943
951
|
//#region src/cli/openIde.ts
|
|
944
952
|
const execFileAsync = promisify(execFile);
|
|
953
|
+
async function openWechatIdeByAutomator(projectPath) {
|
|
954
|
+
(await launchAutomator({
|
|
955
|
+
projectPath,
|
|
956
|
+
trustProject: true
|
|
957
|
+
})).disconnect();
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* @description 若当前项目已在微信开发者工具中打开且自动化可连通,则直接复用现有会话,避免重复拉起 IDE。
|
|
961
|
+
*/
|
|
962
|
+
async function tryReuseOpenedWechatIde(projectPath) {
|
|
963
|
+
try {
|
|
964
|
+
(await connectOpenedAutomator({
|
|
965
|
+
projectPath,
|
|
966
|
+
timeout: 3e3
|
|
967
|
+
})).disconnect();
|
|
968
|
+
logger_default.info("目标项目已在微信开发者工具中打开,跳过重复打开。");
|
|
969
|
+
return true;
|
|
970
|
+
} catch {
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
945
974
|
/**
|
|
946
975
|
* @description 执行 IDE 打开流程,并在登录失效时允许按键重试。
|
|
947
976
|
*/
|
|
@@ -1001,7 +1030,15 @@ function resolveIdeProjectPath(mpDistRoot) {
|
|
|
1001
1030
|
function resolveIdeProjectRoot(mpDistRoot, cwd) {
|
|
1002
1031
|
return resolveIdeProjectPath(mpDistRoot) ?? cwd;
|
|
1003
1032
|
}
|
|
1004
|
-
async function openIde(platform, projectPath) {
|
|
1033
|
+
async function openIde(platform, projectPath, options = {}) {
|
|
1034
|
+
if (platform === "weapp" && projectPath && options.trustProject !== false) try {
|
|
1035
|
+
if (await tryReuseOpenedWechatIde(projectPath)) return;
|
|
1036
|
+
await openWechatIdeByAutomator(projectPath);
|
|
1037
|
+
return;
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
logger_default.warn("通过 automator 启动微信开发者工具并自动信任项目失败,回退到普通 open 流程。");
|
|
1040
|
+
logger_default.error(error);
|
|
1041
|
+
}
|
|
1005
1042
|
const argv = ["open", "-p"];
|
|
1006
1043
|
if (projectPath) argv.push(projectPath);
|
|
1007
1044
|
if (shouldPassPlatformArgToIdeOpen(platform)) argv.push("--platform", platform);
|
|
@@ -1085,7 +1122,7 @@ function emitDashboardEvents$1(handle, events) {
|
|
|
1085
1122
|
handle?.emitRuntimeEvents(events);
|
|
1086
1123
|
}
|
|
1087
1124
|
function registerBuildCommand(cli) {
|
|
1088
|
-
cli.command("build [root]", "build for production").option("--target <target>", `[string] transpile target (default: 'modules')`).option("--outDir <dir>", `[string] output directory (default: dist)`).option("-p, --platform <platform>", `[string] target platform (weapp | h5 | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--sourcemap [output]", `[boolean | "inline" | "hidden"] output source maps for build (default: false)`).option("--minify [minifier]", "[boolean | \"terser\" | \"esbuild\"] enable/disable minification, or specify minifier to use (default: esbuild)").option("--emptyOutDir", `[boolean] force empty outDir when it's outside of root`).option("-w, --watch", `[boolean] rebuilds when modules have changed on disk`).option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 输出分包分析仪表盘`, { default: false }).action(async (root, options) => {
|
|
1125
|
+
cli.command("build [root]", "build for production").option("--target <target>", `[string] transpile target (default: 'modules')`).option("--outDir <dir>", `[string] output directory (default: dist)`).option("-p, --platform <platform>", `[string] target platform (weapp | h5 | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--sourcemap [output]", `[boolean | "inline" | "hidden"] output source maps for build (default: false)`).option("--minify [minifier]", "[boolean | \"terser\" | \"esbuild\"] enable/disable minification, or specify minifier to use (default: esbuild)").option("--emptyOutDir", `[boolean] force empty outDir when it's outside of root`).option("-w, --watch", `[boolean] rebuilds when modules have changed on disk`).option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 输出分包分析仪表盘`, { default: false }).action(async (root, options) => {
|
|
1089
1126
|
filterDuplicateOptions(options);
|
|
1090
1127
|
const configFile = resolveConfigFile(options);
|
|
1091
1128
|
const targets = resolveRuntimeTargets(options);
|
|
@@ -1105,6 +1142,8 @@ function registerBuildCommand(cli) {
|
|
|
1105
1142
|
if (targets.runMini) {
|
|
1106
1143
|
const miniBuildStartedAt = Date.now();
|
|
1107
1144
|
const output = await buildService.build(options);
|
|
1145
|
+
const miniBuildDurationMs = Date.now() - miniBuildStartedAt;
|
|
1146
|
+
logger_default.success(`小程序构建完成,耗时:${colors.green(formatDuration(miniBuildDurationMs))}`);
|
|
1108
1147
|
if (!Array.isArray(output) && "output" in output) logBuildPackageSizeReport({
|
|
1109
1148
|
output,
|
|
1110
1149
|
subPackageMap: ctx.scanService?.subPackageMap,
|
|
@@ -1122,7 +1161,7 @@ function registerBuildCommand(cli) {
|
|
|
1122
1161
|
level: "success",
|
|
1123
1162
|
title: "mini build completed",
|
|
1124
1163
|
detail: `生产构建已完成,当前 analyze 结果包含 ${analyzeResult.packages.length} 个包。`,
|
|
1125
|
-
durationMs:
|
|
1164
|
+
durationMs: miniBuildDurationMs,
|
|
1126
1165
|
tags: ["build", "mini"]
|
|
1127
1166
|
}]);
|
|
1128
1167
|
}
|
|
@@ -1132,13 +1171,14 @@ function registerBuildCommand(cli) {
|
|
|
1132
1171
|
const webBuildStartedAt = Date.now();
|
|
1133
1172
|
try {
|
|
1134
1173
|
await webService?.build();
|
|
1135
|
-
|
|
1174
|
+
const webBuildDurationMs = Date.now() - webBuildStartedAt;
|
|
1175
|
+
logger_default.success(`Web 构建完成,输出目录:${colors.green(configService.relativeCwd(webConfig.outDir))},耗时:${colors.green(formatDuration(webBuildDurationMs))}`);
|
|
1136
1176
|
emitDashboardEvents$1(analyzeHandle, [{
|
|
1137
1177
|
kind: "build",
|
|
1138
1178
|
level: "success",
|
|
1139
1179
|
title: "web build completed",
|
|
1140
1180
|
detail: `Web 构建已完成,输出目录 ${configService.relativeCwd(webConfig.outDir)}。`,
|
|
1141
|
-
durationMs:
|
|
1181
|
+
durationMs: webBuildDurationMs,
|
|
1142
1182
|
tags: ["build", "web"]
|
|
1143
1183
|
}]);
|
|
1144
1184
|
} catch (error) {
|
|
@@ -1163,7 +1203,7 @@ function registerBuildCommand(cli) {
|
|
|
1163
1203
|
detail: "构建完成后准备打开 IDE 项目。",
|
|
1164
1204
|
tags: ["ide", "open"]
|
|
1165
1205
|
}]);
|
|
1166
|
-
await openIde(configService.platform, resolveIdeProjectPath(configService.mpDistRoot));
|
|
1206
|
+
await openIde(configService.platform, resolveIdeProjectPath(configService.mpDistRoot), { trustProject: options.trustProject });
|
|
1167
1207
|
}
|
|
1168
1208
|
if (analyzeHandle) await analyzeHandle.waitForExit();
|
|
1169
1209
|
ctx.watcherService?.closeAll();
|
|
@@ -1486,12 +1526,25 @@ function sleep(ms) {
|
|
|
1486
1526
|
}
|
|
1487
1527
|
//#endregion
|
|
1488
1528
|
//#region src/cli/commands/ide.ts
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1529
|
+
async function waitForTermination(cleanup) {
|
|
1530
|
+
await new Promise((resolve) => {
|
|
1531
|
+
const signals = ["SIGINT", "SIGTERM"];
|
|
1532
|
+
let cleaning = false;
|
|
1533
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
1534
|
+
const teardown = async () => {
|
|
1535
|
+
if (cleaning) return;
|
|
1536
|
+
cleaning = true;
|
|
1537
|
+
for (const signal of signals) process.off(signal, handlers.get(signal));
|
|
1538
|
+
await cleanup();
|
|
1539
|
+
resolve();
|
|
1540
|
+
};
|
|
1541
|
+
for (const signal of signals) {
|
|
1542
|
+
const handler = () => {
|
|
1543
|
+
teardown();
|
|
1544
|
+
};
|
|
1545
|
+
handlers.set(signal, handler);
|
|
1546
|
+
process.on(signal, handler);
|
|
1547
|
+
}
|
|
1495
1548
|
});
|
|
1496
1549
|
}
|
|
1497
1550
|
/**
|
|
@@ -1511,7 +1564,7 @@ async function runIdeCommand(action, root, options) {
|
|
|
1511
1564
|
});
|
|
1512
1565
|
if (resolved.platform !== "weapp") throw new Error("`weapp-vite ide logs` 当前仅支持微信小程序平台。");
|
|
1513
1566
|
if (!resolved.projectPath) throw new Error("无法解析微信开发者工具项目目录,请显式传入 root 或检查 project.config.json。");
|
|
1514
|
-
if (options.open) await openIde(resolved.platform, resolved.projectPath);
|
|
1567
|
+
if (options.open) await openIde(resolved.platform, resolved.projectPath, { trustProject: options.trustProject });
|
|
1515
1568
|
const forwardConsoleOptions = await resolveForwardConsoleOptions({
|
|
1516
1569
|
...resolved.weappViteConfig,
|
|
1517
1570
|
forwardConsole: resolved.weappViteConfig?.forwardConsole === false ? { enabled: true } : {
|
|
@@ -1531,25 +1584,12 @@ async function runIdeCommand(action, root, options) {
|
|
|
1531
1584
|
await session.close();
|
|
1532
1585
|
});
|
|
1533
1586
|
}
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
cleaning = true;
|
|
1541
|
-
for (const signal of signals) process.off(signal, handlers.get(signal));
|
|
1542
|
-
await cleanup();
|
|
1543
|
-
resolve();
|
|
1544
|
-
};
|
|
1545
|
-
const handlers = /* @__PURE__ */ new Map();
|
|
1546
|
-
for (const signal of signals) {
|
|
1547
|
-
const handler = () => {
|
|
1548
|
-
teardown();
|
|
1549
|
-
};
|
|
1550
|
-
handlers.set(signal, handler);
|
|
1551
|
-
process.on(signal, handler);
|
|
1552
|
-
}
|
|
1587
|
+
/**
|
|
1588
|
+
* @description 注册 IDE 相关子命令。
|
|
1589
|
+
*/
|
|
1590
|
+
function registerIdeCommand(cli) {
|
|
1591
|
+
cli.command("ide [action] [root]", "forward Wechat DevTools console logs to terminal").option("-o, --open", "[boolean] open ide before attaching log bridge").option("-p, --platform <platform>", "[string] target platform (weapp | h5)").option("--project-config <path>", "[string] project config path (miniprogram only)").option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).action(async (action, root, options) => {
|
|
1592
|
+
await runIdeCommand(action, root, options);
|
|
1553
1593
|
});
|
|
1554
1594
|
}
|
|
1555
1595
|
//#endregion
|
|
@@ -1599,7 +1639,7 @@ function registerNpmCommand(cli) {
|
|
|
1599
1639
|
//#endregion
|
|
1600
1640
|
//#region src/cli/commands/open.ts
|
|
1601
1641
|
function registerOpenCommand(cli) {
|
|
1602
|
-
cli.command("open [root]").option("-p, --platform <platform>", `[string] target platform (weapp | h5)`).action(async (root, options) => {
|
|
1642
|
+
cli.command("open [root]").option("-p, --platform <platform>", `[string] target platform (weapp | h5)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).action(async (root, options) => {
|
|
1603
1643
|
filterDuplicateOptions(options);
|
|
1604
1644
|
const configFile = resolveConfigFile(options);
|
|
1605
1645
|
const targets = resolveRuntimeTargets(options);
|
|
@@ -1610,7 +1650,7 @@ function registerOpenCommand(cli) {
|
|
|
1610
1650
|
projectPath: root,
|
|
1611
1651
|
cliPlatform: targets.rawPlatform
|
|
1612
1652
|
});
|
|
1613
|
-
await openIde(platform, projectPath ?? resolveIdeProjectRoot(mpDistRoot, process.cwd()));
|
|
1653
|
+
await openIde(platform, projectPath ?? resolveIdeProjectRoot(mpDistRoot, process.cwd()), { trustProject: options.trustProject });
|
|
1614
1654
|
});
|
|
1615
1655
|
}
|
|
1616
1656
|
//#endregion
|
|
@@ -1641,6 +1681,339 @@ function registerPrepareCommand(cli) {
|
|
|
1641
1681
|
});
|
|
1642
1682
|
}
|
|
1643
1683
|
//#endregion
|
|
1684
|
+
//#region package.json
|
|
1685
|
+
var version = "6.14.0";
|
|
1686
|
+
//#endregion
|
|
1687
|
+
//#region src/cli/devHotkeys.ts
|
|
1688
|
+
const DEV_SCREENSHOT_DIR = ".tmp/weapp-vite-dev-screenshots";
|
|
1689
|
+
const DEFAULT_SCREENSHOT_TIMEOUT = 3e4;
|
|
1690
|
+
const REG_PENDING_PREFIX = /^正在/;
|
|
1691
|
+
const FULLWIDTH_ASCII_START = 65281;
|
|
1692
|
+
const FULLWIDTH_ASCII_END = 65374;
|
|
1693
|
+
const FULLWIDTH_ASCII_OFFSET = 65248;
|
|
1694
|
+
const HOTKEY_DEDUP_WINDOW_MS = 32;
|
|
1695
|
+
function formatMcpUrl(host, port, endpoint) {
|
|
1696
|
+
return `http://${host}:${port}${endpoint}`;
|
|
1697
|
+
}
|
|
1698
|
+
function forwardSigint() {
|
|
1699
|
+
process.kill(process.pid, "SIGINT");
|
|
1700
|
+
}
|
|
1701
|
+
function forwardSigtstp() {
|
|
1702
|
+
process.kill(process.pid, "SIGTSTP");
|
|
1703
|
+
}
|
|
1704
|
+
function formatProjectLabel(cwd) {
|
|
1705
|
+
return path.basename(cwd) || cwd;
|
|
1706
|
+
}
|
|
1707
|
+
function formatMcpStatus(state) {
|
|
1708
|
+
if (!state.mcpEnabled) return "已禁用";
|
|
1709
|
+
return state.mcpRunning ? "运行中" : "未启动";
|
|
1710
|
+
}
|
|
1711
|
+
function formatFooterLine(state) {
|
|
1712
|
+
if (state.currentAction) return `执行中 ${state.currentAction}`;
|
|
1713
|
+
return "就绪 等待操作...";
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* @description 生成带状态的开发态快捷键帮助文本。
|
|
1717
|
+
*/
|
|
1718
|
+
function formatDevHotkeyHelpWithState(state) {
|
|
1719
|
+
const key = (value) => colors.bold(colors.green(value));
|
|
1720
|
+
const actionRows = [{
|
|
1721
|
+
key: key("s"),
|
|
1722
|
+
description: "截图当前页面并保存到本地"
|
|
1723
|
+
}, {
|
|
1724
|
+
key: key("m"),
|
|
1725
|
+
description: "开关 MCP 服务"
|
|
1726
|
+
}];
|
|
1727
|
+
const processRows = [
|
|
1728
|
+
{
|
|
1729
|
+
key: key("q"),
|
|
1730
|
+
description: "退出当前 dev"
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
key: key("Ctrl+C"),
|
|
1734
|
+
description: "强制中断当前 dev"
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
key: key("Ctrl+Z"),
|
|
1738
|
+
description: "暂时挂起当前 dev,恢复终端控制"
|
|
1739
|
+
}
|
|
1740
|
+
];
|
|
1741
|
+
const helpRows = [{
|
|
1742
|
+
key: key("h"),
|
|
1743
|
+
description: "重新显示这份帮助"
|
|
1744
|
+
}];
|
|
1745
|
+
const keyColumnWidth = Math.max(...[
|
|
1746
|
+
...actionRows,
|
|
1747
|
+
...processRows,
|
|
1748
|
+
...helpRows
|
|
1749
|
+
].map((row) => row.key.length));
|
|
1750
|
+
const formatRows = (rows) => rows.map(({ key, description }) => `按 ${key.padEnd(keyColumnWidth)} ${description}`);
|
|
1751
|
+
return [
|
|
1752
|
+
`${colors.bold(colors.green("DEV"))} weapp-vite v${version} ${state.projectLabel ?? "weapp"}`,
|
|
1753
|
+
"",
|
|
1754
|
+
"快捷命令",
|
|
1755
|
+
...formatRows(actionRows),
|
|
1756
|
+
"",
|
|
1757
|
+
"进程控制",
|
|
1758
|
+
...formatRows(processRows),
|
|
1759
|
+
"",
|
|
1760
|
+
"帮助",
|
|
1761
|
+
...formatRows(helpRows),
|
|
1762
|
+
"",
|
|
1763
|
+
`当前状态:${state.currentAction ?? "等待操作"} / MCP ${formatMcpStatus(state)}`
|
|
1764
|
+
].join("\n");
|
|
1765
|
+
}
|
|
1766
|
+
/**
|
|
1767
|
+
* @description 生成带状态的开发态快捷键简短提示。
|
|
1768
|
+
*/
|
|
1769
|
+
function formatDevHotkeyHintWithState(state) {
|
|
1770
|
+
const key = (value) => colors.bold(colors.green(value));
|
|
1771
|
+
if (state.currentAction) return `${formatFooterLine(state)},按 ${key("h")} 显示帮助,按 ${key("q")} 退出`;
|
|
1772
|
+
return `开发快捷键已就绪,按 ${key("h")} 显示帮助,按 ${key("q")} 退出`;
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* @description 生成开发态截图输出路径。
|
|
1776
|
+
*/
|
|
1777
|
+
function resolveDevScreenshotOutputPath(cwd, now = /* @__PURE__ */ new Date()) {
|
|
1778
|
+
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
1779
|
+
return path.join(cwd, DEV_SCREENSHOT_DIR, `screenshot-${stamp}.png`);
|
|
1780
|
+
}
|
|
1781
|
+
function formatLogPath(cwd, targetPath) {
|
|
1782
|
+
const relativePath = path.relative(cwd, targetPath);
|
|
1783
|
+
if (!relativePath || relativePath.startsWith("..")) return targetPath;
|
|
1784
|
+
return relativePath;
|
|
1785
|
+
}
|
|
1786
|
+
function formatResolvedScreenshotPath(cwd, fallbackPath, result) {
|
|
1787
|
+
return formatLogPath(cwd, result.path ?? fallbackPath);
|
|
1788
|
+
}
|
|
1789
|
+
function normalizeInputChar(input) {
|
|
1790
|
+
if (input.length !== 1) return input;
|
|
1791
|
+
const codePoint = input.codePointAt(0);
|
|
1792
|
+
if (!codePoint) return input;
|
|
1793
|
+
if (codePoint >= FULLWIDTH_ASCII_START && codePoint <= FULLWIDTH_ASCII_END) return String.fromCodePoint(codePoint - FULLWIDTH_ASCII_OFFSET);
|
|
1794
|
+
return input;
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* @description 执行当前页面截图并输出结果日志。
|
|
1798
|
+
*/
|
|
1799
|
+
async function runScreenshotAction(options) {
|
|
1800
|
+
const outputPath = resolveDevScreenshotOutputPath(options.cwd);
|
|
1801
|
+
await fs$1.mkdir(path.dirname(outputPath), { recursive: true });
|
|
1802
|
+
logger_default.info(`[dev action] 正在截图当前页面,输出到 ${colors.cyan(formatLogPath(options.cwd, outputPath))}`);
|
|
1803
|
+
const result = await takeScreenshot({
|
|
1804
|
+
fullPage: true,
|
|
1805
|
+
projectPath: options.projectPath,
|
|
1806
|
+
sharedSession: true,
|
|
1807
|
+
outputPath,
|
|
1808
|
+
timeout: DEFAULT_SCREENSHOT_TIMEOUT
|
|
1809
|
+
});
|
|
1810
|
+
const resolvedPath = formatResolvedScreenshotPath(options.cwd, outputPath, result);
|
|
1811
|
+
logger_default.success(`[dev action] 当前页面截图完成:${colors.cyan(resolvedPath)}`);
|
|
1812
|
+
return resolvedPath;
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* @description 在开发态启动终端快捷键,并将动作输出到本地日志。
|
|
1816
|
+
*/
|
|
1817
|
+
function startDevHotkeys(options) {
|
|
1818
|
+
if (options.platform !== "weapp" || !process.stdin.isTTY) return;
|
|
1819
|
+
emitKeypressEvents(process.stdin);
|
|
1820
|
+
const hasSetRawMode = typeof process.stdin.setRawMode === "function";
|
|
1821
|
+
if (hasSetRawMode) process.stdin.setRawMode(true);
|
|
1822
|
+
process.stdin.resume();
|
|
1823
|
+
let closed = false;
|
|
1824
|
+
let running = false;
|
|
1825
|
+
let mcpHandle;
|
|
1826
|
+
let onData;
|
|
1827
|
+
let onKeypress;
|
|
1828
|
+
let onSigcont;
|
|
1829
|
+
let currentAction;
|
|
1830
|
+
let lastAction;
|
|
1831
|
+
let lastRenderedPanel = "";
|
|
1832
|
+
const recentInputs = /* @__PURE__ */ new Map();
|
|
1833
|
+
const resolvedMcp = resolveWeappMcpConfig(options.mcpConfig);
|
|
1834
|
+
const getState = () => ({
|
|
1835
|
+
currentAction,
|
|
1836
|
+
lastAction,
|
|
1837
|
+
mcpEnabled: resolvedMcp.enabled,
|
|
1838
|
+
mcpRunning: Boolean(mcpHandle?.close),
|
|
1839
|
+
projectLabel: formatProjectLabel(options.cwd)
|
|
1840
|
+
});
|
|
1841
|
+
const detachTerminal = () => {
|
|
1842
|
+
if (hasSetRawMode) process.stdin.setRawMode(false);
|
|
1843
|
+
process.stdin.pause();
|
|
1844
|
+
};
|
|
1845
|
+
const attachTerminal = () => {
|
|
1846
|
+
if (closed) return;
|
|
1847
|
+
if (hasSetRawMode) process.stdin.setRawMode(true);
|
|
1848
|
+
process.stdin.resume();
|
|
1849
|
+
};
|
|
1850
|
+
const ensureTerminalActive = () => {
|
|
1851
|
+
if (closed) return;
|
|
1852
|
+
if (hasSetRawMode) process.stdin.setRawMode(true);
|
|
1853
|
+
process.stdin.resume();
|
|
1854
|
+
};
|
|
1855
|
+
const close = () => {
|
|
1856
|
+
if (closed) return;
|
|
1857
|
+
closed = true;
|
|
1858
|
+
if (onData) process.stdin.off("data", onData);
|
|
1859
|
+
if (onKeypress) process.stdin.off("keypress", onKeypress);
|
|
1860
|
+
if (onSigcont) process.off("SIGCONT", onSigcont);
|
|
1861
|
+
detachTerminal();
|
|
1862
|
+
if (mcpHandle?.close) mcpHandle.close().catch((error) => {
|
|
1863
|
+
logger_default.warn(`[dev action] MCP 服务关闭失败:${error instanceof Error ? error.message : String(error)}`);
|
|
1864
|
+
});
|
|
1865
|
+
closeSharedMiniProgram(options.projectPath).catch((error) => {
|
|
1866
|
+
logger_default.warn(`[dev action] DevTools 会话关闭失败:${error instanceof Error ? error.message : String(error)}`);
|
|
1867
|
+
});
|
|
1868
|
+
};
|
|
1869
|
+
const printPanel = (message, force = false) => {
|
|
1870
|
+
if (!force && message === lastRenderedPanel) return;
|
|
1871
|
+
lastRenderedPanel = message;
|
|
1872
|
+
logger_default.info(message);
|
|
1873
|
+
};
|
|
1874
|
+
const printHelp = () => {
|
|
1875
|
+
printPanel(formatDevHotkeyHelpWithState(getState()), true);
|
|
1876
|
+
ensureTerminalActive();
|
|
1877
|
+
};
|
|
1878
|
+
const printHint = () => {
|
|
1879
|
+
printPanel(formatDevHotkeyHintWithState(getState()));
|
|
1880
|
+
ensureTerminalActive();
|
|
1881
|
+
};
|
|
1882
|
+
const restore = () => {
|
|
1883
|
+
if (closed) return;
|
|
1884
|
+
if (onData) process.stdin.off("data", onData);
|
|
1885
|
+
if (onKeypress) process.stdin.off("keypress", onKeypress);
|
|
1886
|
+
attachTerminal();
|
|
1887
|
+
if (onData) process.stdin.on("data", onData);
|
|
1888
|
+
if (onKeypress) process.stdin.on("keypress", onKeypress);
|
|
1889
|
+
printHint();
|
|
1890
|
+
};
|
|
1891
|
+
const suspend = () => {
|
|
1892
|
+
lastRenderedPanel = "";
|
|
1893
|
+
detachTerminal();
|
|
1894
|
+
forwardSigtstp();
|
|
1895
|
+
};
|
|
1896
|
+
const toggleMcp = async () => {
|
|
1897
|
+
if (!resolvedMcp.enabled) {
|
|
1898
|
+
logger_default.warn("[dev action] MCP 已在配置中禁用,跳过切换。");
|
|
1899
|
+
return "MCP 已禁用";
|
|
1900
|
+
}
|
|
1901
|
+
if (mcpHandle?.close) {
|
|
1902
|
+
const url = formatMcpUrl(resolvedMcp.host, resolvedMcp.port, resolvedMcp.endpoint);
|
|
1903
|
+
logger_default.info(`[dev action] 正在关闭 MCP 服务:${colors.cyan(url)}`);
|
|
1904
|
+
await mcpHandle.close();
|
|
1905
|
+
mcpHandle = void 0;
|
|
1906
|
+
logger_default.success(`[dev action] MCP 服务已关闭:${colors.cyan(url)}`);
|
|
1907
|
+
return `MCP 已关闭 (${url})`;
|
|
1908
|
+
}
|
|
1909
|
+
const url = formatMcpUrl(resolvedMcp.host, resolvedMcp.port, resolvedMcp.endpoint);
|
|
1910
|
+
logger_default.info(`[dev action] 正在启动 MCP 服务:${colors.cyan(url)}`);
|
|
1911
|
+
mcpHandle = await startWeappViteMcpServer({
|
|
1912
|
+
endpoint: resolvedMcp.endpoint,
|
|
1913
|
+
host: resolvedMcp.host,
|
|
1914
|
+
port: resolvedMcp.port,
|
|
1915
|
+
transport: "streamable-http",
|
|
1916
|
+
unref: false,
|
|
1917
|
+
workspaceRoot: options.cwd
|
|
1918
|
+
});
|
|
1919
|
+
logger_default.success(`[dev action] MCP 服务已启动:${colors.cyan(url)}`);
|
|
1920
|
+
return `MCP 已启动 (${url})`;
|
|
1921
|
+
};
|
|
1922
|
+
const runAction = (label, pendingLabel, action) => {
|
|
1923
|
+
if (running) {
|
|
1924
|
+
const current = currentAction ?? "已有命令";
|
|
1925
|
+
logger_default.warn(`[dev action] 当前正在${current.replace(REG_PENDING_PREFIX, "")},请稍后再试。`);
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
running = true;
|
|
1929
|
+
currentAction = pendingLabel;
|
|
1930
|
+
printHint();
|
|
1931
|
+
action().then((summary) => {
|
|
1932
|
+
if (summary) lastAction = summary;
|
|
1933
|
+
}).catch((error) => {
|
|
1934
|
+
logger_default.error(`[dev action] ${label}失败:${error instanceof Error ? error.message : String(error)}`);
|
|
1935
|
+
}).finally(() => {
|
|
1936
|
+
running = false;
|
|
1937
|
+
currentAction = void 0;
|
|
1938
|
+
if (!closed) printHint();
|
|
1939
|
+
});
|
|
1940
|
+
};
|
|
1941
|
+
const handleInput = (input) => {
|
|
1942
|
+
if (closed) return;
|
|
1943
|
+
const normalizedInput = normalizeInputChar(input);
|
|
1944
|
+
if (normalizedInput === "") {
|
|
1945
|
+
close();
|
|
1946
|
+
forwardSigint();
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
if (normalizedInput === "") {
|
|
1950
|
+
suspend();
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
const normalized = normalizedInput.toLowerCase();
|
|
1954
|
+
if (normalized === "q") {
|
|
1955
|
+
close();
|
|
1956
|
+
forwardSigint();
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
if (normalized === "h") {
|
|
1960
|
+
printHelp();
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
if (normalized === "s") {
|
|
1964
|
+
runAction("截图", "正在截图当前页面", async () => {
|
|
1965
|
+
return `截图已保存到 ${await runScreenshotAction(options)}`;
|
|
1966
|
+
});
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
if (normalized === "m") runAction("MCP 切换", mcpHandle?.close ? "正在关闭 MCP 服务" : "正在启动 MCP 服务", async () => {
|
|
1970
|
+
return await toggleMcp();
|
|
1971
|
+
});
|
|
1972
|
+
};
|
|
1973
|
+
const handleInputOnce = (input, source) => {
|
|
1974
|
+
const normalizedInput = normalizeInputChar(input);
|
|
1975
|
+
const now = Date.now();
|
|
1976
|
+
for (const [token, timestamp] of recentInputs) if (now - timestamp > HOTKEY_DEDUP_WINDOW_MS) recentInputs.delete(token);
|
|
1977
|
+
const dedupKey = normalizedInput;
|
|
1978
|
+
const recentEntry = recentInputs.get(dedupKey);
|
|
1979
|
+
if (recentEntry !== void 0) {
|
|
1980
|
+
const [recentSource, recentTimestamp] = recentEntry.split(":");
|
|
1981
|
+
if (recentSource !== source && now - Number(recentTimestamp) <= HOTKEY_DEDUP_WINDOW_MS) return;
|
|
1982
|
+
}
|
|
1983
|
+
recentInputs.set(dedupKey, `${source}:${now}`);
|
|
1984
|
+
handleInput(normalizedInput);
|
|
1985
|
+
};
|
|
1986
|
+
onData = (chunk) => {
|
|
1987
|
+
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
1988
|
+
for (const char of text) handleInputOnce(char, "data");
|
|
1989
|
+
};
|
|
1990
|
+
process.stdin.on("data", onData);
|
|
1991
|
+
onKeypress = (str, key) => {
|
|
1992
|
+
if (key?.ctrl && key.name === "c") {
|
|
1993
|
+
handleInputOnce("", "keypress");
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
if (key?.ctrl && key.name === "z") {
|
|
1997
|
+
handleInputOnce("", "keypress");
|
|
1998
|
+
return;
|
|
1999
|
+
}
|
|
2000
|
+
if (typeof str === "string" && str) handleInputOnce(str, "keypress");
|
|
2001
|
+
};
|
|
2002
|
+
process.stdin.on("keypress", onKeypress);
|
|
2003
|
+
onSigcont = () => {
|
|
2004
|
+
restore();
|
|
2005
|
+
};
|
|
2006
|
+
process.on("SIGCONT", onSigcont);
|
|
2007
|
+
if (!options.silentStartupHint) printHint();
|
|
2008
|
+
if (resolvedMcp.enabled && resolvedMcp.autoStart) runAction("MCP 自动启动", "正在启动 MCP 服务", async () => {
|
|
2009
|
+
await toggleMcp();
|
|
2010
|
+
});
|
|
2011
|
+
return {
|
|
2012
|
+
close,
|
|
2013
|
+
restore
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
//#endregion
|
|
1644
2017
|
//#region src/cli/commands/serve.ts
|
|
1645
2018
|
function emitDashboardEvents(handle, events) {
|
|
1646
2019
|
handle?.emitRuntimeEvents(events);
|
|
@@ -1656,6 +2029,17 @@ const REG_DIST_POSIX_SEP = /\\/g;
|
|
|
1656
2029
|
function hasAnalyzeData(result) {
|
|
1657
2030
|
return result.packages.length > 0 || result.modules.length > 0;
|
|
1658
2031
|
}
|
|
2032
|
+
function waitForServeShutdownSignal() {
|
|
2033
|
+
return new Promise((resolve) => {
|
|
2034
|
+
const onSignal = () => {
|
|
2035
|
+
process.off("SIGINT", onSignal);
|
|
2036
|
+
process.off("SIGTERM", onSignal);
|
|
2037
|
+
resolve();
|
|
2038
|
+
};
|
|
2039
|
+
process.on("SIGINT", onSignal);
|
|
2040
|
+
process.on("SIGTERM", onSignal);
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
1659
2043
|
async function collectOutputFiles(root) {
|
|
1660
2044
|
const entries = await fs$1.readdir(root, { withFileTypes: true });
|
|
1661
2045
|
const files = [];
|
|
@@ -1730,7 +2114,7 @@ async function analyzeUiFallback(ctx) {
|
|
|
1730
2114
|
};
|
|
1731
2115
|
}
|
|
1732
2116
|
function registerServeCommand(cli) {
|
|
1733
|
-
cli.command("[root]", "start dev server").alias("serve").alias("dev").option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("-p, --platform <platform>", `[string] target platform (weapp | h5 | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--host [host]", `[string] web dev server host`).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 启动分包分析仪表盘 (实验特性)`, { default: false }).action(async (root, options) => {
|
|
2117
|
+
cli.command("[root]", "start dev server").alias("serve").alias("dev").option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("-p, --platform <platform>", `[string] target platform (weapp | h5 | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--host [host]", `[string] web dev server host`).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 启动分包分析仪表盘 (实验特性)`, { default: false }).action(async (root, options) => {
|
|
1734
2118
|
filterDuplicateOptions(options);
|
|
1735
2119
|
const configFile = resolveConfigFile(options);
|
|
1736
2120
|
const targets = resolveRuntimeTargets(options);
|
|
@@ -1787,162 +2171,181 @@ function registerServeCommand(cli) {
|
|
|
1787
2171
|
const enableAnalyze = Boolean(isUiEnabled(options) && targets.runMini);
|
|
1788
2172
|
let analyzeHandle;
|
|
1789
2173
|
let analyzeRunId = 0;
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
2174
|
+
const devHotkeysSession = targets.runMini ? startDevHotkeys({
|
|
2175
|
+
cwd: configService.cwd,
|
|
2176
|
+
mcpConfig: configService.weappViteConfig?.weapp?.mcp,
|
|
2177
|
+
platform: configService.platform,
|
|
2178
|
+
projectPath: resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd),
|
|
2179
|
+
silentStartupHint: true
|
|
2180
|
+
}) : void 0;
|
|
2181
|
+
try {
|
|
2182
|
+
const runAnalyze = async () => {
|
|
2183
|
+
const startedAt = Date.now();
|
|
2184
|
+
try {
|
|
2185
|
+
const result = await analyzeSubpackages(await createCompilerContext({
|
|
2186
|
+
key: `serve-ui-analyze:${process.pid}:${++analyzeRunId}`,
|
|
2187
|
+
cwd: configService.cwd,
|
|
2188
|
+
mode: configService.mode,
|
|
2189
|
+
isDev: false,
|
|
2190
|
+
configFile,
|
|
2191
|
+
inlineConfig: createInlineConfig(targets.mpPlatform),
|
|
2192
|
+
cliPlatform: targets.rawPlatform,
|
|
2193
|
+
projectConfigPath: options.projectConfig,
|
|
2194
|
+
syncSupportFiles: false
|
|
2195
|
+
}));
|
|
2196
|
+
if (hasAnalyzeData(result)) return {
|
|
2197
|
+
result,
|
|
2198
|
+
durationMs: Date.now() - startedAt,
|
|
2199
|
+
mode: "full"
|
|
2200
|
+
};
|
|
2201
|
+
} catch (error) {
|
|
2202
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2203
|
+
logger_default.warn(`[ui] 完整分析失败,已回退到 dist 文件扫描:${message}`);
|
|
2204
|
+
return {
|
|
2205
|
+
result: await analyzeUiFallback(ctx),
|
|
2206
|
+
durationMs: Date.now() - startedAt,
|
|
2207
|
+
mode: "fallback",
|
|
2208
|
+
fallbackReason: message
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
1812
2211
|
return {
|
|
1813
2212
|
result: await analyzeUiFallback(ctx),
|
|
1814
2213
|
durationMs: Date.now() - startedAt,
|
|
1815
2214
|
mode: "fallback",
|
|
1816
|
-
fallbackReason:
|
|
2215
|
+
fallbackReason: "完整分析结果为空,已回退到 dist 文件扫描。"
|
|
1817
2216
|
};
|
|
1818
|
-
}
|
|
1819
|
-
return {
|
|
1820
|
-
result: await analyzeUiFallback(ctx),
|
|
1821
|
-
durationMs: Date.now() - startedAt,
|
|
1822
|
-
mode: "fallback",
|
|
1823
|
-
fallbackReason: "完整分析结果为空,已回退到 dist 文件扫描。"
|
|
1824
2217
|
};
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
if (!analyzeHandle) return;
|
|
1828
|
-
emitDashboardEvents(analyzeHandle, [{
|
|
1829
|
-
kind: reason === "watch" ? "hmr" : "build",
|
|
1830
|
-
level: "info",
|
|
1831
|
-
title: reason === "watch" ? "analyze refresh started" : "initial analyze started",
|
|
1832
|
-
detail: reason === "watch" ? "检测到新的构建结束事件,开始刷新 analyze 面板。" : "开发态 UI 已启动,开始生成第一份 analyze 结果。",
|
|
1833
|
-
tags: reason === "watch" ? ["watch", "analyze"] : ["initial", "analyze"]
|
|
1834
|
-
}]);
|
|
1835
|
-
const next = await runAnalyze();
|
|
1836
|
-
if (next.mode === "fallback") emitDashboardEvents(analyzeHandle, [{
|
|
1837
|
-
kind: "diagnostic",
|
|
1838
|
-
level: "warning",
|
|
1839
|
-
title: "analyze fallback enabled",
|
|
1840
|
-
detail: next.fallbackReason ?? "完整分析不可用,已回退到 dist 文件扫描。",
|
|
1841
|
-
durationMs: next.durationMs,
|
|
1842
|
-
tags: ["analyze", "fallback"]
|
|
1843
|
-
}]);
|
|
1844
|
-
await analyzeHandle.update(next.result);
|
|
1845
|
-
emitDashboardEvents(analyzeHandle, [{
|
|
1846
|
-
kind: next.mode === "fallback" ? "diagnostic" : "build",
|
|
1847
|
-
level: next.mode === "fallback" ? "warning" : "success",
|
|
1848
|
-
title: reason === "watch" ? "analyze refresh completed" : "initial analyze completed",
|
|
1849
|
-
detail: next.mode === "fallback" ? `analyze 已回退到 dist 扫描,当前包含 ${next.result.packages.length} 个包。` : `analyze 已刷新完成,当前包含 ${next.result.packages.length} 个包与 ${next.result.modules.length} 个模块。`,
|
|
1850
|
-
durationMs: next.durationMs,
|
|
1851
|
-
tags: next.mode === "fallback" ? ["analyze", "fallback"] : ["analyze", reason === "watch" ? "refresh" : "initial"]
|
|
1852
|
-
}]);
|
|
1853
|
-
};
|
|
1854
|
-
if (targets.runMini) {
|
|
1855
|
-
const buildResult = await buildService.build(options);
|
|
1856
|
-
if (enableAnalyze) {
|
|
1857
|
-
const initialAnalyze = await runAnalyze();
|
|
1858
|
-
analyzeHandle = await startAnalyzeDashboard(initialAnalyze.result, {
|
|
1859
|
-
watch: true,
|
|
1860
|
-
cwd: configService.cwd,
|
|
1861
|
-
packageManagerAgent: configService.packageManager.agent,
|
|
1862
|
-
silentStartupLog: true
|
|
1863
|
-
}) ?? void 0;
|
|
2218
|
+
const triggerAnalyzeUpdate = async (reason = "watch") => {
|
|
2219
|
+
if (!analyzeHandle) return;
|
|
1864
2220
|
emitDashboardEvents(analyzeHandle, [{
|
|
1865
|
-
kind: "
|
|
1866
|
-
level: "
|
|
1867
|
-
title: "
|
|
1868
|
-
detail:
|
|
1869
|
-
|
|
1870
|
-
tags: ["dev", "ui"]
|
|
2221
|
+
kind: reason === "watch" ? "hmr" : "build",
|
|
2222
|
+
level: "info",
|
|
2223
|
+
title: reason === "watch" ? "analyze refresh started" : "initial analyze started",
|
|
2224
|
+
detail: reason === "watch" ? "检测到新的构建结束事件,开始刷新 analyze 面板。" : "开发态 UI 已启动,开始生成第一份 analyze 结果。",
|
|
2225
|
+
tags: reason === "watch" ? ["watch", "analyze"] : ["initial", "analyze"]
|
|
1871
2226
|
}]);
|
|
1872
|
-
|
|
2227
|
+
const next = await runAnalyze();
|
|
2228
|
+
if (next.mode === "fallback") emitDashboardEvents(analyzeHandle, [{
|
|
1873
2229
|
kind: "diagnostic",
|
|
1874
2230
|
level: "warning",
|
|
1875
|
-
title: "
|
|
1876
|
-
detail:
|
|
1877
|
-
durationMs:
|
|
1878
|
-
tags: [
|
|
1879
|
-
"analyze",
|
|
1880
|
-
"fallback",
|
|
1881
|
-
"initial"
|
|
1882
|
-
]
|
|
2231
|
+
title: "analyze fallback enabled",
|
|
2232
|
+
detail: next.fallbackReason ?? "完整分析不可用,已回退到 dist 文件扫描。",
|
|
2233
|
+
durationMs: next.durationMs,
|
|
2234
|
+
tags: ["analyze", "fallback"]
|
|
1883
2235
|
}]);
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
2236
|
+
await analyzeHandle.update(next.result);
|
|
2237
|
+
emitDashboardEvents(analyzeHandle, [{
|
|
2238
|
+
kind: next.mode === "fallback" ? "diagnostic" : "build",
|
|
2239
|
+
level: next.mode === "fallback" ? "warning" : "success",
|
|
2240
|
+
title: reason === "watch" ? "analyze refresh completed" : "initial analyze completed",
|
|
2241
|
+
detail: next.mode === "fallback" ? `analyze 已回退到 dist 扫描,当前包含 ${next.result.packages.length} 个包。` : `analyze 已刷新完成,当前包含 ${next.result.packages.length} 个包与 ${next.result.modules.length} 个模块。`,
|
|
2242
|
+
durationMs: next.durationMs,
|
|
2243
|
+
tags: next.mode === "fallback" ? ["analyze", "fallback"] : ["analyze", reason === "watch" ? "refresh" : "initial"]
|
|
2244
|
+
}]);
|
|
2245
|
+
};
|
|
2246
|
+
if (targets.runMini) {
|
|
2247
|
+
const miniBuildStartedAt = Date.now();
|
|
2248
|
+
const buildResult = await buildService.build(options);
|
|
2249
|
+
logger_default.success(`小程序初次构建完成,耗时:${formatDuration(Date.now() - miniBuildStartedAt)}`);
|
|
2250
|
+
if (enableAnalyze) {
|
|
2251
|
+
const initialAnalyze = await runAnalyze();
|
|
2252
|
+
analyzeHandle = await startAnalyzeDashboard(initialAnalyze.result, {
|
|
2253
|
+
watch: true,
|
|
2254
|
+
cwd: configService.cwd,
|
|
2255
|
+
packageManagerAgent: configService.packageManager.agent,
|
|
2256
|
+
silentStartupLog: true
|
|
2257
|
+
}) ?? void 0;
|
|
2258
|
+
emitDashboardEvents(analyzeHandle, [{
|
|
2259
|
+
kind: "command",
|
|
2260
|
+
level: "success",
|
|
2261
|
+
title: "dev ui session ready",
|
|
2262
|
+
detail: `开发态分析面板已启动,当前包含 ${initialAnalyze.result.packages.length} 个包。`,
|
|
2263
|
+
durationMs: initialAnalyze.durationMs,
|
|
2264
|
+
tags: ["dev", "ui"]
|
|
2265
|
+
}]);
|
|
2266
|
+
if (initialAnalyze.mode === "fallback") emitDashboardEvents(analyzeHandle, [{
|
|
2267
|
+
kind: "diagnostic",
|
|
2268
|
+
level: "warning",
|
|
2269
|
+
title: "initial analyze fallback enabled",
|
|
2270
|
+
detail: initialAnalyze.fallbackReason ?? "完整分析不可用,已回退到 dist 文件扫描。",
|
|
2271
|
+
durationMs: initialAnalyze.durationMs,
|
|
2272
|
+
tags: [
|
|
2273
|
+
"analyze",
|
|
2274
|
+
"fallback",
|
|
2275
|
+
"initial"
|
|
2276
|
+
]
|
|
2277
|
+
}]);
|
|
2278
|
+
let updating = false;
|
|
2279
|
+
if (analyzeHandle && buildResult && typeof buildResult.on === "function") buildResult.on("event", (event) => {
|
|
2280
|
+
if (event.code !== "END" || updating) return;
|
|
2281
|
+
updating = true;
|
|
2282
|
+
triggerAnalyzeUpdate("watch").finally(() => {
|
|
2283
|
+
updating = false;
|
|
2284
|
+
});
|
|
1890
2285
|
});
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2286
|
+
if (analyzeHandle) {
|
|
2287
|
+
updating = true;
|
|
2288
|
+
await triggerAnalyzeUpdate("initial");
|
|
2289
|
+
updating = false;
|
|
2290
|
+
}
|
|
1896
2291
|
}
|
|
1897
2292
|
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2293
|
+
let webServer;
|
|
2294
|
+
if (targets.runWeb) {
|
|
2295
|
+
const webServerStartedAt = Date.now();
|
|
2296
|
+
try {
|
|
2297
|
+
webServer = await webService?.startDevServer();
|
|
2298
|
+
logger_default.success(`Web 开发服务启动完成,耗时:${formatDuration(Date.now() - webServerStartedAt)}`);
|
|
2299
|
+
emitDashboardEvents(analyzeHandle, [{
|
|
2300
|
+
kind: "system",
|
|
2301
|
+
level: "success",
|
|
2302
|
+
title: "web dev server started",
|
|
2303
|
+
detail: "Web 开发服务器已启动,可与小程序调试 UI 并行工作。",
|
|
2304
|
+
durationMs: Date.now() - webServerStartedAt,
|
|
2305
|
+
tags: ["dev", "web"]
|
|
2306
|
+
}]);
|
|
2307
|
+
} catch (error) {
|
|
2308
|
+
emitDashboardEvents(analyzeHandle, [{
|
|
2309
|
+
kind: "diagnostic",
|
|
2310
|
+
level: "error",
|
|
2311
|
+
title: "web dev server failed",
|
|
2312
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
2313
|
+
durationMs: Date.now() - webServerStartedAt,
|
|
2314
|
+
tags: ["dev", "web"]
|
|
2315
|
+
}]);
|
|
2316
|
+
logger_default.error(error);
|
|
2317
|
+
throw error;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
if (targets.runMini) {
|
|
2321
|
+
logBuildAppFinish(configService, webServer, {
|
|
2322
|
+
skipWeb: !targets.runWeb,
|
|
2323
|
+
uiUrls: analyzeHandle?.urls
|
|
2324
|
+
});
|
|
2325
|
+
devHotkeysSession?.restore();
|
|
2326
|
+
} else if (targets.runWeb) logBuildAppFinish(configService, webServer, { skipMini: true });
|
|
2327
|
+
if (options.open && targets.runMini) {
|
|
1913
2328
|
emitDashboardEvents(analyzeHandle, [{
|
|
1914
|
-
kind: "
|
|
1915
|
-
level: "
|
|
1916
|
-
title: "
|
|
1917
|
-
detail:
|
|
1918
|
-
|
|
1919
|
-
tags: ["dev", "web"]
|
|
2329
|
+
kind: "command",
|
|
2330
|
+
level: "info",
|
|
2331
|
+
title: "opening ide",
|
|
2332
|
+
detail: "开发服务已就绪,准备打开 IDE 项目。",
|
|
2333
|
+
tags: ["ide", "open"]
|
|
1920
2334
|
}]);
|
|
1921
|
-
|
|
1922
|
-
|
|
2335
|
+
if (!await maybeStartForwardConsole({
|
|
2336
|
+
platform: configService.platform,
|
|
2337
|
+
mpDistRoot: configService.mpDistRoot,
|
|
2338
|
+
cwd: configService.cwd,
|
|
2339
|
+
weappViteConfig: configService.weappViteConfig
|
|
2340
|
+
})) await openIde(configService.platform, resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd), { trustProject: options.trustProject });
|
|
2341
|
+
devHotkeysSession?.restore();
|
|
1923
2342
|
}
|
|
2343
|
+
if (analyzeHandle) await analyzeHandle.waitForExit();
|
|
2344
|
+
else if (targets.runMini || targets.runWeb) await waitForServeShutdownSignal();
|
|
2345
|
+
} finally {
|
|
2346
|
+
devHotkeysSession?.close();
|
|
2347
|
+
ctx.watcherService?.closeAll();
|
|
1924
2348
|
}
|
|
1925
|
-
if (targets.runMini) logBuildAppFinish(configService, webServer, {
|
|
1926
|
-
skipWeb: !targets.runWeb,
|
|
1927
|
-
uiUrls: analyzeHandle?.urls
|
|
1928
|
-
});
|
|
1929
|
-
else if (targets.runWeb) logBuildAppFinish(configService, webServer, { skipMini: true });
|
|
1930
|
-
if (options.open && targets.runMini) {
|
|
1931
|
-
emitDashboardEvents(analyzeHandle, [{
|
|
1932
|
-
kind: "command",
|
|
1933
|
-
level: "info",
|
|
1934
|
-
title: "opening ide",
|
|
1935
|
-
detail: "开发服务已就绪,准备打开 IDE 项目。",
|
|
1936
|
-
tags: ["ide", "open"]
|
|
1937
|
-
}]);
|
|
1938
|
-
if (!await maybeStartForwardConsole({
|
|
1939
|
-
platform: configService.platform,
|
|
1940
|
-
mpDistRoot: configService.mpDistRoot,
|
|
1941
|
-
cwd: configService.cwd,
|
|
1942
|
-
weappViteConfig: configService.weappViteConfig
|
|
1943
|
-
})) await openIde(configService.platform, resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd));
|
|
1944
|
-
}
|
|
1945
|
-
if (analyzeHandle) await analyzeHandle.waitForExit();
|
|
1946
2349
|
});
|
|
1947
2350
|
}
|
|
1948
2351
|
//#endregion
|
|
@@ -2031,13 +2434,12 @@ const SKIP_COMMANDS = new Set([
|
|
|
2031
2434
|
"ide",
|
|
2032
2435
|
"mcp"
|
|
2033
2436
|
]);
|
|
2034
|
-
const
|
|
2437
|
+
const REG_EADDRINUSE = /EADDRINUSE/;
|
|
2035
2438
|
let started = false;
|
|
2036
2439
|
function shouldAutoStartMcp(argv) {
|
|
2037
2440
|
const command = argv[0];
|
|
2038
2441
|
if (!command || command.startsWith("-")) return true;
|
|
2039
2442
|
if (SKIP_COMMANDS.has(command)) return false;
|
|
2040
|
-
if (DEV_COMMANDS.has(command)) return true;
|
|
2041
2443
|
return command.includes("/") || command.includes("\\") || command.startsWith(".");
|
|
2042
2444
|
}
|
|
2043
2445
|
async function maybeAutoStartMcpServer(argv, cliOptions) {
|
|
@@ -2067,7 +2469,7 @@ async function maybeAutoStartMcpServer(argv, cliOptions) {
|
|
|
2067
2469
|
logger_default.info(` ➜ ${colors.cyan(mcpUrl)}`);
|
|
2068
2470
|
} catch (error) {
|
|
2069
2471
|
const message = error instanceof Error ? error.message : String(error);
|
|
2070
|
-
if (
|
|
2472
|
+
if (REG_EADDRINUSE.test(message)) {
|
|
2071
2473
|
logger_default.info(`[mcp] 端口 ${resolvedMcp.port} 已被占用,跳过自动启动。`);
|
|
2072
2474
|
started = true;
|
|
2073
2475
|
return;
|
|
@@ -2147,22 +2549,19 @@ function resolveManagedTsconfigBootstrapRoot(args) {
|
|
|
2147
2549
|
return path.resolve(firstArg);
|
|
2148
2550
|
}
|
|
2149
2551
|
try {
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
if (await tryRunIdeCommand(args)) return;
|
|
2552
|
+
const args = process.argv.slice(2);
|
|
2553
|
+
if (!await tryRunIdeCommand(args)) {
|
|
2153
2554
|
const managedTsconfigBootstrapRoot = resolveManagedTsconfigBootstrapRoot(args);
|
|
2154
2555
|
if (managedTsconfigBootstrapRoot) await syncManagedTsconfigBootstrapFiles(managedTsconfigBootstrapRoot);
|
|
2155
2556
|
cli.parse(process.argv, { run: false });
|
|
2156
2557
|
await maybeAutoStartMcpServer(args, cli.options);
|
|
2157
2558
|
await cli.runMatchedCommand();
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2559
|
+
}
|
|
2560
|
+
} catch (error) {
|
|
2561
|
+
if (!handlePrepareLifecycleError(process.argv.slice(2), error)) {
|
|
2160
2562
|
handleCLIError(error);
|
|
2161
2563
|
process.exitCode = 1;
|
|
2162
|
-
}
|
|
2163
|
-
} catch (error) {
|
|
2164
|
-
handleCLIError(error);
|
|
2165
|
-
process.exitCode = 1;
|
|
2564
|
+
}
|
|
2166
2565
|
}
|
|
2167
2566
|
//#endregion
|
|
2168
2567
|
export {};
|