vite-plugin-taro 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/dist/node/plugins/client/client-taro.js +12 -8
- package/dist/node/plugins/h5/create-stencil-client-adapter.d.ts +21 -0
- package/dist/node/plugins/h5/create-stencil-client-adapter.js +92 -0
- package/dist/node/plugins/h5/plugins.d.ts +10 -0
- package/dist/node/plugins/h5/plugins.js +50 -61
- package/dist/node/plugins/wx/dev/dev-host.js +103 -216
- package/dist/node/plugins/wx/dev/hmr-files.d.ts +4 -5
- package/dist/node/plugins/wx/dev/hmr-files.js +18 -8
- package/dist/node/plugins/wx/dev/patch-publisher.d.ts +25 -5
- package/dist/node/plugins/wx/dev/patch-publisher.js +30 -9
- package/dist/node/plugins/wx/dev/react-refresh.d.ts +12 -0
- package/dist/node/plugins/wx/dev/react-refresh.js +111 -108
- package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +25 -0
- package/dist/node/plugins/wx/dev/wx-dev-options.js +147 -0
- package/dist/node/utils/oxc-transform.d.ts +21 -0
- package/dist/node/utils/oxc-transform.js +58 -0
- package/dist/node/utils/serialized-task-queue.d.ts +6 -2
- package/dist/node/utils/serialized-task-queue.js +10 -2
- package/dist/runtime/wx/dev/dev-runtime.js +70 -26
- package/package.json +13 -12
- package/src/node/plugins/client/client-taro.ts +13 -8
- package/src/node/plugins/h5/create-stencil-client-adapter.ts +110 -0
- package/src/node/plugins/h5/plugins.ts +52 -84
- package/src/node/plugins/wx/dev/dev-host.ts +121 -256
- package/src/node/plugins/wx/dev/hmr-files.ts +20 -8
- package/src/node/plugins/wx/dev/patch-publisher.ts +36 -10
- package/src/node/plugins/wx/dev/react-refresh.ts +125 -129
- package/src/node/plugins/wx/dev/wx-dev-options.ts +200 -0
- package/src/node/utils/oxc-transform.ts +77 -0
- package/src/node/utils/serialized-task-queue.ts +15 -3
- package/src/runtime/wx/dev/dev-runtime.ts +80 -28
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
// The `DevRuntime` base class is injected into the chunk by Rolldown's dev-mode
|
|
6
6
|
// transform, so the WX host only extends it.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// sequences are ignored when another Page requires the same physical file.
|
|
8
|
+
// Every Page explicitly passes the inert hmr/patches.js export here before importing its capsule. The runtime applies that
|
|
9
|
+
// cumulative suffix synchronously, reports its successful application frontier, and ignores sequences replayed by other Pages.
|
|
11
10
|
/**
|
|
12
11
|
* Per-module hot state, mirroring Rolldown's web runtime: accept is a passive registration;
|
|
13
12
|
* the propagation invokes the previous execution's callbacks with the fresh exports.
|
|
@@ -134,14 +133,12 @@ class WxDevRuntime extends DevRuntime {
|
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
|
-
/** Consumed once per App heap from hmr/info.js; the host buildId
|
|
136
|
+
/** Consumed once per App heap from hmr/info.js; the host buildId identifies its cumulative patch history. */
|
|
138
137
|
initialize(info) {
|
|
139
138
|
if (this.hmrInfo) {
|
|
140
139
|
return;
|
|
141
140
|
}
|
|
142
141
|
this.hmrInfo = info;
|
|
143
|
-
// Anchor: the host publishes only after the runtime reports its delivery position.
|
|
144
|
-
void this.sendReport({ kind: 'delivery', seq: this.appliedSeq });
|
|
145
142
|
}
|
|
146
143
|
/** True between a patch delivery and the next page show: a hot reload is in progress. */
|
|
147
144
|
hotReloading = false;
|
|
@@ -153,42 +150,89 @@ class WxDevRuntime extends DevRuntime {
|
|
|
153
150
|
clearHotReloading() {
|
|
154
151
|
this.hotReloading = false;
|
|
155
152
|
}
|
|
156
|
-
/**
|
|
157
|
-
|
|
153
|
+
/** Applies one Page-delivered payload before that Page imports its capsule. */
|
|
154
|
+
applyPatches(payload) {
|
|
155
|
+
// The initial physical dependency exports undefined until the host has a patch range.
|
|
156
|
+
if (!payload)
|
|
157
|
+
return;
|
|
158
158
|
const info = this.hmrInfo;
|
|
159
159
|
if (!info || payload.buildId !== info.buildId) {
|
|
160
160
|
console.warn('[vpt] patches for a stale build');
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
-
const deliveredSeq = Math.max(this.appliedSeq, payload.patches.at(-1)?.seq ?? 0);
|
|
164
|
-
void this.sendReport({ kind: 'delivery', seq: deliveredSeq });
|
|
165
163
|
// A delivered patch means DevTools is about to replay the page lifecycle on the
|
|
166
164
|
// re-executing Pages; the capsule wrapper suppresses the synthetic unmount/mount so
|
|
167
165
|
// the React tree survives and Refresh swaps the code in place.
|
|
168
166
|
this.hotReloading = true;
|
|
169
167
|
// Apply synchronously: the page's imports below the require resolve against the
|
|
170
168
|
// freshly registered modules, so the re-executed Page evaluates with the new code.
|
|
171
|
-
this.
|
|
169
|
+
if (this.applyPatchBatch(payload.patches)) {
|
|
170
|
+
// The host may publish later generations while this synchronous apply runs. Reporting only afterward makes this
|
|
171
|
+
// the application frontier: publisher history is never pruned merely because its JavaScript file was observed.
|
|
172
|
+
void this.sendReport({ kind: 'applied', seq: this.appliedSeq });
|
|
173
|
+
}
|
|
172
174
|
}
|
|
173
|
-
/**
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Folds one cumulative physical patch file into a single logical HMR update.
|
|
177
|
+
*
|
|
178
|
+
* `hmr/patches.js` can contain several unacknowledged Rolldown patches and can be required by several Page shells. The
|
|
179
|
+
* runtime must therefore ignore replayed sequences, reject a missing sequence, and move directly from the currently live
|
|
180
|
+
* module generation to the latest published generation without rendering intermediate generations.
|
|
181
|
+
*
|
|
182
|
+
* For an appliedSeq of 4:
|
|
183
|
+
*
|
|
184
|
+
* - [5, 6, 7] registers every factory, performs one update using their unioned changedIds, commits appliedSeq 7, and reports 7;
|
|
185
|
+
* - a second Page evaluating [5, 6, 7] skips the complete replay and leaves the latest factories untouched;
|
|
186
|
+
* - [5, 7] fails at the expected sequence 6, keeps appliedSeq 4, and requests a full rebuild because factory 6 is unrecoverable.
|
|
187
|
+
*/
|
|
188
|
+
applyPatchBatch(patches) {
|
|
189
|
+
// Keep the initial watermark immutable throughout the fold. Comparing replays against a moving watermark would allow
|
|
190
|
+
// a duplicate new sequence in the same payload to masquerade as an already-applied patch.
|
|
191
|
+
const previousSeq = this.appliedSeq;
|
|
192
|
+
// Mutable only during this synchronous pass. `nextSeq` validates continuity while `changedIds` unions every incremental
|
|
193
|
+
// patch's roots for the one final graph traversal; neither value escapes into persistent runtime state.
|
|
194
|
+
let nextSeq = previousSeq + 1;
|
|
195
|
+
const changedIds = new Set();
|
|
196
|
+
try {
|
|
197
|
+
for (const patch of patches) {
|
|
198
|
+
// The same physical file is evaluated once per affected Page. Those later evaluations replay its prefix and
|
|
199
|
+
// must not let an old factory overwrite the newer factory already stored in the Rolldown runtime.
|
|
200
|
+
if (patch.seq <= previousSeq) {
|
|
201
|
+
continue;
|
|
182
202
|
}
|
|
203
|
+
// Every patch is incremental: if one physical write was missed, later factories cannot reconstruct modules
|
|
204
|
+
// changed only by that missing patch. Rebuilding is safer than silently running a mixed module generation.
|
|
205
|
+
if (patch.seq !== nextSeq) {
|
|
206
|
+
throw new Error(`missing patch sequence ${nextSeq}`);
|
|
207
|
+
}
|
|
208
|
+
// A patch factory only registers module graphs and module factories; it does not execute application modules.
|
|
209
|
+
// Running all of them first leaves the registry at the latest generation while avoiding intermediate renders.
|
|
183
210
|
patch.factory();
|
|
184
|
-
|
|
185
|
-
|
|
211
|
+
for (const changedId of patch.changedIds) {
|
|
212
|
+
changedIds.add(changedId);
|
|
213
|
+
}
|
|
214
|
+
nextSeq++;
|
|
186
215
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return;
|
|
216
|
+
// A payload containing only replayed sequences requires no graph work and must not alter the application watermark.
|
|
217
|
+
if (nextSeq === previousSeq + 1) {
|
|
218
|
+
return true;
|
|
191
219
|
}
|
|
220
|
+
// Apply once after every factory is registered. React Refresh arms a newly executed module's hot.accept callback
|
|
221
|
+
// in a microtask; applying consecutive patches separately would inspect that intermediate context too early and
|
|
222
|
+
// incorrectly bubble through the capsule to the native Page shell as though no HMR boundary existed.
|
|
223
|
+
this.applyHmrUpdate(changedIds);
|
|
224
|
+
// Commit application only after graph propagation and boundary callbacks succeed. A failure leaves the old watermark
|
|
225
|
+
// intact and requests a full rebuild below, so a partially applied batch is never acknowledged as healthy.
|
|
226
|
+
this.appliedSeq = nextSeq - 1;
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.warn('[vpt] patch batch failed; apply stopped', error);
|
|
231
|
+
void this.sendReport({
|
|
232
|
+
kind: 'rebuild',
|
|
233
|
+
reason: Error.isError(error) ? error.message : String(error)
|
|
234
|
+
});
|
|
235
|
+
return false;
|
|
192
236
|
}
|
|
193
237
|
}
|
|
194
238
|
/** Sends one metadata-only report to the host; executable code never travels over HTTP. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-taro",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"author": "sep2",
|
|
5
5
|
"description": "Vite 8 plugin for building one React/Taro codebase for WeChat Mini Program and H5 targets.",
|
|
6
6
|
"type": "module",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/sep2/vite-plugin-taro/issues"
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://
|
|
15
|
+
"homepage": "https://vpt.js.org",
|
|
16
16
|
"main": "./dist/vite.js",
|
|
17
17
|
"module": "./dist/vite.js",
|
|
18
18
|
"types": "./dist/vite.d.ts",
|
|
@@ -58,24 +58,25 @@
|
|
|
58
58
|
"@babel/plugin-transform-modules-systemjs": "^7.29.8",
|
|
59
59
|
"@rolldown/plugin-babel": "^0.2.3",
|
|
60
60
|
"@tailwindcss-mangle/engine": "0.2.0",
|
|
61
|
-
"@tarojs/components": "
|
|
62
|
-
"@tarojs/helper": "
|
|
63
|
-
"@tarojs/plugin-platform-h5": "
|
|
64
|
-
"@tarojs/plugin-platform-weapp": "
|
|
65
|
-
"@tarojs/router": "
|
|
66
|
-
"@tarojs/runtime": "
|
|
67
|
-
"@tarojs/taro": "
|
|
61
|
+
"@tarojs/components": "4.2.0",
|
|
62
|
+
"@tarojs/helper": "4.2.0",
|
|
63
|
+
"@tarojs/plugin-platform-h5": "4.2.0",
|
|
64
|
+
"@tarojs/plugin-platform-weapp": "4.2.0",
|
|
65
|
+
"@tarojs/router": "4.2.0",
|
|
66
|
+
"@tarojs/runtime": "4.2.0",
|
|
67
|
+
"@tarojs/taro": "4.2.0",
|
|
68
68
|
"@vitejs/plugin-react": "^6.0.5",
|
|
69
69
|
"@weapp-tailwindcss/postcss": "3.2.8",
|
|
70
|
-
"babel-plugin-transform-taroapi": "
|
|
70
|
+
"babel-plugin-transform-taroapi": "4.2.0",
|
|
71
|
+
"oxc-walker": "1.1.1",
|
|
71
72
|
"picocolors": "^1.1.1",
|
|
72
73
|
"react-reconciler": "0.33.0",
|
|
73
74
|
"react-refresh": "^0.18.0",
|
|
74
75
|
"rolldown": "1.2.3",
|
|
75
76
|
"tailwindcss": "^4.3.3",
|
|
76
77
|
"weapp-tailwindcss": "^5.2.11",
|
|
77
|
-
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.
|
|
78
|
-
"@tarojs/react": "npm:vite-plugin-taro-react@0.5.
|
|
78
|
+
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.5",
|
|
79
|
+
"@tarojs/react": "npm:vite-plugin-taro-react@0.5.5"
|
|
79
80
|
},
|
|
80
81
|
"peerDependencies": {
|
|
81
82
|
"react": "^19.0.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from 'vite'
|
|
2
2
|
import type { VitePluginTaroTarget } from '../../../options.ts'
|
|
3
3
|
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
4
|
-
import {
|
|
4
|
+
import { resolvePackageFile } from '../../utils/packages.ts'
|
|
5
5
|
import { clientTaroNativeId } from './constant.ts'
|
|
6
6
|
import { injectTaroFrameworkApis } from './inject-taro-framework-apis.ts'
|
|
7
7
|
|
|
@@ -33,15 +33,22 @@ const clientTaroModules = new Map([
|
|
|
33
33
|
|
|
34
34
|
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
35
35
|
export function createClientTaroPlugin(target: VitePluginTaroTarget): Plugin {
|
|
36
|
-
const
|
|
36
|
+
const platformTaroId = resolvePlatformTaroId(target)
|
|
37
37
|
|
|
38
38
|
return {
|
|
39
39
|
name: 'vpt:client-taro',
|
|
40
40
|
enforce: 'pre',
|
|
41
41
|
|
|
42
|
-
resolveId(id, importer) {
|
|
42
|
+
async resolveId(id, importer) {
|
|
43
43
|
if (id === '@tarojs/taro') {
|
|
44
|
-
|
|
44
|
+
if (!isClientTaroFacade(importer)) {
|
|
45
|
+
return clientTaroApiPath
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Delegate the platform backend to Vite instead of returning an absolute dependency path. H5 marks this
|
|
49
|
+
// backend as an optimization root, so delegation lets Vite substitute its prebundled facade. Removing it
|
|
50
|
+
// bypasses CommonJS interop and exposes backend details such as base64-js directly to the browser.
|
|
51
|
+
return this.resolve(platformTaroId, importer, { skipSelf: true })
|
|
45
52
|
}
|
|
46
53
|
return clientTaroModules.get(id)
|
|
47
54
|
},
|
|
@@ -55,10 +62,8 @@ export function createClientTaroPlugin(target: VitePluginTaroTarget): Plugin {
|
|
|
55
62
|
}
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
function
|
|
59
|
-
return target === 'h5'
|
|
60
|
-
? packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
61
|
-
: packageRequire.resolve('@tarojs/taro')
|
|
65
|
+
function resolvePlatformTaroId(target: VitePluginTaroTarget): string {
|
|
66
|
+
return target === 'h5' ? '@tarojs/plugin-platform-h5/dist/runtime/apis' : '@tarojs/taro'
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
function isClientTaroFacade(importer: string | undefined): boolean {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { WalkerEnter } from 'oxc-walker'
|
|
2
|
+
import type { RolldownMagicString } from 'rolldown'
|
|
3
|
+
import type { Plugin } from 'vite'
|
|
4
|
+
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
5
|
+
import { transformWithOxcWalker } from '../../utils/oxc-transform.ts'
|
|
6
|
+
import { packageRequire } from '../../utils/packages.ts'
|
|
7
|
+
|
|
8
|
+
const stencilClientPath = packageRequire.resolve('@stencil/core/internal/client', {
|
|
9
|
+
paths: [packageRequire.resolve('@tarojs/components/package.json')]
|
|
10
|
+
})
|
|
11
|
+
const normalizedStencilClientPath = normalizeModuleId(stencilClientPath)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates the compiler-owned adaptation of Stencil's client style insertion.
|
|
15
|
+
*
|
|
16
|
+
* Taro components inject their styles through this internal client. Its default insertion point places those styles
|
|
17
|
+
* after application CSS, allowing component defaults to override application rules. The adapter is registered in both
|
|
18
|
+
* Vite's application pipeline and the independent dependency-optimization build: removing either registration leaves
|
|
19
|
+
* production or development with an unadapted client. This explicit dual registration removes the former optimization
|
|
20
|
+
* exclusion while keeping one transformation implementation.
|
|
21
|
+
*/
|
|
22
|
+
export function createStencilClientAdapter(): Plugin {
|
|
23
|
+
return {
|
|
24
|
+
name: 'vpt:h5-stencil-client',
|
|
25
|
+
transform: adaptStencilClient
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Applies the shared Stencil adaptation with one Oxc parse and one range edit.
|
|
31
|
+
*
|
|
32
|
+
* The physical module check is essential because the optimizer and application pipelines can
|
|
33
|
+
* present query-suffixed or platform-normalized IDs. Transforming by source text alone could
|
|
34
|
+
* modify user code that happens to contain the same insertion expression. Source maps remain
|
|
35
|
+
* enabled because this adapter runs before Vite/Rolldown's later transforms in both pipelines;
|
|
36
|
+
* dropping the map would attribute downstream diagnostics to the edited generated positions.
|
|
37
|
+
*/
|
|
38
|
+
export function adaptStencilClient(code: string, id: string) {
|
|
39
|
+
if (normalizeModuleId(id) !== normalizedStencilClientPath) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return transformWithOxcWalker({
|
|
44
|
+
code,
|
|
45
|
+
filename: id,
|
|
46
|
+
sourcemap: true,
|
|
47
|
+
createVisitor: createStencilVisitor
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Finds Stencil's exact default style insertion call and replaces only its insertion anchor.
|
|
53
|
+
*
|
|
54
|
+
* Stencil normally inserts `styleElm` before the first stylesheet link. During Vite development,
|
|
55
|
+
* application CSS is commonly represented by a `<style>` element instead, so that link-only
|
|
56
|
+
* lookup returns `null` and Taro component defaults are appended after application CSS. Those
|
|
57
|
+
* defaults then override the application's selectors despite having the same specificity.
|
|
58
|
+
*
|
|
59
|
+
* Taro Stencil components are identified by the `sc-taro-` scope prefix. For those components,
|
|
60
|
+
* the replacement anchors before the first `<style>` or stylesheet `<link>`, keeping component
|
|
61
|
+
* defaults before application rules. The original link-only lookup is preserved for every other
|
|
62
|
+
* Stencil component so VPT does not globally redefine upstream style-ordering behavior.
|
|
63
|
+
*/
|
|
64
|
+
function createStencilVisitor(editor: RolldownMagicString): WalkerEnter {
|
|
65
|
+
return function enter(node) {
|
|
66
|
+
if (
|
|
67
|
+
node.type !== 'CallExpression' ||
|
|
68
|
+
node.callee.type !== 'MemberExpression' ||
|
|
69
|
+
node.callee.computed ||
|
|
70
|
+
node.callee.object.type !== 'Identifier' ||
|
|
71
|
+
node.callee.object.name !== 'styleContainerNode' ||
|
|
72
|
+
node.callee.property.type !== 'Identifier' ||
|
|
73
|
+
node.callee.property.name !== 'insertBefore'
|
|
74
|
+
) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Match the complete upstream call, not merely `insertBefore`: range edits have no
|
|
79
|
+
// generated-AST type safety, so a broad match could silently alter unrelated runtime
|
|
80
|
+
// behavior when Stencil changes its implementation.
|
|
81
|
+
const [style, query] = node.arguments
|
|
82
|
+
const selector = query?.type === 'CallExpression' ? query.arguments[0] : undefined
|
|
83
|
+
if (
|
|
84
|
+
node.arguments.length !== 2 ||
|
|
85
|
+
style?.type !== 'Identifier' ||
|
|
86
|
+
style.name !== 'styleElm' ||
|
|
87
|
+
query?.type !== 'CallExpression' ||
|
|
88
|
+
query.callee.type !== 'MemberExpression' ||
|
|
89
|
+
query.callee.computed ||
|
|
90
|
+
query.callee.object.type !== 'Identifier' ||
|
|
91
|
+
query.callee.object.name !== 'styleContainerNode' ||
|
|
92
|
+
query.callee.property.type !== 'Identifier' ||
|
|
93
|
+
query.callee.property.name !== 'querySelector' ||
|
|
94
|
+
selector?.type !== 'Literal' ||
|
|
95
|
+
selector.value !== 'link'
|
|
96
|
+
) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Replace only the second argument expression. Preserving the surrounding Stencil
|
|
101
|
+
// source avoids Babel-style whole-file regeneration and keeps its formatting, comments,
|
|
102
|
+
// and source positions stable. Removing this edit restores the H5 cascade bug described
|
|
103
|
+
// above; applying it unconditionally would change non-Taro Stencil components.
|
|
104
|
+
editor.overwrite(
|
|
105
|
+
query.start,
|
|
106
|
+
query.end,
|
|
107
|
+
'scopeId.startsWith("sc-taro-") ? styleContainerNode.querySelector("style,link[rel=\\"stylesheet\\"]") : styleContainerNode.querySelector("link")'
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type NodePath, type PluginObj, types } from '@babel/core'
|
|
3
|
-
import babel from '@rolldown/plugin-babel'
|
|
1
|
+
import babel, { defineRolldownBabelPreset } from '@rolldown/plugin-babel'
|
|
4
2
|
import type { HtmlTagDescriptor, Plugin, PluginOption } from 'vite'
|
|
5
3
|
import type { VitePluginTaroOptions } from '../../../options.ts'
|
|
6
4
|
import { esTarget } from '../../utils/constant.ts'
|
|
@@ -8,6 +6,7 @@ import { toViteFileImportPath } from '../../utils/modules.ts'
|
|
|
8
6
|
import { packageRequire } from '../../utils/packages.ts'
|
|
9
7
|
import { clientTaroApiId } from '../client/client-taro.ts'
|
|
10
8
|
import { h5AppPath } from './constant.ts'
|
|
9
|
+
import { createStencilClientAdapter } from './create-stencil-client-adapter.ts'
|
|
11
10
|
import { createModuleResolver } from './resolver/module-resolver.ts'
|
|
12
11
|
|
|
13
12
|
/** Creates the plugins that own the H5 target. */
|
|
@@ -28,12 +27,6 @@ function createH5TargetPlugin(options: VitePluginTaroOptions): Plugin {
|
|
|
28
27
|
resolve: {
|
|
29
28
|
mainFields: ['main:h5', 'browser', 'module', 'jsnext:main', 'jsnext'],
|
|
30
29
|
alias: [
|
|
31
|
-
{
|
|
32
|
-
find: /^@stencil\/core\/internal\/client$/,
|
|
33
|
-
replacement: packageRequire.resolve('@stencil/core/internal/client', {
|
|
34
|
-
paths: [packageRequire.resolve('@tarojs/components/package.json')]
|
|
35
|
-
})
|
|
36
|
-
},
|
|
37
30
|
{
|
|
38
31
|
find: /^@tarojs\/components$/,
|
|
39
32
|
replacement: packageRequire.resolve('@tarojs/components/lib/react')
|
|
@@ -45,7 +38,15 @@ function createH5TargetPlugin(options: VitePluginTaroOptions): Plugin {
|
|
|
45
38
|
]
|
|
46
39
|
},
|
|
47
40
|
optimizeDeps: {
|
|
48
|
-
|
|
41
|
+
// The compiler-owned H5 app and Taro facade are injected after Vite's initial HTML scan. Prebundle
|
|
42
|
+
// the facade's platform backend as one boundary so its CommonJS implementation details receive
|
|
43
|
+
// interop without duplicating their package list. ReactDOM needs the same treatment for the H5 app.
|
|
44
|
+
include: ['@tarojs/plugin-platform-h5/dist/runtime/apis', 'react-dom/client'],
|
|
45
|
+
// Dependency optimization is its own Rolldown build and does not run application transform plugins.
|
|
46
|
+
// Register the same adapter there so optimized Taro components cannot embed Stencil's original client.
|
|
47
|
+
rolldownOptions: {
|
|
48
|
+
plugins: [createStencilClientAdapter()]
|
|
49
|
+
}
|
|
49
50
|
},
|
|
50
51
|
build: {
|
|
51
52
|
target: esTarget
|
|
@@ -98,86 +99,53 @@ function createH5IndexHtmlTags(): HtmlTagDescriptor[] {
|
|
|
98
99
|
]
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
[
|
|
112
|
-
packageRequire.resolve('babel-plugin-transform-taroapi'),
|
|
113
|
-
{
|
|
114
|
-
packageName: clientTaroApiId,
|
|
115
|
-
definition: packageRequire(
|
|
116
|
-
packageRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json')
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
]
|
|
120
|
-
]
|
|
121
|
-
})
|
|
122
|
-
]
|
|
123
|
-
}
|
|
102
|
+
/**
|
|
103
|
+
* Coarse source prefilter for the upstream Taro API transform.
|
|
104
|
+
*
|
|
105
|
+
* The plugin has two independent responsibilities: adapting imports from the compiler facade and normalizing camel-case
|
|
106
|
+
* H5 ARIA attributes. Matching `aria` followed by any uppercase letter is intentionally broader than Taro's current
|
|
107
|
+
* attribute table. A duplicated exact list would silently stop routing files through Babel when upstream adds another
|
|
108
|
+
* attribute, while a broad false positive costs only one unnecessary transform. Ordinary application modules match
|
|
109
|
+
* neither branch and remain entirely outside Babel's parser and generator.
|
|
110
|
+
*/
|
|
111
|
+
export const h5TaroApiTransformCodeFilter = /virtual:taro\/api|\baria[A-Z]/
|
|
124
112
|
|
|
125
|
-
/**
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
visitor: {
|
|
130
|
-
CallExpression(callPath) {
|
|
131
|
-
if (!isStencilStyleInsertBeforeCall(callPath)) {
|
|
132
|
-
return
|
|
133
|
-
}
|
|
113
|
+
/** Creates a filterable Babel preset containing Taro's upstream, scope-aware API transform. */
|
|
114
|
+
function createH5TaroApiPreset() {
|
|
115
|
+
const transformTaroApiPath = packageRequire.resolve('babel-plugin-transform-taroapi')
|
|
116
|
+
const definition = packageRequire(packageRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json'))
|
|
134
117
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
118
|
+
return defineRolldownBabelPreset({
|
|
119
|
+
preset: function h5TaroApiPreset() {
|
|
120
|
+
return {
|
|
121
|
+
plugins: [
|
|
122
|
+
[
|
|
123
|
+
transformTaroApiPath,
|
|
124
|
+
{
|
|
125
|
+
packageName: clientTaroApiId,
|
|
126
|
+
definition
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
]
|
|
147
130
|
}
|
|
131
|
+
},
|
|
132
|
+
rolldown: {
|
|
133
|
+
// @rolldown/plugin-babel can lift a preset filter into its native transform hook. The Taro plugin must be
|
|
134
|
+
// nested in this preset rather than passed through Babel's top-level `plugins`: explicit plugins may apply
|
|
135
|
+
// to every module, so their presence deliberately disables Rolldown's preset-level code filtering.
|
|
136
|
+
filter: { code: h5TaroApiTransformCodeFilter }
|
|
148
137
|
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Identifies Stencil's default component-style insertion call. */
|
|
153
|
-
function isStencilStyleInsertBeforeCall(callPath: NodePath<BabelTypes.CallExpression>): boolean {
|
|
154
|
-
const { callee, arguments: callArguments } = callPath.node
|
|
155
|
-
return (
|
|
156
|
-
types.isMemberExpression(callee) &&
|
|
157
|
-
types.isIdentifier(callee.object, { name: 'styleContainerNode' }) &&
|
|
158
|
-
types.isIdentifier(callee.property, { name: 'insertBefore' }) &&
|
|
159
|
-
types.isIdentifier(callArguments[0], { name: 'styleElm' }) &&
|
|
160
|
-
isStyleQuery(callArguments[1], 'link')
|
|
161
|
-
)
|
|
138
|
+
})
|
|
162
139
|
}
|
|
163
140
|
|
|
164
|
-
/**
|
|
165
|
-
function
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** Creates one style-container querySelector call. */
|
|
176
|
-
function createStyleQuery(selector: string): ReturnType<typeof types.callExpression> {
|
|
177
|
-
return types.callExpression(
|
|
178
|
-
types.memberExpression(types.identifier('styleContainerNode'), types.identifier('querySelector')),
|
|
179
|
-
[types.stringLiteral(selector)]
|
|
180
|
-
)
|
|
141
|
+
/** Creates H5-only transforms for Stencil CSS ordering and Taro API imports. */
|
|
142
|
+
function createH5SupportPlugins(): PluginOption[] {
|
|
143
|
+
return [
|
|
144
|
+
createStencilClientAdapter(),
|
|
145
|
+
babel({
|
|
146
|
+
presets: [createH5TaroApiPreset()]
|
|
147
|
+
})
|
|
148
|
+
]
|
|
181
149
|
}
|
|
182
150
|
|
|
183
151
|
/** Creates H5 Taro compile-time constants. */
|