vite-plugin-taro 0.5.3 → 0.5.5

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 (33) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/node/plugins/client/client-taro.js +12 -8
  4. package/dist/node/plugins/h5/create-stencil-client-adapter.d.ts +21 -0
  5. package/dist/node/plugins/h5/create-stencil-client-adapter.js +92 -0
  6. package/dist/node/plugins/h5/plugins.d.ts +10 -0
  7. package/dist/node/plugins/h5/plugins.js +50 -61
  8. package/dist/node/plugins/wx/dev/dev-host.js +103 -216
  9. package/dist/node/plugins/wx/dev/hmr-files.d.ts +4 -5
  10. package/dist/node/plugins/wx/dev/hmr-files.js +18 -8
  11. package/dist/node/plugins/wx/dev/patch-publisher.d.ts +25 -5
  12. package/dist/node/plugins/wx/dev/patch-publisher.js +30 -9
  13. package/dist/node/plugins/wx/dev/react-refresh.d.ts +12 -0
  14. package/dist/node/plugins/wx/dev/react-refresh.js +111 -108
  15. package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +25 -0
  16. package/dist/node/plugins/wx/dev/wx-dev-options.js +147 -0
  17. package/dist/node/utils/oxc-transform.d.ts +21 -0
  18. package/dist/node/utils/oxc-transform.js +58 -0
  19. package/dist/node/utils/serialized-task-queue.d.ts +6 -2
  20. package/dist/node/utils/serialized-task-queue.js +10 -2
  21. package/dist/runtime/wx/dev/dev-runtime.js +70 -26
  22. package/package.json +13 -12
  23. package/src/node/plugins/client/client-taro.ts +13 -8
  24. package/src/node/plugins/h5/create-stencil-client-adapter.ts +110 -0
  25. package/src/node/plugins/h5/plugins.ts +52 -84
  26. package/src/node/plugins/wx/dev/dev-host.ts +121 -256
  27. package/src/node/plugins/wx/dev/hmr-files.ts +20 -8
  28. package/src/node/plugins/wx/dev/patch-publisher.ts +36 -10
  29. package/src/node/plugins/wx/dev/react-refresh.ts +125 -129
  30. package/src/node/plugins/wx/dev/wx-dev-options.ts +200 -0
  31. package/src/node/utils/oxc-transform.ts +77 -0
  32. package/src/node/utils/serialized-task-queue.ts +15 -3
  33. package/src/runtime/wx/dev/dev-runtime.ts +80 -28
@@ -5,9 +5,8 @@
5
5
  // The `DevRuntime` base class is injected into the chunk by Rolldown's dev-mode
6
6
  // transform, so the WX host only extends it.
7
7
  //
8
- // Delivery is passive: every valid hmr/patches.js suffix is acknowledged by Rolldown
9
- // sequence, then applied synchronously before the Page continues evaluating. Already-applied
10
- // sequences are ignored when another Page requires the same physical file.
8
+ // Every Page explicitly passes the inert hmr/patches.js export here before importing its capsule. The runtime applies that
9
+ // cumulative suffix synchronously, reports its successful application frontier, and ignores sequences replayed by other Pages.
11
10
 
12
11
  import type { DevRuntime as RolldownDevRuntime } from 'rolldown/experimental/runtime-types'
13
12
 
@@ -110,7 +109,7 @@ class WxDevRuntime extends DevRuntime {
110
109
  }
111
110
 
112
111
  /** Computes accepting boundaries and every executed module that must be re-armed. */
113
- private computeHmrUpdate(changedIds: readonly string[]): HmrUpdate | undefined {
112
+ private computeHmrUpdate(changedIds: Iterable<string>): HmrUpdate | undefined {
114
113
  // Mutable traversal accumulators are confined to one synchronous update plan.
115
114
  const boundaries: string[] = []
116
115
  const updateSet = new Set<string>()
@@ -166,7 +165,7 @@ class WxDevRuntime extends DevRuntime {
166
165
  * Applies one patch in three phases: capture old contexts, evict the whole update set,
167
166
  * then re-run accepting modules and pass their fresh exports to the old contexts.
168
167
  */
169
- private applyHmrUpdate(changedIds: readonly string[]): void {
168
+ private applyHmrUpdate(changedIds: Iterable<string>): void {
170
169
  const update = this.computeHmrUpdate(changedIds)
171
170
  if (!update) return
172
171
 
@@ -195,14 +194,12 @@ class WxDevRuntime extends DevRuntime {
195
194
  }
196
195
  }
197
196
 
198
- /** Consumed once per App heap from hmr/info.js; the host buildId is the delivery identity. */
197
+ /** Consumed once per App heap from hmr/info.js; the host buildId identifies its cumulative patch history. */
199
198
  initialize(info: HmrInfo): void {
200
199
  if (this.hmrInfo) {
201
200
  return
202
201
  }
203
202
  this.hmrInfo = info
204
- // Anchor: the host publishes only after the runtime reports its delivery position.
205
- void this.sendReport({ kind: 'delivery', seq: this.appliedSeq })
206
203
  }
207
204
 
208
205
  /** True between a patch delivery and the next page show: a hot reload is in progress. */
@@ -218,17 +215,17 @@ class WxDevRuntime extends DevRuntime {
218
215
  this.hotReloading = false
219
216
  }
220
217
 
221
- /** The only direct effect of hmr/patches.js: validate, store, acknowledge, and apply. */
222
- storePatches(payload: PatchPayload): void {
218
+ /** Applies one Page-delivered payload before that Page imports its capsule. */
219
+ applyPatches(payload: PatchPayload | undefined): void {
220
+ // The initial physical dependency exports undefined until the host has a patch range.
221
+ if (!payload) return
222
+
223
223
  const info = this.hmrInfo
224
224
  if (!info || payload.buildId !== info.buildId) {
225
225
  console.warn('[vpt] patches for a stale build')
226
226
  return
227
227
  }
228
228
 
229
- const deliveredSeq = Math.max(this.appliedSeq, payload.patches.at(-1)?.seq ?? 0)
230
- void this.sendReport({ kind: 'delivery', seq: deliveredSeq })
231
-
232
229
  // A delivered patch means DevTools is about to replay the page lifecycle on the
233
230
  // re-executing Pages; the capsule wrapper suppresses the synthetic unmount/mount so
234
231
  // the React tree survives and Refresh swaps the code in place.
@@ -236,27 +233,82 @@ class WxDevRuntime extends DevRuntime {
236
233
 
237
234
  // Apply synchronously: the page's imports below the require resolve against the
238
235
  // freshly registered modules, so the re-executed Page evaluates with the new code.
239
- this.applyPatches(payload.patches)
236
+ if (this.applyPatchBatch(payload.patches)) {
237
+ // The host may publish later generations while this synchronous apply runs. Reporting only afterward makes this
238
+ // the application frontier: publisher history is never pruned merely because its JavaScript file was observed.
239
+ void this.sendReport({ kind: 'applied', seq: this.appliedSeq })
240
+ }
240
241
  }
241
242
 
242
- /** Applies one physical suffix in Rolldown sequence order. */
243
- private applyPatches(patches: readonly PatchProgram[]): void {
244
- for (const patch of patches) {
245
- if (patch.seq <= this.appliedSeq) continue
243
+ /**
244
+ * Folds one cumulative physical patch file into a single logical HMR update.
245
+ *
246
+ * `hmr/patches.js` can contain several unacknowledged Rolldown patches and can be required by several Page shells. The
247
+ * runtime must therefore ignore replayed sequences, reject a missing sequence, and move directly from the currently live
248
+ * module generation to the latest published generation without rendering intermediate generations.
249
+ *
250
+ * For an appliedSeq of 4:
251
+ *
252
+ * - [5, 6, 7] registers every factory, performs one update using their unioned changedIds, commits appliedSeq 7, and reports 7;
253
+ * - a second Page evaluating [5, 6, 7] skips the complete replay and leaves the latest factories untouched;
254
+ * - [5, 7] fails at the expected sequence 6, keeps appliedSeq 4, and requests a full rebuild because factory 6 is unrecoverable.
255
+ */
256
+ private applyPatchBatch(patches: readonly PatchProgram[]): boolean {
257
+ // Keep the initial watermark immutable throughout the fold. Comparing replays against a moving watermark would allow
258
+ // a duplicate new sequence in the same payload to masquerade as an already-applied patch.
259
+ const previousSeq = this.appliedSeq
260
+
261
+ // Mutable only during this synchronous pass. `nextSeq` validates continuity while `changedIds` unions every incremental
262
+ // patch's roots for the one final graph traversal; neither value escapes into persistent runtime state.
263
+ let nextSeq = previousSeq + 1
264
+ const changedIds = new Set<string>()
265
+
266
+ try {
267
+ for (const patch of patches) {
268
+ // The same physical file is evaluated once per affected Page. Those later evaluations replay its prefix and
269
+ // must not let an old factory overwrite the newer factory already stored in the Rolldown runtime.
270
+ if (patch.seq <= previousSeq) {
271
+ continue
272
+ }
246
273
 
247
- try {
248
- const expectedSeq = this.appliedSeq + 1
249
- if (patch.seq !== expectedSeq) {
250
- throw new Error(`missing patch sequence ${expectedSeq}`)
274
+ // Every patch is incremental: if one physical write was missed, later factories cannot reconstruct modules
275
+ // changed only by that missing patch. Rebuilding is safer than silently running a mixed module generation.
276
+ if (patch.seq !== nextSeq) {
277
+ throw new Error(`missing patch sequence ${nextSeq}`)
251
278
  }
279
+
280
+ // A patch factory only registers module graphs and module factories; it does not execute application modules.
281
+ // Running all of them first leaves the registry at the latest generation while avoiding intermediate renders.
252
282
  patch.factory()
253
- this.applyHmrUpdate(patch.changedIds)
254
- this.appliedSeq = patch.seq
255
- } catch (error) {
256
- console.warn(`[vpt] patch sequence ${patch.seq} failed; apply stopped`, error)
257
- void this.sendReport({ kind: 'rebuild' })
258
- return
283
+
284
+ for (const changedId of patch.changedIds) {
285
+ changedIds.add(changedId)
286
+ }
287
+
288
+ nextSeq++
259
289
  }
290
+
291
+ // A payload containing only replayed sequences requires no graph work and must not alter the application watermark.
292
+ if (nextSeq === previousSeq + 1) {
293
+ return true
294
+ }
295
+
296
+ // Apply once after every factory is registered. React Refresh arms a newly executed module's hot.accept callback
297
+ // in a microtask; applying consecutive patches separately would inspect that intermediate context too early and
298
+ // incorrectly bubble through the capsule to the native Page shell as though no HMR boundary existed.
299
+ this.applyHmrUpdate(changedIds)
300
+
301
+ // Commit application only after graph propagation and boundary callbacks succeed. A failure leaves the old watermark
302
+ // intact and requests a full rebuild below, so a partially applied batch is never acknowledged as healthy.
303
+ this.appliedSeq = nextSeq - 1
304
+ return true
305
+ } catch (error) {
306
+ console.warn('[vpt] patch batch failed; apply stopped', error)
307
+ void this.sendReport({
308
+ kind: 'rebuild',
309
+ reason: Error.isError(error) ? error.message : String(error)
310
+ })
311
+ return false
260
312
  }
261
313
  }
262
314