vite-plugin-taro 0.2.2 → 0.3.1
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 +83 -106
- package/README.zh.md +83 -104
- package/dist/node/build-context.d.ts +25 -0
- package/dist/node/build-context.js +48 -0
- package/dist/node/css/css-pipeline.d.ts +21 -0
- package/dist/node/css/css-pipeline.js +129 -0
- package/dist/node/plugins/conditional-directives.d.ts +3 -0
- package/dist/node/plugins/conditional-directives.js +62 -0
- package/dist/node/plugins/taro-runtime.d.ts +5 -0
- package/dist/node/plugins/taro-runtime.js +18 -0
- package/dist/node/targets/h5/plugin.d.ts +6 -0
- package/dist/node/targets/h5/plugin.js +117 -0
- package/dist/node/targets/h5/virtual-modules.d.ts +5 -0
- package/dist/node/targets/h5/virtual-modules.js +60 -0
- package/dist/node/targets/wx/companion-assets.d.ts +19 -0
- package/dist/node/targets/wx/companion-assets.js +129 -0
- package/dist/node/targets/wx/dev-server/development-session.d.ts +31 -0
- package/dist/node/targets/wx/dev-server/development-session.js +202 -0
- package/dist/node/targets/wx/dev-server/full-build-scheduler.d.ts +14 -0
- package/dist/node/targets/wx/dev-server/full-build-scheduler.js +60 -0
- package/dist/node/targets/wx/dev-server/js-utils.d.ts +5 -0
- package/dist/node/targets/wx/dev-server/js-utils.js +28 -0
- package/dist/node/targets/wx/dev-server/output.d.ts +19 -0
- package/dist/node/targets/wx/dev-server/output.js +44 -0
- package/dist/node/targets/wx/dev-server/rolldown-runtime-source.d.ts +8 -0
- package/dist/node/targets/wx/dev-server/rolldown-runtime-source.js +95 -0
- package/dist/node/targets/wx/dev-server/update-server-state.d.ts +65 -0
- package/dist/node/targets/wx/dev-server/update-server-state.js +116 -0
- package/dist/node/targets/wx/dev-server/update-transport.d.ts +28 -0
- package/dist/node/targets/wx/dev-server/update-transport.js +212 -0
- package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.d.ts +44 -0
- package/dist/node/targets/wx/dev-server/vite-bundled-dev-adapter.js +145 -0
- package/dist/node/targets/wx/development-files.d.ts +8 -0
- package/dist/node/targets/wx/development-files.js +8 -0
- package/dist/node/targets/wx/plugin.d.ts +6 -0
- package/dist/node/targets/wx/plugin.js +143 -0
- package/dist/node/targets/wx/react-refresh.d.ts +4 -0
- package/dist/node/targets/wx/react-refresh.js +38 -0
- package/dist/node/targets/wx/virtual-modules.d.ts +16 -0
- package/dist/node/targets/wx/virtual-modules.js +120 -0
- package/dist/node/utils/async.d.ts +8 -0
- package/dist/node/utils/async.js +16 -0
- package/dist/node/utils/filesystem.d.ts +13 -0
- package/dist/node/utils/filesystem.js +43 -0
- package/dist/{vite/utils.d.ts → node/utils/modules.d.ts} +2 -2
- package/dist/{vite/utils.js → node/utils/modules.js} +10 -3
- package/dist/node/utils/packages.d.ts +2 -0
- package/dist/node/utils/packages.js +8 -0
- package/dist/node/vite-plugin.d.ts +4 -0
- package/dist/node/vite-plugin.js +33 -0
- package/dist/options.d.ts +21 -0
- package/dist/{shim/h5.d.ts → runtime/h5/taro-runtime.d.ts} +3 -1
- package/dist/runtime/h5/taro-runtime.js +9 -0
- package/dist/runtime/taro/api.d.ts +5 -0
- package/dist/{virtual → runtime/taro}/api.js +3 -0
- package/dist/runtime/taro/components.d.ts +2 -0
- package/dist/runtime/taro/components.js +2 -0
- package/dist/runtime/wx/page-update.d.ts +6 -0
- package/dist/runtime/wx/page-update.js +157 -0
- package/dist/{shim/wx.d.ts → runtime/wx/taro-runtime.d.ts} +1 -0
- package/dist/{shim/wx.js → runtime/wx/taro-runtime.js} +1 -0
- package/dist/runtime/wx/update-client-state.d.ts +68 -0
- package/dist/runtime/wx/update-client-state.js +84 -0
- package/dist/runtime/wx/update-client.d.ts +1 -0
- package/dist/runtime/wx/update-client.js +170 -0
- package/dist/vite.d.ts +2 -2
- package/dist/vite.js +1 -1
- package/package.json +15 -11
- package/src/node/build-context.ts +63 -0
- package/src/node/css/css-pipeline.ts +147 -0
- package/src/node/plugins/conditional-directives.ts +76 -0
- package/src/node/plugins/taro-runtime.ts +22 -0
- package/src/node/targets/h5/plugin.ts +135 -0
- package/src/node/targets/h5/virtual-modules.ts +71 -0
- package/src/node/targets/wx/companion-assets.ts +170 -0
- package/src/node/targets/wx/dev-server/development-session.ts +253 -0
- package/src/node/targets/wx/dev-server/full-build-scheduler.ts +62 -0
- package/src/node/targets/wx/dev-server/js-utils.ts +33 -0
- package/src/node/targets/wx/dev-server/output.ts +56 -0
- package/src/node/targets/wx/dev-server/rolldown-runtime-source.ts +95 -0
- package/src/node/targets/wx/dev-server/update-server-state.ts +183 -0
- package/src/node/targets/wx/dev-server/update-transport.ts +261 -0
- package/src/node/targets/wx/dev-server/vite-bundled-dev-adapter.ts +203 -0
- package/src/node/targets/wx/development-files.ts +11 -0
- package/src/node/targets/wx/plugin.ts +163 -0
- package/src/node/targets/wx/react-refresh.ts +51 -0
- package/src/node/targets/wx/virtual-modules.ts +152 -0
- package/src/node/utils/async.ts +19 -0
- package/src/node/utils/filesystem.ts +45 -0
- package/src/{vite/utils.ts → node/utils/modules.ts} +11 -3
- package/src/node/utils/packages.ts +10 -0
- package/src/node/vite-plugin.ts +41 -0
- package/src/options.ts +25 -0
- package/src/runtime/h5/taro-css.d.ts +3 -0
- package/src/runtime/h5/taro-runtime.ts +10 -0
- package/src/{virtual → runtime/taro}/api.ts +3 -0
- package/src/runtime/taro/components.ts +2 -0
- package/src/runtime/wx/page-update.ts +230 -0
- package/src/runtime/wx/react-refresh.d.ts +20 -0
- package/src/{shim/wx.ts → runtime/wx/taro-runtime.ts} +1 -0
- package/src/runtime/wx/update-client-state.ts +138 -0
- package/src/runtime/wx/update-client.ts +222 -0
- package/src/vite.ts +2 -2
- package/dist/shim/h5.js +0 -5
- package/dist/virtual/api.d.ts +0 -3
- package/dist/virtual/components.d.ts +0 -1
- package/dist/virtual/components.js +0 -1
- package/dist/vite/constants.d.ts +0 -4
- package/dist/vite/constants.js +0 -8
- package/dist/vite/plugins.d.ts +0 -8
- package/dist/vite/plugins.js +0 -186
- package/dist/vite/tailwindcss.d.ts +0 -3
- package/dist/vite/tailwindcss.js +0 -35
- package/dist/vite/targets/h5.d.ts +0 -31
- package/dist/vite/targets/h5.js +0 -201
- package/dist/vite/targets/wx.d.ts +0 -74
- package/dist/vite/targets/wx.js +0 -362
- package/dist/vite/types.d.ts +0 -38
- package/dist/vite/virtual-modules.d.ts +0 -3
- package/dist/vite/virtual-modules.js +0 -13
- package/dist/vite/vite-plugin-taro.d.ts +0 -7
- package/dist/vite/vite-plugin-taro.js +0 -80
- package/src/shim/h5.ts +0 -6
- package/src/virtual/components.ts +0 -1
- package/src/vite/constants.ts +0 -12
- package/src/vite/plugins.ts +0 -218
- package/src/vite/tailwindcss.ts +0 -41
- package/src/vite/targets/h5.ts +0 -229
- package/src/vite/targets/wx.ts +0 -436
- package/src/vite/types.ts +0 -48
- package/src/vite/virtual-modules.ts +0 -14
- package/src/vite/vite-plugin-taro.ts +0 -106
- /package/dist/{vite/types.js → options.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-taro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@babel/core": "^7.29.7",
|
|
55
55
|
"@rolldown/plugin-babel": "^0.2.3",
|
|
56
|
-
"@tailwindcss/vite": "^4.3.1",
|
|
57
56
|
"@tarojs/components": "^4.2.0",
|
|
58
57
|
"@tarojs/helper": "^4.2.0",
|
|
59
58
|
"@tarojs/plugin-platform-h5": "^4.2.0",
|
|
@@ -61,26 +60,31 @@
|
|
|
61
60
|
"@tarojs/router": "^4.2.0",
|
|
62
61
|
"@tarojs/runtime": "^4.2.0",
|
|
63
62
|
"@tarojs/taro": "^4.2.0",
|
|
64
|
-
"@vitejs/plugin-react": "^6.0.
|
|
63
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
65
64
|
"babel-plugin-transform-taroapi": "^4.2.0",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
65
|
+
"picocolors": "^1.1.1",
|
|
66
|
+
"react-refresh": "^0.18.0",
|
|
67
|
+
"tailwindcss": "^4.3.2",
|
|
68
|
+
"weapp-tailwindcss": "^5.1.14",
|
|
69
|
+
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.3.1",
|
|
70
|
+
"@tarojs/react": "npm:vite-plugin-taro-react@0.3.1"
|
|
70
71
|
},
|
|
71
72
|
"peerDependencies": {
|
|
72
73
|
"react": "^19.0.0",
|
|
73
74
|
"react-dom": "^19.0.0",
|
|
74
|
-
"vite": "^8.
|
|
75
|
+
"vite": "^8.1.4"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"@types/babel__core": "^7.20.5",
|
|
78
|
-
"@types/node": "^26.
|
|
79
|
-
"
|
|
80
|
-
"
|
|
79
|
+
"@types/node": "^26.1.1",
|
|
80
|
+
"@types/react": "^19.2.17",
|
|
81
|
+
"@types/react-refresh": "^0.14.7",
|
|
82
|
+
"typescript": "^7.0.2",
|
|
83
|
+
"vite": "^8.1.4"
|
|
81
84
|
},
|
|
82
85
|
"scripts": {
|
|
83
86
|
"build": "node ../../scripts/sync-plugin-readme.ts && node ../../scripts/clean-directory.ts dist && tsc --project tsconfig.json",
|
|
87
|
+
"test": "node --test",
|
|
84
88
|
"typecheck": "tsc --project tsconfig.json --noEmit"
|
|
85
89
|
}
|
|
86
90
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import type { ConfigEnv, ResolvedConfig } from 'vite'
|
|
3
|
+
import type { JsonObject, VitePluginTaroOptions, VitePluginTaroPageOption, VitePluginTaroTarget } from '../options.ts'
|
|
4
|
+
import { CssPipeline } from './css/css-pipeline.ts'
|
|
5
|
+
|
|
6
|
+
type ProjectContext = Readonly<{
|
|
7
|
+
target: VitePluginTaroTarget
|
|
8
|
+
appComponentFile: string
|
|
9
|
+
pages: readonly VitePluginTaroPageOption[]
|
|
10
|
+
appConfig: JsonObject
|
|
11
|
+
projectConfigJson: JsonObject
|
|
12
|
+
projectPrivateConfigJson?: JsonObject
|
|
13
|
+
sitemapJson: JsonObject
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
/** Owns the shared project, Vite lifecycle state, and cross-target services for one build. */
|
|
17
|
+
export class BuildContext {
|
|
18
|
+
readonly project: ProjectContext
|
|
19
|
+
readonly css: CssPipeline
|
|
20
|
+
private developmentMode: boolean | undefined
|
|
21
|
+
private resolvedViteConfig: ResolvedConfig | undefined
|
|
22
|
+
|
|
23
|
+
constructor(options: VitePluginTaroOptions) {
|
|
24
|
+
this.project = {
|
|
25
|
+
target: options.target,
|
|
26
|
+
appComponentFile: path.resolve(options.app),
|
|
27
|
+
pages: options.pages,
|
|
28
|
+
appConfig: {
|
|
29
|
+
...options.appJson,
|
|
30
|
+
pages: options.pages.map((page) => page.path)
|
|
31
|
+
},
|
|
32
|
+
projectConfigJson: options.projectConfigJson,
|
|
33
|
+
projectPrivateConfigJson: options.projectPrivateConfigJson,
|
|
34
|
+
sitemapJson: options.sitemapJson
|
|
35
|
+
}
|
|
36
|
+
this.css = new CssPipeline(options.target)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
configure(environment: ConfigEnv): void {
|
|
40
|
+
if (this.developmentMode !== undefined)
|
|
41
|
+
throw new Error('vite-plugin-taro build context was already configured.')
|
|
42
|
+
this.developmentMode = environment.command === 'serve'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resolve(config: ResolvedConfig): void {
|
|
46
|
+
if (this.developmentMode === undefined) {
|
|
47
|
+
throw new Error('vite-plugin-taro build context resolved before it was configured.')
|
|
48
|
+
}
|
|
49
|
+
if (this.resolvedViteConfig) throw new Error('vite-plugin-taro build context was already resolved.')
|
|
50
|
+
this.resolvedViteConfig = config
|
|
51
|
+
this.css.resolve(config.root)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get development(): boolean {
|
|
55
|
+
if (this.developmentMode === undefined) throw new Error('vite-plugin-taro build context is not configured.')
|
|
56
|
+
return this.developmentMode
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get vite(): ResolvedConfig {
|
|
60
|
+
if (!this.resolvedViteConfig) throw new Error('vite-plugin-taro build context is not resolved.')
|
|
61
|
+
return this.resolvedViteConfig
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import type { Plugin } from 'vite'
|
|
3
|
+
import { createContext } from 'weapp-tailwindcss/core'
|
|
4
|
+
import { createWeappTailwindcssGenerator, resolveTailwindV4Source } from 'weapp-tailwindcss/generator'
|
|
5
|
+
import type { VitePluginTaroTarget } from '../../options.ts'
|
|
6
|
+
import { normalizeModuleId } from '../utils/modules.ts'
|
|
7
|
+
|
|
8
|
+
const wxStyleOptions = {
|
|
9
|
+
cssCalc: false,
|
|
10
|
+
autoprefixer: false,
|
|
11
|
+
rem2rpx: true,
|
|
12
|
+
px2rpx: true
|
|
13
|
+
} as const
|
|
14
|
+
|
|
15
|
+
type WxCssContext = ReturnType<typeof createContext>
|
|
16
|
+
type CssTransformResult = { code: string; map: null }
|
|
17
|
+
|
|
18
|
+
/** Owns CSS generation and the class-name state shared by normal chunks and literal WX patches. */
|
|
19
|
+
export class CssPipeline {
|
|
20
|
+
readonly plugin: Plugin
|
|
21
|
+
private readonly target: VitePluginTaroTarget
|
|
22
|
+
private readonly runtimeClassSet = new Set<string>()
|
|
23
|
+
private projectRoot: string | undefined
|
|
24
|
+
private wxContext: WxCssContext | undefined
|
|
25
|
+
|
|
26
|
+
constructor(target: VitePluginTaroTarget) {
|
|
27
|
+
this.target = target
|
|
28
|
+
this.plugin = this.createPlugin()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resolve(projectRoot: string): void {
|
|
32
|
+
if (this.projectRoot) throw new Error('vite-plugin-taro CSS pipeline was already resolved.')
|
|
33
|
+
this.projectRoot = projectRoot
|
|
34
|
+
this.wxContext = this.target === 'wx' ? createWxCssContext(projectRoot) : undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async transformWxClassNames(code: string, filename: string): Promise<CssTransformResult> {
|
|
38
|
+
if (!this.wxContext || this.runtimeClassSet.size === 0) return { code, map: null }
|
|
39
|
+
const result = await this.wxContext.transformJs(code, {
|
|
40
|
+
runtimeSet: this.runtimeClassSet,
|
|
41
|
+
filename,
|
|
42
|
+
generateMap: false
|
|
43
|
+
})
|
|
44
|
+
return { code: result.code, map: null }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private createPlugin(): Plugin {
|
|
48
|
+
const pipeline = this
|
|
49
|
+
return {
|
|
50
|
+
name: 'vite-plugin-taro:css',
|
|
51
|
+
enforce: 'pre',
|
|
52
|
+
|
|
53
|
+
buildStart() {
|
|
54
|
+
pipeline.runtimeClassSet.clear()
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
async transform(code, id) {
|
|
58
|
+
if (!isCssModuleId(id) || !shouldGenerateTailwindCss(code)) return
|
|
59
|
+
|
|
60
|
+
const projectRoot = pipeline.getProjectRoot()
|
|
61
|
+
const cssFile = resolveCssFile(id, projectRoot)
|
|
62
|
+
const cssBase = path.dirname(cssFile)
|
|
63
|
+
const source = await resolveTailwindV4Source({
|
|
64
|
+
projectRoot,
|
|
65
|
+
cwd: projectRoot,
|
|
66
|
+
base: cssBase,
|
|
67
|
+
css: code,
|
|
68
|
+
cssSources: [{ file: cssFile, base: cssBase, css: code, dependencies: [cssFile] }]
|
|
69
|
+
})
|
|
70
|
+
const generator = createWeappTailwindcssGenerator(source)
|
|
71
|
+
const generated = await generator.generate({
|
|
72
|
+
target: pipeline.target === 'wx' ? 'weapp' : 'web',
|
|
73
|
+
scanSources: true,
|
|
74
|
+
candidates: [],
|
|
75
|
+
styleOptions: pipeline.target === 'wx' ? wxStyleOptions : undefined
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
for (const className of generated.classSet) pipeline.runtimeClassSet.add(className)
|
|
79
|
+
for (const dependency of generated.dependencies) this.addWatchFile(dependency)
|
|
80
|
+
return generated.css
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async renderChunk(code, chunk) {
|
|
84
|
+
if (pipeline.target !== 'wx') return
|
|
85
|
+
return await pipeline.transformWxClassNames(code, chunk.fileName)
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async generateBundle(_, bundle) {
|
|
89
|
+
if (pipeline.target !== 'wx') return
|
|
90
|
+
const core = pipeline.getWxContext()
|
|
91
|
+
await Promise.all(
|
|
92
|
+
Object.entries(bundle).map(async ([fileName, item]) => {
|
|
93
|
+
if (item.type === 'asset' && fileName.endsWith('.css')) {
|
|
94
|
+
await transformWxssAsset(core, item)
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private getProjectRoot(): string {
|
|
103
|
+
if (!this.projectRoot) throw new Error('vite-plugin-taro CSS pipeline was used before configuration resolved.')
|
|
104
|
+
return this.projectRoot
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private getWxContext(): WxCssContext {
|
|
108
|
+
if (!this.wxContext) throw new Error('vite-plugin-taro expected a resolved WeChat CSS pipeline.')
|
|
109
|
+
return this.wxContext
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function createWxCssContext(projectRoot: string): WxCssContext {
|
|
114
|
+
return createContext({
|
|
115
|
+
appType: 'taro',
|
|
116
|
+
tailwindcssBasedir: projectRoot,
|
|
117
|
+
generator: { target: 'weapp' },
|
|
118
|
+
...wxStyleOptions,
|
|
119
|
+
logLevel: 'silent'
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function transformWxssAsset(core: WxCssContext, item: { source?: string | Uint8Array }): Promise<void> {
|
|
124
|
+
const result = await core.transformWxss(getAssetSource(item), { isMainChunk: true })
|
|
125
|
+
item.source = result.css
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function shouldGenerateTailwindCss(code: string): boolean {
|
|
129
|
+
const tailwindEntryImportPattern =
|
|
130
|
+
/@(import|reference)\s+(?:url\(\s*)?(?:["'])tailwindcss(?:\/(?:theme|preflight|utilities)(?:\.css)?)?(?:["'])/
|
|
131
|
+
return code.includes('tailwindcss') && tailwindEntryImportPattern.test(code)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isCssModuleId(id: string): boolean {
|
|
135
|
+
return /\.(?:css|scss|sass|less|styl|stylus)(?:$|[?#])/.test(id)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function getAssetSource(item: { source?: string | Uint8Array }): string {
|
|
139
|
+
if (typeof item.source === 'string') return item.source
|
|
140
|
+
return item.source ? new TextDecoder().decode(item.source) : ''
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function resolveCssFile(id: string, root: string): string {
|
|
144
|
+
const normalizedId = normalizeModuleId(id)
|
|
145
|
+
const cleanId = normalizedId.startsWith('/@fs/') ? normalizedId.slice('/@fs'.length) : normalizedId
|
|
146
|
+
return path.isAbsolute(cleanId) ? cleanId : path.resolve(root, cleanId)
|
|
147
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
|
+
import type { VitePluginTaroTarget } from '../../options.ts'
|
|
3
|
+
import type { BuildContext } from '../build-context.ts'
|
|
4
|
+
import { normalizeModuleId } from '../utils/modules.ts'
|
|
5
|
+
|
|
6
|
+
export function createConditionalDirectivePlugin(context: BuildContext): Plugin {
|
|
7
|
+
return {
|
|
8
|
+
name: 'vite-plugin-taro:conditional-directives',
|
|
9
|
+
enforce: 'pre',
|
|
10
|
+
transform(code, id) {
|
|
11
|
+
if (!isConditionalDirectiveSource(id) || !code.includes('#if')) return
|
|
12
|
+
return { code: transformConditionalDirectives(code, context.project.target), map: null }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isConditionalDirectiveSource(id: string): boolean {
|
|
18
|
+
const normalizedId = normalizeModuleId(id)
|
|
19
|
+
return !normalizedId.includes('/node_modules/') && /\.(?:[cm]?[jt]sx?|css|s[ac]ss|less|styl)$/.test(normalizedId)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type Directive = {
|
|
23
|
+
name: 'ifdef' | 'ifndef' | 'else' | 'endif'
|
|
24
|
+
target: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type DirectiveFrame = {
|
|
28
|
+
parentActive: boolean
|
|
29
|
+
matched: boolean
|
|
30
|
+
active: boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function transformConditionalDirectives(code: string, target: VitePluginTaroTarget): string {
|
|
34
|
+
const lines = code.match(/[^\n]*(?:\n|$)/g) ?? []
|
|
35
|
+
const frames: DirectiveFrame[] = []
|
|
36
|
+
let transformed = ''
|
|
37
|
+
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
if (!line) continue
|
|
40
|
+
const directive = parseDirective(line)
|
|
41
|
+
const lineEnding = line.match(/\r?\n$/)?.[0] ?? ''
|
|
42
|
+
if (!directive) {
|
|
43
|
+
transformed += frames.every((frame) => frame.active) ? line : lineEnding
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (directive.name === 'ifdef' || directive.name === 'ifndef') {
|
|
48
|
+
const parentActive = frames.every((frame) => frame.active)
|
|
49
|
+
const targetMatched = directive.target.toLowerCase() === target
|
|
50
|
+
const matched = directive.name === 'ifdef' ? targetMatched : !targetMatched
|
|
51
|
+
frames.push({ parentActive, matched, active: parentActive && matched })
|
|
52
|
+
} else if (directive.name === 'else') {
|
|
53
|
+
const frame = frames.at(-1)
|
|
54
|
+
if (frame) frame.active = frame.parentActive && !frame.matched
|
|
55
|
+
} else {
|
|
56
|
+
frames.pop()
|
|
57
|
+
}
|
|
58
|
+
transformed += lineEnding
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return transformed
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseDirective(line: string): Directive | undefined {
|
|
65
|
+
const match = line.match(/^\s*(?:(?:\/\/)|(?:\/\*))\s*#(ifdef|ifndef|if|elif|else|endif)\b([^*\r\n]*)/)
|
|
66
|
+
if (!match) return
|
|
67
|
+
const name = match[1]
|
|
68
|
+
if (name === 'if' || name === 'elif') {
|
|
69
|
+
throw new Error(`vite-plugin-taro no longer supports #${name}; use #ifdef, #ifndef, or #else.`)
|
|
70
|
+
}
|
|
71
|
+
if (name !== 'ifdef' && name !== 'ifndef' && name !== 'else' && name !== 'endif') return
|
|
72
|
+
return {
|
|
73
|
+
name,
|
|
74
|
+
target: match[2]?.replace(/\*\/$/, '').trim() ?? ''
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
|
+
import { resolvePackageFile } from '../utils/packages.ts'
|
|
3
|
+
|
|
4
|
+
/** Public IDs used by Taro's API transform and generated target modules. */
|
|
5
|
+
export const virtualTaroApiId = 'virtual:taro/api'
|
|
6
|
+
const virtualTaroComponentsId = 'virtual:taro/components'
|
|
7
|
+
|
|
8
|
+
const runtimeModules = new Map([
|
|
9
|
+
[virtualTaroApiId, resolvePackageFile('dist/runtime/taro/api.js')],
|
|
10
|
+
[virtualTaroComponentsId, resolvePackageFile('dist/runtime/taro/components.js')]
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
/** Resolves target-neutral Taro shims once instead of duplicating this concern in every target plugin. */
|
|
14
|
+
export function createTaroRuntimePlugin(): Plugin {
|
|
15
|
+
return {
|
|
16
|
+
name: 'vite-plugin-taro:runtime',
|
|
17
|
+
enforce: 'pre',
|
|
18
|
+
resolveId(id) {
|
|
19
|
+
return runtimeModules.get(id)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { types as BabelTypes, NodePath, PluginObj } from '@babel/core'
|
|
2
|
+
import babel from '@rolldown/plugin-babel'
|
|
3
|
+
import type { Plugin, PluginOption, UserConfig } from 'vite'
|
|
4
|
+
import type { BuildContext } from '../../build-context.ts'
|
|
5
|
+
import { virtualTaroApiId } from '../../plugins/taro-runtime.ts'
|
|
6
|
+
import { stripVirtualPrefix } from '../../utils/modules.ts'
|
|
7
|
+
import { packageRequire } from '../../utils/packages.ts'
|
|
8
|
+
import { createH5IndexHtmlTags, isH5VirtualModuleId, loadH5VirtualModule } from './virtual-modules.ts'
|
|
9
|
+
|
|
10
|
+
/** Creates the plugins that own the complete H5 target lifecycle. */
|
|
11
|
+
export function createH5TargetPlugins(context: BuildContext): PluginOption[] {
|
|
12
|
+
return [...createH5SupportPlugins(), createH5TargetPlugin(context)]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function createH5TargetPlugin(context: BuildContext): Plugin {
|
|
16
|
+
return {
|
|
17
|
+
name: 'vite-plugin-taro:h5',
|
|
18
|
+
|
|
19
|
+
resolveId: {
|
|
20
|
+
order: 'pre',
|
|
21
|
+
handler(id) {
|
|
22
|
+
return isH5VirtualModuleId(id) ? `\0${id}` : undefined
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
load: {
|
|
27
|
+
order: 'post',
|
|
28
|
+
handler(id) {
|
|
29
|
+
return loadH5VirtualModule(stripVirtualPrefix(id), context)
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
transformIndexHtml: {
|
|
34
|
+
order: 'pre',
|
|
35
|
+
handler() {
|
|
36
|
+
return createH5IndexHtmlTags(context)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Creates H5-only Babel transforms for Stencil CSS ordering and Taro API imports. */
|
|
43
|
+
function createH5SupportPlugins(): PluginOption[] {
|
|
44
|
+
return [
|
|
45
|
+
babel({
|
|
46
|
+
include: /[\\/]@stencil[\\/]core[\\/]internal[\\/]client[\\/]index\.js(?:\?.*)?$/,
|
|
47
|
+
exclude: [],
|
|
48
|
+
plugins: [rewriteStencilStyleInsertion]
|
|
49
|
+
}),
|
|
50
|
+
babel({
|
|
51
|
+
plugins: [
|
|
52
|
+
[
|
|
53
|
+
packageRequire.resolve('babel-plugin-transform-taroapi'),
|
|
54
|
+
{
|
|
55
|
+
packageName: virtualTaroApiId,
|
|
56
|
+
definition: packageRequire(
|
|
57
|
+
packageRequire.resolve('@tarojs/plugin-platform-h5/dist/definition.json')
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Keeps Stencil-injected Taro component styles before application stylesheets. */
|
|
67
|
+
function rewriteStencilStyleInsertion(): PluginObj {
|
|
68
|
+
return {
|
|
69
|
+
name: 'rewrite-stencil-style-insertion',
|
|
70
|
+
visitor: {
|
|
71
|
+
CallExpression(path: NodePath<BabelTypes.CallExpression>) {
|
|
72
|
+
if (!isStencilStyleInsertBeforeCall(path)) return
|
|
73
|
+
path.get('arguments.1').replaceWithSourceString(
|
|
74
|
+
`scopeId.startsWith('sc-taro-') ? styleContainerNode.querySelector('style,link[rel="stylesheet"]') : styleContainerNode.querySelector('link')`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isStencilStyleInsertBeforeCall(path: NodePath<BabelTypes.CallExpression>): boolean {
|
|
82
|
+
return (
|
|
83
|
+
path.get('callee').matchesPattern('styleContainerNode.insertBefore') &&
|
|
84
|
+
path.get('arguments.0').toString() === 'styleElm' &&
|
|
85
|
+
path.get('arguments.1').toString() === "styleContainerNode.querySelector('link')"
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Supplies the complete H5 target configuration from the same target owner as its plugins. */
|
|
90
|
+
export function createH5ViteConfig(context: BuildContext): UserConfig {
|
|
91
|
+
return {
|
|
92
|
+
define: createH5TaroDefines(),
|
|
93
|
+
resolve: {
|
|
94
|
+
mainFields: ['main:h5', 'browser', 'module', 'jsnext:main', 'jsnext'],
|
|
95
|
+
alias: [
|
|
96
|
+
{
|
|
97
|
+
find: /^@stencil\/core\/internal\/client$/,
|
|
98
|
+
replacement: packageRequire.resolve('@stencil/core/internal/client', {
|
|
99
|
+
paths: [packageRequire.resolve('@tarojs/components/package.json')]
|
|
100
|
+
})
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
find: /^@tarojs\/components$/,
|
|
104
|
+
replacement: packageRequire.resolve('@tarojs/components/lib/react')
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
find: /^@tarojs\/components\/dist\/components$/,
|
|
108
|
+
replacement: packageRequire.resolve('@tarojs/components/dist/components')
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
find: /^@tarojs\/taro$/,
|
|
112
|
+
replacement: packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
optimizeDeps: {
|
|
117
|
+
exclude: ['@stencil/core/internal/client']
|
|
118
|
+
},
|
|
119
|
+
build: {
|
|
120
|
+
target: 'es2018',
|
|
121
|
+
minify: !context.development
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function createH5TaroDefines(): Record<string, string> {
|
|
127
|
+
return {
|
|
128
|
+
'process.env.FRAMEWORK': JSON.stringify('react'),
|
|
129
|
+
'process.env.SUPPORT_TARO_POLYFILL': JSON.stringify('disabled'),
|
|
130
|
+
'process.env.TARO_ENV': JSON.stringify('h5'),
|
|
131
|
+
'process.env.TARO_PLATFORM': JSON.stringify('web'),
|
|
132
|
+
'process.env.SUPPORT_DINGTALK_NAVIGATE': JSON.stringify('disabled'),
|
|
133
|
+
DEPRECATED_ADAPTER_COMPONENT: 'false'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { HtmlTagDescriptor } from 'vite'
|
|
2
|
+
import type { JsonObject, VitePluginTaroPageOption } from '../../../options.ts'
|
|
3
|
+
import type { BuildContext } from '../../build-context.ts'
|
|
4
|
+
import { createPageComponentImportPath, toViteFileImportPath } from '../../utils/modules.ts'
|
|
5
|
+
import { resolvePackageFile } from '../../utils/packages.ts'
|
|
6
|
+
|
|
7
|
+
const h5TaroRuntimeImportPath = toViteFileImportPath(resolvePackageFile('dist/runtime/h5/taro-runtime.js'))
|
|
8
|
+
|
|
9
|
+
const virtualH5EntryId = 'virtual:vite-plugin-taro/h5'
|
|
10
|
+
|
|
11
|
+
export function isH5VirtualModuleId(id: string): boolean {
|
|
12
|
+
return id === virtualH5EntryId
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function loadH5VirtualModule(id: string, context: BuildContext): string | undefined {
|
|
16
|
+
if (id === virtualH5EntryId) return createH5EntrySource(context)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createH5IndexHtmlTags(context: BuildContext): HtmlTagDescriptor[] | undefined {
|
|
20
|
+
if (context.project.target !== 'h5') return
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
tag: 'script',
|
|
24
|
+
attrs: { type: 'module' },
|
|
25
|
+
children: `import '${virtualH5EntryId}'`,
|
|
26
|
+
injectTo: 'body'
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createH5EntrySource(context: BuildContext): string {
|
|
32
|
+
const appConfig = JSON.stringify(createH5AppConfig(context.project.appConfig))
|
|
33
|
+
const routes = createH5RoutesSource(context.project.pages)
|
|
34
|
+
return `import {
|
|
35
|
+
createHashHistory,
|
|
36
|
+
createReactApp,
|
|
37
|
+
createRouter,
|
|
38
|
+
handleAppMount,
|
|
39
|
+
window
|
|
40
|
+
} from ${JSON.stringify(h5TaroRuntimeImportPath)}
|
|
41
|
+
import React from 'react'
|
|
42
|
+
import ReactDOM from 'react-dom/client'
|
|
43
|
+
import AppComponent from ${JSON.stringify(toViteFileImportPath(context.project.appComponentFile))}
|
|
44
|
+
|
|
45
|
+
const config = window.__taroAppConfig = ${appConfig}
|
|
46
|
+
config.routes = ${routes}
|
|
47
|
+
const app = createReactApp(AppComponent, React, ReactDOM, config)
|
|
48
|
+
const history = createHashHistory({ window })
|
|
49
|
+
handleAppMount(config, history)
|
|
50
|
+
createRouter(history, app, config, React)
|
|
51
|
+
`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createH5AppConfig(sharedAppConfig: JsonObject): JsonObject {
|
|
55
|
+
return { router: {}, ...sharedAppConfig }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createH5RoutesSource(pages: readonly VitePluginTaroPageOption[]): string {
|
|
59
|
+
const routes = pages.map((page) =>
|
|
60
|
+
[
|
|
61
|
+
'Object.assign({',
|
|
62
|
+
` path: ${JSON.stringify(page.path)},`,
|
|
63
|
+
' load: async function(context, params) {',
|
|
64
|
+
` const page = await import(${JSON.stringify(createPageComponentImportPath(page.path))})`,
|
|
65
|
+
' return [page, context, params]',
|
|
66
|
+
' }',
|
|
67
|
+
`}, ${JSON.stringify(page.config)})`
|
|
68
|
+
].join('\n')
|
|
69
|
+
)
|
|
70
|
+
return `[\n${routes.join(',\n')}\n]`
|
|
71
|
+
}
|