vite-plugin-taro 0.0.3 → 0.0.4

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.md CHANGED
@@ -1,114 +1,159 @@
1
1
  # vite-plugin-taro
2
2
 
3
- Vite 8 + React 19 plugin for building one React/Taro codebase for both WeChat Mini Program (`wx`) and Web (`h5`) targets.
3
+ [![npm version](https://img.shields.io/npm/v/vite-plugin-taro.svg)](https://www.npmjs.com/package/vite-plugin-taro)
4
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
5
 
5
- - npm: <https://www.npmjs.com/package/vite-plugin-taro>
6
- - Sample H5 demo: <https://sep2.github.io/vite-plugin-taro/>
7
- - Repository: <https://github.com/sep2/vite-plugin-taro>
6
+ Vite 8 plugin for building one React 19 + Taro 4 app as either Web (`h5`) or WeChat Mini Program (`wx`).
8
7
 
9
- ## Features
8
+ ## Highlights
10
9
 
11
- - `wx` target: emits WeChat Mini Program JS/JSON/WXML/WXSS assets.
12
- - `h5` target: emits a Web app using the Taro H5 runtime and router.
13
- - React 19 support via patched Taro runtime packages published as npm aliases.
14
- - No app-side `patchedDependencies` required.
15
- - Taro-style conditional compilation comments for TS/JS/JSX/TSX and style files.
16
- - Target-specific Vite/Rolldown and WeChat output setup.
10
+ - Builds the same React/Taro pages for `h5` and `wx` targets.
11
+ - Uses React 19-compatible Taro React packages published by this monorepo.
12
+ - Generates Taro-style app/page entries instead of requiring generated files in your app source.
13
+ - Emits WeChat Mini Program assets: `app.json`, page JSON, WXML, WXS, WXSS, and CommonJS chunks.
14
+ - Boots H5 with Taro's official router/runtime and component CSS.
15
+ - Handles Tailwind CSS v4 for H5 and transforms Tailwind output for WeChat Mini Programs.
16
+ - Strips inactive Taro-style conditional compilation blocks before Vite parses code.
17
+ - Provides app-facing facades for Taro APIs and components.
18
+
19
+ ## Compatibility
20
+
21
+ | Dependency | Supported version |
22
+ | --- | --- |
23
+ | Node.js | `^20.19.0` or `>=22.12.0` |
24
+ | Vite | `^8.0.0` |
25
+ | React / React DOM | `^19.0.0` |
26
+ | Taro runtime packages | `4.2.0` |
27
+ | Tailwind CSS | `4.x` |
17
28
 
18
29
  ## Install
19
30
 
20
31
  ```sh
21
- pnpm add -D vite-plugin-taro vite
32
+ pnpm add -D vite vite-plugin-taro
22
33
  pnpm add react react-dom
23
34
  ```
24
35
 
25
- ## Vite usage
36
+ ## Package exports
37
+
38
+ | Import | Use |
39
+ | --- | --- |
40
+ | `vite-plugin-taro/vite` | Recommended Vite plugin entry. Exports the default plugin plus option/target types. |
41
+ | `vite-plugin-taro` | Same plugin entry as `vite-plugin-taro/vite`. |
42
+ | `vite-plugin-taro/components` | Re-export of Taro React components. Use this in application code. |
43
+ | `vite-plugin-taro/taro` | Taro API facade. Use this instead of importing `@tarojs/taro` directly. |
44
+ | `vite-plugin-taro/shim/h5` | Internal H5 runtime shim used by generated entries. |
45
+ | `vite-plugin-taro/shim/wx` | Internal WeChat runtime shim used by generated entries. |
46
+
47
+ Application code should normally use only `vite-plugin-taro/components` and `vite-plugin-taro/taro`.
48
+
49
+ ## Minimal setup
50
+
51
+ ### Vite config
26
52
 
27
53
  ```ts
28
- import taro from 'vite-plugin-taro/vite'
29
54
  import { defineConfig, loadEnv } from 'vite'
55
+ import vitePluginTaro, { type VitePluginTaroTarget } from 'vite-plugin-taro/vite'
56
+
57
+ function getTarget(value: string | undefined): VitePluginTaroTarget {
58
+ if (value === 'h5' || value === 'wx') return value
59
+ throw new Error('VITE_PLUGIN_TARO_TARGET must be "h5" or "wx".')
60
+ }
30
61
 
31
62
  export default defineConfig(({ mode }) => {
32
63
  const env = loadEnv(mode, process.cwd(), 'VITE_PLUGIN_TARO_')
33
- const target = env.VITE_PLUGIN_TARO_TARGET as 'wx' | 'h5'
64
+ const target = getTarget(env.VITE_PLUGIN_TARO_TARGET)
34
65
 
35
66
  return {
36
67
  base: target === 'h5' ? './' : undefined,
68
+ build: {
69
+ outDir: `dist/${target}`
70
+ },
37
71
  plugins: [
38
- taro({
72
+ vitePluginTaro({
39
73
  target,
40
74
  app: 'src/app.ts',
41
- pages: [{ path: 'pages/index/index', config: {} }],
75
+ pages: [
76
+ {
77
+ path: 'pages/index/index',
78
+ config: {
79
+ navigationBarTitleText: 'Home'
80
+ }
81
+ }
82
+ ],
42
83
  appJson: {},
43
84
  projectConfigJson: {
44
85
  appid: env.VITE_PLUGIN_TARO_WECHAT_APP_ID || 'touristappid'
45
86
  },
46
- sitemapJson: { rules: [{ action: 'allow', page: '*' }] }
87
+ sitemapJson: {
88
+ rules: [{ action: 'allow', page: '*' }]
89
+ }
47
90
  })
48
91
  ]
49
92
  }
50
93
  })
51
94
  ```
52
95
 
53
- Example scripts:
96
+ ### App component
54
97
 
55
- ```json
56
- {
57
- "scripts": {
58
- "build:h5": "NODE_ENV=production VITE_PLUGIN_TARO_TARGET=h5 vite build",
59
- "build:wx": "NODE_ENV=production VITE_PLUGIN_TARO_TARGET=wx vite build",
60
- "dev:h5": "NODE_ENV=development VITE_PLUGIN_TARO_TARGET=h5 vite",
61
- "dev:wx": "NODE_ENV=development VITE_PLUGIN_TARO_TARGET=wx vite build --watch"
62
- }
63
- }
64
- ```
98
+ `app` points to a module that default-exports the root React app component.
65
99
 
66
- Application code should usually import only from the plugin virtual modules. `virtual:taro` is default-export only; call APIs as `Taro.xxx`.
100
+ ```tsx
101
+ // src/app.ts
102
+ import type { PropsWithChildren } from 'react'
103
+ import Taro from 'vite-plugin-taro/taro'
104
+ import './app.css'
67
105
 
68
- ```ts
69
- import Taro from 'virtual:taro'
70
- import { Text, View } from 'virtual:taro/components'
106
+ export default function App({ children }: PropsWithChildren) {
107
+ Taro.useLaunch(() => {
108
+ console.log('App launch')
109
+ })
71
110
 
72
- Taro.useLaunch(() => {})
73
- Taro.getWindowInfo()
111
+ return children
112
+ }
74
113
  ```
75
114
 
76
- For Taro namespace types:
115
+ ### Page component
77
116
 
78
- ```ts
79
- import type Taro from 'virtual:taro'
117
+ Each `pages[].path` maps to `src/${path}.tsx`.
80
118
 
81
- type Color = Taro.Color
82
- ```
119
+ ```tsx
120
+ // src/pages/index/index.tsx
121
+ import { Text, View } from 'vite-plugin-taro/components'
122
+ import Taro from 'vite-plugin-taro/taro'
83
123
 
84
- Add the virtual module declarations to the app `tsconfig.json`:
124
+ export default function IndexPage() {
125
+ const windowInfo = Taro.getWindowInfo()
85
126
 
86
- ```json
87
- {
88
- "compilerOptions": {
89
- "types": ["vite/client", "vite-plugin-taro/client"]
90
- }
127
+ return (
128
+ <View>
129
+ <Text>Viewport width: {windowInfo.windowWidth}</Text>
130
+ </View>
131
+ )
91
132
  }
92
133
  ```
93
134
 
94
- ## Styling
135
+ ### HTML shell for H5
95
136
 
96
- `vite-plugin-taro` does not bundle a Tailwind or `weapp-tailwindcss` pipeline. Add styling plugins directly in the app's Vite config when needed. See [`loan-genius`](../loan-genius) for an example using Tailwind v4 and `weapp-tailwindcss`.
137
+ For H5 builds, keep a normal Vite `index.html`. The plugin injects the generated Taro H5 entry automatically.
97
138
 
98
- ## Options
139
+ ```html
140
+ <div id="app"></div>
141
+ ```
142
+
143
+ ## Plugin options
99
144
 
100
145
  ```ts
101
- type TaroTarget = 'wx' | 'h5'
146
+ type VitePluginTaroTarget = 'wx' | 'h5'
102
147
 
103
- type TaroPageOption = {
148
+ type VitePluginTaroPageOption = {
104
149
  path: string
105
150
  config: Record<string, unknown>
106
151
  }
107
152
 
108
- interface TaroPluginOptions {
109
- target: TaroTarget
153
+ type VitePluginTaroOptions = {
154
+ target: VitePluginTaroTarget
110
155
  app: string
111
- pages: TaroPageOption[]
156
+ pages: VitePluginTaroPageOption[]
112
157
  appJson: Record<string, unknown>
113
158
  projectConfigJson: Record<string, unknown>
114
159
  sitemapJson: Record<string, unknown>
@@ -117,33 +162,35 @@ interface TaroPluginOptions {
117
162
 
118
163
  | Option | Description |
119
164
  | --- | --- |
120
- | `target` | Active build target: `wx` or `h5`. |
165
+ | `target` | Active target for this Vite invocation: `h5` or `wx`. |
121
166
  | `app` | Source file that default-exports the root React app component. |
122
- | `pages` | Ordered page list. Also becomes `app.json.pages` and H5 route order. |
123
- | `appJson` | Base `app.json` content. `pages` is overwritten from `pages`. |
124
- | `projectConfigJson` | `project.config.json` emitted for WeChat builds. |
125
- | `sitemapJson` | `sitemap.json` emitted for WeChat builds. |
167
+ | `pages` | Ordered page list. The order becomes `app.json.pages` and the H5 route order. |
168
+ | `pages[].path` | Taro-style route and output path without extension, for example `pages/index/index`. The page component must exist at `src/${path}.tsx`. |
169
+ | `pages[].config` | Page JSON config merged into WeChat page JSON and H5 route config. |
170
+ | `appJson` | Base app config. The plugin overwrites `pages` from `options.pages`. |
171
+ | `projectConfigJson` | WeChat `project.config.json` content emitted for `wx` builds. |
172
+ | `sitemapJson` | WeChat `sitemap.json` content emitted for `wx` builds. |
126
173
 
127
- ## App virtual modules
174
+ ## Scripts in your app
128
175
 
129
- | Import | Purpose |
130
- | --- | --- |
131
- | `virtual:taro` | Default-only Taro API facade. Use this instead of importing `@tarojs/taro` directly. |
132
- | `virtual:taro/components` | Re-export of `@tarojs/components`. Use this in app code. |
176
+ Use separate scripts or environment files to build each target.
133
177
 
134
- ## Package exports
178
+ ```json
179
+ {
180
+ "scripts": {
181
+ "dev:h5": "VITE_PLUGIN_TARO_TARGET=h5 vite",
182
+ "build:h5": "VITE_PLUGIN_TARO_TARGET=h5 vite build",
183
+ "dev:wx": "VITE_PLUGIN_TARO_TARGET=wx vite build --watch",
184
+ "build:wx": "VITE_PLUGIN_TARO_TARGET=wx vite build"
185
+ }
186
+ }
187
+ ```
135
188
 
136
- | Import | Purpose |
137
- | --- | --- |
138
- | `vite-plugin-taro` | Default Vite plugin entry. |
139
- | `vite-plugin-taro/vite` | Default Vite plugin entry. |
140
- | `vite-plugin-taro/client` | Type declarations for `virtual:taro` and `virtual:taro/components`. |
141
- | `vite-plugin-taro/shim/h5` | H5 runtime shim used by generated entries. |
142
- | `vite-plugin-taro/shim/wx` | WeChat runtime shim used by generated entries. |
189
+ On Windows shells, use `cross-env` or your package manager's environment-file support.
143
190
 
144
191
  ## Conditional compilation
145
192
 
146
- vite-plugin-taro strips inactive Taro-style conditional comment blocks before Vite parses source files. Supported files include TypeScript, JavaScript, JSX/TSX, CSS, Sass, Less, and Stylus.
193
+ The plugin strips inactive Taro-style conditional comment blocks before Vite parses source files. Supported source types include TypeScript, JavaScript, JSX/TSX, CSS, Sass, Less, and Stylus.
147
194
 
148
195
  ```ts
149
196
  // #ifdef wx
@@ -163,62 +210,67 @@ console.log('fallback')
163
210
  // #endif
164
211
  ```
165
212
 
166
- Supported directives are `#ifdef`, `#ifndef`, `#if`, `#elif`, `#else`, and `#endif`. Expressions support simple target tokens with `!`, `&&`, and `||`.
213
+ Supported directives are `#ifdef`, `#ifndef`, `#if`, `#elif`, `#else`, and `#endif`. Expressions support target tokens with `!`, `&&`, and `||`.
167
214
 
168
- ## Target output
169
-
170
- ### `wx`
215
+ ## Styling
171
216
 
172
- vite-plugin-taro configures Rolldown for WeChat-compatible CommonJS chunks and emits Mini Program assets including:
217
+ - H5 builds use `@tailwindcss/vite`.
218
+ - WeChat builds use `weapp-tailwindcss` with Tailwind CSS v4 support, `px`/`rem` to `rpx` conversion, and WeChat-compatible selector output.
219
+ - CSS emitted by Vite for `wx` is collected into `app.wxss`; page-level `.wxss` files are emitted as companions.
220
+ - Import global styles from the app component, for example `import './app.css'`.
173
221
 
174
- - `app.js`, `app.json`, `app.wxss`.
175
- - Page `*.js`, `*.json`, `*.wxml`, and `*.wxss` files.
176
- - Shared Taro recursive template assets: `base.wxml`, `comp.js`, `comp.json`, `comp.wxml`, `utils.wxs`.
177
- - `project.config.json` and `sitemap.json`.
222
+ ## Target outputs
178
223
 
179
224
  ### `h5`
180
225
 
181
- vite-plugin-taro injects a virtual module into `index.html`, creates Taro H5 route records from `pages`, and mounts the app with Taro's hash-history router.
226
+ The plugin injects a virtual module into `index.html`, imports Taro's component styles, creates H5 route records from `pages`, mounts the root app, and uses Taro's hash-history router.
182
227
 
183
- For GitHub Pages or any subpath deployment, set a relative/base path in Vite, for example:
228
+ Typical output directory:
184
229
 
185
- ```ts
186
- export default defineConfig({
187
- base: './'
188
- })
230
+ ```text
231
+ dist/h5/
189
232
  ```
190
233
 
191
- ## React 19 compatibility
192
-
193
- Taro 4.2's official React runtime targets React 18. vite-plugin-taro depends on two small React 19-compatible runtime packages generated from the official Taro npm tarballs plus local patch files:
194
-
195
- - `vite-plugin-taro-react`
196
- - `vite-plugin-taro-plugin-framework-react`
197
-
198
- When packed/published by pnpm, workspace aliases become npm aliases to these patched packages:
234
+ ### `wx`
199
235
 
200
- ```json
201
- {
202
- "@tarojs/react": "npm:vite-plugin-taro-react@4.2.0-react19.2",
203
- "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@4.2.0-react19.2"
204
- }
236
+ The plugin configures Rolldown for WeChat-compatible CommonJS chunks and emits Mini Program companion files.
237
+
238
+ Typical output directory:
239
+
240
+ ```text
241
+ dist/wx/
242
+ ├── app.js
243
+ ├── app.json
244
+ ├── app.wxss
245
+ ├── base.wxml
246
+ ├── comp.js
247
+ ├── comp.json
248
+ ├── comp.wxml
249
+ ├── project.config.json
250
+ ├── sitemap.json
251
+ ├── utils.wxs
252
+ └── pages/**
205
253
  ```
206
254
 
207
- That means app users get React 19-compatible Taro runtime packages automatically and do not need local patches.
255
+ Open the `wx` output directory with WeChat DevTools.
208
256
 
209
- ## Publishing from this repository
257
+ ## Limitations
210
258
 
211
- ```sh
212
- pnpm install
213
- pnpm publish:dry
214
- pnpm publish:all
259
+ - Supported targets are currently `h5` and WeChat Mini Program (`wx`). Other Taro platforms are not generated by this plugin.
260
+ - Page modules follow the fixed convention `src/${page.path}.tsx`.
261
+ - `projectConfigJson` and `sitemapJson` are required by the option type even though they are only emitted for `wx` builds.
262
+ - Import Taro APIs/components through `vite-plugin-taro/taro` and `vite-plugin-taro/components`; direct `@tarojs/*` imports can bypass target aliases.
215
263
 
216
- # If npm 2FA is enabled:
217
- pnpm publish:all -- --otp 123456
218
- ```
264
+ ## Troubleshooting
219
265
 
220
- The package publishes built ESM JavaScript and `.d.ts` files from `dist`.
266
+ | Problem | Check |
267
+ | --- | --- |
268
+ | `VITE_PLUGIN_TARO_TARGET must be "h5" or "wx"` | Set the target environment variable before running Vite. |
269
+ | A page cannot be resolved | Confirm that `pages[].path` has a matching `src/${path}.tsx` file. |
270
+ | H5 component styles load in the wrong order | Make sure the plugin is registered and `vite-plugin-taro/components` is used for components. |
271
+ | WeChat DevTools cannot open the project | Check `projectConfigJson.appid` and open the generated `dist/wx` directory, not the source package. |
272
+ | Taro APIs behave differently per target | Import from `vite-plugin-taro/taro` so the plugin can apply target-specific runtime aliases and H5 API transforms. |
221
273
 
222
274
  ## License
223
275
 
224
- MIT.
276
+ MIT. See [`LICENSE`](LICENSE).
@@ -0,0 +1 @@
1
+ export * from '@tarojs/components';
@@ -0,0 +1,8 @@
1
+ import { hooks } from '@tarojs/runtime';
2
+ import Taro from '@tarojs/taro';
3
+ if (hooks.isExist('initNativeApi')) {
4
+ hooks.call('initNativeApi', Taro);
5
+ }
6
+ // @ts-expect-error @tarojs/taro declares export= types, but vite-plugin-taro target aliases expose runtime named exports.
7
+ export * from '@tarojs/taro';
8
+ export default Taro;
package/dist/shim/h5.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import '@tarojs/plugin-platform-h5/dist/runtime';
2
- import '@tarojs/components/global.css';
3
2
  // @ts-expect-error Taro exposes createReactApp from this runtime-only deep entry without types.
4
3
  export { createReactApp } from '@tarojs/plugin-framework-react/dist/runtime';
5
4
  export { createBrowserHistory, createHashHistory, createRouter, handleAppMount } from '@tarojs/router';
@@ -4,7 +4,7 @@ import { normalizeModuleId } from './utils.js';
4
4
  *
5
5
  * Mirrors Taro's CSS #ifdef/#ifndef handling, generalized before Vite parses code.
6
6
  */
7
- export function createTaroConditionalDirectivePlugin(context) {
7
+ export function createVitePluginTaroConditionalDirectivePlugin(context) {
8
8
  const target = context.target;
9
9
  return {
10
10
  name: 'vite-plugin-taro-conditional-directives',
@@ -19,7 +19,7 @@ export function createTaroConditionalDirectivePlugin(context) {
19
19
  /**
20
20
  * Filters files where Taro's conditional comments are meaningful.
21
21
  *
22
- * vite-plugin-taro-only: source filter for vite-plugin-taro's generalized conditional-directive transform.
22
+ * Plugin-only: source filter for generalized conditional-directive transform.
23
23
  */
24
24
  function isConditionalDirectiveSource(id) {
25
25
  const normalizedId = normalizeModuleId(id);
@@ -85,7 +85,7 @@ function toConditionalDirectiveName(value) {
85
85
  /**
86
86
  * Updates the active conditional stack using Taro-style #ifdef/#ifndef/#else/#endif semantics.
87
87
  *
88
- * vite-plugin-taro-only: stack-based #if/#elif/#else support has no Taro webpack counterpart.
88
+ * Plugin-only: stack-based #if/#elif/#else support has no Taro webpack counterpart.
89
89
  */
90
90
  function updateConditionalDirectiveFrames(frames, directive, target) {
91
91
  if (directive.name === 'ifdef' || directive.name === 'ifndef' || directive.name === 'if') {
@@ -128,9 +128,9 @@ function evaluateConditionalDirective(directive, target) {
128
128
  return evaluateConditionalExpression(directive.expression, target);
129
129
  }
130
130
  /**
131
- * Supports simple #if expressions with !, &&, and || over vite-plugin-taro target tokens.
131
+ * Supports simple #if expressions with !, &&, and || over the configured target token.
132
132
  *
133
- * vite-plugin-taro-only: #if expressions with && and || have no Taro webpack counterpart.
133
+ * Plugin-only: #if expressions with && and || have no Taro webpack counterpart.
134
134
  */
135
135
  function evaluateConditionalExpression(expression, target) {
136
136
  const orTerms = expression.split('||');
@@ -141,9 +141,9 @@ function evaluateConditionalExpression(expression, target) {
141
141
  .every((factor) => evaluateConditionalFactor(factor, target)));
142
142
  }
143
143
  /**
144
- * Evaluates one vite-plugin-taro target token, optionally negated.
144
+ * Evaluates one target token, optionally negated.
145
145
  *
146
- * vite-plugin-taro-only: negated #if factors have no Taro webpack counterpart.
146
+ * Plugin-only: negated #if factors have no Taro webpack counterpart.
147
147
  */
148
148
  function evaluateConditionalFactor(factor, target) {
149
149
  let token = factor.replace(/[()]/g, '').trim();
@@ -156,7 +156,7 @@ function evaluateConditionalFactor(factor, target) {
156
156
  return negated ? !matched : matched;
157
157
  }
158
158
  /**
159
- * Checks whether a directive target list includes the current vite-plugin-taro target.
159
+ * Checks whether a directive target list includes the current target.
160
160
  *
161
161
  * Mirrors Taro's simple CSS platform membership checks.
162
162
  */
@@ -170,7 +170,7 @@ function matchesDirectiveTarget(expression, target) {
170
170
  /**
171
171
  * Preserves source line counts when conditional blocks are stripped.
172
172
  *
173
- * vite-plugin-taro-only: preserves Vite source-map line counts while stripping conditional blocks.
173
+ * Plugin-only: preserves Vite source-map line counts while stripping conditional blocks.
174
174
  */
175
175
  function getLineEnding(line) {
176
176
  const match = line.match(/\r?\n$/);
@@ -179,7 +179,7 @@ function getLineEnding(line) {
179
179
  /**
180
180
  * Returns whether all active nested conditional frames include the current line.
181
181
  *
182
- * vite-plugin-taro-only: stack activity helper for generalized conditional directives.
182
+ * Plugin-only: stack activity helper for generalized conditional directives.
183
183
  */
184
184
  function isDirectiveStackActive(frames) {
185
185
  return frames.every((frame) => frame.active);
@@ -0,0 +1,35 @@
1
+ import tailwindcss from '@tailwindcss/vite';
2
+ import { WeappTailwindcss } from 'weapp-tailwindcss/vite';
3
+ export function createTailwindcssPlugins(context) {
4
+ if (context.target === 'h5')
5
+ return [tailwindcss()];
6
+ const plugins = WeappTailwindcss({
7
+ appType: 'taro',
8
+ generator: {
9
+ target: 'weapp'
10
+ },
11
+ tailwindcss: {
12
+ version: 4,
13
+ packageName: 'tailwindcss'
14
+ },
15
+ cssCalc: false,
16
+ // skyline does not support -webkit prefix.
17
+ autoprefixer: false,
18
+ postcssOptions: {
19
+ // Tailwind v4 prod mode emits legacy :before/:after selectors; skyline requires ::before/::after.
20
+ plugins: [createWechatPseudoElementPlugin()]
21
+ },
22
+ rem2rpx: true,
23
+ px2rpx: true
24
+ });
25
+ return plugins ?? [];
26
+ }
27
+ function createWechatPseudoElementPlugin() {
28
+ const legacyPseudoElementPattern = /(?<!:):(before|after)\b/g;
29
+ return {
30
+ postcssPlugin: 'vite-plugin-taro-wechat-pseudo-elements',
31
+ Rule(rule) {
32
+ rule.selector = rule.selector.replace(legacyPseudoElementPattern, '::$1');
33
+ }
34
+ };
35
+ }
@@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react';
3
3
  import { isProd, nodeRequire } from '../constants.js';
4
4
  import { createPageComponentImport } from '../utils.js';
5
5
  const virtualH5Id = 'virtual:vite-plugin-taro/h5';
6
+ const patchStencilCssOrder = true;
6
7
  /**
7
8
  * Checks whether an id belongs to an H5 virtual module.
8
9
  */
@@ -26,6 +27,17 @@ export function createH5ViteConfig() {
26
27
  resolve: {
27
28
  mainFields: ['main:h5', 'browser', 'module', 'jsnext:main', 'jsnext'],
28
29
  alias: [
30
+ // Resolve Stencil's transitive runtime import after Taro components are optimized separately.
31
+ ...(patchStencilCssOrder
32
+ ? [
33
+ {
34
+ find: /^@stencil\/core\/internal\/client$/,
35
+ replacement: nodeRequire.resolve('@stencil/core/internal/client', {
36
+ paths: [nodeRequire.resolve('@tarojs/components/package.json')]
37
+ })
38
+ }
39
+ ]
40
+ : []),
29
41
  // H5 React code must use Taro's React component wrappers, not the raw custom-element entry.
30
42
  { find: /^@tarojs\/components$/, replacement: nodeRequire.resolve('@tarojs/components/lib/react') },
31
43
  // Taro's H5 router/components deep-import this custom-element loader; make it resolvable under pnpm.
@@ -40,6 +52,10 @@ export function createH5ViteConfig() {
40
52
  }
41
53
  ]
42
54
  },
55
+ optimizeDeps: {
56
+ // Keep the Stencil runtime in Vite's transform pipeline so rewriteStencilStyleInsertion can patch it.
57
+ exclude: [patchStencilCssOrder ? '@stencil/core/internal/client' : ''].filter(Boolean)
58
+ },
43
59
  build: {
44
60
  target: 'es2018',
45
61
  minify: isProd
@@ -52,21 +68,44 @@ export function createH5ViteConfig() {
52
68
  * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-platform-h5/src/program.ts#L219-L249
53
69
  */
54
70
  export function createH5SupportPlugins() {
55
- return [
56
- ...react(),
57
- // Mirrors Taro H5: rewrite default Taro.xxx calls from virtual:taro to named H5 API imports.
58
- babel({
59
- plugins: [
60
- [
61
- nodeRequire.resolve('babel-plugin-transform-taroapi'),
62
- {
63
- packageName: 'virtual:taro',
64
- definition: nodeRequire(nodeRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json'))
65
- }
66
- ]
71
+ const plugins = [...react()];
72
+ if (patchStencilCssOrder) {
73
+ plugins.push(babel({
74
+ include: /[\\/]@stencil[\\/]core[\\/]internal[\\/]client[\\/]index\.js(?:\?.*)?$/,
75
+ exclude: [],
76
+ plugins: [rewriteStencilStyleInsertion]
77
+ }));
78
+ }
79
+ // Mirrors Taro H5: rewrite default Taro.xxx calls from vite-plugin-taro/taro to named H5 API imports.
80
+ plugins.push(babel({
81
+ plugins: [
82
+ [
83
+ nodeRequire.resolve('babel-plugin-transform-taroapi'),
84
+ {
85
+ packageName: 'vite-plugin-taro/taro',
86
+ definition: nodeRequire(nodeRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json'))
87
+ }
67
88
  ]
68
- })
69
- ];
89
+ ]
90
+ }));
91
+ return plugins;
92
+ }
93
+ function rewriteStencilStyleInsertion() {
94
+ return {
95
+ name: 'rewrite-stencil-style-insertion',
96
+ visitor: {
97
+ CallExpression(path) {
98
+ if (!isStencilStyleInsertBeforeCall(path))
99
+ return;
100
+ path.get('arguments.1').replaceWithSourceString(`scopeId.startsWith('sc-taro-') ? styleContainerNode.querySelector('style,link[rel="stylesheet"]') : styleContainerNode.querySelector('link')`);
101
+ }
102
+ }
103
+ };
104
+ }
105
+ function isStencilStyleInsertBeforeCall(path) {
106
+ return (path.get('callee').matchesPattern('styleContainerNode.insertBefore') &&
107
+ path.get('arguments.0').toString() === 'styleElm' &&
108
+ path.get('arguments.1').toString() === "styleContainerNode.querySelector('link')");
70
109
  }
71
110
  /**
72
111
  * Creates compile-time constants expected by Taro's Web runtime packages.
@@ -102,14 +141,16 @@ export function createWebIndexHtmlTags(context) {
102
141
  }
103
142
  /**
104
143
  * Builds the generated Web entry around Taro's official Web router/runtime APIs.
105
- * vite-plugin-taro omits Taro's generated pxTransform initialization; apps should handle style transforms in their own Vite pipeline.
144
+ * Base Taro CSS is imported before the app; component CSS order is handled by rewriteStencilStyleInsertion.
106
145
  *
107
146
  * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/h5.ts#L120-L150
108
147
  */
109
148
  export function createWebEntry(context) {
110
149
  const webAppConfigCode = JSON.stringify(createWebAppConfig(context.appConfig));
111
150
  const webRoutesConfigCode = createWebRoutesConfig(context.pages);
112
- return `import {
151
+ return `import ${JSON.stringify(nodeRequire.resolve('@tarojs/components/global.css'))}
152
+ import ${JSON.stringify(nodeRequire.resolve('@tarojs/components/dist/taro-components/taro-components.css'))}
153
+ import {
113
154
  createHashHistory,
114
155
  createReactApp,
115
156
  createRouter,
@@ -29,7 +29,7 @@ export function loadWxVirtualModule(cleanId, context) {
29
29
  }
30
30
  }
31
31
  const taroWechatComponentsReactPath = nodeRequire.resolve('@tarojs/plugin-platform-weapp/dist/components-react');
32
- const pluginSourcePath = normalizeModuleId(path.dirname(nodeRequire.resolve('vite-plugin-taro/vite')));
32
+ const vitePluginTaroSourcePath = normalizeModuleId(path.dirname(nodeRequire.resolve('vite-plugin-taro/vite')));
33
33
  const taroVersion = String(nodeRequire('@tarojs/runtime/package.json').version);
34
34
  /**
35
35
  * Configures wx target entry, output, and chunk layout.
@@ -107,9 +107,7 @@ function createWechatTaroDefines() {
107
107
  */
108
108
  function isWxTaroChunkModule(id) {
109
109
  const normalizedId = normalizeModuleId(id);
110
- return (normalizedId.includes('/node_modules/@tarojs/') ||
111
- normalizedId.startsWith(`${pluginSourcePath}/`) ||
112
- normalizedId.includes('virtual:taro'));
110
+ return normalizedId.includes('/node_modules/@tarojs/') || normalizedId.startsWith(`${vitePluginTaroSourcePath}/`);
113
111
  }
114
112
  /**
115
113
  * Names Rolldown's helper chunk like Taro webpack's runtime chunk.
@@ -156,7 +154,7 @@ export function emitWechatImplicitChunksForVirtualApp(emitter, context, cleanId)
156
154
  }
157
155
  /**
158
156
  * Builds the generated WeChat app entry that registers Taro's React App config.
159
- * vite-plugin-taro omits Taro's generated pxTransform initialization; apps should handle style transforms in their own Vite pipeline.
157
+ * vite-plugin-taro omits Taro's generated pxTransform initialization because styles are handled by Tailwind.
160
158
  *
161
159
  * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/app.ts#L54-L63
162
160
  */