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,198 @@
1
+ import { types } from '@babel/core';
2
+ import { memoize } from '../../../utils/memoize.js';
3
+ import { transformWithBabel } from '../../../utils/transform.js';
4
+ /** The React DevTools hook protocol name; free references must target `global` in wx. */
5
+ const reactDevtoolsHookProtocol = '__REACT_DEVTOOLS_GLOBAL_HOOK__';
6
+ /**
7
+ * Creates the serve-only React Refresh adaptation transforms for the wx target.
8
+ *
9
+ * @vitejs/plugin-react's generated refresh code assumes the web HTML preamble and a browser
10
+ * global scope; wx has neither. Each transform adapts one piece of that contract:
11
+ * - the refresh runtime module (id-filtered): the vendored runtime reads and assigns
12
+ * `window` protocol globals (rewritten to `global`) and must inject itself at evaluation
13
+ * — the preamble's `injectIntoGlobalHook` call has no HTML home in wx;
14
+ * - react-family modules (filtered on free references): the DevTools hook is read as a free
15
+ * variable, which the WeChat runtime scope never resolves against `global` — every free
16
+ * reference becomes an explicit member access;
17
+ * - boundary modules (filtered on the guard): the preamble's `$RefreshReg$` global is not
18
+ * needed because the transform generates local wrappers over the imported refresh
19
+ * runtime, so the guard that checks for the global is removed.
20
+ *
21
+ * Each transform's filter is its routing: the three domains are disjoint, so a module is
22
+ * transformed by at most one of them, and modules outside all three never reach a handler.
23
+ */
24
+ export function createWxReactRefreshTransforms() {
25
+ return [
26
+ {
27
+ name: 'vpt:wx-react-refresh-runtime',
28
+ apply: 'serve',
29
+ transform: {
30
+ order: 'post',
31
+ // The vendored refresh runtime module; id-filtered, so no code scan.
32
+ filter: { id: /^\/@react-refresh(?:\?|$)/ },
33
+ handler(code, id) {
34
+ return fixRefreshRuntime({ code, id });
35
+ }
36
+ }
37
+ },
38
+ {
39
+ name: 'vpt:wx-react-devtools-hook',
40
+ apply: 'serve',
41
+ transform: {
42
+ order: 'post',
43
+ // Matches only free references (react-family modules). The member accesses in
44
+ // the refresh runtime and the dev runtime chunk never match, so they need no
45
+ // id exclusion.
46
+ filter: { code: /(^|[^.\w$])__REACT_DEVTOOLS_GLOBAL_HOOK__/ },
47
+ handler(code, id) {
48
+ return fixReactDevtoolsHook({ code, id });
49
+ }
50
+ }
51
+ },
52
+ {
53
+ name: 'vpt:wx-refresh-preamble-guard',
54
+ apply: 'serve',
55
+ transform: {
56
+ order: 'post',
57
+ // Vite's documented refresh protocol global; the generated guard is its only
58
+ // occurrence, in boundary modules.
59
+ filter: { code: /window\.\$RefreshReg\$/ },
60
+ handler(code, id) {
61
+ return transformWithBabel(code, id, [removeRefreshPreambleGuard], false);
62
+ }
63
+ }
64
+ }
65
+ ];
66
+ }
67
+ /**
68
+ * React-family modules: free `__REACT_DEVTOOLS_GLOBAL_HOOK__` reads must target `global`.
69
+ *
70
+ * The renderer checks the hook with `typeof __REACT_DEVTOOLS_GLOBAL_HOOK__` and injects via
71
+ * `hook.inject(...)` — but in the WeChat runtime, free-variable reads never resolve against
72
+ * `global`'s properties (verified: the free lookup is undefined while
73
+ * `global.__REACT_DEVTOOLS_GLOBAL_HOOK__` exists), so the renderer would silently skip
74
+ * injection and React Refresh would have no renderer to schedule re-renders on.
75
+ *
76
+ * The name is unique to the React DevTools protocol, so rewriting every free reference to an
77
+ * explicit member access is precise. The hook itself is created on `global` by the dev
78
+ * runtime chunk (see dev-runtime.ts).
79
+ */
80
+ function rewriteReactDevtoolsHookGlobal() {
81
+ return {
82
+ name: 'vpt:wx-react-devtools-hook-global',
83
+ visitor: {
84
+ Identifier(identifierPath) {
85
+ const node = identifierPath.node;
86
+ if (!types.isIdentifier(node, { name: reactDevtoolsHookProtocol })) {
87
+ return;
88
+ }
89
+ const parent = identifierPath.parentPath;
90
+ // A member expression property (e.g. `global.__REACT_DEVTOOLS_GLOBAL_HOOK__`)
91
+ // is already explicit and must not be rewritten again.
92
+ if (parent.isMemberExpression() && parent.node.property === node) {
93
+ return;
94
+ }
95
+ identifierPath.replaceWith(types.memberExpression(types.identifier('global'), types.identifier(node.name)));
96
+ }
97
+ }
98
+ };
99
+ }
100
+ /**
101
+ * Refresh runtime module: self-inject at evaluation — the wx App heap has no HTML preamble.
102
+ *
103
+ * In web Vite, the HTML preamble calls `injectIntoGlobalHook(window)` before any module
104
+ * loads; nothing does that in wx. The call must live in this module itself:
105
+ * - its closure owns the refresh state (helpersByRendererID, mountedRoots), so the same
106
+ * instance that the generated boundary code imports must bootstrap itself;
107
+ * - the dev runtime chunk cannot reach it: the module is in a lazily-loaded chunk that
108
+ * requires the runtime chunk first, so it does not exist when the runtime evaluates.
109
+ *
110
+ * Unlike the preamble's `$RefreshReg$` globals (removed by removeRefreshPreambleGuard
111
+ * because boundary modules define local wrappers), the hook machinery has no local
112
+ * equivalent — without it the refresh runtime never learns the renderer or the mounted
113
+ * roots, so the injection is the one preamble responsibility that must be replicated.
114
+ *
115
+ * Timing is safe because injectIntoGlobalHook replays hook.renderers: the renderer already
116
+ * injected into the hook (created by the dev runtime chunk) when the App mounted, and the
117
+ * replay captures it; the patched commit hooks then track every later mount, including the
118
+ * remounts on re-execution.
119
+ */
120
+ function injectRefreshGlobalHook() {
121
+ return {
122
+ name: 'vpt:wx-refresh-global-hook-injection',
123
+ visitor: {
124
+ Program(programPath) {
125
+ // The renderer already injected into the hook (created by the dev runtime
126
+ // chunk) when the App mounted; injectIntoGlobalHook replays its renderers.
127
+ programPath.pushContainer('body', types.expressionStatement(types.callExpression(types.identifier('injectIntoGlobalHook'), [types.identifier('global')])));
128
+ }
129
+ }
130
+ };
131
+ }
132
+ /**
133
+ * Refresh runtime module: rewrites the generated `window.<protocol>` accesses to `global`.
134
+ *
135
+ * The vendored refresh runtime is written for browsers and uses `window` for its protocol
136
+ * globals, but the WeChat runtime has no `window` — the free identifier is undefined — so the
137
+ * top-level assignment would throw at module evaluation, and the ignored-exports read
138
+ * inside the refresh validator would crash every update pass.
139
+ *
140
+ * Only the exact known protocol names are rewritten, one by one, so unrelated `window`
141
+ * accesses are never touched and future protocol additions are deliberate.
142
+ */
143
+ function rewriteRefreshRuntimeWindowAccess() {
144
+ /**
145
+ * Refresh protocol globals that must land on the WeChat `global`:
146
+ * - `__registerBeforePerformReactRefresh`: assigned at module scope; in web, the HMR
147
+ * client registers pre-refresh callbacks through it — the assignment throws on
148
+ * undefined `window`;
149
+ * - `__getReactRefreshIgnoredExports`: read in validateRefreshBoundaryAndEnqueueUpdate
150
+ * as an optional extension point — a read on undefined `window` crashes.
151
+ */
152
+ const refreshRuntimeWindowGlobals = ['__registerBeforePerformReactRefresh', '__getReactRefreshIgnoredExports'];
153
+ return {
154
+ name: 'vpt:wx-refresh-runtime-window-access',
155
+ visitor: {
156
+ MemberExpression(memberPath) {
157
+ const member = memberPath.node;
158
+ if (!types.isIdentifier(member.object, { name: 'window' }) ||
159
+ !types.isIdentifier(member.property) ||
160
+ !refreshRuntimeWindowGlobals.includes(member.property.name)) {
161
+ return;
162
+ }
163
+ // `global` is the WeChat global object — the same one the hook injection
164
+ // and the rest of the wx glue speak — so the protocol globals land on the
165
+ // App heap like any other global hook.
166
+ member.object = types.identifier('global');
167
+ }
168
+ }
169
+ };
170
+ }
171
+ /** Boundary modules: remove the generated `if (!window.$RefreshReg$) throw Error(...)` guard. */
172
+ function removeRefreshPreambleGuard() {
173
+ return {
174
+ name: 'vpt:wx-refresh-preamble-guard',
175
+ visitor: {
176
+ IfStatement(ifPath) {
177
+ // The guard is a web-only sanity check that the HTML preamble installed the
178
+ // `$RefreshReg$` global. wx has no preamble and no such global — but the
179
+ // boundary module does not need it: the plugin transform generates local
180
+ // `$RefreshReg$`/`$RefreshSig$` wrappers that delegate to the imported
181
+ // refresh runtime, so registration works without the global. The guard
182
+ // itself only crashes on the undefined `window`, so it is removed.
183
+ const test = ifPath.node.test;
184
+ if (types.isUnaryExpression(test, { operator: '!' }) &&
185
+ types.isMemberExpression(test.argument) &&
186
+ types.isIdentifier(test.argument.object, { name: 'window' }) &&
187
+ types.isIdentifier(test.argument.property, { name: '$RefreshReg$' })) {
188
+ ifPath.remove();
189
+ }
190
+ }
191
+ }
192
+ };
193
+ }
194
+ // The refresh runtime module and the react-family modules are immutable for the server's
195
+ // lifetime (they only change when the plugin is rebuilt), so their Babel transforms run once
196
+ // per module and every build reuses the output.
197
+ const fixRefreshRuntime = memoize(({ code, id }) => transformWithBabel(code, id, [rewriteRefreshRuntimeWindowAccess, injectRefreshGlobalHook], false), { getCacheKey: ({ code }) => code });
198
+ const fixReactDevtoolsHook = memoize(({ code, id }) => transformWithBabel(code, id, [rewriteReactDevtoolsHookGlobal], false), { getCacheKey: ({ code }) => code });
@@ -0,0 +1,45 @@
1
+ import type { Rolldown } from 'vite';
2
+ /** Identifies Rolldown's generated helper module independently of its unstable output filename. */
3
+ export declare const rolldownRuntimeId = "\0rolldown/runtime.js";
4
+ /** Resolves the direct React Reconciler dependency without assuming pnpm's layout. */
5
+ export declare const reactReconcilerRoot: string;
6
+ /** Identifies the amphibious bootstrap that initializes SystemJS and serves every native shell. */
7
+ export declare const bootstrapPath: string;
8
+ /** Identifies the native transport source materialized before Rolldown finalizes content hashes. */
9
+ export declare const transportPath: string;
10
+ /** Redirects Vite's injected browser preload helper to the bootstrap identity loader. */
11
+ export declare const vitePreloadId = "\0vite/preload-helper.js";
12
+ /** Forces the native App shell entry to emit at WeChat's required root path. */
13
+ export declare const appShellFileName = "app.js";
14
+ /** Identifies the synchronous native App shell source. */
15
+ export declare const appShellPath: string;
16
+ /** Identifies the App capsule kept behind the native shell boundary. */
17
+ export declare const appCapsulePath: string;
18
+ /** Forces Taro's recursive native Component entry to emit at its configured root path. */
19
+ export declare const componentShellFileName = "comp.js";
20
+ /** Identifies the synchronous recursive Component shell source. */
21
+ export declare const componentShellPath: string;
22
+ /** Identifies the recursive Component capsule kept behind the native shell boundary. */
23
+ export declare const componentCapsulePath: string;
24
+ /** Resolves the configured Page component from its route-qualified capsule importer. */
25
+ export declare const pageComponentId = "\0vpt:page-component";
26
+ /** Gives every Page shell one private capsule target that can be resolved using its route. */
27
+ export declare const pageCapsuleId = "\0vpt:page-capsule";
28
+ /** Provides the Page capsule source specialized through a stable route query. */
29
+ export declare const pageCapsulePath: string;
30
+ /** Identifies the reusable synchronous native Page shell source. */
31
+ export declare const pageShellPath: string;
32
+ export type WxChunk = Rolldown.PreRenderedChunk | Rolldown.RenderedChunk;
33
+ /** Build-graph role of an explicit native lifecycle entry. */
34
+ export type WxEntryRole = 'shell' | 'capsule';
35
+ /** Runtime domain in which one final wx JavaScript chunk executes. */
36
+ export type WxExecutionKind = 'native' | 'capsule' | 'amphibious';
37
+ /** Returns the one explicit lifecycle role owned by a chunk. */
38
+ export declare function getWxEntryRole(chunk: WxChunk): WxEntryRole | undefined;
39
+ /** Tests whether a chunk contains the physical transport implementation. */
40
+ export declare function isTransportModule(chunk: WxChunk): boolean;
41
+ /**
42
+ * Classifies one final output chunk by execution domain. Entry role is deliberately independent: explicit capsule entries
43
+ * normally fall through to capsule rendering, but a capsule containing an amphibious runtime executes in both domains.
44
+ */
45
+ export declare function getWxExecutionKind(chunk: WxChunk): WxExecutionKind;
@@ -0,0 +1,66 @@
1
+ import path from 'node:path';
2
+ import { normalizeModuleId } from '../../utils/modules.js';
3
+ import { packageRequire, resolvePackageFile } from '../../utils/packages.js';
4
+ /** Identifies Rolldown's generated helper module independently of its unstable output filename. */
5
+ export const rolldownRuntimeId = '\0rolldown/runtime.js';
6
+ /** Resolves the direct React Reconciler dependency without assuming pnpm's layout. */
7
+ export const reactReconcilerRoot = normalizeModuleId(path.dirname(packageRequire.resolve('react-reconciler/package.json')));
8
+ /** Identifies the amphibious bootstrap that initializes SystemJS and serves every native shell. */
9
+ export const bootstrapPath = resolvePackageFile('dist/runtime/wx/amphibious/bootstrap.js');
10
+ /** Identifies the native transport source materialized before Rolldown finalizes content hashes. */
11
+ export const transportPath = resolvePackageFile('dist/runtime/wx/amphibious/transport.js');
12
+ /** Redirects Vite's injected browser preload helper to the bootstrap identity loader. */
13
+ export const vitePreloadId = '\0vite/preload-helper.js';
14
+ /** Forces the native App shell entry to emit at WeChat's required root path. */
15
+ export const appShellFileName = 'app.js';
16
+ /** Identifies the synchronous native App shell source. */
17
+ export const appShellPath = resolvePackageFile('dist/runtime/wx/native/app.js');
18
+ /** Identifies the App capsule kept behind the native shell boundary. */
19
+ export const appCapsulePath = resolvePackageFile('dist/runtime/wx/capsule/app.js');
20
+ /** Forces Taro's recursive native Component entry to emit at its configured root path. */
21
+ export const componentShellFileName = 'comp.js';
22
+ /** Identifies the synchronous recursive Component shell source. */
23
+ export const componentShellPath = resolvePackageFile('dist/runtime/wx/native/component.js');
24
+ /** Identifies the recursive Component capsule kept behind the native shell boundary. */
25
+ export const componentCapsulePath = resolvePackageFile('dist/runtime/wx/capsule/component.js');
26
+ /** Resolves the configured Page component from its route-qualified capsule importer. */
27
+ export const pageComponentId = '\0vpt:page-component';
28
+ /** Gives every Page shell one private capsule target that can be resolved using its route. */
29
+ export const pageCapsuleId = '\0vpt:page-capsule';
30
+ /** Provides the Page capsule source specialized through a stable route query. */
31
+ export const pageCapsulePath = resolvePackageFile('dist/runtime/wx/capsule/page.js');
32
+ /** Identifies the reusable synchronous native Page shell source. */
33
+ export const pageShellPath = resolvePackageFile('dist/runtime/wx/native/page.js');
34
+ // These fixed source identities describe entry roles independently from the final execution kind. A capsule entry may,
35
+ // for example, become amphibious when Rolldown coalesces its generated runtime into the same output chunk.
36
+ const shellModuleIds = new Set([appShellPath, componentShellPath, pageShellPath]);
37
+ const capsuleModuleIds = new Set([appCapsulePath, componentCapsulePath, pageCapsulePath]);
38
+ const amphibiousModuleIds = new Set([bootstrapPath, rolldownRuntimeId]);
39
+ /** Returns the one explicit lifecycle role owned by a chunk. */
40
+ export function getWxEntryRole(chunk) {
41
+ const ownsShell = containsModule(chunk, shellModuleIds);
42
+ const ownsCapsule = containsModule(chunk, capsuleModuleIds);
43
+ if (ownsShell && ownsCapsule) {
44
+ throw new Error(`wx chunk mixes shell and capsule entries: ${chunk.moduleIds.join(', ')}`);
45
+ }
46
+ return ownsShell ? 'shell' : ownsCapsule ? 'capsule' : undefined;
47
+ }
48
+ /** Tests whether a chunk contains the physical transport implementation. */
49
+ export function isTransportModule(chunk) {
50
+ return chunk.moduleIds.includes(transportPath);
51
+ }
52
+ /**
53
+ * Classifies one final output chunk by execution domain. Entry role is deliberately independent: explicit capsule entries
54
+ * normally fall through to capsule rendering, but a capsule containing an amphibious runtime executes in both domains.
55
+ */
56
+ export function getWxExecutionKind(chunk) {
57
+ const entryRole = getWxEntryRole(chunk);
58
+ if (containsModule(chunk, amphibiousModuleIds)) {
59
+ return 'amphibious';
60
+ }
61
+ return entryRole === 'shell' || isTransportModule(chunk) ? 'native' : 'capsule';
62
+ }
63
+ /** Tests normalized chunk module IDs against one fixed identity set. */
64
+ function containsModule(chunk, moduleIds) {
65
+ return chunk.moduleIds.some((moduleId) => moduleIds.has(normalizeModuleId(moduleId)));
66
+ }
@@ -0,0 +1,21 @@
1
+ /** Compiles one JSX interface module and attaches its opaque native sources to Rolldown metadata. */
2
+ export declare function compileNativeComponentInterface({ code, id, sourcemap, addWatchFile }: {
3
+ code: string;
4
+ id: string;
5
+ sourcemap: boolean;
6
+ addWatchFile: (file: string) => void;
7
+ }): Promise<{
8
+ code: string;
9
+ map: import("rolldown").ExistingRawSourceMap | null;
10
+ meta: {
11
+ "vpt:native-components": {
12
+ sources: (import("./native-component-interface.ts").NativeComponentDefinition & {
13
+ assets: readonly {
14
+ relativePath: string;
15
+ byteLength: number;
16
+ }[];
17
+ })[];
18
+ assetBytes: number;
19
+ };
20
+ };
21
+ }>;
@@ -0,0 +1,29 @@
1
+ import path from 'node:path';
2
+ import { normalizeModuleId } from '../../../utils/modules.js';
3
+ import { collectNativeComponentAssets, nativeComponentMetaKey } from './native-component-assets.js';
4
+ import { transformNativeComponentInterfaces } from './native-component-interface.js';
5
+ /** Compiles one JSX interface module and attaches its opaque native sources to Rolldown metadata. */
6
+ export async function compileNativeComponentInterface({ code, id, sourcemap, addWatchFile }) {
7
+ const transformed = transformNativeComponentInterfaces(code, id, sourcemap);
8
+ const interfacePath = normalizeModuleId(id);
9
+ const nativeComponents = await Promise.all(transformed.definitions.map((definition) => collectNativeComponentAssets(definition, interfacePath)));
10
+ nativeComponents.forEach((source) => {
11
+ addWatchFile(source.folder);
12
+ source.assets.forEach((asset) => {
13
+ addWatchFile(path.join(source.folder, asset.relativePath));
14
+ });
15
+ });
16
+ const assetBytes = nativeComponents.reduce((sourceTotal, source) => {
17
+ return sourceTotal + source.assets.reduce((assetTotal, asset) => assetTotal + asset.byteLength, 0);
18
+ }, 0);
19
+ return {
20
+ code: transformed.code,
21
+ map: transformed.map,
22
+ meta: {
23
+ [nativeComponentMetaKey]: {
24
+ sources: nativeComponents,
25
+ assetBytes
26
+ }
27
+ }
28
+ };
29
+ }
@@ -0,0 +1,15 @@
1
+ import type { Rolldown } from 'vite';
2
+ /** Creates opaque native files and their registrations from each surviving JSX interface module. */
3
+ export declare function createNativeComponentOutput({ bundle, getModuleInfo }: {
4
+ bundle: Rolldown.OutputBundle;
5
+ getModuleInfo: (moduleId: string) => {
6
+ meta: Rolldown.CustomPluginOptions;
7
+ } | null;
8
+ }): Promise<{
9
+ files: Rolldown.EmittedAsset[];
10
+ registrations: {
11
+ name: string;
12
+ componentPath: string;
13
+ fields: readonly string[];
14
+ }[];
15
+ }>;
@@ -0,0 +1,39 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { isGeneratedSubpackageFile } from '../placement/plan.js';
4
+ import { getNativeComponentSources } from './native-component-assets.js';
5
+ /** Creates opaque native files and their registrations from each surviving JSX interface module. */
6
+ export async function createNativeComponentOutput({ bundle, getModuleInfo }) {
7
+ // Files and registrations accumulate in final chunk order for deterministic output.
8
+ const files = [];
9
+ const registrations = [];
10
+ for (const output of Object.values(bundle)) {
11
+ if (output.type !== 'chunk') {
12
+ continue;
13
+ }
14
+ const packageRoot = isGeneratedSubpackageFile(output.fileName)
15
+ ? path.posix.dirname(path.posix.dirname(output.fileName))
16
+ : undefined;
17
+ for (const moduleId of output.moduleIds) {
18
+ const sources = getNativeComponentSources(getModuleInfo(moduleId)?.meta);
19
+ for (const source of sources) {
20
+ const name = path.posix.basename(source.folder);
21
+ const componentFolder = path.posix.join('components', name);
22
+ const outputFolder = packageRoot ? path.posix.join(packageRoot, componentFolder) : componentFolder;
23
+ registrations.push({
24
+ name,
25
+ componentPath: `/${path.posix.join(outputFolder, source.entry)}`,
26
+ fields: source.fields
27
+ });
28
+ for (const asset of source.assets) {
29
+ files.push({
30
+ type: 'asset',
31
+ fileName: path.posix.join(outputFolder, asset.relativePath),
32
+ source: await readFile(path.join(source.folder, asset.relativePath))
33
+ });
34
+ }
35
+ }
36
+ }
37
+ }
38
+ return { files, registrations };
39
+ }
@@ -0,0 +1,26 @@
1
+ import type { Rolldown } from 'vite';
2
+ import type { NativeComponentDefinition } from './native-component-interface.ts';
3
+ type NativeComponentAsset = {
4
+ relativePath: string;
5
+ byteLength: number;
6
+ };
7
+ export declare const nativeComponentMetaKey = "vpt:native-components";
8
+ type NativeComponentSource = NativeComponentDefinition & {
9
+ assets: readonly NativeComponentAsset[];
10
+ };
11
+ type NativeComponentMetadata = {
12
+ sources: readonly NativeComponentSource[];
13
+ assetBytes: number;
14
+ };
15
+ declare module 'rolldown' {
16
+ interface CustomPluginOptions {
17
+ [nativeComponentMetaKey]?: NativeComponentMetadata;
18
+ }
19
+ }
20
+ /** Reads the native contribution to a transformed module's package weight. */
21
+ export declare function getNativeComponentAssetBytes(meta: Rolldown.CustomPluginOptions | undefined): number;
22
+ /** Reads native sources attached to one transformed JSX interface module. */
23
+ export declare function getNativeComponentSources(meta: Rolldown.CustomPluginOptions | undefined): readonly NativeComponentSource[];
24
+ /** Collects a native component folder as opaque, recursively ordered assets without copying its interface module. */
25
+ export declare function collectNativeComponentAssets(definition: NativeComponentDefinition, interfacePath: string): Promise<NativeComponentSource>;
26
+ export {};
@@ -0,0 +1,76 @@
1
+ import { readdir, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { normalizeModuleId } from '../../../utils/modules.js';
4
+ export const nativeComponentMetaKey = 'vpt:native-components';
5
+ /** Reads the native contribution to a transformed module's package weight. */
6
+ export function getNativeComponentAssetBytes(meta) {
7
+ return meta?.[nativeComponentMetaKey]?.assetBytes ?? 0;
8
+ }
9
+ /** Reads native sources attached to one transformed JSX interface module. */
10
+ export function getNativeComponentSources(meta) {
11
+ return meta?.[nativeComponentMetaKey]?.sources ?? [];
12
+ }
13
+ /** Collects a native component folder as opaque, recursively ordered assets without copying its interface module. */
14
+ export async function collectNativeComponentAssets(definition, interfacePath) {
15
+ await requireNativeComponentDirectory(definition.folder);
16
+ await requireNativeComponentEntry(definition);
17
+ // This mutable accumulator is local to one traversal and avoids repeatedly copying growing asset arrays.
18
+ const assets = [];
19
+ await collectDirectory(definition.folder, [], assets, normalizeModuleId(interfacePath));
20
+ return { ...definition, assets };
21
+ }
22
+ /** Rejects a missing or non-directory source before Rolldown starts its recursive traversal. */
23
+ async function requireNativeComponentDirectory(folder) {
24
+ try {
25
+ if ((await stat(folder)).isDirectory()) {
26
+ return;
27
+ }
28
+ }
29
+ catch (error) {
30
+ if (Error.isError(error) && 'code' in error && error.code === 'ENOENT') {
31
+ throw new Error(`Native component folder does not exist: ${folder}`, { cause: error });
32
+ }
33
+ throw error;
34
+ }
35
+ throw new Error(`Native component source is not a directory: ${folder}`);
36
+ }
37
+ /** Rejects a missing or non-file JavaScript entry before native output registration. */
38
+ async function requireNativeComponentEntry(definition) {
39
+ const entryPath = path.join(definition.folder, `${definition.entry}.js`);
40
+ try {
41
+ if ((await stat(entryPath)).isFile()) {
42
+ return;
43
+ }
44
+ }
45
+ catch (error) {
46
+ if (Error.isError(error) && 'code' in error && error.code === 'ENOENT') {
47
+ throw new Error(`Native component entry file does not exist: ${entryPath}`, { cause: error });
48
+ }
49
+ throw error;
50
+ }
51
+ throw new Error(`Native component entry is not a file: ${entryPath}`);
52
+ }
53
+ /** Traverses entries lexically so output remains deterministic across filesystems. */
54
+ async function collectDirectory(folder, segments, assets, interfacePath) {
55
+ const directory = path.join(folder, ...segments);
56
+ const entries = await readdir(directory, { withFileTypes: true });
57
+ entries.sort((left, right) => left.name.localeCompare(right.name));
58
+ for (const entry of entries) {
59
+ const entrySegments = [...segments, entry.name];
60
+ if (entry.isDirectory()) {
61
+ await collectDirectory(folder, entrySegments, assets, interfacePath);
62
+ continue;
63
+ }
64
+ if (!entry.isFile()) {
65
+ continue;
66
+ }
67
+ const sourcePath = path.join(folder, ...entrySegments);
68
+ if (normalizeModuleId(sourcePath) === interfacePath) {
69
+ continue;
70
+ }
71
+ assets.push({
72
+ relativePath: entrySegments.join('/'),
73
+ byteLength: (await stat(sourcePath)).size
74
+ });
75
+ }
76
+ }
@@ -0,0 +1,12 @@
1
+ import type { ExistingRawSourceMap } from 'rolldown';
2
+ export type NativeComponentDefinition = {
3
+ folder: string;
4
+ entry: string;
5
+ fields: readonly string[];
6
+ };
7
+ /** Replaces native component interface calls with source-folder names and returns their static metadata. */
8
+ export declare function transformNativeComponentInterfaces(code: string, id: string, sourcemap: boolean): {
9
+ code: string;
10
+ map: ExistingRawSourceMap | null;
11
+ definitions: NativeComponentDefinition[];
12
+ };