vite-plugin-taro 0.0.2 → 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.
Files changed (42) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +205 -54
  3. package/dist/public/components.js +1 -1
  4. package/dist/public/taro.js +8 -10
  5. package/dist/shim/h5.js +5 -6
  6. package/dist/shim/wx.js +5 -5
  7. package/dist/vite/constants.js +3 -0
  8. package/dist/vite/plugins.js +186 -0
  9. package/dist/vite/tailwindcss.js +35 -0
  10. package/dist/vite/targets/h5.js +202 -0
  11. package/dist/vite/targets/wx.js +364 -0
  12. package/dist/vite/types.js +1 -0
  13. package/dist/vite/{utils.d.ts → utils.js} +13 -4
  14. package/dist/vite/vite-plugin-taro.js +80 -0
  15. package/dist/vite.js +1 -851
  16. package/package.json +23 -24
  17. package/src/public/components.ts +1 -0
  18. package/src/public/taro.ts +10 -0
  19. package/src/shim/h5.ts +6 -0
  20. package/src/shim/wx.ts +6 -0
  21. package/src/vite/constants.ts +5 -0
  22. package/src/vite/plugins.ts +218 -0
  23. package/src/vite/tailwindcss.ts +41 -0
  24. package/src/vite/targets/h5.ts +230 -0
  25. package/src/vite/targets/wx.ts +438 -0
  26. package/{dist/vite/types.d.ts → src/vite/types.ts} +31 -21
  27. package/src/vite/utils.ts +35 -0
  28. package/src/vite/vite-plugin-taro.ts +105 -0
  29. package/src/vite.ts +2 -0
  30. package/dist/public/components.d.ts +0 -1
  31. package/dist/public/taro.js.map +0 -1
  32. package/dist/shim/h5.d.ts +0 -3
  33. package/dist/shim/wx.d.ts +0 -3
  34. package/dist/vite/constants.d.ts +0 -2
  35. package/dist/vite/plugins.d.ts +0 -8
  36. package/dist/vite/tailwindcss.d.ts +0 -3
  37. package/dist/vite/targets/h5.d.ts +0 -31
  38. package/dist/vite/targets/wx.d.ts +0 -74
  39. package/dist/vite/taro.d.ts +0 -7
  40. package/dist/vite.d.ts +0 -2
  41. package/dist/vite.js.map +0 -1
  42. /package/{dist → src}/public/taro.d.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-taro",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Vite 8 plugin for building one React/Taro codebase for WeChat Mini Program and H5 targets.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -14,42 +14,42 @@
14
14
  "homepage": "https://github.com/sep2/vite-plugin-taro/tree/main/packages/vite-plugin-taro#readme",
15
15
  "main": "./dist/vite.js",
16
16
  "module": "./dist/vite.js",
17
- "types": "./dist/vite.d.ts",
18
17
  "exports": {
19
18
  ".": {
20
- "types": "./dist/vite.d.ts",
21
- "import": "./dist/vite.js",
22
- "default": "./dist/vite.js"
23
- },
24
- "./vite": {
25
- "types": "./dist/vite.d.ts",
19
+ "types": "./src/vite.ts",
26
20
  "import": "./dist/vite.js",
27
21
  "default": "./dist/vite.js"
28
22
  },
29
23
  "./components": {
30
- "types": "./dist/public/components.d.ts",
24
+ "types": "./src/public/components.ts",
31
25
  "import": "./dist/public/components.js",
32
26
  "default": "./dist/public/components.js"
33
27
  },
34
28
  "./taro": {
35
- "types": "./dist/public/taro.d.ts",
29
+ "types": "./src/public/taro.d.ts",
36
30
  "import": "./dist/public/taro.js",
37
31
  "default": "./dist/public/taro.js"
38
32
  },
39
33
  "./shim/h5": {
40
- "types": "./dist/shim/h5.d.ts",
34
+ "types": "./src/shim/h5.ts",
41
35
  "import": "./dist/shim/h5.js",
42
36
  "default": "./dist/shim/h5.js"
43
37
  },
44
38
  "./shim/wx": {
45
- "types": "./dist/shim/wx.d.ts",
39
+ "types": "./src/shim/wx.ts",
46
40
  "import": "./dist/shim/wx.js",
47
41
  "default": "./dist/shim/wx.js"
48
42
  },
43
+ "./vite": {
44
+ "types": "./src/vite.ts",
45
+ "import": "./dist/vite.js",
46
+ "default": "./dist/vite.js"
47
+ },
49
48
  "./package.json": "./package.json"
50
49
  },
51
50
  "files": [
52
51
  "dist",
52
+ "src",
53
53
  "LICENSE",
54
54
  "README.md"
55
55
  ],
@@ -70,7 +70,9 @@
70
70
  "node": "^20.19.0 || >=22.12.0"
71
71
  },
72
72
  "dependencies": {
73
+ "@babel/core": "^7.29.7",
73
74
  "@rolldown/plugin-babel": "^0.2.3",
75
+ "@tailwindcss/vite": "^4.3.1",
74
76
  "@tarojs/components": "^4.2.0",
75
77
  "@tarojs/helper": "^4.2.0",
76
78
  "@tarojs/plugin-platform-h5": "^4.2.0",
@@ -80,10 +82,10 @@
80
82
  "@tarojs/taro": "^4.2.0",
81
83
  "@vitejs/plugin-react": "^6.0.2",
82
84
  "babel-plugin-transform-taroapi": "^4.2.0",
83
- "tailwindcss": "^4.3.0",
84
- "weapp-tailwindcss": "^5.0.5",
85
- "@tarojs/react": "npm:vite-plugin-taro-react@4.2.0-react19.1",
86
- "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@4.2.0-react19.1"
85
+ "tailwindcss": "^4.3.1",
86
+ "weapp-tailwindcss": "^5.0.13",
87
+ "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@4.2.0-react19.3",
88
+ "@tarojs/react": "npm:vite-plugin-taro-react@4.2.0-react19.3"
87
89
  },
88
90
  "peerDependencies": {
89
91
  "react": "^19.0.0",
@@ -91,16 +93,13 @@
91
93
  "vite": "^8.0.0"
92
94
  },
93
95
  "devDependencies": {
94
- "@types/node": "^24.10.1",
96
+ "@types/babel__core": "^7.20.5",
97
+ "@types/node": "^26.0.0",
95
98
  "@typescript/native-preview": "latest",
96
- "typescript": "^5.9.3",
97
- "vite": "^8.0.16",
98
- "vite-plugin-dts": "^5.0.2"
99
+ "vite": "^8.0.16"
99
100
  },
100
101
  "scripts": {
101
- "clean": "rm -rf dist",
102
- "build": "pnpm -w prepare:taro && pnpm clean && vite build",
103
- "typecheck": "pnpm -w prepare:taro && tsgo --project tsconfig.json",
104
- "pack:dry": "pnpm pack --dry-run"
102
+ "build": "rm -rf dist && tsgo --project tsconfig.json",
103
+ "typecheck": "tsgo --project tsconfig.json --noEmit"
105
104
  }
106
105
  }
@@ -0,0 +1 @@
1
+ export * from '@tarojs/components'
@@ -0,0 +1,10 @@
1
+ import { hooks } from '@tarojs/runtime'
2
+ import Taro from '@tarojs/taro'
3
+
4
+ if (hooks.isExist('initNativeApi')) {
5
+ hooks.call('initNativeApi', Taro)
6
+ }
7
+
8
+ // @ts-expect-error @tarojs/taro declares export= types, but vite-plugin-taro target aliases expose runtime named exports.
9
+ export * from '@tarojs/taro'
10
+ export default Taro
package/src/shim/h5.ts ADDED
@@ -0,0 +1,6 @@
1
+ import '@tarojs/plugin-platform-h5/dist/runtime'
2
+
3
+ // @ts-expect-error Taro exposes createReactApp from this runtime-only deep entry without types.
4
+ export { createReactApp } from '@tarojs/plugin-framework-react/dist/runtime'
5
+ export { createBrowserHistory, createHashHistory, createRouter, handleAppMount } from '@tarojs/router'
6
+ export { window } from '@tarojs/runtime'
package/src/shim/wx.ts ADDED
@@ -0,0 +1,6 @@
1
+ import '@tarojs/plugin-platform-weapp/dist/runtime.js'
2
+
3
+ // @ts-expect-error Taro exposes createReactApp from this runtime-only deep entry without types.
4
+ export { createReactApp } from '@tarojs/plugin-framework-react/dist/runtime'
5
+ export { default as ReactDOM } from '@tarojs/react'
6
+ export { createPageConfig, createRecursiveComponentConfig } from '@tarojs/runtime'
@@ -0,0 +1,5 @@
1
+ import { createRequire } from 'node:module'
2
+
3
+ export const isProd = process.env.NODE_ENV === 'production'
4
+
5
+ export const nodeRequire = createRequire(import.meta.url)
@@ -0,0 +1,218 @@
1
+ import type { Plugin } from 'vite'
2
+ import type { VitePluginTaroBuildContext, VitePluginTaroTarget } from './types.ts'
3
+ import { normalizeModuleId } from './utils.ts'
4
+
5
+ /**
6
+ * Applies Taro-style conditional compilation comments before Vite parses source files.
7
+ *
8
+ * Mirrors Taro's CSS #ifdef/#ifndef handling, generalized before Vite parses code.
9
+ */
10
+ export function createVitePluginTaroConditionalDirectivePlugin(context: VitePluginTaroBuildContext): Plugin {
11
+ const target = context.target
12
+ return {
13
+ name: 'vite-plugin-taro-conditional-directives',
14
+ enforce: 'pre',
15
+ transform(code, id) {
16
+ if (!isConditionalDirectiveSource(id) || !code.includes('#if')) return
17
+ return { code: transformConditionalDirectives(code, target), map: null }
18
+ }
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Filters files where Taro's conditional comments are meaningful.
24
+ *
25
+ * Plugin-only: source filter for generalized conditional-directive transform.
26
+ */
27
+ function isConditionalDirectiveSource(id: string): boolean {
28
+ const normalizedId = normalizeModuleId(id)
29
+ if (normalizedId.includes('/node_modules/')) return false
30
+ return /\.(?:[cm]?[jt]sx?|css|s[ac]ss|less|styl)(?:\?|$)/.test(normalizedId)
31
+ }
32
+
33
+ type ConditionalDirectiveName = 'ifdef' | 'ifndef' | 'if' | 'elif' | 'else' | 'endif'
34
+
35
+ type ConditionalDirective = {
36
+ name: ConditionalDirectiveName
37
+ expression: string
38
+ }
39
+
40
+ type ConditionalDirectiveFrame = {
41
+ parentActive: boolean
42
+ active: boolean
43
+ matched: boolean
44
+ }
45
+
46
+ /**
47
+ * Removes inactive blocks guarded by Taro conditional comments.
48
+ *
49
+ * Mirrors Taro's CSS #ifdef/#ifndef handling.
50
+ */
51
+ function transformConditionalDirectives(code: string, target: VitePluginTaroTarget): string {
52
+ const lines = code.match(/[^\n]*(?:\n|$)/g) ?? []
53
+ const frames: ConditionalDirectiveFrame[] = []
54
+ let transformed = ''
55
+
56
+ for (const line of lines) {
57
+ if (!line) continue
58
+ const directive = parseConditionalDirective(line)
59
+ const lineEnding = getLineEnding(line)
60
+ if (directive) {
61
+ updateConditionalDirectiveFrames(frames, directive, target)
62
+ transformed += lineEnding
63
+ continue
64
+ }
65
+ transformed += isDirectiveStackActive(frames) ? line : lineEnding
66
+ }
67
+
68
+ return transformed
69
+ }
70
+
71
+ /**
72
+ * Parses one Taro conditional compilation directive from a comment-only line.
73
+ *
74
+ * Mirrors Taro's CSS comment-token handling.
75
+ */
76
+ function parseConditionalDirective(line: string): ConditionalDirective | undefined {
77
+ const match = line.match(/^\s*(?:(?:\/\/)|(?:\/\*))\s*#(ifdef|ifndef|if|elif|else|endif)\b([^*\r\n]*)/)
78
+ if (!match) return
79
+ const name = toConditionalDirectiveName(match[1])
80
+ if (!name) return
81
+ return {
82
+ name,
83
+ expression: match[2]?.replace(/\*\/$/, '').trim() ?? ''
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Converts a regex capture into a supported directive name.
89
+ *
90
+ * Mirrors Taro's CSS #ifdef/#ifndef/#endif token handling.
91
+ */
92
+ function toConditionalDirectiveName(value: string): ConditionalDirectiveName | undefined {
93
+ if (
94
+ value === 'ifdef' ||
95
+ value === 'ifndef' ||
96
+ value === 'if' ||
97
+ value === 'elif' ||
98
+ value === 'else' ||
99
+ value === 'endif'
100
+ ) {
101
+ return value
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Updates the active conditional stack using Taro-style #ifdef/#ifndef/#else/#endif semantics.
107
+ *
108
+ * Plugin-only: stack-based #if/#elif/#else support has no Taro webpack counterpart.
109
+ */
110
+ function updateConditionalDirectiveFrames(
111
+ frames: ConditionalDirectiveFrame[],
112
+ directive: ConditionalDirective,
113
+ target: VitePluginTaroTarget
114
+ ): void {
115
+ if (directive.name === 'ifdef' || directive.name === 'ifndef' || directive.name === 'if') {
116
+ const conditionMatched = evaluateConditionalDirective(directive, target)
117
+ const parentActive = isDirectiveStackActive(frames)
118
+ frames.push({ parentActive, active: parentActive && conditionMatched, matched: conditionMatched })
119
+ return
120
+ }
121
+
122
+ const currentFrame = frames.at(-1)
123
+ if (!currentFrame) return
124
+
125
+ if (directive.name === 'elif') {
126
+ if (currentFrame.matched) {
127
+ currentFrame.active = false
128
+ return
129
+ }
130
+ const conditionMatched = evaluateConditionalDirective(directive, target)
131
+ currentFrame.active = currentFrame.parentActive && conditionMatched
132
+ currentFrame.matched = conditionMatched
133
+ return
134
+ }
135
+
136
+ if (directive.name === 'else') {
137
+ currentFrame.active = currentFrame.parentActive && !currentFrame.matched
138
+ currentFrame.matched = true
139
+ return
140
+ }
141
+
142
+ if (directive.name === 'endif') frames.pop()
143
+ }
144
+
145
+ /**
146
+ * Evaluates the small expression subset used by Taro conditional comments.
147
+ *
148
+ * Mirrors Taro's simple CSS platform membership checks.
149
+ */
150
+ function evaluateConditionalDirective(directive: ConditionalDirective, target: VitePluginTaroTarget): boolean {
151
+ if (directive.name === 'ifndef') return !matchesDirectiveTarget(directive.expression, target)
152
+ if (directive.name === 'ifdef') return matchesDirectiveTarget(directive.expression, target)
153
+ return evaluateConditionalExpression(directive.expression, target)
154
+ }
155
+
156
+ /**
157
+ * Supports simple #if expressions with !, &&, and || over the configured target token.
158
+ *
159
+ * Plugin-only: #if expressions with && and || have no Taro webpack counterpart.
160
+ */
161
+ function evaluateConditionalExpression(expression: string, target: VitePluginTaroTarget): boolean {
162
+ const orTerms = expression.split('||')
163
+ return orTerms.some((term) =>
164
+ term
165
+ .split('&&')
166
+ .map((factor) => factor.trim())
167
+ .filter(Boolean)
168
+ .every((factor) => evaluateConditionalFactor(factor, target))
169
+ )
170
+ }
171
+
172
+ /**
173
+ * Evaluates one target token, optionally negated.
174
+ *
175
+ * Plugin-only: negated #if factors have no Taro webpack counterpart.
176
+ */
177
+ function evaluateConditionalFactor(factor: string, target: VitePluginTaroTarget): boolean {
178
+ let token = factor.replace(/[()]/g, '').trim()
179
+ let negated = false
180
+ while (token.startsWith('!')) {
181
+ negated = !negated
182
+ token = token.slice(1).trim()
183
+ }
184
+ const matched = matchesDirectiveTarget(token, target)
185
+ return negated ? !matched : matched
186
+ }
187
+
188
+ /**
189
+ * Checks whether a directive target list includes the current target.
190
+ *
191
+ * Mirrors Taro's simple CSS platform membership checks.
192
+ */
193
+ function matchesDirectiveTarget(expression: string, target: VitePluginTaroTarget): boolean {
194
+ const tokens = expression
195
+ .split(/[\s,|&()!]+/)
196
+ .map((token) => token.trim().toLowerCase())
197
+ .filter(Boolean)
198
+ return tokens.includes(target)
199
+ }
200
+
201
+ /**
202
+ * Preserves source line counts when conditional blocks are stripped.
203
+ *
204
+ * Plugin-only: preserves Vite source-map line counts while stripping conditional blocks.
205
+ */
206
+ function getLineEnding(line: string): string {
207
+ const match = line.match(/\r?\n$/)
208
+ return match?.[0] ?? ''
209
+ }
210
+
211
+ /**
212
+ * Returns whether all active nested conditional frames include the current line.
213
+ *
214
+ * Plugin-only: stack activity helper for generalized conditional directives.
215
+ */
216
+ function isDirectiveStackActive(frames: ConditionalDirectiveFrame[]): boolean {
217
+ return frames.every((frame) => frame.active)
218
+ }
@@ -0,0 +1,41 @@
1
+ import tailwindcss from '@tailwindcss/vite'
2
+ import type { PluginOption } from 'vite'
3
+ import { WeappTailwindcss } from 'weapp-tailwindcss/vite'
4
+ import type { VitePluginTaroBuildContext } from './types.ts'
5
+
6
+ export function createTailwindcssPlugins(context: VitePluginTaroBuildContext): PluginOption[] {
7
+ if (context.target === 'h5') return [tailwindcss()]
8
+
9
+ const plugins = WeappTailwindcss({
10
+ appType: 'taro',
11
+ generator: {
12
+ target: 'weapp'
13
+ },
14
+ tailwindcss: {
15
+ version: 4,
16
+ packageName: 'tailwindcss'
17
+ },
18
+ cssCalc: false,
19
+ // skyline does not support -webkit prefix.
20
+ autoprefixer: false,
21
+ postcssOptions: {
22
+ // Tailwind v4 prod mode emits legacy :before/:after selectors; skyline requires ::before/::after.
23
+ plugins: [createWechatPseudoElementPlugin()]
24
+ },
25
+ rem2rpx: true,
26
+ px2rpx: true
27
+ })
28
+
29
+ return plugins ?? []
30
+ }
31
+
32
+ function createWechatPseudoElementPlugin() {
33
+ const legacyPseudoElementPattern = /(?<!:):(before|after)\b/g
34
+
35
+ return {
36
+ postcssPlugin: 'vite-plugin-taro-wechat-pseudo-elements',
37
+ Rule(rule: { selector: string }) {
38
+ rule.selector = rule.selector.replace(legacyPseudoElementPattern, '::$1')
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,230 @@
1
+ import type { types as BabelTypes, NodePath, PluginObj } from '@babel/core'
2
+ import babel from '@rolldown/plugin-babel'
3
+ import react from '@vitejs/plugin-react'
4
+ import type { HtmlTagDescriptor, PluginOption, UserConfig } from 'vite'
5
+ import { isProd, nodeRequire } from '../constants.ts'
6
+ import type { JsonObject, VitePluginTaroBuildContext, VitePluginTaroPageOption } from '../types.ts'
7
+ import { createPageComponentImport } from '../utils.ts'
8
+
9
+ const virtualH5Id = 'virtual:vite-plugin-taro/h5'
10
+ const patchStencilCssOrder = true
11
+
12
+ /**
13
+ * Checks whether an id belongs to an H5 virtual module.
14
+ */
15
+ export function isH5VirtualModuleId(id: string): boolean {
16
+ return id === virtualH5Id
17
+ }
18
+
19
+ /**
20
+ * Loads generated source for H5 virtual modules.
21
+ */
22
+ export function loadH5VirtualModule(cleanId: string, context: VitePluginTaroBuildContext): string | undefined {
23
+ if (cleanId !== virtualH5Id) return
24
+ return createWebEntry(context)
25
+ }
26
+
27
+ /**
28
+ * Configures the Vite pieces needed for Taro H5 resolve/runtime behavior.
29
+ */
30
+ export function createH5ViteConfig(): UserConfig {
31
+ return {
32
+ define: createH5TaroDefines(),
33
+ resolve: {
34
+ mainFields: ['main:h5', 'browser', 'module', 'jsnext:main', 'jsnext'],
35
+ alias: [
36
+ // Resolve Stencil's transitive runtime import after Taro components are optimized separately.
37
+ ...(patchStencilCssOrder
38
+ ? [
39
+ {
40
+ find: /^@stencil\/core\/internal\/client$/,
41
+ replacement: nodeRequire.resolve('@stencil/core/internal/client', {
42
+ paths: [nodeRequire.resolve('@tarojs/components/package.json')]
43
+ })
44
+ }
45
+ ]
46
+ : []),
47
+ // H5 React code must use Taro's React component wrappers, not the raw custom-element entry.
48
+ { find: /^@tarojs\/components$/, replacement: nodeRequire.resolve('@tarojs/components/lib/react') },
49
+ // Taro's H5 router/components deep-import this custom-element loader; make it resolvable under pnpm.
50
+ {
51
+ find: /^@tarojs\/components\/dist\/components$/,
52
+ replacement: nodeRequire.resolve('@tarojs/components/dist/components')
53
+ },
54
+ // H5 APIs are exported from the platform API barrel; the generic @tarojs/taro root is native-oriented.
55
+ {
56
+ find: /^@tarojs\/taro$/,
57
+ replacement: nodeRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
58
+ }
59
+ ]
60
+ },
61
+ optimizeDeps: {
62
+ // Keep the Stencil runtime in Vite's transform pipeline so rewriteStencilStyleInsertion can patch it.
63
+ exclude: [patchStencilCssOrder ? '@stencil/core/internal/client' : ''].filter(Boolean)
64
+ },
65
+ build: {
66
+ target: 'es2018',
67
+ minify: isProd
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Creates H5-only support plugins used before the target emitter runs.
74
+ *
75
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-platform-h5/src/program.ts#L219-L249
76
+ */
77
+ export function createH5SupportPlugins(): PluginOption[] {
78
+ const plugins: PluginOption[] = [...react()]
79
+
80
+ if (patchStencilCssOrder) {
81
+ plugins.push(
82
+ babel({
83
+ include: /[\\/]@stencil[\\/]core[\\/]internal[\\/]client[\\/]index\.js(?:\?.*)?$/,
84
+ exclude: [],
85
+ plugins: [rewriteStencilStyleInsertion]
86
+ })
87
+ )
88
+ }
89
+
90
+ // Mirrors Taro H5: rewrite default Taro.xxx calls from vite-plugin-taro/taro to named H5 API imports.
91
+ plugins.push(
92
+ babel({
93
+ plugins: [
94
+ [
95
+ nodeRequire.resolve('babel-plugin-transform-taroapi'),
96
+ {
97
+ packageName: 'vite-plugin-taro/taro',
98
+ definition: nodeRequire(nodeRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json'))
99
+ }
100
+ ]
101
+ ]
102
+ })
103
+ )
104
+
105
+ return plugins
106
+ }
107
+
108
+ function rewriteStencilStyleInsertion(): PluginObj {
109
+ return {
110
+ name: 'rewrite-stencil-style-insertion',
111
+ visitor: {
112
+ CallExpression(path: NodePath<BabelTypes.CallExpression>) {
113
+ if (!isStencilStyleInsertBeforeCall(path)) return
114
+
115
+ path.get('arguments.1').replaceWithSourceString(
116
+ `scopeId.startsWith('sc-taro-') ? styleContainerNode.querySelector('style,link[rel="stylesheet"]') : styleContainerNode.querySelector('link')`
117
+ )
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ function isStencilStyleInsertBeforeCall(path: NodePath<BabelTypes.CallExpression>): boolean {
124
+ return (
125
+ path.get('callee').matchesPattern('styleContainerNode.insertBefore') &&
126
+ path.get('arguments.0').toString() === 'styleElm' &&
127
+ path.get('arguments.1').toString() === "styleContainerNode.querySelector('link')"
128
+ )
129
+ }
130
+
131
+ /**
132
+ * Creates compile-time constants expected by Taro's Web runtime packages.
133
+ *
134
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-webpack5-runner/src/webpack/H5WebpackPlugin.ts#L51-L69
135
+ */
136
+ function createH5TaroDefines(): Record<string, string> {
137
+ return {
138
+ 'process.env.FRAMEWORK': JSON.stringify('react'),
139
+ 'process.env.SUPPORT_TARO_POLYFILL': JSON.stringify('disabled'),
140
+ 'process.env.TARO_ENV': JSON.stringify('h5'),
141
+ 'process.env.TARO_PLATFORM': JSON.stringify('web'),
142
+ IS_H5: 'true',
143
+ IS_WEAPP: 'false',
144
+ 'process.env.SUPPORT_DINGTALK_NAVIGATE': JSON.stringify('disabled'),
145
+ DEPRECATED_ADAPTER_COMPONENT: 'false'
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Injects vite-plugin-taro's generated Web entry into Vite's HTML shell.
151
+ */
152
+ export function createWebIndexHtmlTags(context: VitePluginTaroBuildContext): HtmlTagDescriptor[] | undefined {
153
+ if (context.target !== 'h5') return
154
+
155
+ const tags: HtmlTagDescriptor[] = []
156
+ tags.push({
157
+ tag: 'script',
158
+ attrs: { type: 'module' },
159
+ children: `import '${virtualH5Id}'`,
160
+ injectTo: 'body'
161
+ })
162
+ return tags
163
+ }
164
+
165
+ /**
166
+ * Builds the generated Web entry around Taro's official Web router/runtime APIs.
167
+ * Base Taro CSS is imported before the app; component CSS order is handled by rewriteStencilStyleInsertion.
168
+ *
169
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/h5.ts#L120-L150
170
+ */
171
+ export function createWebEntry(context: VitePluginTaroBuildContext): string {
172
+ const webAppConfigCode = JSON.stringify(createWebAppConfig(context.appConfig))
173
+ const webRoutesConfigCode = createWebRoutesConfig(context.pages)
174
+
175
+ return `import ${JSON.stringify(nodeRequire.resolve('@tarojs/components/global.css'))}
176
+ import ${JSON.stringify(nodeRequire.resolve('@tarojs/components/dist/taro-components/taro-components.css'))}
177
+ import {
178
+ createHashHistory,
179
+ createReactApp,
180
+ createRouter,
181
+ handleAppMount,
182
+ window
183
+ } from 'vite-plugin-taro/shim/h5'
184
+ import React from 'react'
185
+ import ReactDOM from 'react-dom/client'
186
+ import AppComponent from '${context.appComponentImport}'
187
+
188
+ const config = window.__taroAppConfig = ${webAppConfigCode}
189
+ config.routes = ${webRoutesConfigCode}
190
+ const app = createReactApp(AppComponent, React, ReactDOM, config)
191
+ const history = createHashHistory({ window })
192
+ handleAppMount(config, history)
193
+ createRouter(history, app, config, React)
194
+ `
195
+ }
196
+
197
+ /**
198
+ * Creates the H5 app config consumed by Taro's Web router.
199
+ * Taro's H5 runtime expects `config.router` to exist, even when it is an empty object.
200
+ *
201
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-webpack5-runner/src/plugins/H5Plugin.ts#L49-L53
202
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-webpack5-runner/src/plugins/H5Plugin.ts#L133-L138
203
+ */
204
+ function createWebAppConfig(sharedAppConfig: JsonObject): JsonObject {
205
+ return {
206
+ router: {},
207
+ ...sharedAppConfig
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Creates Web route records in the same shape as Taro's H5 loader.
213
+ *
214
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/h5.ts#L12-L21
215
+ * https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/h5.ts#L108-L114
216
+ */
217
+ function createWebRoutesConfig(webPages: VitePluginTaroPageOption[]): string {
218
+ const webRoutes = webPages.map((page) =>
219
+ [
220
+ 'Object.assign({',
221
+ ` path: ${JSON.stringify(page.path)},`,
222
+ ' load: async function(context, params) {',
223
+ ` const page = await import(${JSON.stringify(createPageComponentImport(page.path))})`,
224
+ ' return [page, context, params]',
225
+ ' }',
226
+ `}, ${JSON.stringify(page.config)})`
227
+ ].join('\n')
228
+ )
229
+ return `[\n${webRoutes.join(',\n')}\n]`
230
+ }