weapp-vite 7.5.0 → 7.7.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.
Files changed (135) hide show
  1. package/README.md +14 -6
  2. package/THIRD_PARTY_NOTICES.md +60 -0
  3. package/bin/bootstrap.js +9 -4
  4. package/bin/bootstrap.test.ts +82 -1
  5. package/bin/nodeVersionWarning.js +17 -0
  6. package/bin/nodeVersionWarning.test.ts +30 -0
  7. package/dist/action-BD56SQh4.mjs +254 -0
  8. package/dist/action-CPtgEl6p.mjs +94 -0
  9. package/dist/action-le0bNff_.mjs +1102 -0
  10. package/dist/action-ytG5oFAw.mjs +138 -0
  11. package/dist/action-zmJrU8PC.mjs +245 -0
  12. package/dist/{analyze-ZJUvEdaY.mjs → analyze-DCZo-sJd.mjs} +4 -71
  13. package/dist/artifacts-TrTX9_jj.mjs +104 -0
  14. package/dist/assets-XyhpYtGl.mjs +630 -0
  15. package/dist/auto-import-components/resolvers.d.mts +1 -1
  16. package/dist/auto-import-components/resolvers.mjs +1 -1
  17. package/dist/auto-import-presets/wevu-router.d.mts +1 -1
  18. package/dist/auto-import-presets/wevu-router.mjs +1 -1
  19. package/dist/auto-import-presets/wevu.d.mts +1 -1
  20. package/dist/auto-import-presets/wevu.mjs +1 -1
  21. package/dist/auto-import-presets.d.mts +2 -2
  22. package/dist/auto-import-presets.mjs +2 -2
  23. package/dist/auto-routes.d.mts +1 -3
  24. package/dist/auto-routes.mjs +3 -4
  25. package/dist/{budget-BD7VqLCl.d.mts → budget-DTPngJU0.d.mts} +1 -10
  26. package/dist/budget-_Mu-4GKn.mjs +63 -0
  27. package/dist/builtProject-B145uOt5.mjs +534 -0
  28. package/dist/{package-7swhyLmf.mjs → classifier-CNTJOYQL.mjs} +5 -9
  29. package/dist/cli-acceptance.mjs +3 -4
  30. package/dist/cli.mjs +142 -4569
  31. package/dist/{config-DRGcCi3h.mjs → config-59ZWhCIf.mjs} +1 -2
  32. package/dist/{config-V0L-IAJf.d.mts → config-BNx2BODw.d.mts} +145 -150
  33. package/dist/config.d.mts +2 -2
  34. package/dist/config.mjs +3 -3
  35. package/dist/{constants-DEZdcsMn.mjs → constants-BOe8mgqL.mjs} +2 -4
  36. package/dist/{createCompilerContextInstance-DJH_P_nZ.mjs → createCompilerContextInstance-BXSdH2E8.mjs} +19930 -14019
  37. package/dist/{createContext-BqYzHhY9.mjs → createContext-W0TeXxbo.mjs} +7 -5
  38. package/dist/dashboard/analyze.d.mts +1 -7
  39. package/dist/dashboard/analyze.mjs +3 -1
  40. package/dist/dashboard/vite.d.mts +2 -4
  41. package/dist/dashboard/vite.mjs +1 -2
  42. package/dist/dashboard.d.mts +2 -2
  43. package/dist/dashboard.mjs +1733 -1
  44. package/dist/dashboardTransport-C9290QgS.mjs +15 -0
  45. package/dist/{dashboardViteBridge-Dy3nAD4m.mjs → dashboardViteBridge-B7QgQo94.mjs} +11 -11
  46. package/dist/{dev-fR5GiJRO.mjs → dev-D1QSExwk.mjs} +6 -3
  47. package/dist/devProvider-Bcvz5nu4.mjs +4966 -0
  48. package/dist/docs/README.md +14 -6
  49. package/dist/docs/ai-workflows.md +2 -0
  50. package/dist/docs/mcp.md +11 -1
  51. package/dist/docs/troubleshooting.md +16 -0
  52. package/dist/docs/vue-sfc.md +25 -2
  53. package/dist/docs/weapp-config.md +29 -0
  54. package/dist/docs/wevu-authoring.md +2 -0
  55. package/dist/doctor-worker.mjs +5 -5
  56. package/dist/doctor.d.mts +2 -8
  57. package/dist/doctor.mjs +24 -31
  58. package/dist/engine-Mnnm_ALP.mjs +53 -0
  59. package/dist/file-5eEfbK60.mjs +1 -0
  60. package/dist/{file-sC3jD7Fh.mjs → file-D8mp5GmB.mjs} +50 -26
  61. package/dist/{files-BqxFIPRp.mjs → files-Cy9jURJu.mjs} +1 -2
  62. package/dist/forwardConsole-D2Q0RIqc.mjs +509 -0
  63. package/dist/getInstance-BXNVH7sU.mjs +1 -0
  64. package/dist/{getInstance-DiGSzBNI.mjs → getInstance-DfNlbr-X.mjs} +2 -3
  65. package/dist/history-dKxzoHmN.mjs +774 -0
  66. package/dist/i18n.d.mts +1 -3
  67. package/dist/i18n.mjs +1 -2
  68. package/dist/{index-C9HjUX5c.d.mts → index-DIZJRrvK.d.mts} +1 -24
  69. package/dist/{index-CaXAtb9e.d.mts → index-SnaW3cvA.d.mts} +0 -12
  70. package/dist/index.d.mts +3 -7
  71. package/dist/index.mjs +6 -6
  72. package/dist/{json-BL8Dhhk6.mjs → json-Cvon2mw5.mjs} +1 -2
  73. package/dist/json.d.mts +1 -1
  74. package/dist/json.mjs +1 -1
  75. package/dist/lib-CJyMBzoe.mjs +140 -0
  76. package/dist/{lifecycle-BROTlwSL.mjs → lifecycle-CUo8PMQc.mjs} +123 -33
  77. package/dist/{loadConfig-C3BQhz7F.mjs → loadConfig-CKIdfW4o.mjs} +2 -3
  78. package/dist/loadConfig-D4WGJcYp.mjs +1 -0
  79. package/dist/logBuildAppFinish-DOBoof6S.mjs +54 -0
  80. package/dist/mcp-D88QvQgG.mjs +84 -0
  81. package/dist/{mcp-Cj8Maqo6.mjs → mcp-ovJgl1N9.mjs} +2 -4
  82. package/dist/mcp.d.mts +1 -3
  83. package/dist/mcp.mjs +1 -1
  84. package/dist/mcpClient-C8JzVZ46.mjs +283 -0
  85. package/dist/{processCleanup-B6KA30Zc.mjs → metadata-HlDKtlsu.mjs} +2 -21
  86. package/dist/nodeEnv-zq1EymWj.mjs +6 -0
  87. package/dist/openIde-QoYKhuuM.mjs +643 -0
  88. package/dist/options-Cz8vZ-0w.mjs +33 -0
  89. package/dist/{chunkStrategy-DRA5WpB-.mjs → package-DR62fAzP.mjs} +32 -31
  90. package/dist/path-E1OjBJAl.mjs +43 -0
  91. package/dist/{platform-CnkySBKz.mjs → platform-BiMpsZIb.mjs} +1 -2
  92. package/dist/{pluginHost--CaeyWpA.mjs → pluginHost-vn8Vty1J.mjs} +1 -2
  93. package/dist/processCleanup-DzB64WI8.mjs +18 -0
  94. package/dist/{protocol-vg8HGJ4n.mjs → protocol-HiSJRrSO.mjs} +43 -41
  95. package/dist/reader-wzPH_W8A.mjs +92 -0
  96. package/dist/realpathScope-DwlLaCk3.mjs +22 -0
  97. package/dist/report-PJVyo-UZ.mjs +105 -0
  98. package/dist/{path-doV773b7.mjs → resolvedId-DaxPh_yV.mjs} +5 -50
  99. package/dist/{resolvers-Dod-euqX.mjs → resolvers-CKYqmRD_.mjs} +10 -20
  100. package/dist/resolvers.d.mts +1 -1
  101. package/dist/resolvers.mjs +1 -1
  102. package/dist/{routes-C7fCmf92.d.mts → routes-DvAFX29h.d.mts} +0 -2
  103. package/dist/{runtime-Ee2HY6gR.d.mts → runtime-BL4RjBRa.d.mts} +1 -9
  104. package/dist/runtime-CKtMVERT.mjs +42 -0
  105. package/dist/{runtime-D6VCNhNY.mjs → runtime-DDUCb7pP.mjs} +4 -8
  106. package/dist/runtime.d.mts +1 -1
  107. package/dist/runtime.mjs +1 -1
  108. package/dist/schematics-DikfOjMD.mjs +90 -0
  109. package/dist/{session-PskhD-nZ.mjs → session-COrQJYif.mjs} +81 -21
  110. package/dist/test.d.mts +1 -3
  111. package/dist/test.mjs +54 -30
  112. package/dist/types-BK2EQ3Jm.d.mts +37 -0
  113. package/dist/{types-CgZn5X6j.d.mts → types-e2BMP9NU.d.mts} +1 -4
  114. package/dist/types.d.mts +4 -4
  115. package/dist/{upload-D4msblBf.mjs → upload-Chal5b3w.mjs} +118 -24
  116. package/dist/upload-worker.mjs +3 -5
  117. package/dist/{utils-CJSCgEj6.mjs → utils-CTGSZp4j.mjs} +72 -146
  118. package/dist/vite.d.mts +2 -4
  119. package/dist/vite.mjs +55 -21
  120. package/dist/volar.mjs +1 -2
  121. package/dist/{wevu-BQWUU7br.mjs → wevu-BaihCXO9.mjs} +1 -2
  122. package/dist/wevu-DTtSOyxB.d.mts +3 -0
  123. package/dist/{wevu-router-Dg1LnBlg.mjs → wevu-router-BIoxDbnu.mjs} +1 -2
  124. package/dist/wevu-router-CdWurGQ4.d.mts +3 -0
  125. package/dist/wxs-7V7MPzeW.mjs +1 -0
  126. package/dist/wxs-BdHHXltv.mjs +110 -0
  127. package/package.json +62 -53
  128. package/dist/dashboard-DvqF3Key.mjs +0 -1842
  129. package/dist/devProvider-BGBkw28J.mjs +0 -1050
  130. package/dist/file-DRb4eWqw.mjs +0 -1
  131. package/dist/getInstance-SiE6WZRh.mjs +0 -1
  132. package/dist/loadConfig-VGtBF4qm.mjs +0 -1
  133. package/dist/mcp-D3Yh24Cj.mjs +0 -529
  134. package/dist/wevu-C4KEC5kO.d.mts +0 -5
  135. package/dist/wevu-router-Cg2sIkIE.d.mts +0 -5
package/README.md CHANGED
@@ -16,13 +16,15 @@
16
16
 
17
17
  ## Node.js 支持范围
18
18
 
19
- 框架及编译依赖链要求 `^22.18.0 || ^24.11.0 || >=26.0.0`:Node 22 至少 22.18.0、Node 24 至少 24.11.0,或 Node 26 及以上版本;不支持 Node 20、23、25。这是 Babel 8 与必需构建依赖支持范围的交集,不能通过关闭 engines 校验恢复旧版本支持。
19
+ 框架及编译依赖链的官方支持范围为 `^22.23.4 || ^24.22.1 || >=26.12.1`:Node 22 至少 22.23.4、Node 24 至少 24.22.1,或 Node 26.12.1 及以上版本。Node 20、23、25 及低于上述最低版本的环境不在官方支持范围内。
20
20
 
21
- 升级已有项目时先升级 Node.js,再重新安装依赖。CLI 会在加载编译依赖前检查实际 Node 版本;`prepare` 也会明确拒绝不支持的环境。直接通过 Vite 或程序 API 消费时同样需要遵守包的 `engines.node`。
21
+ CLI(含 `prepare`)与 Tailwind 集成发现实际 Node 版本超出该范围时,会提示升级并继续尝试执行,不会仅因版本号退出。旧版 Node 若缺少依赖所需的语法或 API,仍可能导致加载或执行失败;直接通过 Vite 或程序 API 消费时也受实际依赖兼容性限制。
22
22
 
23
- `create-weapp-vite` 自身依赖要求更高:Node 22 至少 22.22.2、Node 24 至少 24.15.0,或 Node 26 及以上版本。新建项目按脚手架要求选择 Node,不要将框架最低版本误认为脚手架最低版本。
23
+ 建议升级至受支持 LTS 分支的最新安全补丁版本,再安装或更新依赖。包的 `engines.node` 声明保持不变;如果项目或团队启用了严格 engines 校验,包管理器仍可能拒绝安装。
24
24
 
25
- 发布候选在构建环境中打包,再在独立临时消费者中以严格 engines/peer 校验安装;CI 覆盖 Linux、Windows、macOS 的 Node 22.18.0、24.11.0、26.0.0 及 22/24 当前补丁版本,验证原生和 SFC 构建、prepare 与公开类型。
25
+ `create-weapp-vite` 与框架采用相同的 Node 支持范围;Vite+ 模板要求 `^24.22.1 || >=26.12.1`。
26
+
27
+ 发布候选在构建环境中打包,再在独立临时消费者中以严格 engines/peer 校验安装;CI 覆盖 Linux、Windows、macOS 的 Node 22.23.4、24.22.1、26.12.1 及 22/24 当前补丁版本,验证原生和 SFC 构建、prepare 与公开类型。
26
28
 
27
29
  ## 普通 Vite 与 Vite+
28
30
 
@@ -98,7 +100,7 @@ Hub 的 `/__devframes/__mcp` 聚合端点保持关闭,但与独立模式一样
98
100
 
99
101
  `weapp-vite/dashboard` 是 Node 端共享核心;CLI 独立工作台与 Vite DevTools 复用同一个 `DevframeDefinition` 和 `@weapp-vite/dashboard` 面板。可选适配器位于 `weapp-vite/dashboard/vite`,使用官方 `createPluginFromDevframe`,不会由普通包入口或 CLI 自动加载。
100
102
 
101
- 接入方安装 `@weapp-vite/dashboard`、`@vitejs/devtools` 和 `@vitejs/devtools-kit`。当前接入按 Vite `8.3.0`、DevTools / Kit `0.7.6`、Devframe `1.1.0` 验证;Kit 是可选 peer,宿主依赖不进入小程序产物。
103
+ 接入方安装 `@weapp-vite/dashboard`、`@vitejs/devtools` 和 `@vitejs/devtools-kit`。当前接入使用 Vite `8.3.4`、DevTools / Kit `0.8.0`、Devframe `1.2.5`;Kit 是可选 peer,宿主依赖不进入小程序产物。
102
104
 
103
105
  ```ts
104
106
  import type { DevToolsConfig } from '@vitejs/devtools/config'
@@ -133,7 +135,7 @@ export function createDashboardHost(snapshot: DashboardAnalyzeSnapshot, roots: D
133
135
 
134
136
  每个控制器只同时挂载到一个逻辑宿主。适配器记录成功安装的 Vite 配置身份,并仅在该配置拥有的环境关闭时释放核心。成功重启将所有权移交给新配置,旧实例和未安装的失败候选的清理都不会误释放当前控制器;替换前的资源校验失败时,旧宿主仍可查询和更新。首次 setup 失败或 SDK 安装开始后的失败会释放核心,不承诺回滚部分安装。自行使用 `dashboard.definition` 对接其他 Devframe 宿主时,调用方必须负责最终关闭和启动失败时的 `dashboard.dispose()`。核心不启动服务器,也不拥有外部宿主的认证、Origin 或 MCP 策略;共享宿主不是只读沙箱。
135
137
 
136
- DevTools `0.7.6` 自身存在程序化重启边界:重复使用同一个 `DevTools()` 返回值时,旧实例关闭可能同时关闭新实例的 WebSocket;不安装 Dashboard 也能复现。应在每次重载的 Vite 配置中重新调用 `DevTools()`,不要把该 SDK 插件实例长期缓存在复用的 inline 配置里。上述重启验证使用重新创建的 SDK 宿主和保留的 Dashboard 控制器,不代表修复了上游传输问题。
138
+ DevTools 自身存在程序化重启边界:重复使用同一个 `DevTools()` 返回值时,旧实例关闭可能同时关闭新实例的 WebSocket;不安装 Dashboard 也能复现。应在每次重载的 Vite 配置中重新调用 `DevTools()`,不要把该 SDK 插件实例长期缓存在复用的 inline 配置里。上述重启验证使用重新创建的 SDK 宿主和保留的 Dashboard 控制器,不代表修复了上游传输问题。
137
139
 
138
140
  面板默认位于 `/__weapp-vite/`,自定义目录与应用 `base` 独立。前端复用宿主连接或从页面相对位置发现元数据,复制视图链接保留目录和查询参数但排除认证 fragment。适配器只在开发模式挂载,生产构建不要求可选面板资源,也不导出报告。以上入口仅用于 Node 开发 / 构建宿主,不应导入小程序 AppService。
139
141
 
@@ -590,3 +592,9 @@ const artifact = await buildTestArtifact({ cwd: process.cwd() })
590
592
  ## AI 改动验收
591
593
 
592
594
  通过 `wv accept --inspect --json` 检查环境;审阅配置后运行 `wv accept --trust --json`。现有 MCP 同时提供验收启动、状态、取消和报告工具,无需模型 Key。[接入指南](https://vite.weapp.dev/guide/acceptance)。独立 `weapp-agent` CLI 同仓维护并保留原命令。
595
+
596
+ ## 微信开发者工具多版本
597
+
598
+ 默认使用本机已安装的最新 Stable。用 `wv ide devtools list` 查看安装,`wv ide devtools add "<path-to-cli>"` 登记自定义位置;`wv open --devtools-channel=nightly` 或 `wv build --open --devtools-channel=rc --devtools-version=<version>` 明确选择测试版本。旧 `cliPath` 和路径环境变量继续固定安装,显式渠道/版本可覆盖继承配置。官方版本查询不阻塞默认选择,`--require-official-latest` 可启用严格检查。
599
+
600
+ 仓库包可用 `pnpm e2e:ide:matrix --targets=stable,rc,nightly --suite=ide-smoke` 串行测试已有安装。矩阵记录实际 IDE、基础库和资源清理结果;缺失、未登录、失败或未完成项返回非零。安装与登录由用户完成。同一账号切换安装后可能需要重新扫码;矩阵以非交互模式记录“需要重新登录”并继续其他版本,无需预备多个账号。完整 CLI、编程接口和 MCP 用法见 [weapp-ide-cli 文档](https://vite.weapp.dev/packages/weapp-ide-cli)。
@@ -0,0 +1,60 @@
1
+ # 第三方软件声明
2
+
3
+ weapp-vite 的 JavaScript 产物包含以下 MIT 许可的软件,完整许可证保留如下。
4
+
5
+ ## Chokidar 6.0.0
6
+
7
+ 此副本保留 Chokidar 6 的监听后端与生命周期模型,并包含本地修补:缺失目录的
8
+ Windows 注册恢复,以及目录扫描和文件读取的异步归属隔离。
9
+
10
+ ```text
11
+ The MIT License (MIT)
12
+
13
+ Copyright (c) 2012 Paul Miller (https://paulmillr.com), Elan Shanker
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the “Software”), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in
23
+ all copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
+ THE SOFTWARE.
32
+ ```
33
+
34
+ ## readdirp 5.1.1
35
+
36
+ 此依赖随 Chokidar 打包,保留上游实现。
37
+
38
+ ```text
39
+ MIT License
40
+
41
+ Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com)
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining a copy
44
+ of this software and associated documentation files (the "Software"), to deal
45
+ in the Software without restriction, including without limitation the rights
46
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
47
+ copies of the Software, and to permit persons to whom the Software is
48
+ furnished to do so, subject to the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be included in all
51
+ copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59
+ SOFTWARE.
60
+ ```
package/bin/bootstrap.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { readFileSync } from 'node:fs'
2
+ // 安装生命周期早于 workspace 构建,启动阶段直接使用日志包同源的轻量染色实现。
3
+ import colors from 'picocolors'
2
4
  // eslint-disable-next-line e18e/ban-dependencies -- 启动检查使用与发布 engines 完全相同的 npm semver 语义。
3
5
  import satisfies from 'semver/functions/satisfies.js'
6
+ import { formatNodeVersionWarning } from './nodeVersionWarning.js'
4
7
 
5
8
  const { engines } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
6
9
 
@@ -115,11 +118,13 @@ export async function runWeappViteCLI(options = {}) {
115
118
  importer = () => ['accept', 'mcp'].includes(argv[0])
116
119
  ? import('../dist/cli-acceptance.mjs')
117
120
  : import('../dist/cli.mjs'),
118
- write = message => getGlobalProcess().stderr.write(`\n WARN ${message}\n\n`),
121
+ write = message => getGlobalProcess().stderr.write(`\n ${colors.bold(colors.yellow('警告'))} ${message}\n\n`),
119
122
  } = options
120
- // 在加载 Babel 等依赖前校验同一份发布声明;prepare 的容错不能吞掉不受支持的运行时。
121
- if (!satisfies(nodeVersion, engines.node)) {
122
- throw new Error(`weapp-vite requires Node.js ${engines.node}; current version is ${nodeVersion}. Please upgrade Node.js before running this command.`)
123
+ // Bun 的 versions.node 只是兼容标识;真实 Node 在加载依赖前提示升级,不因版本号阻断命令。
124
+ const bunVersion = getGlobalProcess().versions.bun
125
+ const isBun = typeof bunVersion === 'string' && bunVersion.length > 0
126
+ if (!isBun && !satisfies(nodeVersion, engines.node)) {
127
+ write(formatNodeVersionWarning('weapp-vite', nodeVersion, engines.node))
123
128
  }
124
129
  const restorePrepareGuard = guardPrepareProcessExit(argv)
125
130
  const restoreKnownNoiseGuard = guardKnownLocalPkgResolveNoise()
@@ -1,9 +1,23 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest'
1
+ import realProcess from 'node:process'
2
+ import { stripVTControlCharacters } from 'node:util'
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
4
+ import { runBootstrapFixture } from '../test/helpers/bootstrapFixture'
2
5
  import { formatPrepareSkipMessage, guardKnownLocalPkgResolveNoise, guardPrepareProcessExit, runWeappViteCLI } from './bootstrap.js'
3
6
 
4
7
  describe('bin bootstrap', () => {
8
+ beforeEach(() => {
9
+ vi.stubGlobal('process', {
10
+ ...realProcess,
11
+ exitCode: undefined,
12
+ exit: vi.fn(),
13
+ on: vi.fn(),
14
+ off: vi.fn(),
15
+ })
16
+ })
17
+
5
18
  afterEach(() => {
6
19
  vi.restoreAllMocks()
20
+ vi.unstubAllGlobals()
7
21
  })
8
22
 
9
23
  it('guards process exit state for prepare at bin level', () => {
@@ -90,3 +104,70 @@ describe('bin bootstrap', () => {
90
104
  expect(consoleErrorSpy.mock.calls[0]?.[0]?.message).toBe('boom')
91
105
  })
92
106
  })
107
+
108
+ describe('cold CLI bootstrap without workspace dist', () => {
109
+ it('never reports a child terminated by a signal as successful', async () => {
110
+ const outcome = await runBootstrapFixture(['--eval', 'process.kill(process.pid, "SIGTERM")']).then(
111
+ result => ({ kind: 'exit' as const, result }),
112
+ (error: unknown) => ({ kind: 'signal' as const, error }),
113
+ )
114
+ if (outcome.kind === 'exit') {
115
+ // Windows 可能将强制终止表示为非零退出码,Unix 则通过 signal 报告。
116
+ expect(outcome.result.exitCode).not.toBe(0)
117
+ }
118
+ else {
119
+ expect(outcome.error).toMatchObject({ signal: 'SIGTERM' })
120
+ }
121
+ })
122
+
123
+ it('keeps prepare successful and reports the missing CLI artifact in Chinese on stderr', async () => {
124
+ const result = await runBootstrapFixture(['bin/weapp-vite.js', 'prepare'])
125
+
126
+ expect(result.exitCode).toBe(0)
127
+ expect(result.stdout).toBe('')
128
+ expect(result.stderr).toContain('警告')
129
+ expect(result.stderr).toContain('[prepare] 跳过 .weapp-vite 支持文件预生成:')
130
+ expect(result.stderr.replaceAll('\\', '/')).toContain('dist/cli.mjs')
131
+ expect(result.stderr).not.toContain('@weapp-core/logger')
132
+ })
133
+
134
+ it.each([
135
+ ['build', 'cli.mjs'],
136
+ ['dev', 'cli.mjs'],
137
+ ['accept', 'cli-acceptance.mjs'],
138
+ ['mcp', 'cli-acceptance.mjs'],
139
+ ])('preserves the missing artifact failure for %s', async (command, artifact) => {
140
+ const result = await runBootstrapFixture(['bin/weapp-vite.js', command])
141
+
142
+ expect(result.exitCode).not.toBe(0)
143
+ expect(result.stdout).toBe('')
144
+ expect(result.stderr).toContain('ERR_MODULE_NOT_FOUND')
145
+ expect(result.stderr.replaceAll('\\', '/')).toContain(`dist/${artifact}`)
146
+ expect(result.stderr).not.toContain('@weapp-core/logger')
147
+ })
148
+
149
+ it.each([
150
+ { name: 'forced colors', env: { FORCE_COLOR: '1' }, colored: true },
151
+ { name: 'disabled colors', env: { NO_COLOR: '1' }, colored: false },
152
+ { name: 'NO_COLOR precedence', env: { FORCE_COLOR: '1', NO_COLOR: '1' }, colored: false },
153
+ ])('keeps the Chinese Node warning on stderr with $name', async ({ env, colored }) => {
154
+ const result = await runBootstrapFixture([
155
+ '--input-type=module',
156
+ '--eval',
157
+ `
158
+ const { runWeappViteCLI } = await import('./bin/bootstrap.js')
159
+ await runWeappViteCLI({ argv: ['build'], nodeVersion: '20.19.0', importer: async () => {} })
160
+ `,
161
+ ], env)
162
+
163
+ expect(result.exitCode).toBe(0)
164
+ expect(result.stdout).toBe('')
165
+ expect(result.stderr).toContain('警告')
166
+ expect(result.stderr).toContain('当前 Node.js 版本')
167
+ expect(result.stderr).toContain('20.19.0')
168
+ expect(result.stderr).toContain('推荐版本:')
169
+ expect(result.stderr).toContain('为获得安全修复,建议升级至受支持 LTS 分支的最新补丁版本。')
170
+ expect(result.stderr).toContain('本次将继续运行;若遇到依赖兼容问题,请先升级 Node.js。')
171
+ expect(stripVTControlCharacters(result.stderr) !== result.stderr).toBe(colored)
172
+ })
173
+ })
@@ -0,0 +1,17 @@
1
+ // 此格式器也用于尚无 workspace 构建产物的安装阶段,不能依赖日志包的 dist。
2
+ import colors from 'picocolors'
3
+
4
+ /**
5
+ * 格式化 Node.js 版本升级提示,供 CLI 与构建插件共用。
6
+ * @param {string} name 发出提示的工具名称
7
+ * @param {string} nodeVersion 当前 Node.js 版本
8
+ * @param {string} nodeRange 官方支持的版本范围
9
+ */
10
+ export function formatNodeVersionWarning(name, nodeVersion, nodeRange) {
11
+ return [
12
+ `${name} 检测到当前 Node.js 版本 ${colors.bold(colors.yellow(nodeVersion))} 不在官方支持范围内。`,
13
+ ` 推荐版本:${colors.bold(colors.cyan(nodeRange))}`,
14
+ ' 为获得安全修复,建议升级至受支持 LTS 分支的最新补丁版本。',
15
+ ` ${colors.dim('本次将继续运行;若遇到依赖兼容问题,请先升级 Node.js。')}`,
16
+ ].join('\n')
17
+ }
@@ -0,0 +1,30 @@
1
+ import { stripVTControlCharacters } from 'node:util'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { runBootstrapFixture } from '../test/helpers/bootstrapFixture'
4
+
5
+ describe('cold Node version warning formatter without workspace dist', () => {
6
+ it.each([
7
+ { name: 'forced colors', env: { FORCE_COLOR: '1' }, colored: true },
8
+ { name: 'disabled colors', env: { NO_COLOR: '1' }, colored: false },
9
+ { name: 'NO_COLOR precedence', env: { FORCE_COLOR: '1', NO_COLOR: '1' }, colored: false },
10
+ ])('formats the Chinese warning with $name using only registry dependencies', async ({ env, colored }) => {
11
+ const result = await runBootstrapFixture([
12
+ '--input-type=module',
13
+ '--eval',
14
+ `
15
+ const { formatNodeVersionWarning } = await import('./bin/nodeVersionWarning.js')
16
+ process.stdout.write(formatNodeVersionWarning('weapp.tailwindcss', '20.19.0', '^22.23.4 || ^24.22.1 || >=26.12.1'))
17
+ `,
18
+ ], env)
19
+
20
+ expect(result.exitCode).toBe(0)
21
+ expect(result.stdout).toContain('weapp.tailwindcss 检测到当前 Node.js 版本')
22
+ expect(result.stdout).toContain('20.19.0')
23
+ expect(result.stdout).toContain('推荐版本:')
24
+ expect(result.stdout).toContain('^22.23.4 || ^24.22.1 || >=26.12.1')
25
+ expect(result.stdout).toContain('为获得安全修复,建议升级至受支持 LTS 分支的最新补丁版本。')
26
+ expect(result.stdout).toContain('本次将继续运行;若遇到依赖兼容问题,请先升级 Node.js。')
27
+ expect(result.stderr).toBe('')
28
+ expect(stripVTControlCharacters(result.stdout) !== result.stdout).toBe(colored)
29
+ })
30
+ })
@@ -0,0 +1,254 @@
1
+ import { c as getBackendForCapability } from "./createCompilerContextInstance-BXSdH2E8.mjs";
2
+ import { t as VERSION } from "./constants-BOe8mgqL.mjs";
3
+ import { r as logger_default } from "./logger-DGn5iEVN.mjs";
4
+ import { i as resolveRuntimeTargets } from "./runtime-CKtMVERT.mjs";
5
+ import { n as openIde, r as resolveIdeCommandContext } from "./openIde-QoYKhuuM.mjs";
6
+ import { o as resolveConfigFile, r as filterDuplicateOptions } from "./options-Cz8vZ-0w.mjs";
7
+ import { a as startForwardConsoleBridge, i as resolveForwardConsoleOptions, o as readLatestHmrProfileSummary } from "./forwardConsole-D2Q0RIqc.mjs";
8
+ import process from "node:process";
9
+ import { bootstrapWechatDevtoolsSettings, connectOpenedAutomator, defaultCustomConfigFilePath, detectWechatDevtoolsServicePort, getWechatIdeTestAccounts, getWechatIdeTicket, getWechatIdeToolInfo, queryWechatIdeLogin, refreshWechatIdeTicket, resolveCliPath, resolveProjectAutomatorPort, setWechatIdeTicket } from "weapp-ide-cli";
10
+ // src/cli/commands/ide/action.ts
11
+ async function runIdeDoctor(projectPath, options) {
12
+ const resolvedCli = await resolveCliPath();
13
+ const servicePort = await detectWechatDevtoolsServicePort().then((result) => ({
14
+ ...result,
15
+ error: void 0
16
+ })).catch((error) => ({
17
+ servicePortEnabled: void 0,
18
+ servicePort: void 0,
19
+ error
20
+ }));
21
+ const cliCheck = resolvedCli.cliPath ? {
22
+ status: "ok",
23
+ value: {
24
+ path: resolvedCli.cliPath,
25
+ source: resolvedCli.source
26
+ }
27
+ } : {
28
+ fix: "执行 `weapp config set cliPath <path-to-cli>` 配置微信开发者工具 CLI。",
29
+ message: "未找到可用的微信开发者工具 CLI。",
30
+ status: "failed",
31
+ value: { source: resolvedCli.source }
32
+ };
33
+ const servicePortCheck = servicePort.servicePortEnabled === false ? {
34
+ fix: "在微信开发者工具中打开:设置 -> 安全设置 -> 服务端口。",
35
+ message: "微信开发者工具服务端口已关闭。",
36
+ status: "failed",
37
+ value: servicePort
38
+ } : servicePort.error ? {
39
+ fix: "执行 `wv ide doctor --json` 查看底层错误,并确认微信开发者工具已安装。",
40
+ message: servicePort.error instanceof Error ? servicePort.error.message : String(servicePort.error),
41
+ status: "warning"
42
+ } : {
43
+ status: servicePort.servicePortEnabled === true ? "ok" : "unknown",
44
+ value: {
45
+ enabled: servicePort.servicePortEnabled ?? null,
46
+ port: servicePort.servicePort ?? null
47
+ }
48
+ };
49
+ let loginCheck = {
50
+ fix: "打开微信开发者工具完成登录后重试。",
51
+ message: "暂未确认登录状态。",
52
+ status: "unknown"
53
+ };
54
+ if (resolvedCli.cliPath) try {
55
+ const result = await queryWechatIdeLogin(resolvedCli.cliPath, { timeout: 3e3 });
56
+ loginCheck = result.status === "success" ? {
57
+ status: result.login ? "ok" : "warning",
58
+ value: result.login,
59
+ ...result.login ? {} : { message: "原生 CLI 明确返回未登录,请打开微信开发者工具完成登录。" }
60
+ } : {
61
+ status: "unknown",
62
+ message: `登录查询未确认状态(${result.reason}),不能据此认定未登录。`
63
+ };
64
+ } catch {
65
+ loginCheck = {
66
+ message: "登录查询执行失败,登录状态仍未确认。",
67
+ status: "unknown"
68
+ };
69
+ }
70
+ const projectCheck = projectPath ? {
71
+ status: "ok",
72
+ value: projectPath
73
+ } : {
74
+ fix: "在项目目录执行命令,或显式传入 `wv ide doctor <project-root>`。",
75
+ message: "未解析到微信开发者工具项目目录。",
76
+ status: "warning"
77
+ };
78
+ let automatorCheck = {
79
+ message: projectPath ? "当前项目没有可连接的已打开 automator 会话。" : "缺少项目目录,跳过 automator 检查。",
80
+ status: "unknown"
81
+ };
82
+ let toolCheck = {
83
+ message: "当前没有可读取的 DevTools Tool.getInfo。",
84
+ status: "unknown"
85
+ };
86
+ if (projectPath) try {
87
+ const miniProgram = await connectOpenedAutomator({
88
+ projectPath,
89
+ port: resolveProjectAutomatorPort(projectPath),
90
+ timeout: 3e3
91
+ });
92
+ automatorCheck = {
93
+ status: "ok",
94
+ value: true
95
+ };
96
+ try {
97
+ if (typeof miniProgram.toolInfo === "function") toolCheck = {
98
+ status: "ok",
99
+ value: await miniProgram.toolInfo()
100
+ };
101
+ } catch {
102
+ toolCheck = {
103
+ status: "warning",
104
+ message: "项目自动化连接已建立,但 Tool.getInfo 未能返回工具信息;宿主版本仍未确认。",
105
+ fix: "确认目标项目模拟器就绪后重新运行 doctor;此结果不证明登录失效。"
106
+ };
107
+ } finally {
108
+ miniProgram.disconnect?.();
109
+ }
110
+ } catch (error) {
111
+ automatorCheck = {
112
+ fix: "先执行 `wv open` 打开项目;若服务端口已开启,关闭多余 DevTools 窗口后重试。",
113
+ message: error instanceof Error ? error.message : String(error),
114
+ status: "warning"
115
+ };
116
+ }
117
+ const report = {
118
+ checks: {
119
+ automator: automatorCheck,
120
+ cli: cliCheck,
121
+ login: loginCheck,
122
+ project: projectCheck,
123
+ servicePort: servicePortCheck,
124
+ tool: toolCheck
125
+ },
126
+ configFile: defaultCustomConfigFilePath,
127
+ nodeVersion: process.version,
128
+ platform: process.platform,
129
+ weappViteVersion: VERSION
130
+ };
131
+ const output = JSON.stringify(report, null, 2);
132
+ if (options.json) process.stdout.write(`${output}\n`);
133
+ else logger_default.info(output);
134
+ if (options.strict && Object.values(report.checks).some((check) => check.status === "failed")) throw new Error("微信开发者工具环境诊断未通过,请根据 doctor 输出修复失败项后重试。");
135
+ return report;
136
+ }
137
+ async function waitForTermination(cleanup) {
138
+ await new Promise((resolve) => {
139
+ const signals = ["SIGINT", "SIGTERM"];
140
+ let cleaning = false;
141
+ const handlers = /* @__PURE__ */ new Map();
142
+ const teardown = async () => {
143
+ if (cleaning) return;
144
+ cleaning = true;
145
+ for (const signal of signals) process.off(signal, handlers.get(signal));
146
+ await cleanup();
147
+ resolve();
148
+ };
149
+ for (const signal of signals) {
150
+ const handler = () => {
151
+ teardown();
152
+ };
153
+ handlers.set(signal, handler);
154
+ process.on(signal, handler);
155
+ }
156
+ });
157
+ }
158
+ function formatIdeOutput(data, options) {
159
+ if (options.json) return JSON.stringify(data, null, 2);
160
+ return JSON.stringify(data, null, 2);
161
+ }
162
+ /**
163
+ * @description 执行 ide 子命令。
164
+ */
165
+ async function runIdeCommand(action, root, options) {
166
+ if (action !== "logs" && action !== "setup" && action !== "info" && action !== "test-accounts" && action !== "ticket" && action !== "ticket:set" && action !== "ticket:refresh" && action !== "doctor") throw new Error(`未知 ide 子命令: ${action ?? "(empty)"}`);
167
+ filterDuplicateOptions(options);
168
+ const configFile = resolveConfigFile(options);
169
+ const targets = resolveRuntimeTargets(options);
170
+ const ideBackend = getBackendForCapability(targets, "miniprogram", "ide");
171
+ if (!ideBackend) throw new Error("`weapp-vite ide` 当前仅支持小程序平台。");
172
+ const resolved = await resolveIdeCommandContext({
173
+ configFile,
174
+ mode: options.mode ?? "development",
175
+ platform: ideBackend.platform,
176
+ projectPath: root,
177
+ cliPlatform: targets.rawPlatform
178
+ });
179
+ if (action !== "doctor" && resolved.platform !== "weapp") throw new Error("`weapp-vite ide logs` 当前仅支持微信小程序平台。");
180
+ if (action === "doctor") {
181
+ await runIdeDoctor(resolved.projectPath, options);
182
+ return;
183
+ }
184
+ const projectPath = resolved.projectPath;
185
+ if (!projectPath) throw new Error("无法解析微信开发者工具项目目录,请显式传入 root 或检查 project.config.json。");
186
+ if (action === "setup") {
187
+ const result = await bootstrapWechatDevtoolsSettings({
188
+ projectPath,
189
+ trustProject: options.trustProject
190
+ });
191
+ logger_default.info(`已完成微信开发者工具配置预热:扫描实例 ${result.touchedInstanceCount} 个,检测服务端口配置 ${result.detectedSecurityCount} 处,写入项目信任 ${result.trustedProjectCount} 处。`);
192
+ return;
193
+ }
194
+ if (options.open) await openIde(resolved.platform, projectPath, {
195
+ openRecovery: options.openRecovery,
196
+ trustProject: options.trustProject,
197
+ openStrategy: options.ideOpenStrategy
198
+ });
199
+ if (action === "info") {
200
+ const result = await getWechatIdeToolInfo({ projectPath });
201
+ logger_default.info(formatIdeOutput(result, options));
202
+ return;
203
+ }
204
+ if (action === "test-accounts") {
205
+ const result = await getWechatIdeTestAccounts({ projectPath });
206
+ logger_default.info(formatIdeOutput(result, options));
207
+ return;
208
+ }
209
+ if (action === "ticket") {
210
+ const result = await getWechatIdeTicket({ projectPath });
211
+ logger_default.info(formatIdeOutput(result, options));
212
+ return;
213
+ }
214
+ if (action === "ticket:set") {
215
+ if (!options.ticket) throw new Error("`weapp-vite ide ticket:set` 需要提供 --ticket。");
216
+ await setWechatIdeTicket({
217
+ projectPath,
218
+ ticket: options.ticket
219
+ });
220
+ logger_default.info(`已设置微信开发者工具 ticket:${options.ticket}`);
221
+ return;
222
+ }
223
+ if (action === "ticket:refresh") {
224
+ await refreshWechatIdeTicket({ projectPath });
225
+ logger_default.info("已刷新微信开发者工具 ticket。");
226
+ return;
227
+ }
228
+ const forwardConsoleOptions = await resolveForwardConsoleOptions({
229
+ ...resolved.weappViteConfig,
230
+ forwardConsole: resolved.weappViteConfig?.forwardConsole === false ? { enabled: true } : {
231
+ ...typeof resolved.weappViteConfig?.forwardConsole === "object" ? resolved.weappViteConfig.forwardConsole : {},
232
+ enabled: true
233
+ }
234
+ });
235
+ const latestHmrSummary = await readLatestHmrProfileSummary({
236
+ cwd: resolved.cwd ?? process.cwd(),
237
+ relativeCwd: (value) => resolved.cwd ? value.replace(`${resolved.cwd}/`, "") : value,
238
+ weappViteConfig: resolved.weappViteConfig
239
+ });
240
+ if (latestHmrSummary) logger_default.info(latestHmrSummary.line);
241
+ const session = await startForwardConsoleBridge({
242
+ projectPath,
243
+ port: resolveProjectAutomatorPort(projectPath),
244
+ agentName: void 0,
245
+ logLevels: forwardConsoleOptions.logLevels,
246
+ unhandledErrors: forwardConsoleOptions.unhandledErrors,
247
+ onReadyMessage: "[forwardConsole] 已进入持续监听模式,按 Ctrl+C 退出。"
248
+ });
249
+ await waitForTermination(async () => {
250
+ logger_default.info("[forwardConsole] 正在关闭日志桥接...");
251
+ await session.close();
252
+ });
253
+ }
254
+ export { runIdeCommand };
@@ -0,0 +1,94 @@
1
+ import { r as logger_default } from "./logger-DGn5iEVN.mjs";
2
+ import { t as createCompilerContext } from "./createContext-W0TeXxbo.mjs";
3
+ import { i as resolveRuntimeTargets, t as createInlineConfig } from "./runtime-CKtMVERT.mjs";
4
+ import { o as resolveConfigFile, r as filterDuplicateOptions } from "./options-Cz8vZ-0w.mjs";
5
+ import { t as setCommandNodeEnv } from "./nodeEnv-zq1EymWj.mjs";
6
+ import { o as resolveUploadTimeout, t as UploadCommandError } from "./report-PJVyo-UZ.mjs";
7
+ import { n as resolveUploadPlatforms } from "./upload-Chal5b3w.mjs";
8
+ import { t as terminateStaleSassEmbeddedProcess } from "./processCleanup-DzB64WI8.mjs";
9
+ import { i as prepareAutoUploadMetadata, n as executeUploadTarget, r as UploadExecutionError, t as createUploadTarget } from "./builtProject-B145uOt5.mjs";
10
+ import process from "node:process";
11
+ import path from "node:path";
12
+ // src/cli/commands/upload/action.ts
13
+ async function buildUploadTarget(cwd, platform, options, action, item) {
14
+ const targets = resolveRuntimeTargets({ platform });
15
+ const ctx = await createCompilerContext({
16
+ cwd,
17
+ mode: options.mode ?? "production",
18
+ configFile: resolveConfigFile(options),
19
+ inlineConfig: createInlineConfig(targets),
20
+ cliPlatform: platform,
21
+ projectConfigPath: options.projectConfig,
22
+ emitDefaultAutoImportOutputs: false,
23
+ preloadAppEntry: false
24
+ });
25
+ try {
26
+ const target = await createUploadTarget(ctx.configService, options, action);
27
+ if (item) {
28
+ item.platform = target.platform;
29
+ item.requestedVersion = target.context.version;
30
+ item.stage = "build";
31
+ }
32
+ logger_default.info(`[${action}:${target.platform}] 构建${target.context.version ? ` ${target.context.version}` : ""}`);
33
+ await ctx.buildService.build({});
34
+ return target;
35
+ } finally {
36
+ ctx.watcherService.closeAll();
37
+ terminateStaleSassEmbeddedProcess();
38
+ }
39
+ }
40
+ async function runUploadCommand(root, options, action = "upload") {
41
+ filterDuplicateOptions(options);
42
+ const platforms = resolveUploadPlatforms(options.platform ?? options.p);
43
+ setCommandNodeEnv("production");
44
+ const cwd = path.resolve(root ?? process.cwd());
45
+ if (action === "preview") {
46
+ options = await prepareAutoUploadMetadata(cwd, options, action);
47
+ for (const platform of platforms) {
48
+ const target = await buildUploadTarget(cwd, platform, options, action);
49
+ await executeUploadTarget(target, options, action);
50
+ }
51
+ return;
52
+ }
53
+ const report = {
54
+ schemaVersion: 1,
55
+ action: "upload",
56
+ status: "success",
57
+ results: platforms.map((platform) => ({
58
+ platform: platform ?? null,
59
+ stage: "prepare",
60
+ status: "not-run"
61
+ }))
62
+ };
63
+ let active = report.results[0];
64
+ try {
65
+ const timeoutMs = resolveUploadTimeout(options.timeout);
66
+ options = await prepareAutoUploadMetadata(cwd, options, action);
67
+ for (const item of report.results) item.requestedVersion = options.uv?.trim();
68
+ for (const [index, platform] of platforms.entries()) {
69
+ active = report.results[index];
70
+ const target = await buildUploadTarget(cwd, platform, options, action, active);
71
+ active.stage = "validate";
72
+ const result = await executeUploadTarget(target, options, action, {
73
+ timeoutMs,
74
+ onUpload: () => {
75
+ active.stage = "upload";
76
+ }
77
+ });
78
+ active.status = options.dryRun ? "dry-run" : "success";
79
+ if (!options.dryRun) active.result = result;
80
+ }
81
+ return report;
82
+ } catch (error) {
83
+ report.status = "failed";
84
+ report.error = error instanceof Error ? error.message : String(error);
85
+ active.status = "failed";
86
+ active.error = report.error;
87
+ if (error instanceof UploadExecutionError) {
88
+ active.remoteOutcome = error.remoteOutcome;
89
+ if (error.remoteOutcome === "unknown" && error.reason !== "failed") active.status = "unknown";
90
+ }
91
+ throw new UploadCommandError(report);
92
+ }
93
+ }
94
+ export { runUploadCommand };