vite-plugin-taro 0.6.2 → 0.6.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.
- package/README.en.md +8 -3
- package/README.md +8 -3
- package/dist/node/plugins/wx/dev/dev-host.d.ts +5 -4
- package/dist/node/plugins/wx/dev/dev-host.js +19 -43
- package/dist/node/plugins/wx/dev/plugins.d.ts +6 -15
- package/dist/node/plugins/wx/dev/plugins.js +16 -70
- package/dist/node/plugins/wx/dev/react-refresh.d.ts +9 -3
- package/dist/node/plugins/wx/dev/react-refresh.js +35 -7
- package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +2 -3
- package/dist/node/plugins/wx/dev/wx-dev-options.js +6 -7
- package/dist/node/plugins/wx/plugins.js +5 -11
- package/dist/node/plugins/wx/resolve/resolver.js +4 -4
- package/dist/node/plugins/wx/resolve/{specialize-bootstrap.d.ts → specialize-app-capsule.d.ts} +2 -2
- package/dist/node/plugins/wx/resolve/{specialize-bootstrap.js → specialize-app-capsule.js} +2 -2
- package/dist/node/plugins/wx/styles/plugins.d.ts +141 -3
- package/dist/node/plugins/wx/styles/plugins.js +401 -89
- package/dist/node/utils/vite.d.ts +4 -14
- package/dist/node/utils/vite.js +7 -40
- package/dist/runtime/wx/amphibious/bootstrap.d.ts +0 -2
- package/dist/runtime/wx/amphibious/bootstrap.js +0 -2
- package/dist/runtime/wx/capsule/app.d.ts +2 -2
- package/dist/runtime/wx/capsule/app.js +2 -2
- package/dist/runtime/wx/dev/dev-runtime.js +55 -79
- package/package.json +4 -3
- package/src/node/plugins/wx/dev/dev-host.ts +22 -44
- package/src/node/plugins/wx/dev/plugins.ts +17 -73
- package/src/node/plugins/wx/dev/react-refresh.ts +36 -7
- package/src/node/plugins/wx/dev/wx-dev-options.ts +7 -10
- package/src/node/plugins/wx/plugins.ts +5 -11
- package/src/node/plugins/wx/resolve/resolver.ts +4 -4
- package/src/node/plugins/wx/resolve/{specialize-bootstrap.ts → specialize-app-capsule.ts} +2 -2
- package/src/node/plugins/wx/styles/plugins.ts +518 -93
- package/src/node/utils/vite.ts +13 -58
- package/src/runtime/wx/amphibious/bootstrap.ts +0 -5
- package/src/runtime/wx/capsule/app.ts +5 -2
- package/src/runtime/wx/dev/dev-runtime.ts +71 -120
- package/src/runtime/wx/wechat.d.ts +1 -2
- package/dist/node/plugins/wx/dev/create-style-capture.d.ts +0 -54
- package/dist/node/plugins/wx/dev/create-style-capture.js +0 -173
- package/dist/node/plugins/wx/styles/transform-wx-style.d.ts +0 -8
- package/dist/node/plugins/wx/styles/transform-wx-style.js +0 -9
- package/dist/node/plugins/wx/styles/utils.d.ts +0 -39
- package/dist/node/plugins/wx/styles/utils.js +0 -95
- package/src/node/plugins/wx/dev/create-style-capture.ts +0 -248
- package/src/node/plugins/wx/styles/transform-wx-style.ts +0 -11
- package/src/node/plugins/wx/styles/utils.ts +0 -119
package/README.en.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# VPT
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/vite-plugin-taro)
|
|
4
4
|

|
|
@@ -20,7 +20,7 @@ Continue with the [Quick Start guide](https://vpt.js.org/guides/quick-start/).
|
|
|
20
20
|
|
|
21
21
|
### React Hot Reload in WeChat DevTools
|
|
22
22
|
|
|
23
|
-
<video src="https://github.com/user-attachments/assets/
|
|
23
|
+
<video src="https://github.com/user-attachments/assets/c8289e1e-d8ad-429f-a0d9-a40656b4962a" controls autoplay muted loop playsinline width="100%"></video>
|
|
24
24
|
|
|
25
25
|
- **Vite 8 + React 19** Build one codebase for WeChat Mini Program and Web with the Vite ecosystem.
|
|
26
26
|
- **Hot reload** Preserve App data, the active page, React component state, and input state while editing.
|
|
@@ -31,12 +31,17 @@ Continue with the [Quick Start guide](https://vpt.js.org/guides/quick-start/).
|
|
|
31
31
|
|
|
32
32
|
## Documentation
|
|
33
33
|
|
|
34
|
+
- [Quick Start](https://vpt.js.org/guides/quick-start/)
|
|
35
|
+
- [Styles](https://vpt.js.org/guides/styles/)
|
|
34
36
|
- [Automatic subpackages](https://vpt.js.org/guides/automatic-subpackages/)
|
|
35
37
|
- [Native WeChat components](https://vpt.js.org/guides/native-components/)
|
|
36
38
|
- [Hot module replacement](https://vpt.js.org/guides/hot-module-replacement/)
|
|
39
|
+
- [Configuration options](https://vpt.js.org/guides/configuration/)
|
|
40
|
+
- [Conditional compilation](https://vpt.js.org/guides/conditional-directives/)
|
|
37
41
|
- [Skyline mode](https://vpt.js.org/guides/skyline-mode/)
|
|
38
42
|
- [Migrate from Taro CLI](https://vpt.js.org/guides/migrate-from-taro/)
|
|
39
|
-
- [
|
|
43
|
+
- [Module system](https://vpt.js.org/references/module-system/)
|
|
44
|
+
- [Hot module replacement internals](https://vpt.js.org/references/hmr-implementation/)
|
|
40
45
|
- [Repository management](https://vpt.js.org/references/repository-management/)
|
|
41
46
|
|
|
42
47
|
## License
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# VPT
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/vite-plugin-taro)
|
|
4
4
|

|
|
@@ -21,7 +21,7 @@ npm create vite-taro@latest my-app
|
|
|
21
21
|
|
|
22
22
|
### 已支持微信开发者工具的 React 热更新
|
|
23
23
|
|
|
24
|
-
<video src="https://github.com/user-attachments/assets/
|
|
24
|
+
<video src="https://github.com/user-attachments/assets/c8289e1e-d8ad-429f-a0d9-a40656b4962a" controls autoplay muted loop playsinline width="100%"></video>
|
|
25
25
|
|
|
26
26
|
- **Vite 8 + React 19** 基于 Vite 生态,一份代码覆盖微信小程序与 Web。
|
|
27
27
|
- **热更新** 编辑代码时保留 App 数据、当前页面、React 组件状态与输入状态。
|
|
@@ -32,12 +32,17 @@ npm create vite-taro@latest my-app
|
|
|
32
32
|
|
|
33
33
|
## 文档
|
|
34
34
|
|
|
35
|
+
- [快速开始](https://vpt.js.org/guides/quick-start/)
|
|
36
|
+
- [样式](https://vpt.js.org/guides/styles/)
|
|
35
37
|
- [全自动分包](https://vpt.js.org/guides/automatic-subpackages/)
|
|
36
38
|
- [微信原生组件](https://vpt.js.org/guides/native-components/)
|
|
37
39
|
- [开发者工具热更新](https://vpt.js.org/guides/hot-module-replacement/)
|
|
40
|
+
- [配置选项](https://vpt.js.org/guides/configuration/)
|
|
41
|
+
- [条件编译](https://vpt.js.org/guides/conditional-directives/)
|
|
38
42
|
- [Skyline 模式](https://vpt.js.org/guides/skyline-mode/)
|
|
39
43
|
- [从 Taro CLI 迁移](https://vpt.js.org/guides/migrate-from-taro/)
|
|
40
|
-
- [
|
|
44
|
+
- [模块系统](https://vpt.js.org/references/module-system/)
|
|
45
|
+
- [热更新原理](https://vpt.js.org/references/hmr-implementation/)
|
|
41
46
|
- [仓库维护](https://vpt.js.org/references/repository-management/)
|
|
42
47
|
|
|
43
48
|
## 许可证
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ViteDevServer } from 'vite';
|
|
2
2
|
import type { VptOptions } from '../../../../options.ts';
|
|
3
|
+
import type { WxStylePlugin } from '../styles/plugins.ts';
|
|
3
4
|
export type WxDevHost = Readonly<{
|
|
4
5
|
close: () => Promise<void>;
|
|
5
6
|
}>;
|
|
@@ -9,11 +10,11 @@ export type WxDevHost = Readonly<{
|
|
|
9
10
|
* engine writes directly to the Mini Program output directory instead of serving browser
|
|
10
11
|
* HMR over HTTP.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
13
|
+
* The shared style plugin carries the resolver's immutable App/Page cascade policy while Rolldown remains authoritative for
|
|
14
|
+
* every live import edge.
|
|
14
15
|
*/
|
|
15
|
-
export declare function createWxDevHost({ server, options,
|
|
16
|
+
export declare function createWxDevHost({ server, options, styles }: {
|
|
16
17
|
server: ViteDevServer;
|
|
17
18
|
options: VptOptions;
|
|
18
|
-
|
|
19
|
+
styles: WxStylePlugin;
|
|
19
20
|
}): Promise<WxDevHost>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import colors from 'picocolors';
|
|
4
3
|
import { dev } from 'rolldown/experimental';
|
|
5
4
|
import { asyncScheduler } from 'rxjs';
|
|
6
5
|
import { createHmrResultsStream } from './create-hmr-results-stream.js';
|
|
7
|
-
import {
|
|
8
|
-
import { developmentAppWxssFileName, hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderDevelopmentAppWxss, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
|
|
6
|
+
import { developmentAppWxssFileName, globalWxssFileName, hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderDevelopmentAppWxss, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
|
|
9
7
|
import { createHostActions } from './host-actions.js';
|
|
10
8
|
import { PatchPublisher } from './patch-publisher.js';
|
|
11
9
|
import { createRuntimeReportsStream } from './runtime-reports.js';
|
|
@@ -18,27 +16,16 @@ const hmrSettleMilliseconds = 16;
|
|
|
18
16
|
* engine writes directly to the Mini Program output directory instead of serving browser
|
|
19
17
|
* HMR over HTTP.
|
|
20
18
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* The shared style plugin carries the resolver's immutable App/Page cascade policy while Rolldown remains authoritative for
|
|
20
|
+
* every live import edge.
|
|
23
21
|
*/
|
|
24
|
-
export async function createWxDevHost({ server, options,
|
|
22
|
+
export async function createWxDevHost({ server, options, styles }) {
|
|
25
23
|
const bundledDev = getBundledDev(server);
|
|
26
24
|
// All callbacks admit typed actions through this edge; concatMap is the sole owner of effect ordering and mutable host state.
|
|
27
25
|
const hostActions = createHostActions(applyHostAction, (action, error) => logWxError(server.config.logger, `wx HMR ${action.kind} failed`, error));
|
|
28
|
-
const styleCapture = createStyleCapture({
|
|
29
|
-
applicationEntryIds: applicationEntryIds,
|
|
30
|
-
outDir: server.config.build.outDir,
|
|
31
|
-
// Capture hooks run only after engine.run, when the host action subscription and all reducer dependencies are ready.
|
|
32
|
-
emit: (action) => hostActions.next(action),
|
|
33
|
-
transformTailwindRoot: async (rootId, requestId) => {
|
|
34
|
-
// The capture contains generated CSS, while the sidecar must re-run from raw Tailwind directives. Vite exposes no
|
|
35
|
-
// raw source in its live module graph, so this read is the authoritative source generation rather than a read-back.
|
|
36
|
-
return server.environments.client.pluginContainer.transform(await readFile(rootId, 'utf8'), requestId);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
26
|
const publisher = new PatchPublisher((content) => writeHmrFile(server.config.build.outDir, hmrPatchesFileName, content));
|
|
40
27
|
// Option installation now configures only Rolldown. Build lifecycle results enter through the engine's output action below.
|
|
41
|
-
installWxDevOptions({ bundledDev, server, options
|
|
28
|
+
installWxDevOptions({ bundledDev, server, options });
|
|
42
29
|
const engine = await createEngine();
|
|
43
30
|
const hmrResults = createHmrResultsStream(hmrSettleMilliseconds, asyncScheduler, (result) => {
|
|
44
31
|
// One reduced window becomes one existing host transaction: style preparation, one cumulative patch write, then
|
|
@@ -98,11 +85,15 @@ export async function createWxDevHost({ server, options, applicationEntryIds })
|
|
|
98
85
|
hmrResults.complete();
|
|
99
86
|
runtimeReports.complete();
|
|
100
87
|
await hostActions.waitForIdle();
|
|
101
|
-
// Keep the action edge open until the final generation has admitted
|
|
88
|
+
// Keep the action edge open until the final generation has admitted every output callback.
|
|
102
89
|
await engine.ensureCurrentBuildFinish();
|
|
103
90
|
await hostActions.complete();
|
|
104
91
|
}
|
|
105
92
|
};
|
|
93
|
+
/** Atomically materializes the style plugin's prepared global artifact. */
|
|
94
|
+
async function writeGlobalStyle(wxss) {
|
|
95
|
+
await writeHmrFile(server.config.build.outDir, globalWxssFileName, wxss);
|
|
96
|
+
}
|
|
106
97
|
/** Rotates the build identity and materializes the App metadata for it. */
|
|
107
98
|
async function rotateBuildSession() {
|
|
108
99
|
const port = boundPort(server);
|
|
@@ -142,14 +133,6 @@ export async function createWxDevHost({ server, options, applicationEntryIds })
|
|
|
142
133
|
/** Reduces one merged source action through the existing authoritative host state. */
|
|
143
134
|
function applyHostAction(action) {
|
|
144
135
|
switch (action.kind) {
|
|
145
|
-
case 'capture-graph':
|
|
146
|
-
// The buildStart reader is a live capability; replacing it only here makes the reducer own build rebinding.
|
|
147
|
-
styleCapture.captureGraph(action.getModuleInfo);
|
|
148
|
-
return;
|
|
149
|
-
case 'capture-style':
|
|
150
|
-
// A failed upstream transform emits no action, intentionally retaining the last valid processed CSS generation.
|
|
151
|
-
styleCapture.captureStyle(action.id, action.style);
|
|
152
|
-
return;
|
|
153
136
|
case 'publish':
|
|
154
137
|
return publishUpdates(action.result);
|
|
155
138
|
case 'error':
|
|
@@ -163,20 +146,14 @@ export async function createWxDevHost({ server, options, applicationEntryIds })
|
|
|
163
146
|
logWxError(server.config.logger, 'wx dev build failed', action.result);
|
|
164
147
|
return;
|
|
165
148
|
}
|
|
166
|
-
return
|
|
149
|
+
return publishCompleteStyles();
|
|
167
150
|
case 'listening':
|
|
168
151
|
return rotateBuildSession();
|
|
169
152
|
}
|
|
170
153
|
}
|
|
171
|
-
/**
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
* DevEngine has already written its compiler asset when onOutput fires, but bundled development may have omitted CSS Modules
|
|
175
|
-
* from that asset. Awaiting reconciliation inside the serialized reducer guarantees the subsequent app.wxss rotation—the
|
|
176
|
-
* event that refreshes DevTools—can only expose a generation whose global WXSS already represents the complete App/Page graph.
|
|
177
|
-
*/
|
|
178
|
-
async function reconcileCompleteOutput(output) {
|
|
179
|
-
await styleCapture.reconcileComplete(output);
|
|
154
|
+
/** Publishes graph-complete styles before rotating the App-visible build identity. */
|
|
155
|
+
async function publishCompleteStyles() {
|
|
156
|
+
await styles.finalizeUpdate([], writeGlobalStyle);
|
|
180
157
|
await rotateBuildSession();
|
|
181
158
|
}
|
|
182
159
|
/** Applies one runtime receipt to the active physical patch history. */
|
|
@@ -252,16 +229,15 @@ export async function createWxDevHost({ server, options, applicationEntryIds })
|
|
|
252
229
|
if (patches.length === 0) {
|
|
253
230
|
return;
|
|
254
231
|
}
|
|
255
|
-
// `onHmrUpdates`
|
|
256
|
-
//
|
|
257
|
-
|
|
258
|
-
await styleCapture.publishChanged(patches.flatMap((patch) => patch.changedIds));
|
|
232
|
+
// `onHmrUpdates` runs after every affected transform has updated captured CSS and the live import graph. The style
|
|
233
|
+
// boundary finalizes every factory before atomically publishing their matching WXSS.
|
|
234
|
+
const finalizedPatches = await styles.finalizeUpdate(patches, writeGlobalStyle);
|
|
259
235
|
// Publish global.wxss before the matching JavaScript patch so DevTools observes a coherent HMR transaction.
|
|
260
236
|
// The physical file must exist before Rolldown advances: once committed, later patches may be generated relative to
|
|
261
237
|
// this batch even if DevTools has not observed its file event yet. PatchPublisher keeps the unapplied range cumulative,
|
|
262
238
|
// so any later file generation still carries every factory needed to bridge the runtime's older application frontier.
|
|
263
|
-
await publisher.produce(
|
|
264
|
-
await commitPublishedBatch(
|
|
239
|
+
await publisher.produce(finalizedPatches);
|
|
240
|
+
await commitPublishedBatch(finalizedPatches);
|
|
265
241
|
}
|
|
266
242
|
/**
|
|
267
243
|
* Advances Rolldown's published frontier in the same sequence order materialized in the cumulative physical file.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PluginOption } from 'vite';
|
|
2
2
|
import type { VptOptions } from '../../../../options.ts';
|
|
3
|
+
import type { WxStylePlugin } from '../styles/plugins.ts';
|
|
3
4
|
/** Selects the sole Vite environment that owns the physical Mini Program development project. */
|
|
4
5
|
export declare function isWxClientEnvironment(environment: Readonly<{
|
|
5
6
|
name: string;
|
|
@@ -8,10 +9,10 @@ export declare function isWxClientEnvironment(environment: Readonly<{
|
|
|
8
9
|
* Adds the serve-only bundled-development plugin set for the wx target: the dev adapter,
|
|
9
10
|
* Page HMR activation, and React Refresh adaptation transforms.
|
|
10
11
|
*
|
|
11
|
-
* The
|
|
12
|
-
*
|
|
12
|
+
* The shared style pipeline already owns the resolver's ordered App/Page cascade policy, so the host does not reconstruct it
|
|
13
|
+
* from unrelated Rolldown shell and transport entries.
|
|
13
14
|
*/
|
|
14
|
-
export declare function createWxDevelopmentPlugin(options: VptOptions,
|
|
15
|
+
export declare function createWxDevelopmentPlugin(options: VptOptions, styles: WxStylePlugin): PluginOption[];
|
|
15
16
|
/**
|
|
16
17
|
* Transfers development ownership of `app.wxss` from complete output to the dev host.
|
|
17
18
|
*
|
|
@@ -28,18 +29,8 @@ export declare function createWxDevelopmentPlugin(options: VptOptions, applicati
|
|
|
28
29
|
* only `assets/global.wxss`, which preserves the App heap. The serve-only plugin leaves production output unchanged.
|
|
29
30
|
*/
|
|
30
31
|
export declare function removeDevelopmentAppWxss(bundle: Record<string, unknown>): void;
|
|
31
|
-
/**
|
|
32
|
-
export declare function
|
|
33
|
-
code: string;
|
|
34
|
-
map: null;
|
|
35
|
-
};
|
|
36
|
-
/** Connects the shared WX dev runtime to the application graph's Taro runtime instance. */
|
|
37
|
-
export declare function injectTaroConnection(code: string): {
|
|
38
|
-
code: string;
|
|
39
|
-
map: null;
|
|
40
|
-
};
|
|
41
|
-
/** Activates development-only lifecycle handling for one plugin-owned Page capsule. */
|
|
42
|
-
export declare function injectPageHmr(code: string, route: string): {
|
|
32
|
+
/** Injects the retained snapshot at the exact native Page registration edge. */
|
|
33
|
+
export declare function injectPageShellHmr(code: string): {
|
|
43
34
|
code: string;
|
|
44
35
|
map: null;
|
|
45
36
|
};
|
|
@@ -2,11 +2,10 @@ import { normalizePath, transformWithOxc } from 'vite';
|
|
|
2
2
|
import { esTarget } from '../../../utils/constant.js';
|
|
3
3
|
import { memoize } from '../../../utils/memoize.js';
|
|
4
4
|
import { normalizeModuleId } from '../../../utils/modules.js';
|
|
5
|
-
import {
|
|
5
|
+
import { pageShellPath, rolldownRuntimeId } from '../module/module.js';
|
|
6
6
|
import { createWxDevHost } from './dev-host.js';
|
|
7
7
|
import { developmentAppWxssFileName } from './hmr-files.js';
|
|
8
8
|
import { createWxReactRefreshTransforms } from './react-refresh.js';
|
|
9
|
-
const taroRuntimeId = '@tarojs/runtime';
|
|
10
9
|
/** Selects the sole Vite environment that owns the physical Mini Program development project. */
|
|
11
10
|
export function isWxClientEnvironment(environment) {
|
|
12
11
|
return environment.name === 'client';
|
|
@@ -15,10 +14,10 @@ export function isWxClientEnvironment(environment) {
|
|
|
15
14
|
* Adds the serve-only bundled-development plugin set for the wx target: the dev adapter,
|
|
16
15
|
* Page HMR activation, and React Refresh adaptation transforms.
|
|
17
16
|
*
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
17
|
+
* The shared style pipeline already owns the resolver's ordered App/Page cascade policy, so the host does not reconstruct it
|
|
18
|
+
* from unrelated Rolldown shell and transport entries.
|
|
20
19
|
*/
|
|
21
|
-
export function createWxDevelopmentPlugin(options,
|
|
20
|
+
export function createWxDevelopmentPlugin(options, styles) {
|
|
22
21
|
/*
|
|
23
22
|
* Vite creates this plugin descriptor before a server or DevEngine exists, then invokes configureServer and closeBundle on
|
|
24
23
|
* different lifecycle stacks. This mutable handle transfers the one client-owned host between those hooks: configureServer
|
|
@@ -28,9 +27,7 @@ export function createWxDevelopmentPlugin(options, applicationEntryIds) {
|
|
|
28
27
|
*/
|
|
29
28
|
let host = null;
|
|
30
29
|
// Portable hook filters stay broad; these exact identities exclude similarly named user modules.
|
|
31
|
-
const
|
|
32
|
-
const normalizedPageCapsulePath = normalizePath(pageCapsulePath);
|
|
33
|
-
const normalizedTaroRuntimePath = normalizePath(taroRuntimePath);
|
|
30
|
+
const normalizedPageShellPath = normalizePath(pageShellPath);
|
|
34
31
|
return [
|
|
35
32
|
{
|
|
36
33
|
name: 'vpt:wx-dev',
|
|
@@ -68,7 +65,7 @@ export function createWxDevelopmentPlugin(options, applicationEntryIds) {
|
|
|
68
65
|
host = await createWxDevHost({
|
|
69
66
|
server: server,
|
|
70
67
|
options: options,
|
|
71
|
-
|
|
68
|
+
styles: styles
|
|
72
69
|
});
|
|
73
70
|
}
|
|
74
71
|
},
|
|
@@ -107,41 +104,15 @@ export function createWxDevelopmentPlugin(options, applicationEntryIds) {
|
|
|
107
104
|
}
|
|
108
105
|
},
|
|
109
106
|
{
|
|
110
|
-
name: 'vpt:wx-
|
|
107
|
+
name: 'vpt:wx-page-shell-hmr',
|
|
111
108
|
apply: 'serve',
|
|
112
109
|
transform: {
|
|
113
110
|
order: 'post',
|
|
114
|
-
filter: { id: /\/runtime\/wx\/
|
|
111
|
+
filter: { id: /\/runtime\/wx\/native\/page\.js(?:\?|$)/ },
|
|
115
112
|
handler(code, id) {
|
|
116
|
-
if (normalizeModuleId(id) !==
|
|
113
|
+
if (normalizeModuleId(id) !== normalizedPageShellPath)
|
|
117
114
|
return;
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: 'vpt:wx-page-hmr',
|
|
124
|
-
apply: 'serve',
|
|
125
|
-
transform: {
|
|
126
|
-
order: 'post',
|
|
127
|
-
filter: { id: /\/runtime\/wx\/capsule\/page\.js(?:\?|$)/ },
|
|
128
|
-
handler(code, id) {
|
|
129
|
-
if (normalizeModuleId(id) !== normalizedPageCapsulePath)
|
|
130
|
-
return;
|
|
131
|
-
return injectPageHmr(code, getPageRoute(id));
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: 'vpt:wx-taro-hmr',
|
|
137
|
-
apply: 'serve',
|
|
138
|
-
transform: {
|
|
139
|
-
order: 'post',
|
|
140
|
-
filter: { id: /\/runtime\/wx\/capsule\/taro-runtime\.js(?:\?|$)/ },
|
|
141
|
-
handler(code, id) {
|
|
142
|
-
if (normalizeModuleId(id) !== normalizedTaroRuntimePath)
|
|
143
|
-
return;
|
|
144
|
-
return injectTaroConnection(code);
|
|
115
|
+
return injectPageShellHmr(code);
|
|
145
116
|
}
|
|
146
117
|
}
|
|
147
118
|
},
|
|
@@ -166,42 +137,17 @@ export function createWxDevelopmentPlugin(options, applicationEntryIds) {
|
|
|
166
137
|
export function removeDevelopmentAppWxss(bundle) {
|
|
167
138
|
delete bundle[developmentAppWxssFileName];
|
|
168
139
|
}
|
|
169
|
-
/**
|
|
170
|
-
export function
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
/** Connects the shared WX dev runtime to the application graph's Taro runtime instance. */
|
|
177
|
-
export function injectTaroConnection(code) {
|
|
178
|
-
if (!/\bCurrent\b/.test(code) || !/\bdocument\b/.test(code) || !/\binjectPageInstance\b/.test(code)) {
|
|
179
|
-
throw new Error('WX Taro runtime must expose Current, document, and injectPageInstance for HMR');
|
|
140
|
+
/** Injects the retained snapshot at the exact native Page registration edge. */
|
|
141
|
+
export function injectPageShellHmr(code) {
|
|
142
|
+
const registration = 'Page(pageConfig)';
|
|
143
|
+
if (!code.includes(registration)) {
|
|
144
|
+
throw new Error('WX native Page shell must register pageConfig');
|
|
180
145
|
}
|
|
181
|
-
const taroImport = `import { Current as __vptCurrent, document as __vptDocument, injectPageInstance as __vptInjectPageInstance } from ${JSON.stringify(taroRuntimeId)};`;
|
|
182
146
|
return {
|
|
183
|
-
code:
|
|
147
|
+
code: code.replace(registration, 'Page(__rolldown_runtime__.injectPageHmr(pageConfig))'),
|
|
184
148
|
map: null
|
|
185
149
|
};
|
|
186
150
|
}
|
|
187
|
-
/** Activates development-only lifecycle handling for one plugin-owned Page capsule. */
|
|
188
|
-
export function injectPageHmr(code, route) {
|
|
189
|
-
if (!/\bconst\s+config\s*=/.test(code) || !/\bexport\s+default\s+config\b/.test(code)) {
|
|
190
|
-
throw new Error('WX Page capsule must declare and default-export config before HMR injection');
|
|
191
|
-
}
|
|
192
|
-
return {
|
|
193
|
-
code: `${code}\n__rolldown_runtime__.injectPageHmr(config, ${JSON.stringify(route)});`,
|
|
194
|
-
map: null
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
/** Reads the stable route carried by every specialized Page capsule ID. */
|
|
198
|
-
function getPageRoute(id) {
|
|
199
|
-
const queryIndex = id.indexOf('?');
|
|
200
|
-
const route = queryIndex < 0 ? null : new URLSearchParams(id.slice(queryIndex + 1)).get('route');
|
|
201
|
-
if (!route)
|
|
202
|
-
throw new Error(`WX Page capsule is missing its route: ${id}`);
|
|
203
|
-
return route;
|
|
204
|
-
}
|
|
205
151
|
/*
|
|
206
152
|
* memoize owns a mutable one-entry-by-input cache. The assembled runtime source is byte-identical across complete generations
|
|
207
153
|
* because both the Rolldown base and injected implementation are immutable for the server lifetime. Reusing its lowered result
|
|
@@ -4,8 +4,9 @@ import type { Plugin } from 'vite';
|
|
|
4
4
|
*
|
|
5
5
|
* @vitejs/plugin-react's generated refresh code assumes the web HTML preamble and a browser
|
|
6
6
|
* global scope; wx has neither. Each transform adapts one piece of that contract:
|
|
7
|
-
* - the refresh runtime module (id-filtered): the
|
|
7
|
+
* - the refresh runtime module (id-filtered): the runtime reads and assigns
|
|
8
8
|
* `window` protocol globals (rewritten to `global`) and must inject itself at evaluation;
|
|
9
|
+
* - React Reconciler: its renderer injection statically depends on the refresh runtime, fixing cold-start order;
|
|
9
10
|
* - react-family modules (filtered on free references): the DevTools hook is read as a free
|
|
10
11
|
* variable, which the WeChat runtime scope never resolves against `global` — every free
|
|
11
12
|
* reference becomes an explicit member access;
|
|
@@ -13,10 +14,15 @@ import type { Plugin } from 'vite';
|
|
|
13
14
|
* needed because the transform generates local wrappers over the imported refresh
|
|
14
15
|
* runtime, so the guard that checks for the global is removed.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* Filters route every adaptation directly. The Reconciler intentionally receives the renderer dependency first and the
|
|
18
|
+
* global-hook rewrite second; modules outside these explicit domains never reach a handler.
|
|
18
19
|
*/
|
|
19
20
|
export declare function createWxReactRefreshTransforms(): Plugin[];
|
|
21
|
+
/** Makes renderer hook injection statically depend on the refresh runtime. */
|
|
22
|
+
export declare function injectReactRefreshRendererDependency(code: string): {
|
|
23
|
+
code: string;
|
|
24
|
+
map: null;
|
|
25
|
+
};
|
|
20
26
|
export declare function transformRefreshRuntime({ code, id }: {
|
|
21
27
|
code: string;
|
|
22
28
|
id: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isReferenceIdentifier } from 'oxc-walker';
|
|
2
2
|
import { memoize } from '../../../utils/memoize.js';
|
|
3
|
+
import { normalizeModuleId } from '../../../utils/modules.js';
|
|
3
4
|
import { transformWithOxcWalker } from '../../../utils/oxc-transform.js';
|
|
5
|
+
import { reactReconcilerRoot } from '../module/module.js';
|
|
4
6
|
/** The React DevTools hook protocol name; free references must target `global` in wx. */
|
|
5
7
|
const reactDevtoolsHookProtocol = '__REACT_DEVTOOLS_GLOBAL_HOOK__';
|
|
6
8
|
/**
|
|
@@ -10,7 +12,7 @@ const reactDevtoolsHookProtocol = '__REACT_DEVTOOLS_GLOBAL_HOOK__';
|
|
|
10
12
|
* - `__getReactRefreshIgnoredExports` is an optional extension point read while validating a refresh boundary.
|
|
11
13
|
* Leaving that read on the nonexistent `window` crashes every update validation pass.
|
|
12
14
|
*
|
|
13
|
-
* Keeping this list explicit prevents the adapter from rewriting unrelated browser accesses if the
|
|
15
|
+
* Keeping this list explicit prevents the adapter from rewriting unrelated browser accesses if the refresh runtime
|
|
14
16
|
* gains new code. Any future React Refresh protocol addition therefore requires a deliberate compatibility decision.
|
|
15
17
|
*/
|
|
16
18
|
const refreshRuntimeWindowGlobals = ['__registerBeforePerformReactRefresh', '__getReactRefreshIgnoredExports'];
|
|
@@ -19,8 +21,9 @@ const refreshRuntimeWindowGlobals = ['__registerBeforePerformReactRefresh', '__g
|
|
|
19
21
|
*
|
|
20
22
|
* @vitejs/plugin-react's generated refresh code assumes the web HTML preamble and a browser
|
|
21
23
|
* global scope; wx has neither. Each transform adapts one piece of that contract:
|
|
22
|
-
* - the refresh runtime module (id-filtered): the
|
|
24
|
+
* - the refresh runtime module (id-filtered): the runtime reads and assigns
|
|
23
25
|
* `window` protocol globals (rewritten to `global`) and must inject itself at evaluation;
|
|
26
|
+
* - React Reconciler: its renderer injection statically depends on the refresh runtime, fixing cold-start order;
|
|
24
27
|
* - react-family modules (filtered on free references): the DevTools hook is read as a free
|
|
25
28
|
* variable, which the WeChat runtime scope never resolves against `global` — every free
|
|
26
29
|
* reference becomes an explicit member access;
|
|
@@ -28,8 +31,8 @@ const refreshRuntimeWindowGlobals = ['__registerBeforePerformReactRefresh', '__g
|
|
|
28
31
|
* needed because the transform generates local wrappers over the imported refresh
|
|
29
32
|
* runtime, so the guard that checks for the global is removed.
|
|
30
33
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
34
|
+
* Filters route every adaptation directly. The Reconciler intentionally receives the renderer dependency first and the
|
|
35
|
+
* global-hook rewrite second; modules outside these explicit domains never reach a handler.
|
|
33
36
|
*/
|
|
34
37
|
export function createWxReactRefreshTransforms() {
|
|
35
38
|
return [
|
|
@@ -38,13 +41,27 @@ export function createWxReactRefreshTransforms() {
|
|
|
38
41
|
apply: 'serve',
|
|
39
42
|
transform: {
|
|
40
43
|
order: 'post',
|
|
41
|
-
// The
|
|
44
|
+
// The refresh runtime module is id-filtered, so no code scan is needed.
|
|
42
45
|
filter: { id: /^\/@react-refresh(?:\?|$)/ },
|
|
43
46
|
handler(code, id) {
|
|
44
47
|
return fixRefreshRuntime({ code, id });
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
},
|
|
51
|
+
{
|
|
52
|
+
name: 'vpt:wx-react-refresh-renderer-dependency',
|
|
53
|
+
apply: 'serve',
|
|
54
|
+
transform: {
|
|
55
|
+
order: 'post',
|
|
56
|
+
filter: { id: /\/react-reconciler\/cjs\/react-reconciler\.development\.js(?:\?|$)/ },
|
|
57
|
+
handler(code, id) {
|
|
58
|
+
const rendererId = `${reactReconcilerRoot}/cjs/react-reconciler.development.js`;
|
|
59
|
+
if (normalizeModuleId(id) !== rendererId)
|
|
60
|
+
return;
|
|
61
|
+
return injectReactRefreshRendererDependency(code);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
48
65
|
{
|
|
49
66
|
name: 'vpt:wx-react-devtools-hook',
|
|
50
67
|
apply: 'serve',
|
|
@@ -86,7 +103,8 @@ export function createWxReactRefreshTransforms() {
|
|
|
86
103
|
* The protocol name is unique, but only reference identifiers are rewritten. Declaration
|
|
87
104
|
* keys and explicit members such as `global.__REACT_DEVTOOLS_GLOBAL_HOOK__` must remain
|
|
88
105
|
* untouched; rewriting those would either produce invalid syntax or double-prefix the hook.
|
|
89
|
-
* The
|
|
106
|
+
* The Reconciler's injected static dependency orders hook injection before renderer initialization independently of Rolldown's
|
|
107
|
+
* final chunking decision.
|
|
90
108
|
*/
|
|
91
109
|
function createReactDevtoolsHookVisitor(editor) {
|
|
92
110
|
return function enter(node, parent) {
|
|
@@ -133,7 +151,7 @@ function createRefreshRuntimeVisitor(editor) {
|
|
|
133
151
|
node.property.type === 'Identifier' &&
|
|
134
152
|
refreshRuntimeWindowGlobals.some((globalName) => globalName === node.property.name)) {
|
|
135
153
|
// `global` is the shared wx App heap used by the dev runtime and hook injection. Only
|
|
136
|
-
// replacing the object range preserves the
|
|
154
|
+
// replacing the object range preserves the upstream runtime byte-for-byte otherwise
|
|
137
155
|
// and prevents unrelated `window` expressions from being silently adapted.
|
|
138
156
|
editor.overwrite(node.object.start, node.object.end, 'global');
|
|
139
157
|
}
|
|
@@ -169,6 +187,16 @@ function createRefreshPreambleGuardVisitor(editor) {
|
|
|
169
187
|
this.skip();
|
|
170
188
|
};
|
|
171
189
|
}
|
|
190
|
+
/** Makes renderer hook injection statically depend on the refresh runtime. */
|
|
191
|
+
export function injectReactRefreshRendererDependency(code) {
|
|
192
|
+
if (!/\bhook\.inject\(internals\)/.test(code)) {
|
|
193
|
+
throw new Error('React Reconciler must inject its renderer into the DevTools hook');
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
code: `import '/@react-refresh'\n${code}`,
|
|
197
|
+
map: null
|
|
198
|
+
};
|
|
199
|
+
}
|
|
172
200
|
export function transformRefreshRuntime({ code, id }) {
|
|
173
201
|
return transformWithOxcWalker({
|
|
174
202
|
code,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InputOptions, OutputOptions
|
|
1
|
+
import type { InputOptions, OutputOptions } from 'rolldown';
|
|
2
2
|
import { type DevEngine } from 'rolldown/experimental';
|
|
3
3
|
import type { ViteDevServer } from 'vite';
|
|
4
4
|
import type { VptOptions } from '../../../../options.ts';
|
|
@@ -19,11 +19,10 @@ export type BundledDev = {
|
|
|
19
19
|
* Installs physical WX output and runtime conventions over Vite's browser-oriented bundled-development options.
|
|
20
20
|
* Build completion deliberately remains outside this options adapter: DevEngine onOutput is the single lifecycle authority.
|
|
21
21
|
*/
|
|
22
|
-
export declare function installWxDevOptions({ bundledDev, server, options
|
|
22
|
+
export declare function installWxDevOptions({ bundledDev, server, options }: {
|
|
23
23
|
bundledDev: BundledDev;
|
|
24
24
|
server: ViteDevServer;
|
|
25
25
|
options: VptOptions;
|
|
26
|
-
hostPlugins: Plugin[];
|
|
27
26
|
}): void;
|
|
28
27
|
/** Returns the configured output after rejecting states unsupported by the physical WX engine. */
|
|
29
28
|
export declare function requireSingleOutput(rolldownOptions: BundledDevRolldownOptions): OutputOptions;
|
|
@@ -8,7 +8,7 @@ import { appShellFileName } from '../module/module.js';
|
|
|
8
8
|
* Installs physical WX output and runtime conventions over Vite's browser-oriented bundled-development options.
|
|
9
9
|
* Build completion deliberately remains outside this options adapter: DevEngine onOutput is the single lifecycle authority.
|
|
10
10
|
*/
|
|
11
|
-
export function installWxDevOptions({ bundledDev, server, options
|
|
11
|
+
export function installWxDevOptions({ bundledDev, server, options }) {
|
|
12
12
|
/*
|
|
13
13
|
* Vite owns this mutable adapter method and calls it later when constructing DevEngine. Replacing that one seam preserves
|
|
14
14
|
* Vite's resolved graph while applying WX physical-output conventions to every options generation. Capturing and mutating one
|
|
@@ -78,10 +78,10 @@ export function installWxDevOptions({ bundledDev, server, options, hostPlugins }
|
|
|
78
78
|
};
|
|
79
79
|
/*
|
|
80
80
|
* The plugin list is mutable configuration consumed once by this engine generation. Replace the top-level reference with
|
|
81
|
-
* an ordered composite rather than pushing into Vite's potentially shared nested array
|
|
82
|
-
*
|
|
81
|
+
* an ordered composite rather than pushing into Vite's potentially shared nested array; the reporter observes final output
|
|
82
|
+
* without mutating Vite's retained input list.
|
|
83
83
|
*/
|
|
84
|
-
rolldownOptions.plugins = [rolldownOptions.plugins,
|
|
84
|
+
rolldownOptions.plugins = [rolldownOptions.plugins, createViteReporter(server)];
|
|
85
85
|
disableViteOxcSourcemap(rolldownOptions.plugins);
|
|
86
86
|
return rolldownOptions;
|
|
87
87
|
};
|
|
@@ -105,7 +105,7 @@ function ensureSingleOutput(rolldownOptions) {
|
|
|
105
105
|
/**
|
|
106
106
|
* Prepends entry banners after Rolldown's analysis so their native requires remain physical dependencies rather than chunk
|
|
107
107
|
* graph edges. The App initializes the runtime identity, while every Page explicitly applies the watched patch data before its
|
|
108
|
-
*
|
|
108
|
+
* native Page registration.
|
|
109
109
|
*/
|
|
110
110
|
function createEntryBanner(pageFiles) {
|
|
111
111
|
return (chunk) => {
|
|
@@ -114,8 +114,7 @@ function createEntryBanner(pageFiles) {
|
|
|
114
114
|
}
|
|
115
115
|
if (pageFiles.has(chunk.name)) {
|
|
116
116
|
const patchesPath = path.posix.relative(path.posix.dirname(chunk.fileName), 'hmr/patches.js');
|
|
117
|
-
|
|
118
|
-
return `__rolldown_runtime__.applyPatches(require('${patchesPath}'), ${JSON.stringify(route)});\n`;
|
|
117
|
+
return `__rolldown_runtime__.applyPatches(require('${patchesPath}'));\n`;
|
|
119
118
|
}
|
|
120
119
|
return '';
|
|
121
120
|
};
|
|
@@ -10,19 +10,15 @@ import { renderCapsule } from './render/capsule.js';
|
|
|
10
10
|
import { renderNative } from './render/native.js';
|
|
11
11
|
import { materializeTransport } from './render/transport.js';
|
|
12
12
|
import { createResolver } from './resolve/resolver.js';
|
|
13
|
-
import {
|
|
13
|
+
import { createWxStylePlugin } from './styles/plugins.js';
|
|
14
14
|
/** Creates the complete plugin set for the wx target. */
|
|
15
15
|
export function createWxTargetPlugins(options) {
|
|
16
16
|
const resolver = createResolver(options);
|
|
17
17
|
// Reuse the resolver instance's ordered application subset. Rolldown's complete input also contains bootstrap, transport,
|
|
18
18
|
// shell, and component entries; entry membership alone cannot recover which roots define the App/Page CSS cascade.
|
|
19
19
|
const placement = createWxPlacementPlugin();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
createWxStylePlugins(),
|
|
23
|
-
createWxPlugin(options, resolver, placement),
|
|
24
|
-
createWxDevelopmentPlugin(options, resolver.applicationEntryIds)
|
|
25
|
-
];
|
|
20
|
+
const styles = createWxStylePlugin(resolver.applicationEntryIds);
|
|
21
|
+
return [placement, styles, createWxPlugin(options, resolver, placement), createWxDevelopmentPlugin(options, styles)];
|
|
26
22
|
}
|
|
27
23
|
/** Configures the complete wx target build pipeline. */
|
|
28
24
|
function createWxPlugin(options, resolver, placement) {
|
|
@@ -106,10 +102,8 @@ function createWxPlugin(options, resolver, placement) {
|
|
|
106
102
|
},
|
|
107
103
|
generateBundle: {
|
|
108
104
|
/*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* stylesheet is complete before native Page/component companions are emitted. Without this order, the finalizer
|
|
112
|
-
* could consume incomplete Tailwind output or mistake native WXSS companions for additional compiler styles.
|
|
105
|
+
* Registration after the style pipeline makes the compiler stylesheet final before native Page and component
|
|
106
|
+
* companions are emitted. The style finalizer therefore cannot mistake native WXSS for application CSS.
|
|
113
107
|
*/
|
|
114
108
|
order: 'post',
|
|
115
109
|
async handler(_, bundle) {
|