vite-plugin-taro 0.3.2 → 0.4.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 (260) hide show
  1. package/README.en.md +44 -0
  2. package/README.md +22 -497
  3. package/client.d.ts +9 -0
  4. package/dist/node/plugins/client/client-taro.d.ts +4 -0
  5. package/dist/node/plugins/client/client-taro.js +19 -0
  6. package/dist/node/plugins/client/constant.d.ts +4 -0
  7. package/dist/node/plugins/client/constant.js +4 -0
  8. package/dist/node/plugins/conditional/conditional-directives.d.ts +4 -0
  9. package/dist/node/plugins/{conditional-directives.js → conditional/conditional-directives.js} +27 -11
  10. package/dist/node/plugins/css/plugins.d.ts +4 -0
  11. package/dist/node/plugins/css/plugins.js +84 -0
  12. package/dist/node/plugins/h5/constant.d.ts +2 -0
  13. package/dist/node/plugins/h5/constant.js +3 -0
  14. package/dist/node/plugins/h5/plugins.d.ts +4 -0
  15. package/dist/node/plugins/h5/plugins.js +161 -0
  16. package/dist/node/plugins/h5/resolver/module-resolver.d.ts +14 -0
  17. package/dist/node/plugins/h5/resolver/module-resolver.js +19 -0
  18. package/dist/node/plugins/h5/transform-app.d.ts +10 -0
  19. package/dist/node/plugins/h5/transform-app.js +48 -0
  20. package/dist/node/plugins/wx/dev/dev-host.d.ts +15 -0
  21. package/dist/node/plugins/wx/dev/dev-host.js +352 -0
  22. package/dist/node/plugins/wx/dev/hmr-files.d.ts +28 -0
  23. package/dist/node/plugins/wx/dev/hmr-files.js +34 -0
  24. package/dist/node/plugins/wx/dev/patch-publisher.d.ts +22 -0
  25. package/dist/node/plugins/wx/dev/patch-publisher.js +40 -0
  26. package/dist/node/plugins/wx/dev/plugin.d.ts +7 -0
  27. package/dist/node/plugins/wx/dev/plugin.js +73 -0
  28. package/dist/node/plugins/wx/dev/react-refresh.d.ts +20 -0
  29. package/dist/node/plugins/wx/dev/react-refresh.js +198 -0
  30. package/dist/node/plugins/wx/module.d.ts +45 -0
  31. package/dist/node/plugins/wx/module.js +66 -0
  32. package/dist/node/plugins/wx/native/compile-native-component-interface.d.ts +21 -0
  33. package/dist/node/plugins/wx/native/compile-native-component-interface.js +29 -0
  34. package/dist/node/plugins/wx/native/create-native-component-output.d.ts +15 -0
  35. package/dist/node/plugins/wx/native/create-native-component-output.js +39 -0
  36. package/dist/node/plugins/wx/native/native-component-assets.d.ts +26 -0
  37. package/dist/node/plugins/wx/native/native-component-assets.js +76 -0
  38. package/dist/node/plugins/wx/native/native-component-interface.d.ts +12 -0
  39. package/dist/node/plugins/wx/native/native-component-interface.js +201 -0
  40. package/dist/node/plugins/wx/output/files.d.ts +12 -0
  41. package/dist/node/plugins/wx/output/files.js +12 -0
  42. package/dist/node/plugins/wx/output/json.d.ts +14 -0
  43. package/dist/node/plugins/wx/output/json.js +52 -0
  44. package/dist/node/plugins/wx/output/relative-root.d.ts +2 -0
  45. package/dist/node/plugins/wx/output/relative-root.js +6 -0
  46. package/dist/node/plugins/wx/output/templates.d.ts +7 -0
  47. package/dist/node/plugins/wx/output/templates.js +100 -0
  48. package/dist/node/plugins/wx/placement/placer.d.ts +78 -0
  49. package/dist/node/plugins/wx/placement/placer.js +145 -0
  50. package/dist/node/plugins/wx/placement/plan.d.ts +46 -0
  51. package/dist/node/plugins/wx/placement/plan.js +210 -0
  52. package/dist/node/plugins/wx/plugins.d.ts +4 -0
  53. package/dist/node/plugins/wx/plugins.js +137 -0
  54. package/dist/node/plugins/wx/render/capsule-wrapper.d.ts +3 -0
  55. package/dist/node/plugins/wx/render/capsule-wrapper.js +64 -0
  56. package/dist/node/plugins/wx/render/capsule.d.ts +4 -0
  57. package/dist/node/plugins/wx/render/capsule.js +13 -0
  58. package/dist/node/plugins/wx/render/native.d.ts +9 -0
  59. package/dist/node/plugins/wx/render/native.js +45 -0
  60. package/dist/node/plugins/wx/render/transport.d.ts +17 -0
  61. package/dist/node/plugins/wx/render/transport.js +94 -0
  62. package/dist/node/plugins/wx/resolve/resolver.d.ts +7 -0
  63. package/dist/node/plugins/wx/resolve/resolver.js +86 -0
  64. package/dist/node/plugins/wx/resolve/specialize-bootstrap.d.ts +9 -0
  65. package/dist/node/plugins/wx/resolve/specialize-bootstrap.js +9 -0
  66. package/dist/node/plugins/wx/resolve/specialize-page-capsule.d.ts +9 -0
  67. package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +11 -0
  68. package/dist/node/utils/constant.d.ts +1 -0
  69. package/dist/node/utils/constant.js +1 -0
  70. package/dist/node/utils/memoize.d.ts +122 -0
  71. package/dist/node/utils/memoize.js +86 -0
  72. package/dist/node/utils/modules.d.ts +20 -24
  73. package/dist/node/utils/modules.js +21 -34
  74. package/dist/node/utils/once.d.ts +10 -0
  75. package/dist/node/utils/once.js +20 -0
  76. package/dist/node/utils/packages.d.ts +1 -0
  77. package/dist/node/utils/packages.js +1 -1
  78. package/dist/node/utils/project-config.d.ts +3 -0
  79. package/dist/node/utils/project-config.js +8 -0
  80. package/dist/node/utils/serialized-task-queue.d.ts +9 -0
  81. package/dist/node/utils/serialized-task-queue.js +17 -0
  82. package/dist/node/utils/transform.d.ts +11 -0
  83. package/dist/node/utils/transform.js +58 -0
  84. package/dist/node/vite-plugin.d.ts +1 -1
  85. package/dist/node/vite-plugin.js +11 -27
  86. package/dist/options.d.ts +3 -4
  87. package/dist/runtime/{taro → client/taro}/api.d.ts +0 -1
  88. package/dist/runtime/client/taro/api.js +9 -0
  89. package/dist/runtime/client/taro/component.d.ts +1 -0
  90. package/dist/runtime/client/taro/component.js +1 -0
  91. package/dist/runtime/client/taro/define-native-component.d.ts +7 -0
  92. package/dist/runtime/client/taro/define-native-component.js +4 -0
  93. package/dist/runtime/h5/app.d.ts +2 -0
  94. package/dist/runtime/h5/app.js +15 -0
  95. package/dist/runtime/h5/taro-runtime.d.ts +1 -1
  96. package/dist/runtime/h5/taro-runtime.js +1 -4
  97. package/dist/runtime/wx/amphibious/bootstrap.d.ts +4 -0
  98. package/dist/runtime/wx/amphibious/bootstrap.js +16 -0
  99. package/dist/runtime/wx/amphibious/transport.d.ts +2 -0
  100. package/dist/runtime/wx/amphibious/transport.js +4 -0
  101. package/dist/runtime/wx/capsule/app.d.ts +2 -0
  102. package/dist/runtime/wx/capsule/app.js +7 -0
  103. package/dist/runtime/wx/capsule/component.d.ts +3 -0
  104. package/dist/runtime/wx/capsule/component.js +4 -0
  105. package/dist/runtime/wx/capsule/page.d.ts +3 -0
  106. package/dist/runtime/wx/capsule/page.js +68 -0
  107. package/dist/runtime/wx/capsule/taro-runtime.d.ts +6 -0
  108. package/dist/runtime/wx/capsule/taro-runtime.js +6 -0
  109. package/dist/runtime/wx/dev/dev-runtime.d.ts +1 -0
  110. package/dist/runtime/wx/dev/dev-runtime.js +246 -0
  111. package/dist/runtime/wx/native/app.d.ts +1 -0
  112. package/dist/runtime/wx/native/app.js +3 -0
  113. package/dist/runtime/wx/native/component.d.ts +1 -0
  114. package/dist/runtime/wx/native/component.js +3 -0
  115. package/dist/runtime/wx/native/page.d.ts +1 -0
  116. package/dist/runtime/wx/native/page.js +4 -0
  117. package/dist/runtime/wx/systemjs/system-core.d.ts +4 -0
  118. package/dist/runtime/wx/systemjs/system-core.js +331 -0
  119. package/package.json +21 -14
  120. package/src/node/plugins/client/client-taro.ts +23 -0
  121. package/src/node/plugins/client/constant.ts +5 -0
  122. package/src/node/plugins/{conditional-directives.ts → conditional/conditional-directives.ts} +33 -13
  123. package/src/node/plugins/css/plugins.ts +96 -0
  124. package/src/node/plugins/h5/constant.ts +4 -0
  125. package/src/node/plugins/h5/plugins.ts +197 -0
  126. package/src/node/plugins/h5/resolver/module-resolver.ts +32 -0
  127. package/src/node/plugins/h5/transform-app.ts +90 -0
  128. package/src/node/plugins/wx/dev/dev-host.ts +448 -0
  129. package/src/node/plugins/wx/dev/hmr-files.ts +55 -0
  130. package/src/node/plugins/wx/dev/patch-publisher.ts +49 -0
  131. package/src/node/plugins/wx/dev/plugin.ts +82 -0
  132. package/src/node/plugins/wx/dev/react-refresh.ts +227 -0
  133. package/src/node/plugins/wx/module.ts +97 -0
  134. package/src/node/plugins/wx/native/compile-native-component-interface.ts +47 -0
  135. package/src/node/plugins/wx/native/create-native-component-output.ts +57 -0
  136. package/src/node/plugins/wx/native/native-component-assets.ts +114 -0
  137. package/src/node/plugins/wx/native/native-component-interface.ts +265 -0
  138. package/src/node/plugins/wx/output/files.ts +27 -0
  139. package/src/node/plugins/wx/output/json.ts +79 -0
  140. package/src/node/plugins/wx/output/relative-root.ts +7 -0
  141. package/src/node/plugins/wx/output/templates.ts +141 -0
  142. package/src/node/plugins/wx/placement/placer.ts +172 -0
  143. package/src/node/plugins/wx/placement/plan.ts +306 -0
  144. package/src/node/plugins/wx/plugins.ts +165 -0
  145. package/src/node/plugins/wx/render/capsule-wrapper.ts +86 -0
  146. package/src/node/plugins/wx/render/capsule.ts +21 -0
  147. package/src/node/plugins/wx/render/native.ts +84 -0
  148. package/src/node/plugins/wx/render/transport.ts +157 -0
  149. package/src/node/plugins/wx/resolve/resolver.ts +125 -0
  150. package/src/node/plugins/wx/resolve/specialize-bootstrap.ts +27 -0
  151. package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +29 -0
  152. package/src/node/utils/constant.ts +1 -0
  153. package/src/node/utils/memoize.ts +149 -0
  154. package/src/node/utils/modules.ts +36 -38
  155. package/src/node/utils/once.ts +21 -0
  156. package/src/node/utils/packages.ts +1 -1
  157. package/src/node/utils/project-config.ts +10 -0
  158. package/src/node/utils/serialized-task-queue.ts +20 -0
  159. package/src/node/utils/transform.ts +82 -0
  160. package/src/node/vite-plugin.ts +12 -32
  161. package/src/options.ts +3 -4
  162. package/src/runtime/client/taro/api.ts +11 -0
  163. package/src/runtime/client/taro/component.ts +1 -0
  164. package/src/runtime/client/taro/define-native-component.ts +15 -0
  165. package/src/runtime/h5/app.ts +25 -0
  166. package/src/runtime/h5/taro-runtime.ts +1 -4
  167. package/src/runtime/wx/amphibious/bootstrap.ts +22 -0
  168. package/src/runtime/wx/amphibious/transport.ts +10 -0
  169. package/src/runtime/wx/capsule/app.ts +9 -0
  170. package/src/runtime/wx/capsule/component.ts +6 -0
  171. package/src/runtime/wx/capsule/page.ts +96 -0
  172. package/src/runtime/wx/capsule/taro-runtime.ts +14 -0
  173. package/src/runtime/wx/dev/dev-runtime.ts +317 -0
  174. package/src/runtime/wx/native/app.ts +4 -0
  175. package/src/runtime/wx/native/component.ts +4 -0
  176. package/src/runtime/wx/native/page.ts +6 -0
  177. package/src/runtime/wx/systemjs/LICENSE +10 -0
  178. package/src/runtime/wx/systemjs/system-core.js +370 -0
  179. package/src/runtime/wx/systemjs/system.d.ts +55 -0
  180. package/src/runtime/wx/wechat.d.ts +52 -0
  181. package/README.zh.md +0 -521
  182. package/dist/node/build-context.d.ts +0 -25
  183. package/dist/node/build-context.js +0 -47
  184. package/dist/node/css/css-pipeline.d.ts +0 -35
  185. package/dist/node/css/css-pipeline.js +0 -154
  186. package/dist/node/plugins/conditional-directives.d.ts +0 -3
  187. package/dist/node/plugins/taro-runtime.d.ts +0 -5
  188. package/dist/node/plugins/taro-runtime.js +0 -18
  189. package/dist/node/targets/h5/plugin.d.ts +0 -6
  190. package/dist/node/targets/h5/plugin.js +0 -117
  191. package/dist/node/targets/h5/virtual-modules.d.ts +0 -5
  192. package/dist/node/targets/h5/virtual-modules.js +0 -60
  193. package/dist/node/targets/wx/companion-assets.d.ts +0 -19
  194. package/dist/node/targets/wx/companion-assets.js +0 -129
  195. package/dist/node/targets/wx/dev-server/development-session.d.ts +0 -32
  196. package/dist/node/targets/wx/dev-server/development-session.js +0 -215
  197. package/dist/node/targets/wx/dev-server/full-build-scheduler.d.ts +0 -14
  198. package/dist/node/targets/wx/dev-server/full-build-scheduler.js +0 -60
  199. package/dist/node/targets/wx/dev-server/js-utils.d.ts +0 -5
  200. package/dist/node/targets/wx/dev-server/js-utils.js +0 -28
  201. package/dist/node/targets/wx/dev-server/output.d.ts +0 -19
  202. package/dist/node/targets/wx/dev-server/output.js +0 -44
  203. package/dist/node/targets/wx/dev-server/rolldown-runtime-source.d.ts +0 -8
  204. package/dist/node/targets/wx/dev-server/rolldown-runtime-source.js +0 -95
  205. package/dist/node/targets/wx/dev-server/update-server-state.d.ts +0 -65
  206. package/dist/node/targets/wx/dev-server/update-server-state.js +0 -116
  207. package/dist/node/targets/wx/dev-server/update-transport.d.ts +0 -28
  208. package/dist/node/targets/wx/dev-server/update-transport.js +0 -212
  209. package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.d.ts +0 -44
  210. package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.js +0 -145
  211. package/dist/node/targets/wx/development-files.d.ts +0 -8
  212. package/dist/node/targets/wx/development-files.js +0 -8
  213. package/dist/node/targets/wx/plugin.d.ts +0 -6
  214. package/dist/node/targets/wx/plugin.js +0 -144
  215. package/dist/node/targets/wx/react-refresh.d.ts +0 -4
  216. package/dist/node/targets/wx/react-refresh.js +0 -38
  217. package/dist/node/targets/wx/virtual-modules.d.ts +0 -16
  218. package/dist/node/targets/wx/virtual-modules.js +0 -120
  219. package/dist/node/utils/async.d.ts +0 -8
  220. package/dist/node/utils/async.js +0 -16
  221. package/dist/node/utils/filesystem.d.ts +0 -13
  222. package/dist/node/utils/filesystem.js +0 -43
  223. package/dist/runtime/taro/api.js +0 -11
  224. package/dist/runtime/taro/components.d.ts +0 -2
  225. package/dist/runtime/taro/components.js +0 -2
  226. package/dist/runtime/wx/page-update.d.ts +0 -6
  227. package/dist/runtime/wx/page-update.js +0 -157
  228. package/dist/runtime/wx/taro-runtime.d.ts +0 -5
  229. package/dist/runtime/wx/taro-runtime.js +0 -6
  230. package/dist/runtime/wx/update-client-state.d.ts +0 -68
  231. package/dist/runtime/wx/update-client-state.js +0 -84
  232. package/dist/runtime/wx/update-client.d.ts +0 -1
  233. package/dist/runtime/wx/update-client.js +0 -171
  234. package/src/node/build-context.ts +0 -62
  235. package/src/node/css/css-pipeline.ts +0 -171
  236. package/src/node/plugins/taro-runtime.ts +0 -22
  237. package/src/node/targets/h5/plugin.ts +0 -135
  238. package/src/node/targets/h5/virtual-modules.ts +0 -71
  239. package/src/node/targets/wx/companion-assets.ts +0 -174
  240. package/src/node/targets/wx/dev-server/development-session.ts +0 -271
  241. package/src/node/targets/wx/dev-server/full-build-scheduler.ts +0 -62
  242. package/src/node/targets/wx/dev-server/js-utils.ts +0 -33
  243. package/src/node/targets/wx/dev-server/output.ts +0 -56
  244. package/src/node/targets/wx/dev-server/rolldown-runtime-source.ts +0 -95
  245. package/src/node/targets/wx/dev-server/update-server-state.ts +0 -183
  246. package/src/node/targets/wx/dev-server/update-transport.ts +0 -261
  247. package/src/node/targets/wx/dev-server/vite-bundled-dev-adapter.ts +0 -203
  248. package/src/node/targets/wx/development-files.ts +0 -11
  249. package/src/node/targets/wx/plugin.ts +0 -164
  250. package/src/node/targets/wx/react-refresh.ts +0 -51
  251. package/src/node/targets/wx/virtual-modules.ts +0 -152
  252. package/src/node/utils/async.ts +0 -19
  253. package/src/node/utils/filesystem.ts +0 -45
  254. package/src/runtime/taro/api.ts +0 -13
  255. package/src/runtime/taro/components.ts +0 -2
  256. package/src/runtime/wx/page-update.ts +0 -230
  257. package/src/runtime/wx/react-refresh.d.ts +0 -20
  258. package/src/runtime/wx/taro-runtime.ts +0 -7
  259. package/src/runtime/wx/update-client-state.ts +0 -138
  260. package/src/runtime/wx/update-client.ts +0 -223
@@ -0,0 +1,352 @@
1
+ import path from 'node:path';
2
+ import colors from 'picocolors';
3
+ import { build } from 'rolldown';
4
+ import { dev, viteReporterPlugin } from 'rolldown/experimental';
5
+ import { once } from '../../../utils/once.js';
6
+ import { resolvePackageFile } from '../../../utils/packages.js';
7
+ import { appShellFileName } from '../module.js';
8
+ import { hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
9
+ import { PatchPublisher } from './patch-publisher.js';
10
+ /**
11
+ * Creates the wx dev host: the adapter that owns the physical Rolldown DevEngine (created
12
+ * with dev(...)) and the patch publisher, and replaces Vite's bundledDev.listen so the
13
+ * engine writes directly to the Mini Program output directory instead of serving browser
14
+ * HMR over HTTP.
15
+ */
16
+ export async function createWxDevHost({ server, options }) {
17
+ const bundledDev = getBundledDev(server);
18
+ // DevEngine does not reject run() after an initial plugin failure, so settle startup from its first buildEnd result.
19
+ // Later build errors belong to the running server and continue through onOutput/onHmrUpdates.
20
+ const initialBuild = Promise.withResolvers();
21
+ const settleInitialBuild = once((error) => {
22
+ if (error) {
23
+ initialBuild.reject(error);
24
+ }
25
+ else {
26
+ initialBuild.resolve();
27
+ }
28
+ });
29
+ const publisher = new PatchPublisher((content) => writeHmrFile(server.config.build.outDir, hmrPatchesFileName, content));
30
+ // Must install rolldown options before create engine
31
+ installRolldownOptions();
32
+ const engine = await createEngine();
33
+ // The wx dev host owns the only DevEngine. Vite's default listen() would create a second
34
+ // skip-write engine that renders into memory for browser HMR; instead the physical
35
+ // engine's initial build must finish before the HTTP server becomes ready, because
36
+ // DevTools opens the output directory directly and the app requires its files on disk.
37
+ bundledDev._devEngine = engine;
38
+ bundledDev.triggerBundleRegenerationIfStale = async () => false;
39
+ bundledDev.listen = async () => {
40
+ await Promise.all([engine.run(), initialBuild.promise]);
41
+ await engine.ensureCurrentBuildFinish();
42
+ };
43
+ // Vite binds the port only after initServer (and therefore the initial build) completes, so
44
+ // the actual port is not observable while onOutput runs for the first build. The App metadata
45
+ // is written once the port is real; later full builds rewrite it from onOutput.
46
+ server.httpServer?.once('listening', startFreshBuild);
47
+ // The runtime's metadata-only reports land on the control path; the buildId in each report
48
+ // IS the Rolldown client ID.
49
+ server.middlewares.use(hmrControlPath, (req, res) => void handleReport(req, res));
50
+ // Append the DevTools project directory line after Vite's own startup banner: DevTools
51
+ // opens the output directory directly, so the printed path is the one to select.
52
+ const originalPrintUrls = server.printUrls.bind(server);
53
+ server.printUrls = () => {
54
+ originalPrintUrls();
55
+ server.config.logger.info(` ${colors.green('➜')} ${colors.bold('WeChat DevTools')}: ${colors.cyan(relativeToViteConfig(server.config.build.outDir, server.config.configFile, server.config.root))}`);
56
+ };
57
+ return {
58
+ close: async () => {
59
+ await engine.close();
60
+ }
61
+ };
62
+ /** Rotates the build identity and materializes the App metadata for it. */
63
+ async function startFreshBuild() {
64
+ const port = boundPort(server);
65
+ if (port === undefined) {
66
+ // The initial output finishes before Vite binds its port. The listening listener
67
+ // starts the first real client build, avoiding a phantom registered client.
68
+ return;
69
+ }
70
+ const { buildId, previousBuildId } = publisher.startBuild();
71
+ if (previousBuildId) {
72
+ await engine.removeClient(previousBuildId);
73
+ }
74
+ await engine.registerClient(buildId);
75
+ // Publish info last: a heap that observes the new identity is guaranteed to see the
76
+ // matching reset patch file.
77
+ await writeHmrFile(server.config.build.outDir, hmrPatchesFileName, renderInitialHmrPatches());
78
+ await writeHmrInfo(server, buildId, port);
79
+ }
80
+ async function handleReport(req, res) {
81
+ if (req.method !== 'POST') {
82
+ res.statusCode = 404;
83
+ res.end();
84
+ return;
85
+ }
86
+ try {
87
+ const report = JSON.parse(await readBody(req));
88
+ // Only the current build's reports can advance physical delivery;
89
+ // delayed reports from older builds are ignored so they can never influence the
90
+ // live build.
91
+ if (!publisher.isCurrentBuild(report.buildId)) {
92
+ res.end();
93
+ return;
94
+ }
95
+ if (report.kind === 'rebuild') {
96
+ engine.triggerFullBuild();
97
+ res.end();
98
+ return;
99
+ }
100
+ // Commit every newly acknowledged Rolldown payload to this client's ship map.
101
+ const deliveredFiles = publisher.acknowledge(report.seq);
102
+ await Promise.all(deliveredFiles.map((fileName) => engine.notifyPayloadDelivered(fileName)));
103
+ res.end();
104
+ }
105
+ catch (e) {
106
+ logWxError(server.config.logger, 'wx HMR report failed', e);
107
+ res.statusCode = 400;
108
+ res.end();
109
+ }
110
+ }
111
+ /** Creates the physical DevEngine with the wx dev host hooks. */
112
+ async function createEngine() {
113
+ const rolldownOptions = await bundledDev.getRolldownOptions();
114
+ if (!rolldownOptions.output || Array.isArray(rolldownOptions.output)) {
115
+ throw new Error('wx development requires exactly one Rolldown output.');
116
+ }
117
+ return dev(rolldownOptions, rolldownOptions.output, {
118
+ onHmrUpdates: async (result) => {
119
+ if (result instanceof Error) {
120
+ logWxError(server.config.logger, 'wx HMR update failed', result);
121
+ return;
122
+ }
123
+ // Collect the current client's batch first: one HMR event can carry several
124
+ // client envelopes, while only the active build may enter its patch history.
125
+ const batch = [];
126
+ for (const { clientId, update } of result.updates) {
127
+ // Removed and delayed client sessions can still appear in a completed
128
+ // engine batch; they must never enter the current build's patch history.
129
+ if (!publisher.isCurrentBuild(clientId) || update.type === 'Noop') {
130
+ continue;
131
+ }
132
+ if (update.type === 'Patch') {
133
+ batch.push(update);
134
+ continue;
135
+ }
136
+ server.config.logger.info(`[vpt] wx full rebuild required${update.reason ? `: ${update.reason}` : ''}`);
137
+ engine.triggerFullBuild();
138
+ return;
139
+ }
140
+ if (batch.length > 0) {
141
+ await publisher.produce(batch);
142
+ // server.config.logger.info('[vpt] wx patch produced')
143
+ }
144
+ },
145
+ onOutput: async (result) => {
146
+ if (result instanceof Error) {
147
+ logWxError(server.config.logger, 'wx dev build failed', result);
148
+ return;
149
+ }
150
+ // A fresh build identity per complete physical build; the App runtime reads it
151
+ // from hmr/info.js before any module registers.
152
+ await startFreshBuild();
153
+ },
154
+ rebuildStrategy: 'never',
155
+ watch: { skipWrite: false }
156
+ });
157
+ }
158
+ /** Restores physical Mini Program output conventions after Vite applies browser bundled-dev defaults. */
159
+ function installRolldownOptions() {
160
+ const original = bundledDev.getRolldownOptions.bind(bundledDev);
161
+ bundledDev.getRolldownOptions = async () => {
162
+ const rolldownOptions = await original();
163
+ if (Array.isArray(rolldownOptions.output)) {
164
+ throw new Error('wx development requires one configured Rolldown output.');
165
+ }
166
+ rolldownOptions.output ??= {};
167
+ const output = rolldownOptions.output;
168
+ const configuredOutput = server.config.build.rolldownOptions.output;
169
+ if (Array.isArray(configuredOutput)) {
170
+ throw new Error('wx development supports one configured Rolldown output.');
171
+ }
172
+ // Every page entry must depend on hmr/patches.js: DevTools classifies a changed Page
173
+ // dependency as Page JavaScript hot reload and re-executes live Pages, which is the only
174
+ // trigger that delivers physical patches while keeping the App heap alive.
175
+ const pageFiles = new Set(options.pages.map((page) => `${page.path}.js`));
176
+ const configured = (configuredOutput ?? {});
177
+ Object.assign(output, configured, {
178
+ assetFileNames: createStableFileNames(configured.assetFileNames, 'assets/[name][extname]'),
179
+ banner: createEntryBanner(pageFiles),
180
+ chunkFileNames: createStableFileNames(configured.chunkFileNames, 'assets/[name].js'),
181
+ entryFileNames: createStableFileNames(configured.entryFileNames, '[name]'),
182
+ format: 'es',
183
+ minify: true,
184
+ sourcemap: false
185
+ });
186
+ rolldownOptions.experimental ??= {};
187
+ rolldownOptions.experimental.devMode = {
188
+ ...(typeof rolldownOptions.experimental.devMode === 'object'
189
+ ? rolldownOptions.experimental.devMode
190
+ : {}),
191
+ implement: await bundleRuntimeSource(),
192
+ lazy: false
193
+ };
194
+ const reportInitialBuildPlugin = {
195
+ name: 'vpt:wx-report-initial-build',
196
+ buildEnd: settleInitialBuild
197
+ };
198
+ rolldownOptions.plugins = [rolldownOptions.plugins, reportInitialBuildPlugin, createViteReporter(server)];
199
+ disableViteOxcSourcemap(rolldownOptions.plugins);
200
+ return rolldownOptions;
201
+ };
202
+ }
203
+ }
204
+ /** The bound HTTP port, or undefined before Vite's server is listening. */
205
+ function boundPort(server) {
206
+ const httpServer = server.httpServer;
207
+ if (!httpServer) {
208
+ return undefined;
209
+ }
210
+ const address = httpServer.address();
211
+ if (!address || typeof address === 'string') {
212
+ return undefined;
213
+ }
214
+ return address.port;
215
+ }
216
+ /** Writes the immutable App metadata every full build starts from. */
217
+ async function writeHmrInfo(server, buildId, port) {
218
+ const info = {
219
+ buildId,
220
+ endpoint: `${server.config.server.https ? 'https' : 'http'}://${resolveEndpointHost(server)}:${port}${hmrControlPath}`
221
+ };
222
+ await writeHmrFile(server.config.build.outDir, hmrInfoFileName, renderHmrInfo(info));
223
+ }
224
+ /**
225
+ * The project directory shown in the DevTools banner, relative to the Vite config:
226
+ * `dist/wx` instead of the absolute output path, so it can be pasted into DevTools.
227
+ */
228
+ function relativeToViteConfig(outDir, configFile, root) {
229
+ const configDirectory = configFile ? path.dirname(configFile) : root;
230
+ const relativePath = path.relative(configDirectory, outDir).replaceAll('\\', '/');
231
+ if (!relativePath)
232
+ return '.';
233
+ return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
234
+ }
235
+ /** Logs an error with the plugin prefix, distinguishing Error values from unknowns. */
236
+ function logWxError(logger, prefix, error) {
237
+ if (Error.isError(error)) {
238
+ logger.error(`[vpt] ${prefix}`, { error });
239
+ }
240
+ else {
241
+ logger.error(`[vpt] ${prefix} with unknown error: ${error}`);
242
+ }
243
+ }
244
+ // The runtime source is immutable for the host's lifetime (it changes only when the
245
+ // plugin is rebuilt), so the nested bundle runs once and every build reuses it.
246
+ const bundleRuntimeSource = once(
247
+ /** Bundles the runtime host and state machine into one plain script for injection. */
248
+ async function bundleRuntimeSource() {
249
+ // write: false — only the code is consumed; without it rolldown drops the bundle into
250
+ // the default dist/ of the running project.
251
+ const result = await build({
252
+ input: resolvePackageFile('dist/runtime/wx/dev/dev-runtime.js'),
253
+ output: { format: 'iife', minify: true, sourcemap: false },
254
+ write: false
255
+ });
256
+ return result.output[0].code;
257
+ });
258
+ const maximumBodyBytes = 64 * 1024;
259
+ function readBody(req) {
260
+ return new Promise((resolve, reject) => {
261
+ let body = '';
262
+ req.on('data', (chunk) => {
263
+ body += chunk.toString('utf8');
264
+ if (body.length > maximumBodyBytes) {
265
+ reject(new Error('report body too large'));
266
+ req.destroy();
267
+ }
268
+ });
269
+ req.on('end', () => resolve(body));
270
+ req.on('error', reject);
271
+ });
272
+ }
273
+ /** The bound address host, or loopback for wildcard binds; IPv6 literals are bracketed. */
274
+ function resolveEndpointHost(server) {
275
+ const address = server.httpServer?.address();
276
+ if (!address || typeof address === 'string') {
277
+ return '127.0.0.1';
278
+ }
279
+ if (address.address === '0.0.0.0' || address.address === '::') {
280
+ // Wildcard binds accept loopback connections; 127.0.0.1 is the address DevTools can reach.
281
+ return '127.0.0.1';
282
+ }
283
+ return address.address.includes(':') ? `[${address.address}]` : address.address;
284
+ }
285
+ /**
286
+ * Prepends entry banners. Banners are plain text appended after Rolldown's analysis, so the
287
+ * requires never become chunk dependencies (a bare require inside the injected runtime source
288
+ * would stall the build), and the wx render pipeline keeps this text after the hoisted chunk
289
+ * requires — so the runtime chunk exists before these run:
290
+ * - the app entry loads hmr/info.js and initializes the runtime before any module registers;
291
+ * - every page requires hmr/patches.js, the changed dependency that makes DevTools re-execute
292
+ * live Pages and thereby load physical updates.
293
+ */
294
+ function createEntryBanner(pageFiles) {
295
+ return (chunk) => {
296
+ if (chunk.name === appShellFileName) {
297
+ return "__rolldown_runtime__.initialize(require('./hmr/info.js'));\n";
298
+ }
299
+ if (pageFiles.has(chunk.name)) {
300
+ // Page files live at `pages/<route>/index.js`, so the dependency path must be
301
+ // computed relative to each page's own directory.
302
+ const patchesPath = path.posix.relative(path.posix.dirname(chunk.fileName), 'hmr/patches.js');
303
+ return `require('${patchesPath}');\n`;
304
+ }
305
+ return '';
306
+ };
307
+ }
308
+ function createStableFileNames(addon, fallback) {
309
+ if (typeof addon === 'function') {
310
+ return (value) => toStableFileName(String(addon(value)));
311
+ }
312
+ return toStableFileName(typeof addon === 'string' ? addon : fallback);
313
+ }
314
+ function toStableFileName(fileName) {
315
+ return fileName
316
+ .replace(/(^|\/)\[hash(?::\d+)?\](?=\.|$)/g, '$1[name]')
317
+ .replace(/[-_.]\[hash(?::\d+)?\]/g, '')
318
+ .replace(/\[hash(?::\d+)?\]/g, '[name]');
319
+ }
320
+ function disableViteOxcSourcemap(pluginOption) {
321
+ if (Array.isArray(pluginOption)) {
322
+ pluginOption.forEach(disableViteOxcSourcemap);
323
+ return;
324
+ }
325
+ if (!pluginOption || typeof pluginOption !== 'object') {
326
+ return;
327
+ }
328
+ const plugin = pluginOption;
329
+ if (plugin.name === 'builtin:vite-transform' && plugin._options?.transformOptions) {
330
+ plugin._options.transformOptions.sourcemap = false;
331
+ }
332
+ }
333
+ function createViteReporter(server) {
334
+ const { build, logger, root } = server.config;
335
+ return viteReporterPlugin({
336
+ assetsDir: path.join(build.assetsDir, '/'),
337
+ chunkLimit: 2000,
338
+ isLib: Boolean(build.lib),
339
+ isTty: Boolean(process.stdout.isTTY && !process.env.CI),
340
+ logInfo: (message) => logger.info(message),
341
+ reportCompressedSize: false,
342
+ root,
343
+ warnLargeChunks: false
344
+ });
345
+ }
346
+ function getBundledDev(server) {
347
+ const bundledDev = server.environments.client.bundledDev;
348
+ if (!bundledDev) {
349
+ throw new Error('Vite did not create the wx bundled-development environment.');
350
+ }
351
+ return bundledDev;
352
+ }
@@ -0,0 +1,28 @@
1
+ import type { BindingClientHmrUpdate } from 'rolldown/experimental';
2
+ export declare const hmrInfoFileName = "hmr/info.js";
3
+ export declare const hmrPatchesFileName = "hmr/patches.js";
4
+ /** Report endpoint path served by the wx dev control edge. */
5
+ export declare const hmrControlPath = "/__vpt_hmr__";
6
+ /** Immutable App metadata for the current complete physical build. */
7
+ export type HmrInfo = Readonly<{
8
+ buildId: string;
9
+ endpoint: string;
10
+ }>;
11
+ /** The Patch variant of Rolldown's per-client HMR update, admitted into the patch history. */
12
+ export type PatchUpdate = Extract<BindingClientHmrUpdate['update'], {
13
+ type: 'Patch';
14
+ }>;
15
+ /** Renders the synchronous CommonJS metadata module loaded by the runtime chunk. */
16
+ export declare function renderHmrInfo(info: HmrInfo): string;
17
+ /** Provides a valid dependency before the host has a patch range to publish. */
18
+ export declare function renderInitialHmrPatches(): string;
19
+ /**
20
+ * Renders the missing patch suffix as a passive physical delivery module.
21
+ *
22
+ * DevTools re-executes the Page because this file changed. The module only stores the literal
23
+ * Rolldown factories in the persistent App runtime; storePatches applies them synchronously,
24
+ * so the Page's imports below the require resolve against the freshly registered modules.
25
+ */
26
+ export declare function renderHmrPatches(buildId: string, patches: readonly PatchUpdate[]): string;
27
+ /** Publishes one physical HMR file (direct write; atomic rename is reserved for later analysis). */
28
+ export declare function writeHmrFile(outDir: string, fileName: string, source: string): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export const hmrInfoFileName = 'hmr/info.js';
4
+ export const hmrPatchesFileName = 'hmr/patches.js';
5
+ /** Report endpoint path served by the wx dev control edge. */
6
+ export const hmrControlPath = '/__vpt_hmr__';
7
+ /** Renders the synchronous CommonJS metadata module loaded by the runtime chunk. */
8
+ export function renderHmrInfo(info) {
9
+ return `module.exports = Object.freeze(${JSON.stringify(info)});\n`;
10
+ }
11
+ /** Provides a valid dependency before the host has a patch range to publish. */
12
+ export function renderInitialHmrPatches() {
13
+ return 'module.exports = undefined;\n';
14
+ }
15
+ /**
16
+ * Renders the missing patch suffix as a passive physical delivery module.
17
+ *
18
+ * DevTools re-executes the Page because this file changed. The module only stores the literal
19
+ * Rolldown factories in the persistent App runtime; storePatches applies them synchronously,
20
+ * so the Page's imports below the require resolve against the freshly registered modules.
21
+ */
22
+ export function renderHmrPatches(buildId, patches) {
23
+ if (patches.length === 0) {
24
+ throw new Error('Cannot render an empty WX patch range.');
25
+ }
26
+ const rendered = patches.map((patch) => `{seq: ${patch.seq}, changedIds: ${JSON.stringify(patch.changedIds)}, factory: () => {\n${patch.code}\n}}`);
27
+ return `__rolldown_runtime__.storePatches({buildId: ${JSON.stringify(buildId)}, patches: [${rendered.join(',')}]});\n`;
28
+ }
29
+ /** Publishes one physical HMR file (direct write; atomic rename is reserved for later analysis). */
30
+ export async function writeHmrFile(outDir, fileName, source) {
31
+ const filePath = path.join(outDir, fileName);
32
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
33
+ await fs.writeFile(filePath, source);
34
+ }
@@ -0,0 +1,22 @@
1
+ import { type PatchUpdate } from './hmr-files.ts';
2
+ /** Abstracts the physical patches write; the engine owns the file destination. */
3
+ export type WritePatches = (content: string) => Promise<void>;
4
+ /** Owns one build's unacknowledged patches and physical publish decision. */
5
+ export declare class PatchPublisher {
6
+ private readonly writePatches;
7
+ private buildId;
8
+ /** Executable updates retained only until the runtime acknowledges physical delivery. */
9
+ private readonly pendingPatches;
10
+ constructor(writePatches: WritePatches);
11
+ /** True when the buildId belongs to the current full build. */
12
+ isCurrentBuild(buildId: string): boolean;
13
+ /** Begins a fresh build and returns both sides of the client-session rotation. */
14
+ startBuild(): Readonly<{
15
+ buildId: string;
16
+ previousBuildId: string | undefined;
17
+ }>;
18
+ /** Appends a Rolldown batch and publishes every unacknowledged patch. */
19
+ produce(patches: readonly PatchUpdate[]): Promise<void>;
20
+ /** Removes the pending prefix covered by the runtime's Rolldown sequence receipt. */
21
+ acknowledge(seq: number): string[];
22
+ }
@@ -0,0 +1,40 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { renderHmrPatches } from './hmr-files.js';
3
+ /** Owns one build's unacknowledged patches and physical publish decision. */
4
+ export class PatchPublisher {
5
+ writePatches;
6
+ buildId;
7
+ /** Executable updates retained only until the runtime acknowledges physical delivery. */
8
+ pendingPatches = [];
9
+ // Explicit field assignment: node --test strips types and does not support parameter properties.
10
+ constructor(writePatches) {
11
+ this.writePatches = writePatches;
12
+ }
13
+ /** True when the buildId belongs to the current full build. */
14
+ isCurrentBuild(buildId) {
15
+ return buildId === this.buildId;
16
+ }
17
+ /** Begins a fresh build and returns both sides of the client-session rotation. */
18
+ startBuild() {
19
+ const previousBuildId = this.buildId;
20
+ const buildId = randomUUID();
21
+ this.buildId = buildId;
22
+ this.pendingPatches.length = 0;
23
+ return { buildId, previousBuildId };
24
+ }
25
+ /** Appends a Rolldown batch and publishes every unacknowledged patch. */
26
+ async produce(patches) {
27
+ if (this.buildId === undefined || patches.length === 0)
28
+ return;
29
+ this.pendingPatches.push(...patches);
30
+ await this.writePatches(renderHmrPatches(this.buildId, this.pendingPatches));
31
+ }
32
+ /** Removes the pending prefix covered by the runtime's Rolldown sequence receipt. */
33
+ acknowledge(seq) {
34
+ let deliveredCount = 0;
35
+ while (deliveredCount < this.pendingPatches.length && this.pendingPatches[deliveredCount].seq <= seq) {
36
+ deliveredCount++;
37
+ }
38
+ return this.pendingPatches.splice(0, deliveredCount).map((patch) => patch.filename);
39
+ }
40
+ }
@@ -0,0 +1,7 @@
1
+ import type { PluginOption } from 'vite';
2
+ import type { VitePluginTaroOptions } from '../../../../options.ts';
3
+ /**
4
+ * Adds the serve-only bundled-development plugin set for the wx target: the dev adapter
5
+ * (config, runtime lowering, dev host) plus the React Refresh adaptation transforms.
6
+ */
7
+ export declare function createWxDevelopmentPlugin(options: VitePluginTaroOptions): PluginOption[];
@@ -0,0 +1,73 @@
1
+ import { transformWithOxc } from 'vite';
2
+ import { esTarget } from '../../../utils/constant.js';
3
+ import { rolldownRuntimeId } from '../module.js';
4
+ import { memoize } from '../../../utils/memoize.js';
5
+ import { createWxDevHost } from './dev-host.js';
6
+ import { createWxReactRefreshTransforms } from './react-refresh.js';
7
+ /**
8
+ * Adds the serve-only bundled-development plugin set for the wx target: the dev adapter
9
+ * (config, runtime lowering, dev host) plus the React Refresh adaptation transforms.
10
+ */
11
+ export function createWxDevelopmentPlugin(options) {
12
+ let host = null;
13
+ return [
14
+ {
15
+ name: 'vpt:wx-dev',
16
+ apply: 'serve',
17
+ config() {
18
+ return {
19
+ build: {
20
+ // Disable maps in resolved environment config as well as final output so Oxc and Babel skip producing
21
+ // intermediate maps that Rolldown would discard.
22
+ sourcemap: false
23
+ },
24
+ experimental: {
25
+ // Ask Vite to resolve its bundled-development graph and expose the private adapter instance. The wx
26
+ // configureServer hook replaces only its startup method with the directly writing DevEngine.
27
+ bundledDev: true
28
+ }
29
+ };
30
+ },
31
+ transform: {
32
+ order: 'post',
33
+ // The dev-mode transform assembles the runtime chunk (Rolldown's base runtime
34
+ // plus our injected implement) as this module's transform output, which
35
+ // bypasses the build's es2018 lowering. Real-device engines and WeChat's
36
+ // upload parser predate class fields and nullish operators, so the assembled
37
+ // runtime is lowered here — the only module that needs it. The exact id
38
+ // filter needs no code scan; the id must stay in sync with rolldownRuntimeId
39
+ // in module.ts (kept as a regex for the Rolldown-side filter).
40
+ filter: { id: /^\0rolldown\/runtime\.js(?:\?|$)/ },
41
+ handler(code, id) {
42
+ // The `setPublicClassFields` assumption emits plain `this.x = ...`
43
+ // assignments instead of external helpers, whose references the later
44
+ // minifier would mangle.
45
+ return fixRolldownRuntime(code);
46
+ }
47
+ },
48
+ configureServer: {
49
+ // Install after Vite and user plugins have finished configuring the environment, but before server.listen()
50
+ // asks bundledDev to create its hard-coded skip-write DevEngine.
51
+ order: 'post',
52
+ async handler(server) {
53
+ host = await createWxDevHost({ server, options });
54
+ }
55
+ },
56
+ closeBundle() {
57
+ return host?.close();
58
+ }
59
+ },
60
+ ...createWxReactRefreshTransforms()
61
+ ];
62
+ }
63
+ // The assembled runtime chunk is byte-identical on every build (the base runtime and the
64
+ // bundled implement are immutable for the server's lifetime), so the lowering runs once
65
+ // and every build reuses it.
66
+ const fixRolldownRuntime = memoize((code) => {
67
+ return transformWithOxc(code, rolldownRuntimeId, {
68
+ lang: 'js',
69
+ target: esTarget,
70
+ sourcemap: false,
71
+ assumptions: { setPublicClassFields: true }
72
+ });
73
+ });
@@ -0,0 +1,20 @@
1
+ import type { Plugin } from 'vite';
2
+ /**
3
+ * Creates the serve-only React Refresh adaptation transforms for the wx target.
4
+ *
5
+ * @vitejs/plugin-react's generated refresh code assumes the web HTML preamble and a browser
6
+ * global scope; wx has neither. Each transform adapts one piece of that contract:
7
+ * - the refresh runtime module (id-filtered): the vendored runtime reads and assigns
8
+ * `window` protocol globals (rewritten to `global`) and must inject itself at evaluation
9
+ * — the preamble's `injectIntoGlobalHook` call has no HTML home in wx;
10
+ * - react-family modules (filtered on free references): the DevTools hook is read as a free
11
+ * variable, which the WeChat runtime scope never resolves against `global` — every free
12
+ * reference becomes an explicit member access;
13
+ * - boundary modules (filtered on the guard): the preamble's `$RefreshReg$` global is not
14
+ * needed because the transform generates local wrappers over the imported refresh
15
+ * runtime, so the guard that checks for the global is removed.
16
+ *
17
+ * Each transform's filter is its routing: the three domains are disjoint, so a module is
18
+ * transformed by at most one of them, and modules outside all three never reach a handler.
19
+ */
20
+ export declare function createWxReactRefreshTransforms(): Plugin[];