vite-plugin-taro 0.2.2 → 0.3.0
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 +18 -0
- package/dist/node/targets/wx/companion-assets.js +121 -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 +160 -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
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import type { Plugin, PluginOption, UserConfig } from 'vite'
|
|
3
|
+
import type { BuildContext } from '../../build-context.ts'
|
|
4
|
+
import { normalizeModuleId, stripVirtualPrefix } from '../../utils/modules.ts'
|
|
5
|
+
import { packageRequire } from '../../utils/packages.ts'
|
|
6
|
+
import { emitWxCompanionAssets, type WxBundle } from './companion-assets.ts'
|
|
7
|
+
import { WxDevelopmentSession } from './dev-server/development-session.ts'
|
|
8
|
+
import { transformWxReactRefreshModule } from './react-refresh.ts'
|
|
9
|
+
import { emitWxEntryChunks, isWxVirtualModuleId, loadWxVirtualModule, virtualWxAppId } from './virtual-modules.ts'
|
|
10
|
+
|
|
11
|
+
const taroWxComponentsPath = packageRequire.resolve('@tarojs/plugin-platform-weapp/dist/components-react')
|
|
12
|
+
const vitePluginTaroSourcePath = normalizeModuleId(path.dirname(packageRequire.resolve('vite-plugin-taro')))
|
|
13
|
+
const taroVersion = String(packageRequire('@tarojs/runtime/package.json').version)
|
|
14
|
+
|
|
15
|
+
/** Creates the plugins that own the complete WX build and development lifecycle. */
|
|
16
|
+
export function createWxTargetPlugins(context: BuildContext): PluginOption[] {
|
|
17
|
+
return [createWxTargetPlugin(context)]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createWxTargetPlugin(context: BuildContext): Plugin {
|
|
21
|
+
let developmentSession: WxDevelopmentSession | undefined
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
name: 'vite-plugin-taro:wx',
|
|
25
|
+
|
|
26
|
+
resolveId: {
|
|
27
|
+
order: 'pre',
|
|
28
|
+
handler(id) {
|
|
29
|
+
return isWxVirtualModuleId(id) ? `\0${id}` : undefined
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
load: {
|
|
34
|
+
order: 'post',
|
|
35
|
+
handler(id) {
|
|
36
|
+
const cleanId = stripVirtualPrefix(id)
|
|
37
|
+
|
|
38
|
+
emitWxEntryChunks(this, context, cleanId)
|
|
39
|
+
|
|
40
|
+
return loadWxVirtualModule(cleanId, context)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
transform: {
|
|
45
|
+
order: 'post',
|
|
46
|
+
async handler(code, id) {
|
|
47
|
+
if (!context.development) return
|
|
48
|
+
|
|
49
|
+
const transformed = await transformWxReactRefreshModule(code, id, context.project.appComponentFile)
|
|
50
|
+
return transformed === code ? undefined : transformed
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
generateBundle: {
|
|
55
|
+
order: 'post',
|
|
56
|
+
handler(_, bundle) {
|
|
57
|
+
emitWxCompanionAssets(this, bundle as WxBundle, context)
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
configureServer: {
|
|
62
|
+
order: 'post',
|
|
63
|
+
handler(server) {
|
|
64
|
+
developmentSession = new WxDevelopmentSession(context, server)
|
|
65
|
+
developmentSession.install()
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
closeBundle() {
|
|
70
|
+
return developmentSession?.close()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Supplies the complete WX target configuration from the same target owner as its plugin. */
|
|
76
|
+
export function createWxViteConfig(context: BuildContext): UserConfig {
|
|
77
|
+
return {
|
|
78
|
+
define: createWxTaroDefines(),
|
|
79
|
+
experimental: context.development ? { bundledDev: true } : undefined,
|
|
80
|
+
css: {
|
|
81
|
+
lightningcss: {
|
|
82
|
+
visitor: {
|
|
83
|
+
// keep CSS3 style single colon :before, :after
|
|
84
|
+
// while WeChat Mini Program does not support the double colons versions
|
|
85
|
+
Selector(selector) {
|
|
86
|
+
return selector.map((component) => {
|
|
87
|
+
if (
|
|
88
|
+
component.type === 'pseudo-element' &&
|
|
89
|
+
(component.kind === 'before' || component.kind === 'after')
|
|
90
|
+
) {
|
|
91
|
+
return {
|
|
92
|
+
type: 'pseudo-element' as const,
|
|
93
|
+
kind: 'custom' as const,
|
|
94
|
+
name: component.kind
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return component
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
resolve: {
|
|
104
|
+
alias: [{ find: /^@tarojs\/components$/, replacement: taroWxComponentsPath }]
|
|
105
|
+
},
|
|
106
|
+
build: {
|
|
107
|
+
target: 'es2018',
|
|
108
|
+
assetsInlineLimit: 1024,
|
|
109
|
+
cssCodeSplit: false,
|
|
110
|
+
cssMinify: context.development ? false : 'lightningcss',
|
|
111
|
+
minify: !context.development,
|
|
112
|
+
rolldownOptions: {
|
|
113
|
+
input: { app: virtualWxAppId },
|
|
114
|
+
experimental: {
|
|
115
|
+
// remove vite virtual module \0 in comments, which causes WeChat DevTools failed to compile
|
|
116
|
+
attachDebugInfo: 'none'
|
|
117
|
+
},
|
|
118
|
+
output: {
|
|
119
|
+
format: 'cjs',
|
|
120
|
+
entryFileNames: '[name].js',
|
|
121
|
+
assetFileNames: 'assets/[name][extname]',
|
|
122
|
+
chunkFileNames: ({ name }) => `${name === 'rolldown-runtime' ? 'runtime' : name}.js`,
|
|
123
|
+
strictExecutionOrder: true,
|
|
124
|
+
codeSplitting: {
|
|
125
|
+
includeDependenciesRecursively: false,
|
|
126
|
+
minSize: 0,
|
|
127
|
+
groups: [
|
|
128
|
+
{ name: 'taro', test: isWxTaroChunkModule, priority: 100 },
|
|
129
|
+
{ name: 'vendors', test: isNodeModule, priority: 10 },
|
|
130
|
+
{ name: 'common', minShareCount: 2, minModuleSize: 1, priority: 1 }
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function createWxTaroDefines(): Record<string, string> {
|
|
140
|
+
return {
|
|
141
|
+
'process.env.FRAMEWORK': JSON.stringify('react'),
|
|
142
|
+
'process.env.SUPPORT_TARO_POLYFILL': JSON.stringify('disabled'),
|
|
143
|
+
'process.env.TARO_ENV': JSON.stringify('weapp'),
|
|
144
|
+
'process.env.TARO_PLATFORM': JSON.stringify('mini'),
|
|
145
|
+
'process.env.TARO_VERSION': JSON.stringify(taroVersion),
|
|
146
|
+
ENABLE_ADJACENT_HTML: 'false',
|
|
147
|
+
ENABLE_CLONE_NODE: 'false',
|
|
148
|
+
ENABLE_CONTAINS: 'false',
|
|
149
|
+
ENABLE_INNER_HTML: 'false',
|
|
150
|
+
ENABLE_MUTATION_OBSERVER: 'false',
|
|
151
|
+
ENABLE_SIZE_APIS: 'false',
|
|
152
|
+
ENABLE_TEMPLATE_CONTENT: 'false'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function isWxTaroChunkModule(id: string): boolean {
|
|
157
|
+
const normalizedId = normalizeModuleId(id)
|
|
158
|
+
return normalizedId.includes('/node_modules/@tarojs/') || normalizedId.startsWith(`${vitePluginTaroSourcePath}/`)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function isNodeModule(id: string): boolean {
|
|
162
|
+
return normalizeModuleId(id).includes('/node_modules/')
|
|
163
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { transformWithOxc } from 'vite'
|
|
2
|
+
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
3
|
+
|
|
4
|
+
/** Rewrites Vite's browser-oriented Refresh output for the WX App Service global environment. */
|
|
5
|
+
export async function transformWxReactRefreshModule(
|
|
6
|
+
code: string,
|
|
7
|
+
id: string,
|
|
8
|
+
appComponentFile: string
|
|
9
|
+
): Promise<string> {
|
|
10
|
+
const appFile = normalizeModuleId(appComponentFile)
|
|
11
|
+
const instrumented = normalizeModuleId(id) === appFile ? await instrumentWxAppComponent(code, appFile) : code
|
|
12
|
+
return instrumented
|
|
13
|
+
.replaceAll('window.$Refresh', 'globalThis.$Refresh')
|
|
14
|
+
.replaceAll('window.__registerBeforePerformReactRefresh', 'globalThis.__registerBeforePerformReactRefresh')
|
|
15
|
+
.replaceAll('window.__getReactRefreshIgnoredExports', 'globalThis.__getReactRefreshIgnoredExports')
|
|
16
|
+
.replace(
|
|
17
|
+
'export function register(type, id) {',
|
|
18
|
+
'export function register(type, id) {\n if (globalThis.__VITE_PLUGIN_TARO_WX_PAGE_UPDATE__?.blockRefreshRegistration) return'
|
|
19
|
+
)
|
|
20
|
+
.replace(
|
|
21
|
+
'\n performReactRefresh()\n',
|
|
22
|
+
'\n globalThis.__VITE_PLUGIN_TARO_WX_PAGE_UPDATE__?.afterRefresh?.(performReactRefresh())\n'
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Creates the virtual preamble that installs React Refresh before the generated WX App entry executes. */
|
|
27
|
+
export function createWxReactRefreshPreambleSource(): string {
|
|
28
|
+
return `import RefreshRuntime from '/@react-refresh'
|
|
29
|
+
RefreshRuntime.injectIntoGlobalHook(globalThis)
|
|
30
|
+
globalThis.$RefreshReg$ = () => {}
|
|
31
|
+
globalThis.$RefreshSig$ = () => (type) => type
|
|
32
|
+
`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Adds Refresh registration to JSX-free App modules that Vite's normal JSX transform would otherwise skip. */
|
|
36
|
+
async function instrumentWxAppComponent(code: string, appFile: string): Promise<string> {
|
|
37
|
+
const transformed = await transformWithOxc(code, appFile, {
|
|
38
|
+
lang: 'js',
|
|
39
|
+
sourcemap: false,
|
|
40
|
+
jsx: { refresh: true }
|
|
41
|
+
})
|
|
42
|
+
return `import {
|
|
43
|
+
createSignatureFunctionForTransform as __wxCreateRefreshSignature,
|
|
44
|
+
register as __wxRegisterRefreshType
|
|
45
|
+
} from '/@react-refresh'
|
|
46
|
+
const $RefreshReg$ = (type, id) => __wxRegisterRefreshType(type, ${JSON.stringify(`${appFile} `)} + id)
|
|
47
|
+
const $RefreshSig$ = __wxCreateRefreshSignature
|
|
48
|
+
${transformed.code}
|
|
49
|
+
if (import.meta.hot) import.meta.hot.accept()
|
|
50
|
+
`
|
|
51
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the generated WX application graph.
|
|
3
|
+
*
|
|
4
|
+
* App, page, and component IDs become native entry chunks. The Refresh preamble is an App bootstrap module, while the
|
|
5
|
+
* page-preload ID deliberately becomes its own development file with a later, page-only execution phase.
|
|
6
|
+
*/
|
|
7
|
+
import type { VitePluginTaroPageOption } from '../../../options.ts'
|
|
8
|
+
import type { BuildContext } from '../../build-context.ts'
|
|
9
|
+
import { createPageComponentImportPath, toViteFileImportPath } from '../../utils/modules.ts'
|
|
10
|
+
import { resolvePackageFile } from '../../utils/packages.ts'
|
|
11
|
+
import { wxPagePreloadFile } from './development-files.ts'
|
|
12
|
+
import { createWxReactRefreshPreambleSource } from './react-refresh.ts'
|
|
13
|
+
|
|
14
|
+
const wxTaroRuntimeImportPath = runtimeImportPath('taro-runtime.js')
|
|
15
|
+
const wxPageUpdateImportPath = runtimeImportPath('page-update.js')
|
|
16
|
+
const wxUpdateClientImportPath = runtimeImportPath('update-client.js')
|
|
17
|
+
|
|
18
|
+
/** Generated native App entry. */
|
|
19
|
+
export const virtualWxAppId = 'virtual:vite-plugin-taro/wx/app'
|
|
20
|
+
|
|
21
|
+
/** Generated recursive Taro component entry. */
|
|
22
|
+
const virtualWxComponentId = 'virtual:vite-plugin-taro/wx/component'
|
|
23
|
+
|
|
24
|
+
/** Prefix for one generated native entry per configured page route. */
|
|
25
|
+
const virtualWxPageIdPrefix = 'virtual:vite-plugin-taro/wx/page/'
|
|
26
|
+
|
|
27
|
+
/** App bootstrap module that installs React Refresh globals before application modules execute. */
|
|
28
|
+
const virtualWxRefreshPreambleId = 'virtual:vite-plugin-taro/wx/refresh-preamble'
|
|
29
|
+
|
|
30
|
+
/** Development-only entry that initializes all configured page components before update replay. */
|
|
31
|
+
const virtualWxPagePreloadId = 'virtual:vite-plugin-taro/wx/page-preload'
|
|
32
|
+
|
|
33
|
+
type WxChunkEmitter = {
|
|
34
|
+
emitFile(chunk: { type: 'chunk'; id: string; fileName: string; implicitlyLoadedAfterOneOf: string[] }): string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isWxVirtualModuleId(id: string): boolean {
|
|
38
|
+
return (
|
|
39
|
+
id === virtualWxAppId ||
|
|
40
|
+
id === virtualWxComponentId ||
|
|
41
|
+
id === virtualWxRefreshPreambleId ||
|
|
42
|
+
id === virtualWxPagePreloadId ||
|
|
43
|
+
id.startsWith(virtualWxPageIdPrefix)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function loadWxVirtualModule(id: string, context: BuildContext): string | undefined {
|
|
48
|
+
if (id === virtualWxRefreshPreambleId) {
|
|
49
|
+
return createWxReactRefreshPreambleSource()
|
|
50
|
+
}
|
|
51
|
+
if (id === virtualWxAppId) {
|
|
52
|
+
return createWxAppEntrySource(context)
|
|
53
|
+
}
|
|
54
|
+
if (id === virtualWxComponentId) {
|
|
55
|
+
return createWxComponentEntrySource()
|
|
56
|
+
}
|
|
57
|
+
if (id === virtualWxPagePreloadId) {
|
|
58
|
+
return createWxPagePreloadSource(context)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (id.startsWith(virtualWxPageIdPrefix)) {
|
|
62
|
+
const pagePath = id.slice(virtualWxPageIdPrefix.length)
|
|
63
|
+
|
|
64
|
+
const page = context.project.pages.find((candidate) => candidate.path === pagePath)
|
|
65
|
+
if (page) {
|
|
66
|
+
return createWxPageEntrySource(page, context)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Registers every configured page and the shared recursive component as eager WX entry chunks. */
|
|
72
|
+
export function emitWxEntryChunks(emitter: WxChunkEmitter, context: BuildContext, id: string): void {
|
|
73
|
+
if (id !== virtualWxAppId) return
|
|
74
|
+
|
|
75
|
+
for (const page of context.project.pages) {
|
|
76
|
+
emitter.emitFile({
|
|
77
|
+
type: 'chunk',
|
|
78
|
+
id: `${virtualWxPageIdPrefix}${page.path}`,
|
|
79
|
+
fileName: `${page.path}.js`,
|
|
80
|
+
implicitlyLoadedAfterOneOf: [id]
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
emitter.emitFile({
|
|
85
|
+
type: 'chunk',
|
|
86
|
+
id: virtualWxComponentId,
|
|
87
|
+
fileName: 'comp.js',
|
|
88
|
+
implicitlyLoadedAfterOneOf: [id]
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
if (context.development) {
|
|
92
|
+
emitter.emitFile({
|
|
93
|
+
type: 'chunk',
|
|
94
|
+
id: virtualWxPagePreloadId,
|
|
95
|
+
fileName: wxPagePreloadFile,
|
|
96
|
+
implicitlyLoadedAfterOneOf: [id]
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createWxAppEntrySource(context: BuildContext): string {
|
|
102
|
+
const refreshPreamble = context.development ? `import ${JSON.stringify(virtualWxRefreshPreambleId)}\n` : ''
|
|
103
|
+
const updateClient = context.development
|
|
104
|
+
? `import { startWxUpdateClient } from ${JSON.stringify(wxUpdateClientImportPath)}\n`
|
|
105
|
+
: ''
|
|
106
|
+
return `${refreshPreamble}${updateClient}import { createReactApp, ReactDOM } from ${JSON.stringify(wxTaroRuntimeImportPath)}
|
|
107
|
+
import React from 'react'
|
|
108
|
+
import AppComponent from ${JSON.stringify(toViteFileImportPath(context.project.appComponentFile))}
|
|
109
|
+
|
|
110
|
+
const appConfig = ${JSON.stringify(context.project.appConfig)}
|
|
111
|
+
App(createReactApp(AppComponent, React, ReactDOM, appConfig))
|
|
112
|
+
${context.development ? 'startWxUpdateClient()' : ''}
|
|
113
|
+
`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function createWxPageEntrySource(page: VitePluginTaroPageOption, context: BuildContext): string {
|
|
117
|
+
const hotUpdateImport = context.development
|
|
118
|
+
? `import { decorateWxPageConfig, registerWxPage } from ${JSON.stringify(wxPageUpdateImportPath)}\n`
|
|
119
|
+
: ''
|
|
120
|
+
const createConfig = `createPageConfig(PageComponent, '${page.path}', { root: { cn: [] } }, pageConfig)`
|
|
121
|
+
const pageRegistration = context.development
|
|
122
|
+
? `registerWxPage(${JSON.stringify(page.path)}, () => Page(taroPageConfig))`
|
|
123
|
+
: 'Page(taroPageConfig)'
|
|
124
|
+
return `${hotUpdateImport}import { createPageConfig } from ${JSON.stringify(wxTaroRuntimeImportPath)}
|
|
125
|
+
import PageComponent from ${JSON.stringify(createPageComponentImportPath(page.path))}
|
|
126
|
+
|
|
127
|
+
const pageConfig = ${JSON.stringify(page.config)}
|
|
128
|
+
const taroPageConfig = ${context.development ? `decorateWxPageConfig(${createConfig})` : createConfig}
|
|
129
|
+
if (PageComponent && PageComponent.behaviors) {
|
|
130
|
+
taroPageConfig.behaviors = (taroPageConfig.behaviors || []).concat(PageComponent.behaviors)
|
|
131
|
+
}
|
|
132
|
+
${pageRegistration}
|
|
133
|
+
`
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function createWxPagePreloadSource(context: BuildContext): string {
|
|
137
|
+
const imports = context.project.pages.map((page, index) => {
|
|
138
|
+
return `import Page${index} from ${JSON.stringify(createPageComponentImportPath(page.path))}`
|
|
139
|
+
})
|
|
140
|
+
return `${imports.join('\n')}\nvoid [${context.project.pages.map((_, index) => `Page${index}`).join(', ')}]\n`
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function runtimeImportPath(fileName: string): string {
|
|
144
|
+
return toViteFileImportPath(resolvePackageFile('dist/runtime/wx', fileName))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function createWxComponentEntrySource(): string {
|
|
148
|
+
return `import { createRecursiveComponentConfig } from ${JSON.stringify(wxTaroRuntimeImportPath)}
|
|
149
|
+
|
|
150
|
+
Component(createRecursiveComponentConfig())
|
|
151
|
+
`
|
|
152
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Generic asynchronous coordination helpers for Node-side plugin services. */
|
|
2
|
+
export class SerializedTaskQueue {
|
|
3
|
+
private readonly reportError: (error: unknown) => void
|
|
4
|
+
private tail = Promise.resolve()
|
|
5
|
+
|
|
6
|
+
constructor(reportError: (error: unknown) => void) {
|
|
7
|
+
this.reportError = reportError
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
enqueue(task: () => Promise<void>): Promise<void> {
|
|
11
|
+
const work = this.tail.then(task)
|
|
12
|
+
this.tail = work.catch(this.reportError)
|
|
13
|
+
return work
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async waitForIdle(): Promise<void> {
|
|
17
|
+
await this.tail
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Node-only filesystem helpers shared by build targets and development services. */
|
|
2
|
+
import fs from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
type FileSource = string | Uint8Array
|
|
6
|
+
type FileWrite = { file: string; source: FileSource }
|
|
7
|
+
|
|
8
|
+
/** Writes through a sibling temporary file so observers never read partial contents. */
|
|
9
|
+
export async function writeFileAtomically(file: string, source: FileSource): Promise<void> {
|
|
10
|
+
await fs.mkdir(path.dirname(file), { recursive: true })
|
|
11
|
+
const temporaryFile = `${file}.tmp`
|
|
12
|
+
await fs.writeFile(temporaryFile, source)
|
|
13
|
+
await fs.rename(temporaryFile, file)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function writeFilesAtomically(files: FileWrite[]): Promise<void> {
|
|
17
|
+
await Promise.all(files.map(({ file, source }) => writeFileAtomically(file, source)))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Copies a directory when present and treats a missing optional source as empty. */
|
|
21
|
+
export async function copyDirectoryIfExists(source: string, destination: string): Promise<void> {
|
|
22
|
+
if (!source) return
|
|
23
|
+
try {
|
|
24
|
+
await fs.cp(source, destination, { recursive: true, force: true })
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (!isMissingFileError(error)) throw error
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Mirrors one optional file: copy existing files, ignore directories, and remove a missing source's destination. */
|
|
31
|
+
export async function copyFileOrRemove(source: string, destination: string): Promise<void> {
|
|
32
|
+
try {
|
|
33
|
+
const stat = await fs.stat(source)
|
|
34
|
+
if (stat.isDirectory()) return
|
|
35
|
+
await fs.mkdir(path.dirname(destination), { recursive: true })
|
|
36
|
+
await fs.copyFile(source, destination)
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (!isMissingFileError(error)) throw error
|
|
39
|
+
await fs.rm(destination, { recursive: true, force: true })
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isMissingFileError(error: unknown): error is NodeJS.ErrnoException {
|
|
44
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT'
|
|
45
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Node-side helpers for application module files, Vite import specifiers, and normalized module IDs. */
|
|
1
2
|
import path from 'node:path'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -7,8 +8,15 @@ import path from 'node:path'
|
|
|
7
8
|
* https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-webpack5-runner/src/utils/app.ts#L74-L90
|
|
8
9
|
* https://github.com/NervJS/taro/blob/f0e5c39d5f04290db975670411e23c3a396e15f8/packages/taro-loader/src/h5.ts#L12-L21
|
|
9
10
|
*/
|
|
10
|
-
export function
|
|
11
|
-
return
|
|
11
|
+
export function createPageComponentImportPath(pagePath: string): string {
|
|
12
|
+
return toViteFileImportPath(createPageComponentFile(pagePath))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the source file backing a Taro-style page path.
|
|
17
|
+
*/
|
|
18
|
+
function createPageComponentFile(pagePath: string): string {
|
|
19
|
+
return path.resolve(`src/${pagePath}.tsx`)
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
/**
|
|
@@ -17,7 +25,7 @@ export function createPageComponentImport(pagePath: string): string {
|
|
|
17
25
|
* Rolldown does not reliably resolve raw Windows absolute paths from virtual
|
|
18
26
|
* module source, so generated imports use Vite's /@fs/ prefix instead.
|
|
19
27
|
*/
|
|
20
|
-
export function
|
|
28
|
+
export function toViteFileImportPath(filePath: string): string {
|
|
21
29
|
return `/@fs/${normalizeModuleId(path.resolve(filePath))}`
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Resolves dependencies and package-owned files relative to the installed plugin rather than the user project. */
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
export const packageRequire = createRequire(import.meta.url)
|
|
6
|
+
const packageRoot = path.dirname(packageRequire.resolve('vite-plugin-taro/package.json'))
|
|
7
|
+
|
|
8
|
+
export function resolvePackageFile(...segments: string[]): string {
|
|
9
|
+
return path.join(packageRoot, ...segments)
|
|
10
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react'
|
|
2
|
+
import type { Plugin, PluginOption } from 'vite'
|
|
3
|
+
import type { VitePluginTaroOptions } from '../options.ts'
|
|
4
|
+
import { BuildContext } from './build-context.ts'
|
|
5
|
+
import { createConditionalDirectivePlugin } from './plugins/conditional-directives.ts'
|
|
6
|
+
import { createTaroRuntimePlugin } from './plugins/taro-runtime.ts'
|
|
7
|
+
import { createH5TargetPlugins, createH5ViteConfig } from './targets/h5/plugin.ts'
|
|
8
|
+
import { createWxTargetPlugins, createWxViteConfig } from './targets/wx/plugin.ts'
|
|
9
|
+
|
|
10
|
+
/** Creates the Vite plugins for the selected Taro target. */
|
|
11
|
+
export default function vitePluginTaro(options: VitePluginTaroOptions): PluginOption[] {
|
|
12
|
+
const context = new BuildContext(options)
|
|
13
|
+
const targetPlugins =
|
|
14
|
+
context.project.target === 'wx' ? createWxTargetPlugins(context) : createH5TargetPlugins(context)
|
|
15
|
+
|
|
16
|
+
return [
|
|
17
|
+
createBuildCoordinator(context),
|
|
18
|
+
createConditionalDirectivePlugin(context),
|
|
19
|
+
createTaroRuntimePlugin(),
|
|
20
|
+
context.css.plugin,
|
|
21
|
+
...react(),
|
|
22
|
+
...targetPlugins
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Establishes build mode and resolved Vite state before target hooks consume the context. */
|
|
27
|
+
function createBuildCoordinator(context: BuildContext): Plugin {
|
|
28
|
+
return {
|
|
29
|
+
name: 'vite-plugin-taro:build',
|
|
30
|
+
enforce: 'pre',
|
|
31
|
+
|
|
32
|
+
config(_, environment) {
|
|
33
|
+
context.configure(environment)
|
|
34
|
+
return context.project.target === 'wx' ? createWxViteConfig(context) : createH5ViteConfig(context)
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
configResolved(config) {
|
|
38
|
+
context.resolve(config)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Plain JSON object emitted into Mini Program/Web config payloads. */
|
|
2
|
+
export type JsonObject = Record<string, unknown>
|
|
3
|
+
|
|
4
|
+
/** Build target handled by this plugin. */
|
|
5
|
+
export type VitePluginTaroTarget = 'wx' | 'h5'
|
|
6
|
+
|
|
7
|
+
/** Describes one React-backed page shared by WeChat Mini Program and Web builds. */
|
|
8
|
+
export type VitePluginTaroPageOption = {
|
|
9
|
+
/** Taro route and output path without a file extension. */
|
|
10
|
+
path: string
|
|
11
|
+
|
|
12
|
+
/** Page config merged into the generated target config. */
|
|
13
|
+
config: JsonObject
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Required build inputs for the Vite/Rolldown Taro renderer plugin. */
|
|
17
|
+
export interface VitePluginTaroOptions {
|
|
18
|
+
target: VitePluginTaroTarget
|
|
19
|
+
app: string
|
|
20
|
+
pages: VitePluginTaroPageOption[]
|
|
21
|
+
appJson: JsonObject
|
|
22
|
+
projectConfigJson: JsonObject
|
|
23
|
+
projectPrivateConfigJson: JsonObject
|
|
24
|
+
sitemapJson: JsonObject
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Runtime exports consumed by the generated H5 entry. */
|
|
2
|
+
import '@tarojs/components/global.css'
|
|
3
|
+
import '@tarojs/components/dist/taro-components/taro-components.css'
|
|
4
|
+
|
|
5
|
+
// Import the CSS files directly instead of @tarojs/plugin-platform-h5/dist/runtime:
|
|
6
|
+
// that runtime adds only taro-components.css plus optional polyfills, while generated H5 entries also need global.css.
|
|
7
|
+
// @ts-expect-error Taro exposes createReactApp from this runtime-only deep entry without types.
|
|
8
|
+
export { createReactApp } from '@tarojs/plugin-framework-react/dist/runtime'
|
|
9
|
+
export { createBrowserHistory, createHashHistory, createRouter, handleAppMount } from '@tarojs/router'
|
|
10
|
+
export { window } from '@tarojs/runtime'
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** Physical runtime module backing the public `virtual:taro/api` facade. */
|
|
2
|
+
// Ensure Taro's React runtime registers its `initNativeApi` hook before @tarojs/taro is initialized.
|
|
3
|
+
import '@tarojs/plugin-framework-react/dist/runtime'
|
|
1
4
|
import { hooks } from '@tarojs/runtime'
|
|
2
5
|
import Taro from '@tarojs/taro'
|
|
3
6
|
|