vite-plugin-taro 0.6.18 → 0.6.19

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 (133) hide show
  1. package/client.d.ts +2 -3
  2. package/dist/index.js +213574 -0
  3. package/dist/node/plugins/wx/dev/react-refresh.d.ts +14 -13
  4. package/dist/node/utils/packages.d.ts +2 -0
  5. package/package.json +26 -26
  6. package/dist/node/plugins/client/client-taro.js +0 -59
  7. package/dist/node/plugins/client/constant.js +0 -4
  8. package/dist/node/plugins/client/inject-taro-framework-apis.js +0 -9
  9. package/dist/node/plugins/conditional/conditional-directives.js +0 -76
  10. package/dist/node/plugins/h5/constant.js +0 -3
  11. package/dist/node/plugins/h5/create-stencil-client-adapter.js +0 -94
  12. package/dist/node/plugins/h5/plugins.js +0 -179
  13. package/dist/node/plugins/h5/resolver/module-resolver.js +0 -20
  14. package/dist/node/plugins/h5/transform-app.js +0 -48
  15. package/dist/node/plugins/tailwind/tailwind-css.js +0 -3
  16. package/dist/node/plugins/wx/dev/create-hmr-results-stream.js +0 -57
  17. package/dist/node/plugins/wx/dev/dev-host.js +0 -361
  18. package/dist/node/plugins/wx/dev/hmr-files.js +0 -56
  19. package/dist/node/plugins/wx/dev/host-actions.js +0 -58
  20. package/dist/node/plugins/wx/dev/patch-publisher.js +0 -77
  21. package/dist/node/plugins/wx/dev/plugins.js +0 -164
  22. package/dist/node/plugins/wx/dev/react-refresh.js +0 -231
  23. package/dist/node/plugins/wx/dev/runtime-reports.js +0 -45
  24. package/dist/node/plugins/wx/dev/wx-dev-options.js +0 -178
  25. package/dist/node/plugins/wx/module/chunk-path.js +0 -18
  26. package/dist/node/plugins/wx/module/module.js +0 -79
  27. package/dist/node/plugins/wx/native/compile-native-component-interface.js +0 -30
  28. package/dist/node/plugins/wx/native/create-native-component-output.js +0 -39
  29. package/dist/node/plugins/wx/native/native-component-assets.js +0 -76
  30. package/dist/node/plugins/wx/native/native-component-interface.js +0 -203
  31. package/dist/node/plugins/wx/output/files.js +0 -21
  32. package/dist/node/plugins/wx/output/relative-root.js +0 -6
  33. package/dist/node/plugins/wx/output/templates.js +0 -358
  34. package/dist/node/plugins/wx/placer/placement.js +0 -245
  35. package/dist/node/plugins/wx/placer/placer.js +0 -147
  36. package/dist/node/plugins/wx/plugins.js +0 -152
  37. package/dist/node/plugins/wx/render/capsule.js +0 -54
  38. package/dist/node/plugins/wx/render/native.js +0 -543
  39. package/dist/node/plugins/wx/render/system-js/string-editor.js +0 -94
  40. package/dist/node/plugins/wx/render/system-js/system-js.js +0 -588
  41. package/dist/node/plugins/wx/render/transport.js +0 -103
  42. package/dist/node/plugins/wx/resolve/resolver.js +0 -102
  43. package/dist/node/plugins/wx/resolve/specialize-app-capsule.js +0 -9
  44. package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +0 -11
  45. package/dist/node/plugins/wx/styles/plugins.js +0 -459
  46. package/dist/node/utils/constant.js +0 -1
  47. package/dist/node/utils/memoize.js +0 -86
  48. package/dist/node/utils/modules.js +0 -22
  49. package/dist/node/utils/once.js +0 -20
  50. package/dist/node/utils/oxc-transform.js +0 -57
  51. package/dist/node/utils/packages.js +0 -9
  52. package/dist/node/utils/project-config.js +0 -8
  53. package/dist/node/utils/transform.js +0 -32
  54. package/dist/node/utils/vite.js +0 -10
  55. package/dist/node/vpt.js +0 -15
  56. package/dist/options.js +0 -1
  57. package/dist/vite.js +0 -1
  58. package/src/node/plugins/client/client-taro.ts +0 -71
  59. package/src/node/plugins/client/constant.ts +0 -5
  60. package/src/node/plugins/client/inject-taro-framework-apis.ts +0 -11
  61. package/src/node/plugins/conditional/conditional-directives.ts +0 -94
  62. package/src/node/plugins/h5/constant.ts +0 -4
  63. package/src/node/plugins/h5/create-stencil-client-adapter.ts +0 -111
  64. package/src/node/plugins/h5/plugins.ts +0 -194
  65. package/src/node/plugins/h5/resolver/module-resolver.ts +0 -33
  66. package/src/node/plugins/h5/transform-app.ts +0 -90
  67. package/src/node/plugins/tailwind/tailwind-css.ts +0 -4
  68. package/src/node/plugins/wx/dev/create-hmr-results-stream.ts +0 -71
  69. package/src/node/plugins/wx/dev/dev-host.ts +0 -453
  70. package/src/node/plugins/wx/dev/hmr-files.ts +0 -80
  71. package/src/node/plugins/wx/dev/host-actions.ts +0 -88
  72. package/src/node/plugins/wx/dev/patch-publisher.ts +0 -92
  73. package/src/node/plugins/wx/dev/plugins.ts +0 -176
  74. package/src/node/plugins/wx/dev/react-refresh.ts +0 -253
  75. package/src/node/plugins/wx/dev/runtime-reports.ts +0 -70
  76. package/src/node/plugins/wx/dev/wx-dev-options.ts +0 -226
  77. package/src/node/plugins/wx/module/chunk-path.ts +0 -22
  78. package/src/node/plugins/wx/module/module.ts +0 -110
  79. package/src/node/plugins/wx/native/compile-native-component-interface.ts +0 -48
  80. package/src/node/plugins/wx/native/create-native-component-output.ts +0 -60
  81. package/src/node/plugins/wx/native/native-component-assets.ts +0 -113
  82. package/src/node/plugins/wx/native/native-component-interface.ts +0 -267
  83. package/src/node/plugins/wx/output/files.ts +0 -40
  84. package/src/node/plugins/wx/output/relative-root.ts +0 -7
  85. package/src/node/plugins/wx/output/templates.ts +0 -448
  86. package/src/node/plugins/wx/placer/placement.ts +0 -364
  87. package/src/node/plugins/wx/placer/placer.ts +0 -180
  88. package/src/node/plugins/wx/plugins.ts +0 -183
  89. package/src/node/plugins/wx/render/capsule.ts +0 -57
  90. package/src/node/plugins/wx/render/native.ts +0 -694
  91. package/src/node/plugins/wx/render/system-js/string-editor.ts +0 -116
  92. package/src/node/plugins/wx/render/system-js/system-js.ts +0 -821
  93. package/src/node/plugins/wx/render/transport.ts +0 -173
  94. package/src/node/plugins/wx/resolve/resolver.ts +0 -145
  95. package/src/node/plugins/wx/resolve/specialize-app-capsule.ts +0 -27
  96. package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +0 -29
  97. package/src/node/plugins/wx/styles/plugins.ts +0 -595
  98. package/src/node/utils/constant.ts +0 -1
  99. package/src/node/utils/memoize.ts +0 -149
  100. package/src/node/utils/modules.ts +0 -37
  101. package/src/node/utils/once.ts +0 -21
  102. package/src/node/utils/oxc-transform.ts +0 -76
  103. package/src/node/utils/packages.ts +0 -11
  104. package/src/node/utils/project-config.ts +0 -10
  105. package/src/node/utils/transform.ts +0 -48
  106. package/src/node/utils/vite.ts +0 -22
  107. package/src/node/vpt.ts +0 -18
  108. package/src/options.ts +0 -82
  109. package/src/runtime/client/taro/api.ts +0 -11
  110. package/src/runtime/client/taro/component.ts +0 -1
  111. package/src/runtime/client/taro/define-native-component.ts +0 -15
  112. package/src/runtime/h5/app.ts +0 -25
  113. package/src/runtime/h5/taro-css.d.ts +0 -3
  114. package/src/runtime/h5/taro-runtime.ts +0 -7
  115. package/src/runtime/wx/amphibious/bootstrap.ts +0 -17
  116. package/src/runtime/wx/amphibious/transport.ts +0 -8
  117. package/src/runtime/wx/capsule/app.ts +0 -12
  118. package/src/runtime/wx/capsule/component.ts +0 -7
  119. package/src/runtime/wx/capsule/page.ts +0 -29
  120. package/src/runtime/wx/capsule/taro-runtime.ts +0 -8
  121. package/src/runtime/wx/dev/dev-runtime.ts +0 -464
  122. package/src/runtime/wx/native/app.ts +0 -4
  123. package/src/runtime/wx/native/component.ts +0 -4
  124. package/src/runtime/wx/native/custom-wrapper.ts +0 -4
  125. package/src/runtime/wx/native/page.ts +0 -6
  126. package/src/runtime/wx/systemjs/LICENSE +0 -10
  127. package/src/runtime/wx/systemjs/system-core.js +0 -370
  128. package/src/runtime/wx/systemjs/system.d.ts +0 -55
  129. package/src/runtime/wx/wechat.d.ts +0 -56
  130. package/src/vite.ts +0 -2
  131. /package/dist/{vite.d.ts → index.d.ts} +0 -0
  132. /package/dist/runtime/client/taro/{define-native-component.d.ts → native.d.ts} +0 -0
  133. /package/dist/runtime/client/taro/{define-native-component.js → native.js} +0 -0
@@ -1,57 +0,0 @@
1
- import { buffer, debounceTime, filter, Subject } from 'rxjs';
2
- /**
3
- * Adapts Rolldown's non-awaited HMR callback into lossless quiet-window publications.
4
- *
5
- * Debouncing the result stream itself would retain only the final callback and lose incremental patch factories that later
6
- * patches provably do not reproduce. Instead, the debounced view is only a closing notifier for `buffer`: every callback is
7
- * retained in arrival order, and one configured quiet period emits the complete window to the host's existing serialized
8
- * writer. This first stream migration deliberately does not own physical state; `publish` and `reportError` remain synchronous
9
- * admission callbacks so the dev host can enqueue both through its single writer.
10
- *
11
- * DevEngine failures are values, not Observable errors. They represent transient editor generations and carry no executable
12
- * patch, so the stream reports the final error but otherwise removes them. Successful callbacks on either side remain ordered
13
- * and lossless; Rolldown generated each against its unpublished client frontier, and the host delivers every retained payload.
14
- * Completing the returned Subject flushes its current buffer synchronously, allowing host shutdown to await the resulting
15
- * serialized task rather than silently dropping an admitted patch.
16
- *
17
- * Complexity is O(updates + changed files) per emitted window, with one retained reference per callback until the quiet edge.
18
- */
19
- export function createHmrResultsStream(settleMilliseconds, scheduler, publish, reportError) {
20
- /*
21
- * This hot Subject is the sole mutable boundary between Rolldown's non-awaited callback and RxJS. Each next preserves one
22
- * compiler generation by reference and in arrival order. buffer owns the temporary lossless window; debounceTime observes the
23
- * same Subject only to decide when that window closes. Replacing this with a debounced scalar would discard patch factories,
24
- * while letting callback Promises mutate host state directly would overlap publications. Completion flushes the final window
25
- * before shutdown, after which the Subject is never reused.
26
- */
27
- const results = new Subject();
28
- results
29
- .pipe(buffer(results.pipe(debounceTime(settleMilliseconds, scheduler))), filter((window) => window.length > 0))
30
- .subscribe((window) => {
31
- /*
32
- * An Error is one source generation that produced no executable delta; it does not invalidate successful Rolldown
33
- * callbacks already admitted on either side of it. Dropping the whole quiet window would therefore discard real
34
- * patch factories, while starting a complete build would compile the same known-invalid editor contents. Keep the
35
- * old runtime running, report only the latest diagnostic from a repeated parser burst, and continue below with the
36
- * successful callback values exactly as if the temporary invalid save had never produced an HMR payload.
37
- */
38
- const lastFailure = window.findLast((result) => result instanceof Error);
39
- if (lastFailure) {
40
- reportError(lastFailure);
41
- }
42
- const successfulWindow = window.filter((result) => !(result instanceof Error));
43
- if (successfulWindow.length > 0) {
44
- /*
45
- * flatMap preserves callback arrival order and each callback's internal Rolldown order. Updates must not be
46
- * deduplicated: later undelivered patches are deltas and do not reproduce factories from earlier sequences.
47
- * changedFiles is opaque DevEngine metadata and has no identity semantics in the host, so preserving its raw
48
- * concatenation is both cheaper and more faithful than maintaining a second Set-based interpretation here.
49
- */
50
- publish({
51
- updates: successfulWindow.flatMap((result) => result.updates),
52
- changedFiles: successfulWindow.flatMap((result) => result.changedFiles)
53
- });
54
- }
55
- });
56
- return results;
57
- }
@@ -1,361 +0,0 @@
1
- import path from 'node:path';
2
- import colors from 'picocolors';
3
- import { dev } from 'rolldown/experimental';
4
- import { asyncScheduler } from 'rxjs';
5
- import { createHmrResultsStream } from './create-hmr-results-stream.js';
6
- import { developmentAppWxssFileName, globalWxssFileName, hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderDevelopmentAppWxss, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
7
- import { createHostActions } from './host-actions.js';
8
- import { PatchPublisher } from './patch-publisher.js';
9
- import { createRuntimeReportsStream } from './runtime-reports.js';
10
- import { installWxDevOptions, requireSingleOutput } from './wx-dev-options.js';
11
- /** One short trailing-edge window absorbs editor bursts before style preparation and physical Page notification. */
12
- const hmrSettleMilliseconds = 16;
13
- /**
14
- * Creates the wx dev host: the adapter that owns the physical Rolldown DevEngine (created
15
- * with dev(...)) and the patch publisher, and replaces Vite's bundledDev.listen so the
16
- * engine writes directly to the Mini Program output directory instead of serving browser
17
- * HMR over HTTP.
18
- *
19
- * The shared style plugin carries the resolver's immutable App/Page cascade policy while Rolldown remains authoritative for
20
- * every live import edge.
21
- */
22
- export async function createWxDevHost({ server, options, styles }) {
23
- const bundledDev = getBundledDev(server);
24
- // All callbacks admit typed actions through this edge; concatMap is the sole owner of effect ordering and mutable host state.
25
- const hostActions = createHostActions(applyHostAction, (action, error) => logWxError(server.config.logger, `wx HMR ${action.kind} failed`, error));
26
- const publisher = new PatchPublisher((content) => writeHmrFile(server.config.build.outDir, hmrPatchesFileName, content));
27
- // Option installation now configures only Rolldown. Build lifecycle results enter through the engine's output action below.
28
- installWxDevOptions({ bundledDev, server, options });
29
- const engine = await createEngine();
30
- const hmrResults = createHmrResultsStream(hmrSettleMilliseconds, asyncScheduler, (result) => {
31
- // One reduced window becomes one existing host transaction: style preparation, one cumulative patch write, then
32
- // ordered delivery notifications for every original Rolldown payload retained by the stream.
33
- hostActions.next({ kind: 'publish', result: result });
34
- }, (error) => {
35
- /*
36
- * Invalid syntax is a normal intermediate editor generation. Rolldown produced no patch, so neither the published
37
- * nor applied runtime frontier needs repair. Triggering a complete build here would immediately compile the same
38
- * invalid source and empirically wedges that DevEngine generation. Admit only the diagnostic; when the user saves
39
- * valid source, the watch engine emits an ordinary successful callback and resumes the normal publication path.
40
- */
41
- hostActions.next({ kind: 'error', error: error });
42
- });
43
- const runtimeReports = createRuntimeReportsStream(hmrSettleMilliseconds, asyncScheduler, (reports) => {
44
- // ACK conflation happens before admission, but publisher validation and mutation remain ordered with patch writes and
45
- // build rotation. Reports arriving during publication therefore execute only after that physical transaction commits.
46
- hostActions.next({ kind: 'reports', reports: reports });
47
- });
48
- /*
49
- * BundledDev is Vite's mutable environment adapter. Transfer its engine slot to the one physical writer created above so
50
- * Vite middleware and close() address the same engine; leaving the slot untouched would make listen() create a second,
51
- * skip-write browser engine with a divergent graph. Disable Vite's access-triggered regeneration because runtime reports and
52
- * Rolldown HMR results now own every rebuild decision. Finally replace listen so readiness waits for physical initial output
53
- * instead of Vite's in-memory bundle. These assignments are installation-time ownership transfer, never per-update state.
54
- */
55
- bundledDev._devEngine = engine;
56
- bundledDev.triggerBundleRegenerationIfStale = async () => false;
57
- bundledDev.listen = async () => {
58
- /*
59
- * Subscribe before run because DevEngine intentionally fulfills run() after an initial plugin failure and emits that
60
- * Error through onOutput. Observing the existing action edge preserves the exact failure without a second buildEnd
61
- * Promise or forwarding Subject; waitForAction does not consume the action from concatMap's reducer subscription.
62
- */
63
- const initialOutput = hostActions.waitForAction((action) => action.kind === 'output');
64
- await engine.run();
65
- const { result } = await initialOutput;
66
- if (result instanceof Error) {
67
- throw result;
68
- }
69
- await engine.ensureCurrentBuildFinish();
70
- // onOutput admission happens on Rolldown's callback stack, but its style publication runs asynchronously through
71
- // hostActions. Drain that transaction before returning control to Vite: otherwise the HTTP server can bind while the
72
- // initial output action is still finalizing styles, causing both that action and the later listening action to observe
73
- // the port and rotate the build identity twice.
74
- await hostActions.waitForIdle();
75
- };
76
- // Vite binds the port only after initServer (and therefore the initial build) completes, so
77
- // the actual port is not observable while onOutput runs for the first build. The App metadata
78
- // is written once the port is real; later full builds rewrite it from onOutput.
79
- server.httpServer?.once('listening', () => {
80
- // Port availability is lifecycle data, so initial identity rotation follows prior output/capture actions in the reducer.
81
- hostActions.next({ kind: 'listening' });
82
- });
83
- // The runtime's metadata-only reports land on the control path; the buildId in each report
84
- // IS the Rolldown client ID.
85
- server.middlewares.use(hmrControlPath, (req, res) => void handleReport(req, res));
86
- installDevToolsPrinter(server);
87
- return {
88
- close: async () => {
89
- // Quiet-window completion first admits final HMR publications and rebuild reports into the serialized action edge.
90
- hmrResults.complete();
91
- runtimeReports.complete();
92
- await hostActions.waitForIdle();
93
- // Keep the action edge open until the final generation has admitted every output callback.
94
- await engine.ensureCurrentBuildFinish();
95
- await hostActions.complete();
96
- }
97
- };
98
- /** Atomically materializes the style plugin's prepared global artifact. */
99
- async function writeGlobalStyle(wxss) {
100
- await writeHmrFile(server.config.build.outDir, globalWxssFileName, wxss);
101
- }
102
- /** Rotates the build identity and materializes the App metadata for it. */
103
- async function rotateBuildSession() {
104
- const port = boundPort(server);
105
- if (port === undefined) {
106
- // The initial output finishes before Vite binds its port. The listening listener
107
- // starts the first real client build, avoiding a phantom registered client.
108
- return;
109
- }
110
- const { buildId, previousBuildId } = publisher.startBuild();
111
- if (previousBuildId) {
112
- await engine.removeClient(previousBuildId);
113
- }
114
- await engine.registerClient(buildId);
115
- await publishBuildMetadata(server, buildId, port);
116
- }
117
- /**
118
- * Mutates only the request-local HTTP response: unsupported methods become 404, malformed bounded bodies become 400, and a
119
- * valid report is admitted before the default 200 response ends. No response object or parser state crosses requests.
120
- */
121
- async function handleReport(req, res) {
122
- if (req.method !== 'POST') {
123
- res.statusCode = 404;
124
- res.end();
125
- return;
126
- }
127
- try {
128
- const report = JSON.parse(await readBody(req));
129
- runtimeReports.next(report);
130
- res.end();
131
- }
132
- catch (e) {
133
- logWxError(server.config.logger, 'wx HMR report failed', e);
134
- res.statusCode = 400;
135
- res.end();
136
- }
137
- }
138
- /** Reduces one merged source action through the existing authoritative host state. */
139
- function applyHostAction(action) {
140
- switch (action.kind) {
141
- case 'publish':
142
- return publishUpdates(action.result);
143
- case 'error':
144
- logWxError(server.config.logger, 'wx HMR update failed', action.error);
145
- return;
146
- case 'reports':
147
- action.reports.forEach(processReport);
148
- return;
149
- case 'output':
150
- if (action.result instanceof Error) {
151
- logWxError(server.config.logger, 'wx dev build failed', action.result);
152
- return;
153
- }
154
- return publishCompleteStyles();
155
- case 'listening':
156
- return rotateBuildSession();
157
- }
158
- }
159
- /** Publishes graph-complete styles before rotating the App-visible build identity. */
160
- async function publishCompleteStyles() {
161
- await styles.finalizeUpdate([], writeGlobalStyle);
162
- await rotateBuildSession();
163
- }
164
- /** Applies one runtime receipt to the active physical patch history. */
165
- function processReport(report) {
166
- // Delayed reports from older builds must never prune the live build's cumulative patch history.
167
- if (!publisher.isCurrentBuild(report.buildId)) {
168
- return;
169
- }
170
- switch (report.kind) {
171
- case 'rebuild': {
172
- requestFullBuild(report.reason);
173
- return;
174
- }
175
- case 'applied': {
176
- publisher.acknowledge(report.seq);
177
- return;
178
- }
179
- }
180
- }
181
- /** Creates the physical DevEngine with the wx dev host hooks. */
182
- async function createEngine() {
183
- const rolldownOptions = await bundledDev.getRolldownOptions();
184
- const output = requireSingleOutput(rolldownOptions);
185
- return dev(rolldownOptions, output, {
186
- /**
187
- * Admits Rolldown's non-awaited callback without starting asynchronous host work on the binding callback stack.
188
- * The Subject retains Error values as control events and successful values as lossless patch data until its quiet edge.
189
- */
190
- onHmrUpdates: (result) => {
191
- hmrResults.next(result);
192
- },
193
- // Initial and later complete builds share one admission path; startup merely observes the first OutputAction.
194
- onOutput: (result) => {
195
- hostActions.next({ kind: 'output', result: result });
196
- },
197
- rebuildStrategy: 'never',
198
- watch: {
199
- // Rolldown must observe every source generation and emit every incremental factory: later patches do not
200
- // reconstruct modules changed only by an earlier callback. RxJS conflates publication after compilation,
201
- // preserving the complete patch sequence while avoiding repeated physical DevTools notifications.
202
- skipWrite: false,
203
- useDebounce: false
204
- }
205
- });
206
- }
207
- /** Centralizes the one diagnostic and DevEngine command used by every rebuild authority. */
208
- function requestFullBuild(reason) {
209
- server.config.logger.info(`[vpt] wx full rebuild required${reason ? `: ${reason}` : ''}`);
210
- engine.triggerFullBuild();
211
- }
212
- /** Selects active updates and publishes their resulting host transaction. */
213
- async function publishUpdates(result) {
214
- /*
215
- * This transaction-local array preserves every patch in one pass and permits immediate rebuild dominance. It never escapes
216
- * the serialized action. A filter/find/flatMap pipeline would scan a large burst repeatedly and allocate an intermediate.
217
- */
218
- const patches = [];
219
- for (const { clientId, update } of result.updates) {
220
- if (!publisher.isCurrentBuild(clientId) || update.type === 'Noop') {
221
- continue;
222
- }
223
- if (update.type === 'Patch') {
224
- patches.push(update);
225
- continue;
226
- }
227
- requestFullBuild(update.reason);
228
- return;
229
- }
230
- await publishPatchBatch(patches);
231
- }
232
- /** Publishes one coherent WXSS, patch-file, and Rolldown-frontier transaction. */
233
- async function publishPatchBatch(patches) {
234
- if (patches.length === 0) {
235
- return;
236
- }
237
- // `onHmrUpdates` runs after every affected transform has updated captured CSS and the live import graph. The style
238
- // boundary finalizes every factory before atomically publishing their matching WXSS.
239
- const finalizedPatches = await styles.finalizeUpdate(patches, writeGlobalStyle);
240
- // Publish global.wxss before the matching JavaScript patch so DevTools observes a coherent HMR transaction.
241
- // The physical file must exist before Rolldown advances: once committed, later patches may be generated relative to
242
- // this batch even if DevTools has not observed its file event yet. PatchPublisher keeps the unapplied range cumulative,
243
- // so any later file generation still carries every factory needed to bridge the runtime's older application frontier.
244
- await publisher.produce(finalizedPatches);
245
- await commitPublishedBatch(finalizedPatches);
246
- }
247
- /**
248
- * Advances Rolldown's published frontier in the same sequence order materialized in the cumulative physical file.
249
- *
250
- * Given a batch [5, 6], publisher.produce has already made factories [5, 6] visible in hmr/patches.js. This method then
251
- * commits payload 5 followed by payload 6. If DevTools observes neither event before sequence 7 is published, the next
252
- * physical file contains [5, 6, 7], while Rolldown is free to generate 7 relative to its already-published sequence 6.
253
- */
254
- async function commitPublishedBatch(batch) {
255
- // Do not use Promise.all or deduplicate filenames. Multiple sequential payloads may target the same output filename,
256
- // and each notification commits one distinct Rolldown payload. Awaiting in order preserves the exact frontier encoded
257
- // by PatchUpdate.seq and prevents a later payload from becoming visible to the engine before its predecessor.
258
- for (const patch of batch) {
259
- await engine.notifyPayloadDelivered(patch.filename);
260
- }
261
- }
262
- }
263
- /** The bound HTTP port, or undefined before Vite's server is listening. */
264
- function boundPort(server) {
265
- const httpServer = server.httpServer;
266
- if (!httpServer) {
267
- return undefined;
268
- }
269
- const address = httpServer.address();
270
- if (!address || typeof address === 'string') {
271
- return undefined;
272
- }
273
- return address.port;
274
- }
275
- /** Resets physical patches and then exposes one coherent build identity to a freshly compiled App heap. */
276
- async function publishBuildMetadata(server, buildId, port) {
277
- const info = {
278
- buildId,
279
- endpoint: `${server.config.server.https ? 'https' : 'http'}://${resolveEndpointHost(server)}:${port}${hmrControlPath}`
280
- };
281
- await writeHmrFile(server.config.build.outDir, hmrPatchesFileName, renderInitialHmrPatches());
282
- await writeHmrFile(server.config.build.outDir, hmrInfoFileName, renderHmrInfo(info));
283
- // `removeDevelopmentAppWxss` kept the previous physical wrapper in place while the complete output was written. Replace
284
- // it only now, after the empty patch frontier and matching identity are durable. DevTools treats `app.wxss` as an App root,
285
- // so this write intentionally causes the one full refresh allowed at a complete-build boundary; the refreshed App reads
286
- // the new info above. Incremental updates must never write this file because an App refresh could destroy the heap while
287
- // its JavaScript patch is being acknowledged. They publish only the imported `assets/global.wxss` stylesheet instead.
288
- await writeHmrFile(server.config.build.outDir, developmentAppWxssFileName, renderDevelopmentAppWxss(buildId));
289
- }
290
- /** Replaces browser server URLs with the physical project directory consumed by WeChat DevTools. */
291
- function installDevToolsPrinter(server) {
292
- /*
293
- * Vite exposes printing as a mutable server callback because URLs are unknown until startup. WX serves control reports over
294
- * HTTP but users open the physical output directory, so retaining the browser printer advertises unusable navigation URLs.
295
- * Replacing only this presentation callback leaves resolved URLs and server routing untouched and naturally dies with the
296
- * server instance; logging elsewhere would duplicate Vite's one readiness notification.
297
- */
298
- server.printUrls = () => {
299
- server.config.logger.info(` ${colors.green('➜')} ${colors.bold('WeChat DevTools')}: ${colors.cyan(relativeToViteConfig(server.config.build.outDir, server.config.configFile, server.config.root))}`);
300
- };
301
- }
302
- /**
303
- * The project directory shown in the DevTools banner, relative to the Vite config:
304
- * `dist/wx` instead of the absolute output path, so it can be pasted into DevTools.
305
- */
306
- function relativeToViteConfig(outDir, configFile, root) {
307
- const configDirectory = configFile ? path.dirname(configFile) : root;
308
- const relativePath = path.relative(configDirectory, outDir).replaceAll('\\', '/');
309
- if (!relativePath)
310
- return '.';
311
- return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
312
- }
313
- /** Logs an error with the plugin prefix, distinguishing Error values from unknowns. */
314
- function logWxError(logger, prefix, error) {
315
- if (Error.isError(error)) {
316
- logger.error(`[vpt] ${prefix}`, { error });
317
- }
318
- else {
319
- logger.error(`[vpt] ${prefix} with unknown error: ${error}`);
320
- }
321
- }
322
- const maximumBodyBytes = 64 * 1024;
323
- function readBody(req) {
324
- return new Promise((resolve, reject) => {
325
- /*
326
- * Node delivers one HTTP body through multiple callback invocations, so this request-local mutable string is the minimal
327
- * state that joins chunks in wire order. The 64 KiB bound caps both retained memory and repeated-concatenation work; the
328
- * value is parsed once on end and then discarded. Parsing per chunk is invalid because JSON tokens may cross boundaries,
329
- * while retaining request bodies in host state would couple unrelated Page reports and leak across the server lifecycle.
330
- */
331
- let body = '';
332
- req.on('data', (chunk) => {
333
- body += chunk.toString('utf8');
334
- if (body.length > maximumBodyBytes) {
335
- reject(new Error('report body too large'));
336
- req.destroy();
337
- }
338
- });
339
- req.on('end', () => resolve(body));
340
- req.on('error', reject);
341
- });
342
- }
343
- /** The bound address host, or loopback for wildcard binds; IPv6 literals are bracketed. */
344
- function resolveEndpointHost(server) {
345
- const address = server.httpServer?.address();
346
- if (!address || typeof address === 'string') {
347
- return '127.0.0.1';
348
- }
349
- if (address.address === '0.0.0.0' || address.address === '::') {
350
- // Wildcard binds accept loopback connections; 127.0.0.1 is the address DevTools can reach.
351
- return '127.0.0.1';
352
- }
353
- return address.address.includes(':') ? `[${address.address}]` : address.address;
354
- }
355
- function getBundledDev(server) {
356
- const bundledDev = server.environments.client.bundledDev;
357
- if (!bundledDev) {
358
- throw new Error('Vite did not create the wx bundled-development environment.');
359
- }
360
- return bundledDev;
361
- }
@@ -1,56 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import fs from 'node:fs/promises';
3
- import path from 'node:path';
4
- export const developmentAppWxssFileName = 'app.wxss';
5
- export const globalWxssFileName = 'assets/global.wxss';
6
- export const hmrInfoFileName = 'hmr/info.js';
7
- export const hmrPatchesFileName = 'hmr/patches.js';
8
- /** Report endpoint path served by the wx dev control edge. */
9
- export const hmrControlPath = '/__vpt_hmr__';
10
- /** Renders the synchronous CommonJS metadata module loaded by the runtime chunk. */
11
- export function renderHmrInfo(info) {
12
- return `module.exports = Object.freeze(${JSON.stringify(info)});\n`;
13
- }
14
- /** Provides a valid dependency before the host has a patch range to publish. */
15
- export function renderInitialHmrPatches() {
16
- return 'module.exports = undefined;\n';
17
- }
18
- /**
19
- * Renders the native App style entry for one complete development build.
20
- *
21
- * Imported global CSS can change while the entry remains byte-identical. DevTools may then reuse an older persistent compile
22
- * cache after it restarts. Tying this inert comment to the build identity invalidates that cache once per complete build,
23
- * while incremental style updates continue changing only the imported file and therefore preserve the App heap.
24
- */
25
- export function renderDevelopmentAppWxss(buildId) {
26
- return `@import "./assets/global.wxss";\n/* vpt-build:${buildId} */\n`;
27
- }
28
- /**
29
- * Renders the cumulative patch suffix as inert CommonJS data.
30
- *
31
- * DevTools re-executes the Page because this dependency changed. The Page entry passes the exported payload to the persistent
32
- * App runtime synchronously before importing its capsule, keeping delivery explicit and leaving this file free of side effects.
33
- */
34
- export function renderHmrPatches(buildId, patches) {
35
- if (patches.length === 0) {
36
- throw new Error('Cannot render an empty WX patch range.');
37
- }
38
- const rendered = patches.map((patch) => `{seq: ${patch.seq}, changedIds: ${JSON.stringify(patch.changedIds)}, factory: () => {\n${patch.code}\n}}`);
39
- return `module.exports = {buildId: ${JSON.stringify(buildId)}, patches: [${rendered.join(',')}]};\n`;
40
- }
41
- /** Atomically publishes one physical HMR module so DevTools can observe only complete JavaScript generations. */
42
- export async function writeHmrFile(outDir, fileName, source) {
43
- const filePath = path.join(outDir, fileName);
44
- const directory = path.dirname(filePath);
45
- await fs.mkdir(directory, { recursive: true });
46
- const temporaryPath = path.join(directory, `.${path.basename(filePath)}.${randomUUID()}.txt`);
47
- try {
48
- // DevTools ignores the temporary .txt file; keeping it beside the destination guarantees a same-filesystem rename.
49
- await fs.writeFile(temporaryPath, source);
50
- await fs.rename(temporaryPath, filePath);
51
- }
52
- finally {
53
- // rename removes the source path on success; force cleanup covers interrupted writes and failed replacements.
54
- await fs.rm(temporaryPath, { force: true });
55
- }
56
- }
@@ -1,58 +0,0 @@
1
- import { catchError, concatMap, defer, EMPTY, filter, firstValueFrom, lastValueFrom, map, Subject } from 'rxjs';
2
- /**
3
- * Executes semantic host actions one at a time while keeping source admission synchronous.
4
- *
5
- * `concatMap` is the sole effect serializer: each deferred reducer call starts only after the prior Promise settles. Errors are
6
- * converted to empty inner streams so one failed physical transaction is reported without terminating later host actions.
7
- * Barrier envelopes participate in the same ordering but run no effect; resolving one proves every action admitted before it
8
- * has settled. `waitForAction` observes this same admission edge for lifecycle gates without introducing a forwarding Subject.
9
- * Completing the source drains already-admitted effects and gives shutdown one Promise for final quiescence.
10
- */
11
- export function createHostActions(apply, reportError) {
12
- /*
13
- * This Subject is the host's only mutable admission edge. Independent callback stacks synchronously append semantic actions
14
- * or barriers; concatMap owns the queued ordering and admits exactly one asynchronous effect at a time. A Promise chain would
15
- * require mutation at every producer and is permanently rejected after one failure, while mergeMap could overlap physical
16
- * writes and build rotation. The Subject retains no business frontier itself and is completed only after all external sources
17
- * are quiescent, allowing lastValueFrom to prove the final queued effect settled.
18
- */
19
- const envelopes = new Subject();
20
- const completion = lastValueFrom(envelopes.pipe(concatMap((envelope) => {
21
- if (envelope.kind === 'barrier') {
22
- return defer(() => {
23
- envelope.resolve();
24
- return EMPTY;
25
- });
26
- }
27
- return defer(() => Promise.resolve(apply(envelope.action))).pipe(catchError((error) => {
28
- reportError(envelope.action, error);
29
- return EMPTY;
30
- }));
31
- })), { defaultValue: undefined });
32
- return {
33
- complete: async () => {
34
- envelopes.complete();
35
- await completion;
36
- },
37
- next(action) {
38
- envelopes.next({ kind: 'action', action: action });
39
- },
40
- waitForAction(select) {
41
- /*
42
- * Subscribe to the multicast admission Subject rather than creating another lifecycle source. Barrier envelopes are
43
- * internal ordering controls, so expose only semantic actions and let the caller's type guard select its milestone.
44
- * firstValueFrom unsubscribes after the match; concatMap's independent subscription still applies the same action.
45
- */
46
- return firstValueFrom(envelopes.pipe(filter((envelope) => envelope.kind === 'action'), map((envelope) => envelope.action), filter(select)));
47
- },
48
- waitForIdle() {
49
- /*
50
- * The resolver is one transaction-local mutable latch. Enqueuing it behind ordinary actions makes resolution mean
51
- * every earlier effect settled, without completing the shared source needed by final DevEngine output callbacks.
52
- */
53
- const barrier = Promise.withResolvers();
54
- envelopes.next({ kind: 'barrier', resolve: barrier.resolve });
55
- return barrier.promise;
56
- }
57
- };
58
- }
@@ -1,77 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { renderHmrPatches } from './hmr-files.js';
3
- /**
4
- * Owns the cumulative sequence range between the host's published frontier and the runtime's applied frontier.
5
- *
6
- * For example, if the runtime has applied sequence 4:
7
- *
8
- * 1. produce([5, 6]) writes [5, 6];
9
- * 2. produce([7]) before an application report writes [5, 6, 7], so DevTools may miss the first file event safely;
10
- * 3. acknowledge(6) retains [7];
11
- * 4. produce([8]) then writes [7, 8], exactly the suffix the runtime still needs.
12
- *
13
- * The host may advance Rolldown's published frontier through 8 immediately after those writes, but this history is pruned only
14
- * through 6 until the runtime reports successful application. Published sequence and applied sequence are deliberately distinct.
15
- */
16
- export class PatchPublisher {
17
- writePatches;
18
- /*
19
- * This mutable identity is the sole session authority for runtime reports and per-client Rolldown updates. startBuild rotates
20
- * it only after a successful complete output reaches the serialized host reducer. Delayed reports retain their original ID
21
- * and therefore fail isCurrentBuild instead of pruning or rebuilding the new session. An immutable constructor value cannot
22
- * represent full-build rotation, while deriving identity from patches would leave empty builds without a client ID.
23
- */
24
- buildId;
25
- /*
26
- * This mutable ordered suffix bridges two independent frontiers: Rolldown payloads become published immediately after the
27
- * cumulative file is durable, but entries remain here until the runtime acknowledges applying their sequence. Appending is
28
- * lossless because later patches are deltas; prefix removal is the only valid mutation because acknowledgements are monotonic
29
- * frontiers. A Set, latest-only value, or immutable reconstruction would either lose duplicate filenames/order or copy the
30
- * complete unapplied history for every burst.
31
- */
32
- pendingPatches = [];
33
- // Explicit field assignment: node --test strips types and does not support parameter properties.
34
- constructor(writePatches) {
35
- this.writePatches = writePatches;
36
- }
37
- /** True when the buildId belongs to the current full build. */
38
- isCurrentBuild(buildId) {
39
- return buildId === this.buildId;
40
- }
41
- /** Begins a fresh build and returns both sides of the client-session rotation. */
42
- startBuild() {
43
- const previousBuildId = this.buildId;
44
- const buildId = randomUUID();
45
- this.buildId = buildId;
46
- this.pendingPatches.length = 0;
47
- return { buildId, previousBuildId };
48
- }
49
- /**
50
- * Appends a Rolldown batch and publishes the complete range not yet applied by the runtime.
51
- *
52
- * Resolution means the cumulative JavaScript generation is physically visible. The host may then advance Rolldown's
53
- * published frontier immediately; pendingPatches remains intact until an application report proves the runtime caught up.
54
- */
55
- async produce(patches) {
56
- if (this.buildId === undefined || patches.length === 0) {
57
- return;
58
- }
59
- this.pendingPatches.push(...patches);
60
- await this.writePatches(renderHmrPatches(this.buildId, this.pendingPatches));
61
- }
62
- /**
63
- * Removes only the prefix covered by the runtime's successful application frontier. Publication alone never calls this:
64
- * retaining the gap between published and applied frontiers is what lets DevTools safely miss intermediate file events.
65
- */
66
- acknowledge(seq) {
67
- /*
68
- * This local counter scans the monotonic prefix without allocating or invoking a callback for each patch. It exists only
69
- * long enough to supply splice's prefix length; pendingPatches remains the sole durable frontier and is mutated once.
70
- */
71
- let appliedCount = 0;
72
- while (appliedCount < this.pendingPatches.length && this.pendingPatches[appliedCount].seq <= seq) {
73
- appliedCount++;
74
- }
75
- this.pendingPatches.splice(0, appliedCount);
76
- }
77
- }