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,172 @@
1
+ import type { Rolldown } from 'vite'
2
+ import { getWxExecutionKind, isTransportModule } from '../module.ts'
3
+ import {
4
+ createPlacementPlan,
5
+ getSubpackageName,
6
+ isGeneratedSubpackageFile,
7
+ type ModuleGraph,
8
+ mainPackage,
9
+ type PackageLocation,
10
+ type PlacementPlan
11
+ } from './plan.ts'
12
+
13
+ /** Native app.json declaration for one generated code-only subpackage. */
14
+ export type GeneratedSubpackage = {
15
+ /** Stable native alias derived from the generated root hash. */
16
+ name: string
17
+ /** Physical directory containing this subpackage's emitted capsules. */
18
+ root: string
19
+ /** Marks this as a code-only subpackage with no native Page routes. */
20
+ pages: readonly []
21
+ }
22
+
23
+ /**
24
+ * Creates the stateful adapter between graph planning and Rolldown's output lifecycle:
25
+ *
26
+ * - renderStart analyzes transformed modules before chunking.
27
+ * - codeSplitting prevents modules assigned to different packages from being merged.
28
+ * - filename callbacks materialize planned subpackage roots.
29
+ * - renderChunk derives native loading mode from those physical paths.
30
+ * - generateBundle reconciles the plan with chunks that survived tree shaking.
31
+ */
32
+ export function createPlacer() {
33
+ // Filename and output callbacks run after analyze and read this immutable plan through their shared closure.
34
+ let plan: PlacementPlan = new Map()
35
+
36
+ /**
37
+ * Reduces module ownership to one package for filename generation. Unknown Rolldown-generated modules default to
38
+ * main, empty chunks default to main, and a chunk containing multiple known owners is rejected before paths diverge.
39
+ */
40
+ function getChunkLocation(chunk: Rolldown.PreRenderedChunk): PackageLocation {
41
+ let location: PackageLocation | undefined
42
+ for (const moduleId of chunk.moduleIds) {
43
+ const moduleLocation = plan.get(moduleId) ?? mainPackage
44
+ if (!location) {
45
+ location = moduleLocation
46
+ continue
47
+ }
48
+ if (!hasSameLocation(location, moduleLocation)) {
49
+ throw new Error(`wx chunk mixes package owners: ${chunk.moduleIds.join(', ')}`)
50
+ }
51
+ }
52
+ return location ?? mainPackage
53
+ }
54
+
55
+ return {
56
+ /** Assigns every transformed module to main or one generated, size-bounded subpackage. */
57
+ analyze(graph: ModuleGraph): void {
58
+ plan = createPlacementPlan(graph)
59
+ },
60
+
61
+ /**
62
+ * Complete Rolldown fragment required to preserve package placement and native entry semantics.
63
+ *
64
+ * ```text
65
+ * native App/Page/Component shell entry
66
+ * └─ static import / runtime importSync() ─▶ explicit capsule entry + static closure [main, no TLA]
67
+ * └─ System.import() ─▶ lazy-a [package A, TLA allowed]
68
+ * └─ static import ─▶ lazy-b [package B]
69
+ *
70
+ * name() assigns lazy-a and lazy-b to their planned package groups
71
+ * includeDependenciesRecursively false: does not pull lazy-b back into package A
72
+ * preserveEntrySignatures allows cross-chunk bindings without weakening native entry exports
73
+ *
74
+ * package A capsule
75
+ * └─ SystemJS dependency ─▶ package B capsule
76
+ * ▲
77
+ * └─ main transport obtains registration with require.async()
78
+ * ```
79
+ *
80
+ * Explicit entries preserve the shell/capsule rendering boundary while their static edge executes synchronously
81
+ * from main. Once a dynamic boundary is crossed, physical fetches may be asynchronous and modules may use
82
+ * top-level await. SystemJS still links that complete static lazy graph before execution, even across packages.
83
+ */
84
+ rolldownOptions: {
85
+ output: {
86
+ /**
87
+ * Gives every generated subpackage a distinct Rolldown chunk group. Recursive dependency capture must
88
+ * stay disabled: lazy static dependencies may belong to other subpackages and SystemJS links them
89
+ * asynchronously.
90
+ */
91
+ codeSplitting: {
92
+ groups: [
93
+ {
94
+ name(moduleId: string): string | null {
95
+ const location = plan.get(moduleId)
96
+ return location?.kind === 'subpackage' ? getSubpackageName(location.root) : null
97
+ },
98
+ // Do not let Rolldown pull a lazy group's static closure into one chunk. Past the nested dynamic
99
+ // boundary, transport may obtain registrations from several packages asynchronously before
100
+ // SystemJS links and executes the original graph, including cycles and top-level await.
101
+ includeDependenciesRecursively: false
102
+ }
103
+ ]
104
+ },
105
+ // strictExecutionOrder deliberately has no plugin default. When an application enables it through normal
106
+ // Rolldown output options, the generated helper runtime becomes amphibious: CommonJS evaluates it once and
107
+ // transport publishes that cached namespace to SystemJS.
108
+ /** Preserves exact native shell paths while hashing transport and explicit capsule entries. */
109
+ entryFileNames(chunk: Rolldown.PreRenderedChunk): string {
110
+ return getWxExecutionKind(chunk) === 'native' && !isTransportModule(chunk)
111
+ ? '[name]'
112
+ : 'assets/[name]-[hash].js'
113
+ },
114
+ /** Converts the planned owner into its physical main or generated subpackage filename template. */
115
+ chunkFileNames(chunk: Rolldown.PreRenderedChunk): string {
116
+ const location = getChunkLocation(chunk)
117
+ if (location.kind === 'main') {
118
+ return 'assets/[name]-[hash].js'
119
+ }
120
+ // The containing subpackage already supplies a stable identity. Do not leak the Rolldown group name
121
+ // into every physical chunk filename; content identity alone is sufficient beneath that root.
122
+ return `${location.root}/assets/[hash].js`
123
+ },
124
+ // Keep generic assets independent of stylesheet conventions. The CSS adapter sees Tailwind's final
125
+ // mutation and owns the exact global `app.wxss` identity without confusing native Page companions.
126
+ assetFileNames: 'assets/[name]-[hash][extname]'
127
+ },
128
+ // Rolldown rejects strict entry signatures when code-splitting groups disable recursive dependency capture.
129
+ // allow-extension retains required native-entry exports while permitting the extra cross-chunk bindings used
130
+ // to split lazy static closures across physical packages.
131
+ preserveEntrySignatures: 'allow-extension' as const
132
+ },
133
+
134
+ /**
135
+ * Selects loading mode from physical output rather than graph intent. Transport executes in main, so main files
136
+ * use require() and every generated subpackage file uses require.async().
137
+ */
138
+ getLoadMode(chunk: Rolldown.RenderedChunk): 'sync' | 'async' {
139
+ return isGeneratedSubpackageFile(chunk.fileName) ? 'async' : 'sync'
140
+ },
141
+
142
+ /**
143
+ * Reconciles planned ownership with final chunks through module IDs. Tree-shaken subpackages disappear naturally,
144
+ * while roots are deduplicated and sorted before becoming deterministic app.json declarations.
145
+ */
146
+ getSubpackages(bundle: Rolldown.OutputBundle): GeneratedSubpackage[] {
147
+ const emittedSubpackageRoots = new Set<string>()
148
+ for (const output of Object.values(bundle)) {
149
+ if (output.type !== 'chunk') {
150
+ continue
151
+ }
152
+ for (const moduleId of output.moduleIds) {
153
+ const location = plan.get(moduleId)
154
+ if (location?.kind === 'subpackage') {
155
+ emittedSubpackageRoots.add(location.root)
156
+ }
157
+ }
158
+ }
159
+
160
+ return [...emittedSubpackageRoots].sort().map((root) => ({
161
+ name: getSubpackageName(root),
162
+ root,
163
+ pages: []
164
+ }))
165
+ }
166
+ }
167
+ }
168
+
169
+ /** Compares main by discriminant and generated subpackages by their unique physical root. */
170
+ function hasSameLocation(left: PackageLocation, right: PackageLocation): boolean {
171
+ return left.kind === 'main' ? right.kind === 'main' : right.kind === 'subpackage' && left.root === right.root
172
+ }
@@ -0,0 +1,306 @@
1
+ import { createHash } from 'node:crypto'
2
+ import type { Rolldown } from 'vite'
3
+
4
+ // Leave headroom below WeChat's 2M subpackage limit for capsule wrappers and bundler-generated code.
5
+ const subpackagePlanningBudget = 1_900_000
6
+ const generatedSubpackageRootPrefix = 'sub/p_'
7
+
8
+ /** Identifies one generated code-only subpackage by its physical output root. */
9
+ export type SubpackageLocation = {
10
+ /** Discriminates generated subpackages from main. */
11
+ kind: 'subpackage'
12
+ /** Native subpackage root relative to the Mini Program output directory. */
13
+ root: string
14
+ }
15
+
16
+ /** Physical package ownership for one transformed module. */
17
+ export type PackageLocation = { kind: 'main' } | SubpackageLocation
18
+
19
+ /** Immutable module-to-package ownership produced before Rolldown creates chunks. */
20
+ export type PlacementPlan = ReadonlyMap<string, PackageLocation>
21
+
22
+ /** Minimal Rolldown graph interface consumed by the subpackage planner. */
23
+ export type ModuleGraph = {
24
+ /** Every transformed module known after graph construction. */
25
+ moduleIds: Iterable<string>
26
+ /** Reads static edges, dynamic edges, transformed code, and entry ownership. */
27
+ getModuleInfo(moduleId: string): Rolldown.ModuleInfo | null
28
+ /** Adds non-JavaScript output owned by a transformed module to its package weight. */
29
+ getAdditionalModuleBytes?: (info: Rolldown.ModuleInfo) => number
30
+ }
31
+
32
+ /** One independently placeable lazy module together with size and co-location preferences. */
33
+ type PlaceableModule = {
34
+ /** Stable module identity and final ownership key. */
35
+ moduleId: string
36
+ /** UTF-8 size of transformed source used as the bin-packing estimate. */
37
+ estimatedBytes: number
38
+ /** Dynamic roots whose static closures contain this module. */
39
+ consumers: ReadonlySet<string>
40
+ /** Lazy modules connected by a direct static import in either direction. */
41
+ neighbors: ReadonlySet<string>
42
+ }
43
+
44
+ /** Mutable subpackage candidate used only while best-fit packing is in progress. */
45
+ type SubpackageBin = {
46
+ /** Modules currently assigned to this candidate. */
47
+ moduleIds: string[]
48
+ /** Accumulated transformed-source estimate. */
49
+ estimatedBytes: number
50
+ /** Dynamic roots represented by at least one assigned module. */
51
+ consumers: Set<string>
52
+ }
53
+
54
+ /** Final membership and stable physical location for one generated subpackage. */
55
+ type PackedSubpackage = SubpackageLocation & {
56
+ /** Sorted membership used both for stable hashing and ownership assignment. */
57
+ moduleIds: readonly string[]
58
+ }
59
+
60
+ /** Shared main-package value used for every eager or output-generated module. */
61
+ export const mainPackage = { kind: 'main' } as const
62
+
63
+ /**
64
+ * Creates one deterministic subpackage placement plan:
65
+ *
66
+ * 1. Snapshot Rolldown's transformed module graph.
67
+ * 2. Reserve every explicit shell and capsule entry together with its static closure in main.
68
+ * 3. Treat dynamic imports as asynchronous roots, then annotate their modules with affinity.
69
+ * 4. Pack those lazy modules independently under the planning budget.
70
+ * 5. Return only module ownership; chunks and native manifests are reconciled later.
71
+ *
72
+ * Static cycles are deliberately not atomic only after a genuine nested dynamic boundary. System.import() may obtain their
73
+ * registrations from several packages and await top-level execution while preserving the original static ESM graph.
74
+ */
75
+ export function createPlacementPlan({
76
+ moduleIds,
77
+ getModuleInfo,
78
+ getAdditionalModuleBytes,
79
+ planningBudgetBytes = subpackagePlanningBudget
80
+ }: ModuleGraph & { planningBudgetBytes?: number }): PlacementPlan {
81
+ // Materialize the iterable once because every later phase needs stable random access by module ID.
82
+ const infos = new Map<string, Rolldown.ModuleInfo>()
83
+ for (const moduleId of moduleIds) {
84
+ const info = getModuleInfo(moduleId)
85
+ if (info) {
86
+ infos.set(moduleId, info)
87
+ }
88
+ }
89
+
90
+ // Eager ownership is a hard constraint; consumer and neighbor sets below are soft packing preferences only.
91
+ const eagerModules = findEagerModules(infos)
92
+ const consumersByModule = findLazyConsumers({ infos, eagerModules })
93
+ const neighborsByModule = findLazyNeighbors({ infos, eagerModules })
94
+ const placeableModules = [...infos.entries()]
95
+ .filter(([moduleId]) => !eagerModules.has(moduleId))
96
+ .map(([moduleId, info]) => ({
97
+ moduleId,
98
+ estimatedBytes: Buffer.byteLength(info.code ?? '', 'utf8') + (getAdditionalModuleBytes?.(info) ?? 0),
99
+ consumers: consumersByModule.get(moduleId) ?? new Set([moduleId]),
100
+ neighbors: neighborsByModule.get(moduleId) ?? new Set<string>()
101
+ }))
102
+
103
+ // Packing operates at module granularity, so a large lazy closure or cycle may span several subpackages.
104
+ const subpackages = packSubpackages({ modules: placeableModules, planningBudgetBytes }).map(createPackedSubpackage)
105
+ const locationByModule = new Map<string, PackageLocation>()
106
+ for (const moduleId of eagerModules) {
107
+ locationByModule.set(moduleId, mainPackage)
108
+ }
109
+ for (const subpackage of subpackages) {
110
+ for (const moduleId of subpackage.moduleIds) {
111
+ locationByModule.set(moduleId, subpackage)
112
+ }
113
+ }
114
+
115
+ return locationByModule
116
+ }
117
+
118
+ /**
119
+ * Finds modules that must remain in main. Native shells and capsules are explicit entries, and static traversal keeps their
120
+ * complete eager closures synchronous. Every dynamic import is therefore a genuine lazy boundary whose graph may use
121
+ * subpackages and top-level await.
122
+ */
123
+ function findEagerModules(infos: ReadonlyMap<string, Rolldown.ModuleInfo>): Set<string> {
124
+ const eagerModules = new Set<string>()
125
+ const pending = [...infos.values()].filter((info) => info.isEntry).map((info) => info.id)
126
+ while (pending.length > 0) {
127
+ const moduleId = pending.pop()
128
+ if (!moduleId || eagerModules.has(moduleId)) {
129
+ continue
130
+ }
131
+
132
+ const info = infos.get(moduleId)
133
+ if (!info) {
134
+ continue
135
+ }
136
+ eagerModules.add(moduleId)
137
+ pending.push(...info.importedIds)
138
+ }
139
+ return eagerModules
140
+ }
141
+
142
+ /**
143
+ * Records demand after the eager importSync closure has been removed. Every remaining dynamic target starts one lazy root
144
+ * traversal; that traversal follows static edges only and stops before another dynamic boundary. A shared module records
145
+ * every root that can request it. These consumer sets improve co-location but never prevent subpackage splitting.
146
+ */
147
+ function findLazyConsumers({
148
+ infos,
149
+ eagerModules
150
+ }: {
151
+ infos: ReadonlyMap<string, Rolldown.ModuleInfo>
152
+ eagerModules: ReadonlySet<string>
153
+ }): Map<string, Set<string>> {
154
+ const dynamicRoots = new Set<string>()
155
+ for (const info of infos.values()) {
156
+ for (const importedId of info.dynamicallyImportedIds) {
157
+ if (infos.has(importedId) && !eagerModules.has(importedId)) {
158
+ dynamicRoots.add(importedId)
159
+ }
160
+ }
161
+ }
162
+
163
+ const consumersByModule = new Map<string, Set<string>>()
164
+ for (const dynamicRoot of [...dynamicRoots].sort()) {
165
+ const visited = new Set<string>()
166
+ const pending = [dynamicRoot]
167
+ while (pending.length > 0) {
168
+ const moduleId = pending.pop()
169
+ if (!moduleId || visited.has(moduleId) || eagerModules.has(moduleId)) {
170
+ continue
171
+ }
172
+
173
+ const info = infos.get(moduleId)
174
+ if (!info) {
175
+ continue
176
+ }
177
+ visited.add(moduleId)
178
+ const consumers = consumersByModule.get(moduleId) ?? new Set<string>()
179
+ consumers.add(dynamicRoot)
180
+ consumersByModule.set(moduleId, consumers)
181
+ pending.push(...info.importedIds)
182
+ }
183
+ }
184
+ return consumersByModule
185
+ }
186
+
187
+ /**
188
+ * Converts each lazy static edge into an undirected affinity. Direction is irrelevant for co-location scoring, while the
189
+ * original directed dependency remains in Rolldown and later in SystemJS. Cycles are therefore preferences, not atoms.
190
+ */
191
+ function findLazyNeighbors({
192
+ infos,
193
+ eagerModules
194
+ }: {
195
+ infos: ReadonlyMap<string, Rolldown.ModuleInfo>
196
+ eagerModules: ReadonlySet<string>
197
+ }): Map<string, Set<string>> {
198
+ const neighborsByModule = new Map<string, Set<string>>()
199
+ for (const [moduleId, info] of infos) {
200
+ if (eagerModules.has(moduleId)) {
201
+ continue
202
+ }
203
+ for (const importedId of info.importedIds) {
204
+ if (!infos.has(importedId) || eagerModules.has(importedId)) {
205
+ continue
206
+ }
207
+ addNeighbor(neighborsByModule, moduleId, importedId)
208
+ addNeighbor(neighborsByModule, importedId, moduleId)
209
+ }
210
+ }
211
+ return neighborsByModule
212
+ }
213
+
214
+ /** Adds one side of an undirected lazy-module affinity edge. */
215
+ function addNeighbor(neighborsByModule: Map<string, Set<string>>, moduleId: string, neighborId: string): void {
216
+ const neighbors = neighborsByModule.get(moduleId) ?? new Set<string>()
217
+ neighbors.add(neighborId)
218
+ neighborsByModule.set(moduleId, neighbors)
219
+ }
220
+
221
+ /**
222
+ * Packs lazy modules with deterministic best-fit decreasing:
223
+ *
224
+ * 1. Visit larger transformed modules first, with module ID as the stable tie-breaker.
225
+ * 2. Consider only existing bins that stay within the planning budget.
226
+ * 3. Prefer the bin with the least remaining space, minimizing subpackage count in the usual best-fit heuristic.
227
+ * 4. When remaining space ties, prefer shared dynamic consumers and then static neighbors.
228
+ * 5. Create a new bin when no existing bin fits; an individually oversized module receives its own bin.
229
+ */
230
+ function packSubpackages({
231
+ modules,
232
+ planningBudgetBytes
233
+ }: {
234
+ modules: readonly PlaceableModule[]
235
+ planningBudgetBytes: number
236
+ }): SubpackageBin[] {
237
+ const bins: SubpackageBin[] = []
238
+ const sortedModules = [...modules].sort((left, right) => {
239
+ return right.estimatedBytes - left.estimatedBytes || left.moduleId.localeCompare(right.moduleId)
240
+ })
241
+
242
+ for (const module of sortedModules) {
243
+ const candidate = bins
244
+ .filter((bin) => bin.estimatedBytes + module.estimatedBytes <= planningBudgetBytes)
245
+ .map((bin) => ({
246
+ bin,
247
+ remainingBytes: planningBudgetBytes - bin.estimatedBytes - module.estimatedBytes,
248
+ affinity: getAffinity(bin, module)
249
+ }))
250
+ .sort((left, right) => {
251
+ return left.remainingBytes - right.remainingBytes || right.affinity - left.affinity
252
+ })[0]?.bin
253
+
254
+ const bin = candidate ?? {
255
+ moduleIds: [],
256
+ estimatedBytes: 0,
257
+ consumers: new Set<string>()
258
+ }
259
+ if (!candidate) {
260
+ bins.push(bin)
261
+ }
262
+ bin.moduleIds.push(module.moduleId)
263
+ bin.estimatedBytes += module.estimatedBytes
264
+ for (const consumer of module.consumers) {
265
+ bin.consumers.add(consumer)
266
+ }
267
+ }
268
+ return bins
269
+ }
270
+
271
+ /** Scores dynamic-root overlap above direct static adjacency when equally full bins compete. */
272
+ function getAffinity(bin: SubpackageBin, module: PlaceableModule): number {
273
+ let affinity = 0
274
+ for (const consumer of module.consumers) {
275
+ if (bin.consumers.has(consumer)) {
276
+ affinity += 2
277
+ }
278
+ }
279
+ for (const neighbor of module.neighbors) {
280
+ if (bin.moduleIds.includes(neighbor)) {
281
+ affinity += 1
282
+ }
283
+ }
284
+ return affinity
285
+ }
286
+
287
+ /** Freezes bin membership and derives a stable subpackage root from sorted module IDs. */
288
+ function createPackedSubpackage(bin: SubpackageBin): PackedSubpackage {
289
+ const moduleIds = [...bin.moduleIds].sort()
290
+ const hash = createHash('sha256').update(moduleIds.join('\0')).digest('hex').slice(0, 8)
291
+ return {
292
+ kind: 'subpackage',
293
+ root: `${generatedSubpackageRootPrefix}${hash}`,
294
+ moduleIds
295
+ }
296
+ }
297
+
298
+ /** Uses the generated root directory itself as the native subpackage alias. */
299
+ export function getSubpackageName(root: string): string {
300
+ return root.slice(root.lastIndexOf('/') + 1)
301
+ }
302
+
303
+ /** Tests the plugin-owned output prefix that physically identifies every generated subpackage. */
304
+ export function isGeneratedSubpackageFile(fileName: string): boolean {
305
+ return fileName.startsWith(generatedSubpackageRootPrefix)
306
+ }
@@ -0,0 +1,165 @@
1
+ import type { Plugin, PluginOption } from 'vite'
2
+ import type { VitePluginTaroOptions } from '../../../options.ts'
3
+ import { esTarget } from '../../utils/constant.ts'
4
+ import { packageRequire } from '../../utils/packages.ts'
5
+ import { clientTaroNativeId } from '../client/constant.ts'
6
+ import { createWxDevelopmentPlugin } from './dev/plugin.ts'
7
+ import { getWxExecutionKind, isTransportModule } from './module.ts'
8
+ import { compileNativeComponentInterface } from './native/compile-native-component-interface.ts'
9
+ import { getNativeComponentAssetBytes } from './native/native-component-assets.ts'
10
+ import { createOutputFiles } from './output/files.ts'
11
+ import { createPlacer } from './placement/placer.ts'
12
+ import { renderCapsule } from './render/capsule.ts'
13
+ import { renderNative } from './render/native.ts'
14
+ import { materializeTransport } from './render/transport.ts'
15
+ import { createResolver } from './resolve/resolver.ts'
16
+
17
+ /** Creates the complete plugin set for the wx target. */
18
+ export function createWxTargetPlugins(options: VitePluginTaroOptions): PluginOption[] {
19
+ return [createWxPlugin(options), createWxDevelopmentPlugin(options)]
20
+ }
21
+
22
+ /** Configures the complete wx target build pipeline. */
23
+ function createWxPlugin(options: VitePluginTaroOptions): Plugin {
24
+ const resolver = createResolver(options)
25
+ const placer = createPlacer()
26
+
27
+ return {
28
+ name: 'vpt:wx',
29
+
30
+ config(_config, _env) {
31
+ return {
32
+ define: createTaroDefines(),
33
+
34
+ appType: 'custom',
35
+
36
+ oxc: { target: esTarget },
37
+
38
+ resolve: {
39
+ alias: [
40
+ {
41
+ find: /^@tarojs\/components$/,
42
+ replacement: packageRequire.resolve('@tarojs/plugin-platform-weapp/dist/components-react')
43
+ }
44
+ ]
45
+ },
46
+
47
+ build: {
48
+ modulePreload: false,
49
+ cssCodeSplit: false,
50
+ // Let weapp-tailwindcss own final WXSS transformation.
51
+ cssMinify: false,
52
+
53
+ // No base64 assets: Taro warns on image srcs above ~2KB, and inlined
54
+ // images bloat the JS bundle toward the mini program package limit.
55
+ assetsInlineLimit: 0,
56
+
57
+ target: esTarget,
58
+
59
+ rolldownOptions: {
60
+ ...placer.rolldownOptions,
61
+ input: resolver.input
62
+ }
63
+ }
64
+ }
65
+ },
66
+
67
+ resolveId(id, importer) {
68
+ return resolver.resolveId(id, importer, this.environment.config.root)
69
+ },
70
+
71
+ transform: {
72
+ order: 'pre',
73
+ async handler(code, id) {
74
+ const sourcemap = Boolean(this.environment.config.build.sourcemap)
75
+
76
+ if (code.includes(clientTaroNativeId)) {
77
+ return compileNativeComponentInterface({
78
+ code,
79
+ id,
80
+ sourcemap,
81
+ addWatchFile: (file) => this.addWatchFile(file)
82
+ })
83
+ }
84
+
85
+ return resolver.specialize(code, id, sourcemap)
86
+ }
87
+ },
88
+
89
+ renderStart() {
90
+ placer.analyze({
91
+ moduleIds: this.getModuleIds(),
92
+ getModuleInfo: (moduleId) => this.getModuleInfo(moduleId),
93
+ getAdditionalModuleBytes: (info) => getNativeComponentAssetBytes(info.meta)
94
+ })
95
+ },
96
+
97
+ renderChunk: {
98
+ order: 'post',
99
+ async handler(code, chunk, outputOptions, meta) {
100
+ const executionKind = getWxExecutionKind(chunk)
101
+ const sourcemap = Boolean(outputOptions.sourcemap)
102
+
103
+ if (executionKind === 'capsule') {
104
+ return renderCapsule(code, chunk, sourcemap)
105
+ }
106
+
107
+ // Native and amphibious modules share the CommonJS renderer. Amphibious transport exposure is a
108
+ // separate concern materialized from final output paths after the physical transport itself is rendered.
109
+ const native = renderNative({ code, chunk, chunks: meta.chunks, sourcemap })
110
+
111
+ if (isTransportModule(chunk)) {
112
+ return materializeTransport({
113
+ code: native.code,
114
+ transportChunk: chunk,
115
+ chunks: meta.chunks,
116
+ getLoadMode: placer.getLoadMode,
117
+ sourcemap
118
+ })
119
+ }
120
+
121
+ return native
122
+ }
123
+ },
124
+
125
+ generateBundle: {
126
+ order: 'post',
127
+ async handler(_, bundle) {
128
+ const subpackages = placer.getSubpackages(bundle)
129
+
130
+ const outputFiles = await createOutputFiles({
131
+ bundle,
132
+ options,
133
+ subpackages,
134
+ getModuleInfo: (moduleId) => this.getModuleInfo(moduleId)
135
+ })
136
+
137
+ outputFiles.forEach((file) => {
138
+ this.emitFile(file)
139
+ })
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ /** Creates the build-time constants required by Taro's legacy feature gates. */
146
+ function createTaroDefines(): Record<string, string> {
147
+ const taroVersion = String((packageRequire('@tarojs/runtime/package.json') as { version: string }).version)
148
+
149
+ return {
150
+ 'process.env.FRAMEWORK': JSON.stringify('react'),
151
+ 'process.env.SUPPORT_TARO_POLYFILL': JSON.stringify('disabled'),
152
+ 'process.env.TARO_ENV': JSON.stringify('weapp'),
153
+ 'process.env.TARO_PLATFORM': JSON.stringify('mini'),
154
+ 'process.env.TARO_VERSION': JSON.stringify(taroVersion),
155
+ // React's development-only Suspense diagnostics call this browser API without guards.
156
+ 'performance.now': 'Date.now',
157
+ ENABLE_ADJACENT_HTML: 'false',
158
+ ENABLE_CLONE_NODE: 'false',
159
+ ENABLE_CONTAINS: 'false',
160
+ ENABLE_INNER_HTML: 'false',
161
+ ENABLE_MUTATION_OBSERVER: 'false',
162
+ ENABLE_SIZE_APIS: 'false',
163
+ ENABLE_TEMPLATE_CONTENT: 'false'
164
+ }
165
+ }