vite-plugin-taro 0.6.1 → 0.6.3
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 +6 -1
- package/README.md +6 -1
- package/dist/node/plugins/h5/transform-app.js +1 -1
- package/dist/node/plugins/wx/dev/plugins.d.ts +2 -12
- package/dist/node/plugins/wx/dev/plugins.js +12 -66
- 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.js +3 -4
- package/dist/node/plugins/wx/{module.js → module/module.js} +2 -2
- package/dist/node/plugins/wx/placer/placement.d.ts +1 -0
- package/dist/node/plugins/wx/placer/placement.js +1 -1
- package/dist/node/plugins/wx/placer/placer.d.ts +17 -1
- package/dist/node/plugins/wx/placer/placer.js +25 -1
- package/dist/node/plugins/wx/plugins.js +1 -1
- package/dist/node/plugins/wx/render/capsule.d.ts +35 -3
- package/dist/node/plugins/wx/render/capsule.js +53 -12
- package/dist/node/plugins/wx/render/native.d.ts +20 -2
- package/dist/node/plugins/wx/render/native.js +539 -35
- package/dist/node/plugins/wx/render/system-js/string-editor.d.ts +24 -0
- package/dist/node/plugins/wx/render/system-js/string-editor.js +93 -0
- package/dist/node/plugins/wx/render/system-js/system-js.d.ts +23 -0
- package/dist/node/plugins/wx/render/system-js/system-js.js +602 -0
- package/dist/node/plugins/wx/render/transport.js +3 -3
- package/dist/node/plugins/wx/resolve/resolver.js +5 -5
- 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} +3 -3
- package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +1 -1
- package/dist/node/utils/transform.d.ts +0 -3
- package/dist/node/utils/transform.js +0 -23
- 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 +8 -6
- package/src/node/plugins/h5/transform-app.ts +1 -1
- package/src/node/plugins/wx/dev/plugins.ts +12 -69
- package/src/node/plugins/wx/dev/react-refresh.ts +36 -7
- package/src/node/plugins/wx/dev/wx-dev-options.ts +3 -4
- package/src/node/plugins/wx/{module.ts → module/module.ts} +2 -2
- package/src/node/plugins/wx/placer/placement.ts +1 -1
- package/src/node/plugins/wx/placer/placer.ts +27 -2
- package/src/node/plugins/wx/plugins.ts +1 -1
- package/src/node/plugins/wx/render/capsule.ts +53 -17
- package/src/node/plugins/wx/render/native.ts +670 -55
- package/src/node/plugins/wx/render/system-js/string-editor.ts +115 -0
- package/src/node/plugins/wx/render/system-js/system-js.ts +831 -0
- package/src/node/plugins/wx/render/transport.ts +3 -3
- package/src/node/plugins/wx/resolve/resolver.ts +5 -5
- package/src/node/plugins/wx/resolve/{specialize-bootstrap.ts → specialize-app-capsule.ts} +3 -3
- package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +1 -1
- package/src/node/utils/transform.ts +0 -30
- 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/render/capsule-wrapper.d.ts +0 -3
- package/dist/node/plugins/wx/render/capsule-wrapper.js +0 -64
- package/src/node/plugins/wx/render/capsule-wrapper.ts +0 -86
- /package/dist/node/plugins/wx/{chunk-path.d.ts → module/chunk-path.d.ts} +0 -0
- /package/dist/node/plugins/wx/{chunk-path.js → module/chunk-path.js} +0 -0
- /package/dist/node/plugins/wx/{module.d.ts → module/module.d.ts} +0 -0
- /package/src/node/plugins/wx/{chunk-path.ts → module/chunk-path.ts} +0 -0
package/README.en.md
CHANGED
|
@@ -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
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as types from '@babel/types';
|
|
2
2
|
import { createPageComponentImportPath } from '../../utils/modules.js';
|
|
3
3
|
import { createAppConfig } from '../../utils/project-config.js';
|
|
4
4
|
import { replaceWithAst } from '../../utils/transform.js';
|
|
@@ -28,18 +28,8 @@ export declare function createWxDevelopmentPlugin(options: VptOptions, applicati
|
|
|
28
28
|
* only `assets/global.wxss`, which preserves the App heap. The serve-only plugin leaves production output unchanged.
|
|
29
29
|
*/
|
|
30
30
|
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): {
|
|
31
|
+
/** Injects the retained snapshot at the exact native Page registration edge. */
|
|
32
|
+
export declare function injectPageShellHmr(code: string): {
|
|
43
33
|
code: string;
|
|
44
34
|
map: null;
|
|
45
35
|
};
|
|
@@ -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';
|
|
@@ -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',
|
|
@@ -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,
|
|
@@ -3,7 +3,7 @@ import { build } from 'rolldown';
|
|
|
3
3
|
import { viteReporterPlugin } from 'rolldown/experimental';
|
|
4
4
|
import { once } from '../../../utils/once.js';
|
|
5
5
|
import { resolvePackageFile } from '../../../utils/packages.js';
|
|
6
|
-
import { appShellFileName } from '../module.js';
|
|
6
|
+
import { appShellFileName } from '../module/module.js';
|
|
7
7
|
/**
|
|
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.
|
|
@@ -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
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { normalizePath } from 'vite';
|
|
3
|
-
import { normalizeModuleId } from '
|
|
4
|
-
import { packageRequire, resolvePackageFile } from '
|
|
3
|
+
import { normalizeModuleId } from '../../../utils/modules.js';
|
|
4
|
+
import { packageRequire, resolvePackageFile } from '../../../utils/packages.js';
|
|
5
5
|
/** Identifies Rolldown's generated helper module independently of its unstable output filename. */
|
|
6
6
|
export const rolldownRuntimeId = '\0rolldown/runtime.js';
|
|
7
7
|
/** Resolves the direct React Reconciler dependency without assuming pnpm's layout. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
+
export declare const subpackagePlanningBudget = 1900000;
|
|
2
3
|
/** Identifies one generated code-only subpackage by its physical output root. */
|
|
3
4
|
export type SubpackageLocation = {
|
|
4
5
|
/** Discriminates generated subpackages from main. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
// Leave headroom below WeChat's 2M subpackage limit for rendered wrappers and native assets.
|
|
3
|
-
const subpackagePlanningBudget = 1_900_000;
|
|
3
|
+
export const subpackagePlanningBudget = 1_900_000;
|
|
4
4
|
const generatedSubpackageRootPrefix = 'sub/p_';
|
|
5
5
|
/** Shared main-package value used for every synchronously reachable chunk. */
|
|
6
6
|
const mainPackage = { kind: 'main' };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Plugin, type Rolldown } from 'vite';
|
|
2
2
|
import { type GeneratedSubpackage, type PackageLocation } from './placement.ts';
|
|
3
3
|
export type { GeneratedSubpackage, Placement } from './placement.ts';
|
|
4
|
+
/** Selects the explicit React/Taro roots whose complete dependency closure forms the framework vendor chunk. */
|
|
5
|
+
export declare function isWxFrameworkVendorModule(moduleId: string): boolean;
|
|
4
6
|
/** Placement services consumed by the later `vpt:wx` rendering and output hooks. */
|
|
5
7
|
export type WxPlacementPlugin = Plugin & Readonly<{
|
|
6
8
|
getPackageLocation(chunk: Rolldown.RenderedChunk | Rolldown.OutputChunk): PackageLocation;
|
|
@@ -18,6 +20,20 @@ export declare const placementRolldownOptions: {
|
|
|
18
20
|
* participation only; LTHP mutates the resulting OutputChunk filenames later without replacing the chunks.
|
|
19
21
|
*/
|
|
20
22
|
output: {
|
|
23
|
+
/**
|
|
24
|
+
* React and Taro form one stable framework boundary shared by the App and every Page capsule. Keeping their complete
|
|
25
|
+
* dependency closure together prevents application edits from invalidating framework chunk identity and makes later
|
|
26
|
+
* development generations eligible to reuse the unchanged vendor. All remaining modules use Rolldown's automatic
|
|
27
|
+
* chunking; physical WX package placement operates on those final chunks without imposing another split strategy.
|
|
28
|
+
*/
|
|
29
|
+
codeSplitting: {
|
|
30
|
+
groups: {
|
|
31
|
+
name: string;
|
|
32
|
+
test: typeof isWxFrameworkVendorModule;
|
|
33
|
+
priority: number;
|
|
34
|
+
includeDependenciesRecursively: boolean;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
21
37
|
/**
|
|
22
38
|
* Native App/Page/Component shells are files addressed directly by WeChat and must retain the exact names configured
|
|
23
39
|
* in `input`, such as `app.js` and `pages/home/index.js`. Transport is excluded even though it is CommonJS:
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizePath } from 'vite';
|
|
2
|
+
import { getWxExecutionKind, isTransportModule } from '../module/module.js';
|
|
2
3
|
import { getNativeComponentAssetBytes } from '../native/native-component-assets.js';
|
|
3
4
|
import { createPlacement } from './placement.js';
|
|
5
|
+
const pnpmFrameworkPackagePattern = /\/node_modules\/\.pnpm\/(?:@tarojs\+|react(?:-dom|-reconciler)?@|scheduler@)/;
|
|
6
|
+
const workspaceFrameworkPackagePattern = /\/packages\/(?:taro-react|taro-plugin-framework-react)\//;
|
|
7
|
+
/** Selects the explicit React/Taro roots whose complete dependency closure forms the framework vendor chunk. */
|
|
8
|
+
export function isWxFrameworkVendorModule(moduleId) {
|
|
9
|
+
const normalizedId = normalizePath(moduleId);
|
|
10
|
+
return pnpmFrameworkPackagePattern.test(normalizedId) || workspaceFrameworkPackagePattern.test(normalizedId);
|
|
11
|
+
}
|
|
4
12
|
/**
|
|
5
13
|
* Rolldown options owned by WX placement. Every field enforces a distinct output invariant. The plugin returns this object
|
|
6
14
|
* from its config hook, while direct Rolldown integration tests reuse the same value to exercise the identical lifecycle.
|
|
@@ -11,6 +19,22 @@ export const placementRolldownOptions = {
|
|
|
11
19
|
* participation only; LTHP mutates the resulting OutputChunk filenames later without replacing the chunks.
|
|
12
20
|
*/
|
|
13
21
|
output: {
|
|
22
|
+
/**
|
|
23
|
+
* React and Taro form one stable framework boundary shared by the App and every Page capsule. Keeping their complete
|
|
24
|
+
* dependency closure together prevents application edits from invalidating framework chunk identity and makes later
|
|
25
|
+
* development generations eligible to reuse the unchanged vendor. All remaining modules use Rolldown's automatic
|
|
26
|
+
* chunking; physical WX package placement operates on those final chunks without imposing another split strategy.
|
|
27
|
+
*/
|
|
28
|
+
codeSplitting: {
|
|
29
|
+
groups: [
|
|
30
|
+
{
|
|
31
|
+
name: 'vendor',
|
|
32
|
+
test: isWxFrameworkVendorModule,
|
|
33
|
+
priority: 100,
|
|
34
|
+
includeDependenciesRecursively: true
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
14
38
|
/**
|
|
15
39
|
* Native App/Page/Component shells are files addressed directly by WeChat and must retain the exact names configured
|
|
16
40
|
* in `input`, such as `app.js` and `pages/home/index.js`. Transport is excluded even though it is CommonJS:
|
|
@@ -2,7 +2,7 @@ import { esTarget } from '../../utils/constant.js';
|
|
|
2
2
|
import { packageRequire } from '../../utils/packages.js';
|
|
3
3
|
import { clientTaroNativeId } from '../client/constant.js';
|
|
4
4
|
import { createWxDevelopmentPlugin } from './dev/plugins.js';
|
|
5
|
-
import { getWxExecutionKind, isTransportModule } from './module.js';
|
|
5
|
+
import { getWxExecutionKind, isTransportModule } from './module/module.js';
|
|
6
6
|
import { compileNativeComponentInterface } from './native/compile-native-component-interface.js';
|
|
7
7
|
import { createOutputFiles } from './output/files.js';
|
|
8
8
|
import { createWxPlacementPlugin } from './placer/placer.js';
|
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
-
import {
|
|
3
|
-
/**
|
|
4
|
-
|
|
2
|
+
import type { AstTransformResult } from '../../../utils/transform.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Converts one final Rolldown ESM chunk into the inert registration consumed by the WX module runtime.
|
|
5
|
+
*
|
|
6
|
+
* Why this boundary exists:
|
|
7
|
+
*
|
|
8
|
+
* - Rolldown produces an ESM chunk graph, but a Mini Program loads emitted JavaScript through native `require` and
|
|
9
|
+
* `require.async`; it does not provide the browser ESM loader that normally links Vite chunks.
|
|
10
|
+
* - Native App, Page, and Component shells must start through WeChat's synchronous lifecycle APIs, while their application
|
|
11
|
+
* graph still needs ESM linking semantics such as cycles, live exports, dynamic imports, `import.meta`, and top-level await.
|
|
12
|
+
* - The plugin therefore keeps native lifecycle shells as CommonJS and executes application "capsules" through the bundled
|
|
13
|
+
* SystemJS runtime. Native shells enter that graph with `global.System.importSync`, and genuine asynchronous boundaries use
|
|
14
|
+
* the same runtime through `System.import`.
|
|
15
|
+
*
|
|
16
|
+
* What this renderer emits:
|
|
17
|
+
*
|
|
18
|
+
* The result is CommonJS source whose `module.exports` is a SystemJS registration tuple:
|
|
19
|
+
* `[logicalDependencyIds, declaration]`. Requiring a capsule only returns this inert tuple; it does not execute application
|
|
20
|
+
* code or call a global `System.register`. The generated transport can consequently load the physical file from either the
|
|
21
|
+
* main package or a subpackage, then hand its registration to the loader. The loader owns linking, setter invocation,
|
|
22
|
+
* execution order, cycle handling, and export publication.
|
|
23
|
+
*
|
|
24
|
+
* Why references are rewritten:
|
|
25
|
+
*
|
|
26
|
+
* Rolldown imports name physical output files whose relative paths include placement directories and content hashes. The
|
|
27
|
+
* SystemJS registry instead uses package-neutral logical chunk IDs. Canonicalizing both static and literal dynamic references
|
|
28
|
+
* here lets transport independently map a stable module identity to the physical `require` path selected by WX placement.
|
|
29
|
+
* Runtime-computed dynamic IDs cannot be canonicalized and are intentionally preserved.
|
|
30
|
+
*
|
|
31
|
+
* This function runs on final Rolldown output rather than arbitrary source modules. `transformSystemJs` accepts only the
|
|
32
|
+
* normalized final-chunk grammar required by this pipeline and fails the build on unsupported forms instead of risking a
|
|
33
|
+
* partial or semantically incorrect capsule. Source maps remain optional because WX development output deliberately disables
|
|
34
|
+
* them on this startup-critical path.
|
|
35
|
+
*/
|
|
36
|
+
export declare function renderCapsule(code: string, chunk: Rolldown.RenderedChunk, sourcemap: boolean): AstTransformResult;
|
|
@@ -1,13 +1,54 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { resolveLogicalChunkReference } from '../module/chunk-path.js';
|
|
2
|
+
import { transformSystemJs } from './system-js/system-js.js';
|
|
3
|
+
/**
|
|
4
|
+
* Converts one final Rolldown ESM chunk into the inert registration consumed by the WX module runtime.
|
|
5
|
+
*
|
|
6
|
+
* Why this boundary exists:
|
|
7
|
+
*
|
|
8
|
+
* - Rolldown produces an ESM chunk graph, but a Mini Program loads emitted JavaScript through native `require` and
|
|
9
|
+
* `require.async`; it does not provide the browser ESM loader that normally links Vite chunks.
|
|
10
|
+
* - Native App, Page, and Component shells must start through WeChat's synchronous lifecycle APIs, while their application
|
|
11
|
+
* graph still needs ESM linking semantics such as cycles, live exports, dynamic imports, `import.meta`, and top-level await.
|
|
12
|
+
* - The plugin therefore keeps native lifecycle shells as CommonJS and executes application "capsules" through the bundled
|
|
13
|
+
* SystemJS runtime. Native shells enter that graph with `global.System.importSync`, and genuine asynchronous boundaries use
|
|
14
|
+
* the same runtime through `System.import`.
|
|
15
|
+
*
|
|
16
|
+
* What this renderer emits:
|
|
17
|
+
*
|
|
18
|
+
* The result is CommonJS source whose `module.exports` is a SystemJS registration tuple:
|
|
19
|
+
* `[logicalDependencyIds, declaration]`. Requiring a capsule only returns this inert tuple; it does not execute application
|
|
20
|
+
* code or call a global `System.register`. The generated transport can consequently load the physical file from either the
|
|
21
|
+
* main package or a subpackage, then hand its registration to the loader. The loader owns linking, setter invocation,
|
|
22
|
+
* execution order, cycle handling, and export publication.
|
|
23
|
+
*
|
|
24
|
+
* Why references are rewritten:
|
|
25
|
+
*
|
|
26
|
+
* Rolldown imports name physical output files whose relative paths include placement directories and content hashes. The
|
|
27
|
+
* SystemJS registry instead uses package-neutral logical chunk IDs. Canonicalizing both static and literal dynamic references
|
|
28
|
+
* here lets transport independently map a stable module identity to the physical `require` path selected by WX placement.
|
|
29
|
+
* Runtime-computed dynamic IDs cannot be canonicalized and are intentionally preserved.
|
|
30
|
+
*
|
|
31
|
+
* This function runs on final Rolldown output rather than arbitrary source modules. `transformSystemJs` accepts only the
|
|
32
|
+
* normalized final-chunk grammar required by this pipeline and fails the build on unsupported forms instead of risking a
|
|
33
|
+
* partial or semantically incorrect capsule. Source maps remain optional because WX development output deliberately disables
|
|
34
|
+
* them on this startup-critical path.
|
|
35
|
+
*/
|
|
36
|
+
export function renderCapsule(code, chunk, sourcemap) {
|
|
37
|
+
return transformSystemJs({
|
|
38
|
+
code,
|
|
39
|
+
filename: chunk.fileName,
|
|
40
|
+
// Native require must return registration data without executing or globally registering the capsule.
|
|
41
|
+
format: 'commonjs-registration',
|
|
42
|
+
sourcemap,
|
|
43
|
+
// Bind every compile-time chunk edge to the same logical identity understood by transport and SystemJS.
|
|
44
|
+
resolveReference(reference, kind) {
|
|
45
|
+
return resolveCapsuleReference(chunk.fileName, reference, kind);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Canonicalizes physical chunk paths while preserving runtime-computed and package-like dynamic IDs. */
|
|
50
|
+
function resolveCapsuleReference(fileName, reference, kind) {
|
|
51
|
+
if (kind === 'dynamic' && !reference.startsWith('./') && !reference.startsWith('../'))
|
|
52
|
+
return reference;
|
|
53
|
+
return resolveLogicalChunkReference(fileName, reference);
|
|
13
54
|
}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import type { Rolldown } from 'vite';
|
|
2
|
-
import {
|
|
3
|
-
/**
|
|
2
|
+
import type { AstTransformResult } from '../../../utils/transform.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Materializes one final native/amphibious Rolldown chunk as executable WX CommonJS.
|
|
5
|
+
*
|
|
6
|
+
* The transform performs four semantic operations:
|
|
7
|
+
*
|
|
8
|
+
* 1. Static ESM imports are hoisted into source-order `require` calls. Named imports remain property reads from the required
|
|
9
|
+
* namespace so they observe current values. Default and namespace imports receive Babel-compatible CommonJS interop.
|
|
10
|
+
* 2. An import whose target owns a capsule entry is not passed to native `require`. It becomes
|
|
11
|
+
* `global.System.importSync(logicalChunkId)`, synchronously linking the capsule before the native lifecycle call.
|
|
12
|
+
* 3. Local exports are published at declaration and mutation points. Imported re-exports use getters, while assignments and
|
|
13
|
+
* updates notify every alias without changing expression completion values or accidentally matching shadowed bindings.
|
|
14
|
+
* 4. ESM top-level `this` becomes `undefined`. Direct imported calls and tags are explicitly unbound so converting an import
|
|
15
|
+
* into a namespace property does not introduce a false CommonJS receiver.
|
|
16
|
+
*
|
|
17
|
+
* Static dependency loading is emitted before the untouched module body because ESM evaluates dependencies before body
|
|
18
|
+
* statements regardless of where import declarations appear textually. Generated helper names are allocated against every
|
|
19
|
+
* source identifier. Source maps use the same range edits when requested; WX development disables them and keeps this path
|
|
20
|
+
* focused on startup latency.
|
|
21
|
+
*/
|
|
4
22
|
export declare function renderNative({ code, chunk, chunks, sourcemap }: {
|
|
5
23
|
code: string;
|
|
6
24
|
chunk: Rolldown.RenderedChunk;
|