vite-plugin-taro 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +16 -16
- package/README.md +17 -16
- package/dist/node/plugins/client/client-taro.d.ts +4 -2
- package/dist/node/plugins/client/client-taro.js +40 -5
- package/dist/node/plugins/client/inject-taro-framework-apis.d.ts +5 -0
- package/dist/node/plugins/client/inject-taro-framework-apis.js +9 -0
- package/dist/node/plugins/css/plugins.d.ts +1 -3
- package/dist/node/plugins/css/plugins.js +91 -58
- package/dist/node/plugins/h5/plugins.js +0 -4
- package/dist/node/plugins/wx/dev/dev-host.js +0 -3
- package/dist/node/plugins/wx/placement/placer.js +1 -2
- package/dist/node/plugins/wx/plugins.js +10 -1
- package/dist/node/vite-plugin.js +1 -1
- package/dist/runtime/client/taro/api.d.ts +2 -3
- package/dist/runtime/client/taro/api.js +9 -8
- package/package.json +3 -3
- package/src/node/plugins/client/client-taro.ts +48 -5
- package/src/node/plugins/client/inject-taro-framework-apis.ts +11 -0
- package/src/node/plugins/css/plugins.ts +89 -53
- package/src/node/plugins/h5/plugins.ts +0 -4
- package/src/node/plugins/wx/dev/dev-host.ts +0 -3
- package/src/node/plugins/wx/placement/placer.ts +1 -2
- package/src/node/plugins/wx/plugins.ts +10 -1
- package/src/node/vite-plugin.ts +1 -1
- package/src/runtime/client/taro/api.ts +9 -9
- package/dist/node/plugins/wx/dev/publish-wx-dev-style.d.ts +0 -11
- package/dist/node/plugins/wx/dev/publish-wx-dev-style.js +0 -12
- package/src/node/plugins/wx/dev/publish-wx-dev-style.ts +0 -26
package/README.en.md
CHANGED
|
@@ -8,7 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
Build WeChat Mini Program and Web apps with Vite 8, React 19, Taro 4, and Tailwind CSS v4.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Website: <https://vpt.js.org>
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm create vite-taro@latest my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Continue with the [Quick Start guide](https://vpt.js.org/guides/quick-start/).
|
|
12
20
|
|
|
13
21
|
### React Hot Reload in WeChat DevTools
|
|
14
22
|
|
|
@@ -21,23 +29,15 @@ Documentation website: <https://vite-plugin-taro.netlify.app>
|
|
|
21
29
|
- **Built on Taro, beyond Taro** Use Taro components and APIs without the old webpack pipeline.
|
|
22
30
|
- **Skyline ready** Use WeChat Skyline rendering globally or per page.
|
|
23
31
|
|
|
24
|
-
## Create an app
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
npm create vite-taro@latest my-app
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Continue with the [Quick Start guide](https://vite-plugin-taro.netlify.app/guides/quick-start/).
|
|
31
|
-
|
|
32
32
|
## Documentation
|
|
33
33
|
|
|
34
|
-
- [Automatic subpackages](https://
|
|
35
|
-
- [Native WeChat components](https://
|
|
36
|
-
- [Hot module replacement](https://
|
|
37
|
-
- [Skyline mode](https://
|
|
38
|
-
- [Migrate from Taro CLI](https://
|
|
39
|
-
- [Configuration reference](https://
|
|
40
|
-
- [Repository management](https://
|
|
34
|
+
- [Automatic subpackages](https://vpt.js.org/guides/automatic-subpackages/)
|
|
35
|
+
- [Native WeChat components](https://vpt.js.org/guides/native-components/)
|
|
36
|
+
- [Hot module replacement](https://vpt.js.org/guides/hot-module-replacement/)
|
|
37
|
+
- [Skyline mode](https://vpt.js.org/guides/skyline-mode/)
|
|
38
|
+
- [Migrate from Taro CLI](https://vpt.js.org/guides/migrate-from-taro/)
|
|
39
|
+
- [Configuration reference](https://vpt.js.org/references/configuration/)
|
|
40
|
+
- [Repository management](https://vpt.js.org/references/repository-management/)
|
|
41
41
|
|
|
42
42
|
## License
|
|
43
43
|
|
package/README.md
CHANGED
|
@@ -8,7 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
使用 Vite 8、React 19、Taro 4 和 Tailwind CSS v4 构建微信小程序与 Web 应用。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
官网:<https://vpt.js.org>
|
|
12
|
+
|
|
13
|
+
## 快速开始
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm create vite-taro@latest my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
接下来阅读[快速开始](https://vpt.js.org/guides/quick-start/)。
|
|
20
|
+
|
|
12
21
|
|
|
13
22
|
### 已支持微信开发者工具的 React 热更新
|
|
14
23
|
|
|
@@ -21,23 +30,15 @@
|
|
|
21
30
|
- **基于 Taro,超越 Taro** 使用 Taro 组件和 API,摆脱旧式 webpack 链路。
|
|
22
31
|
- **Skyline 就绪** 支持全局或按页面启用微信 Skyline 渲染模式。
|
|
23
32
|
|
|
24
|
-
## 创建应用
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
npm create vite-taro@latest my-app
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
接下来阅读[快速开始](https://vite-plugin-taro.netlify.app/guides/quick-start/)。
|
|
31
|
-
|
|
32
33
|
## 文档
|
|
33
34
|
|
|
34
|
-
- [全自动分包](https://
|
|
35
|
-
- [微信原生组件](https://
|
|
36
|
-
- [开发者工具热更新](https://
|
|
37
|
-
- [Skyline 模式](https://
|
|
38
|
-
- [从 Taro CLI 迁移](https://
|
|
39
|
-
- [配置参考](https://
|
|
40
|
-
- [仓库维护](https://
|
|
35
|
+
- [全自动分包](https://vpt.js.org/guides/automatic-subpackages/)
|
|
36
|
+
- [微信原生组件](https://vpt.js.org/guides/native-components/)
|
|
37
|
+
- [开发者工具热更新](https://vpt.js.org/guides/hot-module-replacement/)
|
|
38
|
+
- [Skyline 模式](https://vpt.js.org/guides/skyline-mode/)
|
|
39
|
+
- [从 Taro CLI 迁移](https://vpt.js.org/guides/migrate-from-taro/)
|
|
40
|
+
- [配置参考](https://vpt.js.org/references/configuration/)
|
|
41
|
+
- [仓库维护](https://vpt.js.org/references/repository-management/)
|
|
41
42
|
|
|
42
43
|
## 许可证
|
|
43
44
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
+
import type { VitePluginTaroTarget } from '../../../options.ts';
|
|
3
|
+
/** Public facade used by transformed application API imports. */
|
|
2
4
|
export declare const clientTaroApiId = "virtual:taro/api";
|
|
3
|
-
/** Creates the
|
|
4
|
-
export declare function createClientTaroPlugin(): Plugin;
|
|
5
|
+
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
6
|
+
export declare function createClientTaroPlugin(target: VitePluginTaroTarget): Plugin;
|
|
@@ -1,19 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeModuleId } from '../../utils/modules.js';
|
|
2
|
+
import { packageRequire, resolvePackageFile } from '../../utils/packages.js';
|
|
2
3
|
import { clientTaroNativeId } from './constant.js';
|
|
4
|
+
import { injectTaroFrameworkApis } from './inject-taro-framework-apis.js';
|
|
5
|
+
/*
|
|
6
|
+
* Taro API resolution uses one public facade while avoiding a recursive `@tarojs/taro` import:
|
|
7
|
+
*
|
|
8
|
+
* 1. Application imports of `virtual:taro/api` or `@tarojs/taro` resolve to the physical `api.js` facade.
|
|
9
|
+
* 2. The facade itself imports `@tarojs/taro`; its importer identifies that request as the platform implementation.
|
|
10
|
+
* 3. H5 receives `@tarojs/plugin-platform-h5` APIs, while WX receives the generic `@tarojs/taro` implementation.
|
|
11
|
+
* 4. React's framework API loader transforms the facade, assigning lifecycle hooks such as `useLaunch` to the same
|
|
12
|
+
* platform object and exposing them as named exports.
|
|
13
|
+
*
|
|
14
|
+
* The importer-sensitive second step removes the need for another public-looking virtual module while retaining one
|
|
15
|
+
* facade object for platform APIs and framework lifecycles.
|
|
16
|
+
*/
|
|
17
|
+
/** Public facade used by transformed application API imports. */
|
|
3
18
|
export const clientTaroApiId = 'virtual:taro/api';
|
|
19
|
+
const clientTaroApiPath = resolvePackageFile('dist/runtime/client/taro/api.js');
|
|
20
|
+
const normalizedClientTaroApiPath = normalizeModuleId(clientTaroApiPath);
|
|
4
21
|
const clientTaroComponentId = 'virtual:taro/components';
|
|
5
22
|
const clientTaroModules = new Map([
|
|
6
|
-
[clientTaroApiId,
|
|
23
|
+
[clientTaroApiId, clientTaroApiPath],
|
|
7
24
|
[clientTaroComponentId, resolvePackageFile('dist/runtime/client/taro/component.js')],
|
|
8
25
|
[clientTaroNativeId, resolvePackageFile('dist/runtime/client/taro/define-native-component.js')]
|
|
9
26
|
]);
|
|
10
|
-
/** Creates the
|
|
11
|
-
export function createClientTaroPlugin() {
|
|
27
|
+
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
28
|
+
export function createClientTaroPlugin(target) {
|
|
29
|
+
const platformTaroPath = resolvePlatformTaroPath(target);
|
|
12
30
|
return {
|
|
13
31
|
name: 'vpt:client-taro',
|
|
14
32
|
enforce: 'pre',
|
|
15
|
-
resolveId(id) {
|
|
33
|
+
resolveId(id, importer) {
|
|
34
|
+
if (id === '@tarojs/taro') {
|
|
35
|
+
return isClientTaroFacade(importer) ? platformTaroPath : clientTaroApiPath;
|
|
36
|
+
}
|
|
16
37
|
return clientTaroModules.get(id);
|
|
38
|
+
},
|
|
39
|
+
// Taro's framework loader transforms source code, so apply it only to the shared physical facade.
|
|
40
|
+
transform(code, id) {
|
|
41
|
+
if (normalizeModuleId(id) === normalizedClientTaroApiPath) {
|
|
42
|
+
return injectTaroFrameworkApis(code);
|
|
43
|
+
}
|
|
17
44
|
}
|
|
18
45
|
};
|
|
19
46
|
}
|
|
47
|
+
function resolvePlatformTaroPath(target) {
|
|
48
|
+
return target === 'h5'
|
|
49
|
+
? packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
50
|
+
: packageRequire.resolve('@tarojs/taro');
|
|
51
|
+
}
|
|
52
|
+
function isClientTaroFacade(importer) {
|
|
53
|
+
return importer !== undefined && normalizeModuleId(importer) === normalizedClientTaroApiPath;
|
|
54
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applies Taro React's standard source-to-source API loader. It imports the framework lifecycle hooks, assigns them to
|
|
3
|
+
* the facade's `taro` object, and emits matching named exports; keeping the hook inventory owned by Taro avoids drift.
|
|
4
|
+
*/
|
|
5
|
+
export declare function injectTaroFrameworkApis(source: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { packageRequire } from '../../utils/packages.js';
|
|
2
|
+
const apiLoader = packageRequire('@tarojs/plugin-framework-react/dist/api-loader');
|
|
3
|
+
/**
|
|
4
|
+
* Applies Taro React's standard source-to-source API loader. It imports the framework lifecycle hooks, assigns them to
|
|
5
|
+
* the facade's `taro` object, and emits matching named exports; keeping the hook inventory owned by Taro avoids drift.
|
|
6
|
+
*/
|
|
7
|
+
export function injectTaroFrameworkApis(source) {
|
|
8
|
+
return apiLoader(source);
|
|
9
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { PluginOption } from 'vite';
|
|
2
2
|
import type { VitePluginTaroTarget } from '../../../options.ts';
|
|
3
|
-
/**
|
|
4
|
-
export declare function adaptWxss(source: string): Promise<string>;
|
|
5
|
-
/** Creates the target-aware Tailwind CSS plugins. */
|
|
3
|
+
/** Creates the target-aware Tailwind pipeline. */
|
|
6
4
|
export declare function createCssPlugins(target: VitePluginTaroTarget): PluginOption[];
|
|
@@ -2,85 +2,118 @@ import path from 'node:path';
|
|
|
2
2
|
import { createStyleHandler } from '@weapp-tailwindcss/postcss';
|
|
3
3
|
import { WeappTailwindcss } from 'weapp-tailwindcss/vite';
|
|
4
4
|
import { packageRequire } from '../../utils/packages.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/*
|
|
6
|
+
* CSS output order for WX:
|
|
7
|
+
*
|
|
8
|
+
* weapp-tailwindcss output hooks
|
|
9
|
+
* → vpt:wx-style-finalizer
|
|
10
|
+
* → vpt:wx native companion emission
|
|
11
|
+
*
|
|
12
|
+
* All three generateBundle hooks retain hook-level `order: 'post'` and therefore execute in registration order. The
|
|
13
|
+
* upstream plugin normally also uses plugin-level `enforce: 'post'`, which would move it behind both VPT plugins and
|
|
14
|
+
* break this sequence. `alignWxGenerateBundleOrder` removes only that broader phase from upstream output hooks.
|
|
15
|
+
*/
|
|
16
|
+
// Tailwind belongs to VPT, not necessarily to the application. Resolving from VPT keeps strict package managers and
|
|
17
|
+
// bundled development from looking for Tailwind in the application's node_modules.
|
|
7
18
|
const tailwindcssBasedir = path.dirname(packageRequire.resolve('tailwindcss/package.json'));
|
|
19
|
+
// Both upstream generation and VPT's final whole-file pass use one conversion policy. If these options diverge, the
|
|
20
|
+
// second pass can preserve browser units or reinterpret syntax that the first pass generated.
|
|
8
21
|
const wxStyleOptions = {
|
|
9
22
|
cssCalc: false,
|
|
10
23
|
autoprefixer: false,
|
|
11
24
|
rem2rpx: true,
|
|
12
25
|
px2rpx: true
|
|
13
26
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return (await transformWxss(source)).css;
|
|
18
|
-
}
|
|
19
|
-
/** Creates the target-aware Tailwind CSS plugins. */
|
|
27
|
+
// The handler is immutable and reusable across builds; only each emitted asset's source is replaced.
|
|
28
|
+
const transformWxStyle = createStyleHandler(wxStyleOptions);
|
|
29
|
+
/** Creates the target-aware Tailwind pipeline. */
|
|
20
30
|
export function createCssPlugins(target) {
|
|
21
31
|
const wx = target === 'wx';
|
|
32
|
+
const tailwindPlugins = WeappTailwindcss({
|
|
33
|
+
// VPT is a custom Vite compiler. Using Taro's adapter would import Taro-specific CSS ownership rules.
|
|
34
|
+
appType: 'weapp-vite',
|
|
35
|
+
// WX generation rewrites Tailwind's split package imports before Vite tries to resolve them in the app.
|
|
36
|
+
// Without this, strict workspaces fail on imports such as `tailwindcss/theme.css`.
|
|
37
|
+
rewriteCssImports: wx,
|
|
38
|
+
platform: wx ? 'weapp' : 'web',
|
|
39
|
+
tailwindcssBasedir,
|
|
40
|
+
generator: {
|
|
41
|
+
target: wx ? 'weapp' : 'web'
|
|
42
|
+
},
|
|
43
|
+
cssOptions: {
|
|
44
|
+
...wxStyleOptions,
|
|
45
|
+
// Browser output still needs vendor prefixes; WXSS does not support or need that browser pass.
|
|
46
|
+
autoprefixer: !wx
|
|
47
|
+
},
|
|
48
|
+
logLevel: 'warn'
|
|
49
|
+
}) ?? [];
|
|
22
50
|
return [
|
|
23
|
-
...(
|
|
24
|
-
|
|
25
|
-
// WX must enable this for split Tailwind imports such as `tailwindcss/theme.css`. Otherwise Vite's
|
|
26
|
-
// PostCSS resolver tries to resolve those imports from the application and fails when Tailwind is owned
|
|
27
|
-
// by vpt. The web generator consumes the imports before that resolver runs, so H5 keeps the
|
|
28
|
-
// upstream default.
|
|
29
|
-
rewriteCssImports: wx,
|
|
30
|
-
// Tailwind is a plugin dependency, not an application dependency. Give weapp-tailwindcss the owning package
|
|
31
|
-
// directory explicitly so bundled development and strict package managers resolve split CSS imports equally.
|
|
32
|
-
tailwindcssBasedir,
|
|
33
|
-
generator: {
|
|
34
|
-
target: wx ? 'weapp' : 'web'
|
|
35
|
-
// webCompat: {
|
|
36
|
-
// preset: 'legacy-web'
|
|
37
|
-
// }
|
|
38
|
-
},
|
|
39
|
-
cssOptions: {
|
|
40
|
-
...wxStyleOptions,
|
|
41
|
-
autoprefixer: !wx
|
|
42
|
-
},
|
|
43
|
-
logLevel: 'warn'
|
|
44
|
-
}) ?? []),
|
|
45
|
-
wx ? createWxssCompatibilityFinalizer() : undefined
|
|
51
|
+
...(wx ? tailwindPlugins.map(alignWxGenerateBundleOrder) : tailwindPlugins),
|
|
52
|
+
wx ? createWxStyleFinalizer() : undefined
|
|
46
53
|
];
|
|
47
54
|
}
|
|
48
55
|
/**
|
|
49
|
-
*
|
|
56
|
+
* Finalizes the one global stylesheet after upstream Tailwind generation.
|
|
50
57
|
*
|
|
51
|
-
* `
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* This plugin runs after the upstream finalizer, repeats only the compatibility transform, and restores the captured
|
|
57
|
-
* global asset to WeChat's required `app.wxss` path. Exact path correlation leaves Page WXSS companions untouched.
|
|
58
|
-
* Remove it when upstream both completes adaptation and preserves the bundler-selected filename.
|
|
58
|
+
* `cssCodeSplit: false` makes the compiler style global, but upstream can name it `.css` or `.wxss` depending on build
|
|
59
|
+
* mode. This hook converts its complete final contents once and gives it the root `app.wxss` identity required by
|
|
60
|
+
* WeChat. Running earlier loses CSS from dynamic chunks; running after native companion emission would also see Page
|
|
61
|
+
* and native-component WXSS files that must remain opaque.
|
|
59
62
|
*/
|
|
60
|
-
function
|
|
63
|
+
function createWxStyleFinalizer() {
|
|
61
64
|
return {
|
|
62
|
-
name: 'vpt:
|
|
63
|
-
enforce: 'post',
|
|
65
|
+
name: 'vpt:wx-style-finalizer',
|
|
64
66
|
generateBundle: {
|
|
65
67
|
order: 'post',
|
|
66
68
|
async handler(_, bundle) {
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
(
|
|
71
|
-
output.names.some((name) => name.replaceAll('\\', '/').endsWith('.css'))));
|
|
72
|
-
if (!globalStyleAsset)
|
|
73
|
-
return;
|
|
74
|
-
// Both finalizers use a post-ordered generateBundle hook. Array order places this hook after the
|
|
75
|
-
// upstream finalizer, where the single Vite global style asset has its final contents and filename.
|
|
76
|
-
const source = typeof globalStyleAsset.source === 'string'
|
|
77
|
-
? globalStyleAsset.source
|
|
78
|
-
: new TextDecoder().decode(globalStyleAsset.source);
|
|
79
|
-
if (source.length > 0) {
|
|
80
|
-
globalStyleAsset.source = await adaptWxss(source);
|
|
69
|
+
const styles = Object.values(bundle).filter(isStyleAsset);
|
|
70
|
+
// More than one compiler style means cssCodeSplit was re-enabled. Choosing one would silently lose CSS.
|
|
71
|
+
if (styles.length > 1) {
|
|
72
|
+
throw new Error('WX builds require one global compiler-emitted stylesheet');
|
|
81
73
|
}
|
|
82
|
-
|
|
74
|
+
// CSS is optional; applications without styles do not need an empty app.wxss.
|
|
75
|
+
if (styles.length === 0)
|
|
76
|
+
return;
|
|
77
|
+
const [style] = styles;
|
|
78
|
+
const source = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source);
|
|
79
|
+
// generateBundle exposes the final asset as mutable so conversion and native placement remain atomic.
|
|
80
|
+
// Without the compatibility pass, browser-only selectors, escaped classes, rem and @property can reach
|
|
81
|
+
// WeChat. Without the rename, bundled development writes paths such as src/app.wxss, which WeChat does
|
|
82
|
+
// not load as the application's global stylesheet.
|
|
83
|
+
style.source = (await transformWxStyle(source)).css;
|
|
84
|
+
style.fileName = 'app.wxss';
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
};
|
|
86
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Adapts upstream plugin descriptors without mutating `weapp-tailwindcss` or patching node_modules.
|
|
91
|
+
*
|
|
92
|
+
* Vite first groups whole plugins by `enforce`, then orders individual hooks. Upstream's output plugins specify both
|
|
93
|
+
* `enforce: 'post'` and `generateBundle.order: 'post'`. The plugin-level phase overrides their earlier registration and
|
|
94
|
+
* places them after VPT's normal plugins, so VPT observes incomplete CSS. Making all of VPT post-enforced would fix that
|
|
95
|
+
* one hook while unnecessarily reordering resolution and transforms.
|
|
96
|
+
*
|
|
97
|
+
* For upstream plugins that actually own generateBundle, clone the descriptor without plugin-level enforcement. Keep
|
|
98
|
+
* hook-level `order: 'post'`: it still waits for ordinary bundle generation, while registration order becomes the sole
|
|
99
|
+
* tie-breaker between upstream generation, VPT finalization and native output. H5 descriptors remain untouched.
|
|
100
|
+
*/
|
|
101
|
+
function alignWxGenerateBundleOrder(pluginOption) {
|
|
102
|
+
// PluginOption permits nested arrays. Preserve their shape while adapting every concrete plugin recursively.
|
|
103
|
+
if (Array.isArray(pluginOption))
|
|
104
|
+
return pluginOption.map(alignWxGenerateBundleOrder);
|
|
105
|
+
if (!pluginOption ||
|
|
106
|
+
typeof pluginOption !== 'object' ||
|
|
107
|
+
!('enforce' in pluginOption) ||
|
|
108
|
+
pluginOption.enforce !== 'post' ||
|
|
109
|
+
!('generateBundle' in pluginOption) ||
|
|
110
|
+
pluginOption.generateBundle === undefined) {
|
|
111
|
+
return pluginOption;
|
|
112
|
+
}
|
|
113
|
+
// Clone rather than mutate: upstream may retain or reuse the descriptor returned by its factory.
|
|
114
|
+
return { ...pluginOption, enforce: undefined };
|
|
115
|
+
}
|
|
116
|
+
/** Selects only the compiler stylesheet; native WXSS assets are emitted by the later WX hook. */
|
|
117
|
+
function isStyleAsset(output) {
|
|
118
|
+
return output.type === 'asset' && /\.(?:css|wxss)$/.test(output.fileName);
|
|
119
|
+
}
|
|
@@ -34,10 +34,6 @@ function createH5TargetPlugin(options) {
|
|
|
34
34
|
{
|
|
35
35
|
find: /^@tarojs\/components\/dist\/components$/,
|
|
36
36
|
replacement: packageRequire.resolve('@tarojs/components/dist/components')
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
find: /^@tarojs\/taro$/,
|
|
40
|
-
replacement: packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
41
37
|
}
|
|
42
38
|
]
|
|
43
39
|
},
|
|
@@ -9,7 +9,6 @@ import { createWxDevMode } from './create-wx-dev-mode.js';
|
|
|
9
9
|
import { emptyOutputDirectory } from './empty-output-directory.js';
|
|
10
10
|
import { hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
|
|
11
11
|
import { PatchPublisher } from './patch-publisher.js';
|
|
12
|
-
import { publishWxDevStyle } from './publish-wx-dev-style.js';
|
|
13
12
|
/**
|
|
14
13
|
* Creates the wx dev host: the adapter that owns the physical Rolldown DevEngine (created
|
|
15
14
|
* with dev(...)) and the patch publisher, and replaces Vite's bundledDev.listen so the
|
|
@@ -118,7 +117,6 @@ export async function createWxDevHost({ server, options }) {
|
|
|
118
117
|
throw new Error('wx development requires exactly one Rolldown output.');
|
|
119
118
|
}
|
|
120
119
|
return dev(rolldownOptions, rolldownOptions.output, {
|
|
121
|
-
onAdditionalAssets: (output) => publishWxDevStyle(output, server.config.build.outDir),
|
|
122
120
|
onHmrUpdates: async (result) => {
|
|
123
121
|
if (result instanceof Error) {
|
|
124
122
|
logWxError(server.config.logger, 'wx HMR update failed', result);
|
|
@@ -151,7 +149,6 @@ export async function createWxDevHost({ server, options }) {
|
|
|
151
149
|
logWxError(server.config.logger, 'wx dev build failed', result);
|
|
152
150
|
return;
|
|
153
151
|
}
|
|
154
|
-
await publishWxDevStyle(result, server.config.build.outDir);
|
|
155
152
|
// A fresh build identity per complete physical build; the App runtime reads it
|
|
156
153
|
// from hmr/info.js before any module registers.
|
|
157
154
|
await startFreshBuild();
|
|
@@ -98,8 +98,7 @@ export function createPlacer() {
|
|
|
98
98
|
// into every physical chunk filename; content identity alone is sufficient beneath that root.
|
|
99
99
|
return `${location.root}/assets/[hash].js`;
|
|
100
100
|
},
|
|
101
|
-
// Keep generic assets independent of
|
|
102
|
-
// mutation and owns the exact global `app.wxss` identity without confusing native Page companions.
|
|
101
|
+
// Keep generic assets independent of native output identities assigned after bundling.
|
|
103
102
|
assetFileNames: 'assets/[name]-[hash][extname]'
|
|
104
103
|
},
|
|
105
104
|
// Rolldown rejects strict entry signatures when code-splitting groups disable recursive dependency capture.
|
|
@@ -36,8 +36,11 @@ function createWxPlugin(options) {
|
|
|
36
36
|
},
|
|
37
37
|
build: {
|
|
38
38
|
modulePreload: false,
|
|
39
|
+
// Mini Program styles are intentionally global. This guarantees one compiler stylesheet for the CSS
|
|
40
|
+
// finalizer; enabling splitting would require Page ownership and must not be silently flattened.
|
|
39
41
|
cssCodeSplit: false,
|
|
40
|
-
//
|
|
42
|
+
// Preserve readable source for the final WX compatibility pass; browser minification can emit syntax
|
|
43
|
+
// unsupported by WeChat and would make the subsequent whole-file conversion harder to reason about.
|
|
41
44
|
cssMinify: false,
|
|
42
45
|
// No base64 assets: Taro warns on image srcs above ~2KB, and inlined
|
|
43
46
|
// images bloat the JS bundle toward the mini program package limit.
|
|
@@ -99,6 +102,12 @@ function createWxPlugin(options) {
|
|
|
99
102
|
}
|
|
100
103
|
},
|
|
101
104
|
generateBundle: {
|
|
105
|
+
/*
|
|
106
|
+
* This hook is registered after createCssPlugins() and shares hook-level `order: 'post'` with the adapted
|
|
107
|
+
* upstream hooks and VPT style finalizer. Registration order therefore guarantees that app.wxss is complete
|
|
108
|
+
* before native Page/component companions are emitted. Without this order, the CSS finalizer could consume
|
|
109
|
+
* incomplete Tailwind output or mistake native WXSS companions for additional compiler styles.
|
|
110
|
+
*/
|
|
102
111
|
order: 'post',
|
|
103
112
|
async handler(_, bundle) {
|
|
104
113
|
const subpackages = placer.getSubpackages(bundle);
|
package/dist/node/vite-plugin.js
CHANGED
|
@@ -8,7 +8,7 @@ import { createWxTargetPlugins } from './plugins/wx/plugins.js';
|
|
|
8
8
|
export default function vitePluginTaro(options) {
|
|
9
9
|
return [
|
|
10
10
|
createConditionalDirectivePlugin(options.target),
|
|
11
|
-
createClientTaroPlugin(),
|
|
11
|
+
createClientTaroPlugin(options.target),
|
|
12
12
|
...createCssPlugins(options.target),
|
|
13
13
|
...react(),
|
|
14
14
|
...(options.target === 'wx' ? createWxTargetPlugins(options) : []),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
1
|
+
/*
|
|
2
|
+
* This physical module is the shared facade, not the generic Taro implementation. Its own `@tarojs/taro` request is
|
|
3
|
+
* resolved by the client plugin to the selected platform APIs, while application requests resolve back to this facade.
|
|
4
|
+
* React's API loader then extends this same object with framework lifecycle hooks.
|
|
5
|
+
*/
|
|
6
|
+
import taro from '@tarojs/taro';
|
|
7
|
+
// Re-export platform APIs while preserving object identity for the framework loader's lifecycle assignments.
|
|
8
|
+
// @ts-expect-error @tarojs/taro uses export= types while Rolldown exposes its runtime properties as named exports.
|
|
8
9
|
export * from '@tarojs/taro';
|
|
9
|
-
export default
|
|
10
|
+
export default taro;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-taro",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
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",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"rolldown": "1.2.3",
|
|
75
75
|
"tailwindcss": "^4.3.3",
|
|
76
76
|
"weapp-tailwindcss": "^5.2.11",
|
|
77
|
-
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.
|
|
78
|
-
"@tarojs/react": "npm:vite-plugin-taro-react@0.5.
|
|
77
|
+
"@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.3",
|
|
78
|
+
"@tarojs/react": "npm:vite-plugin-taro-react@0.5.3"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"react": "^19.0.0",
|
|
@@ -1,23 +1,66 @@
|
|
|
1
1
|
import type { Plugin } from 'vite'
|
|
2
|
-
import {
|
|
2
|
+
import type { VitePluginTaroTarget } from '../../../options.ts'
|
|
3
|
+
import { normalizeModuleId } from '../../utils/modules.ts'
|
|
4
|
+
import { packageRequire, resolvePackageFile } from '../../utils/packages.ts'
|
|
3
5
|
import { clientTaroNativeId } from './constant.ts'
|
|
6
|
+
import { injectTaroFrameworkApis } from './inject-taro-framework-apis.ts'
|
|
4
7
|
|
|
8
|
+
/*
|
|
9
|
+
* Taro API resolution uses one public facade while avoiding a recursive `@tarojs/taro` import:
|
|
10
|
+
*
|
|
11
|
+
* 1. Application imports of `virtual:taro/api` or `@tarojs/taro` resolve to the physical `api.js` facade.
|
|
12
|
+
* 2. The facade itself imports `@tarojs/taro`; its importer identifies that request as the platform implementation.
|
|
13
|
+
* 3. H5 receives `@tarojs/plugin-platform-h5` APIs, while WX receives the generic `@tarojs/taro` implementation.
|
|
14
|
+
* 4. React's framework API loader transforms the facade, assigning lifecycle hooks such as `useLaunch` to the same
|
|
15
|
+
* platform object and exposing them as named exports.
|
|
16
|
+
*
|
|
17
|
+
* The importer-sensitive second step removes the need for another public-looking virtual module while retaining one
|
|
18
|
+
* facade object for platform APIs and framework lifecycles.
|
|
19
|
+
*/
|
|
20
|
+
/** Public facade used by transformed application API imports. */
|
|
5
21
|
export const clientTaroApiId = 'virtual:taro/api'
|
|
22
|
+
|
|
23
|
+
const clientTaroApiPath = resolvePackageFile('dist/runtime/client/taro/api.js')
|
|
24
|
+
const normalizedClientTaroApiPath = normalizeModuleId(clientTaroApiPath)
|
|
25
|
+
|
|
6
26
|
const clientTaroComponentId = 'virtual:taro/components'
|
|
27
|
+
|
|
7
28
|
const clientTaroModules = new Map([
|
|
8
|
-
[clientTaroApiId,
|
|
29
|
+
[clientTaroApiId, clientTaroApiPath],
|
|
9
30
|
[clientTaroComponentId, resolvePackageFile('dist/runtime/client/taro/component.js')],
|
|
10
31
|
[clientTaroNativeId, resolvePackageFile('dist/runtime/client/taro/define-native-component.js')]
|
|
11
32
|
])
|
|
12
33
|
|
|
13
|
-
/** Creates the
|
|
14
|
-
export function createClientTaroPlugin(): Plugin {
|
|
34
|
+
/** Creates the shared Taro facade backed by the selected target's API implementation. */
|
|
35
|
+
export function createClientTaroPlugin(target: VitePluginTaroTarget): Plugin {
|
|
36
|
+
const platformTaroPath = resolvePlatformTaroPath(target)
|
|
37
|
+
|
|
15
38
|
return {
|
|
16
39
|
name: 'vpt:client-taro',
|
|
17
40
|
enforce: 'pre',
|
|
18
41
|
|
|
19
|
-
resolveId(id) {
|
|
42
|
+
resolveId(id, importer) {
|
|
43
|
+
if (id === '@tarojs/taro') {
|
|
44
|
+
return isClientTaroFacade(importer) ? platformTaroPath : clientTaroApiPath
|
|
45
|
+
}
|
|
20
46
|
return clientTaroModules.get(id)
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// Taro's framework loader transforms source code, so apply it only to the shared physical facade.
|
|
50
|
+
transform(code, id) {
|
|
51
|
+
if (normalizeModuleId(id) === normalizedClientTaroApiPath) {
|
|
52
|
+
return injectTaroFrameworkApis(code)
|
|
53
|
+
}
|
|
21
54
|
}
|
|
22
55
|
}
|
|
23
56
|
}
|
|
57
|
+
|
|
58
|
+
function resolvePlatformTaroPath(target: VitePluginTaroTarget): string {
|
|
59
|
+
return target === 'h5'
|
|
60
|
+
? packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
61
|
+
: packageRequire.resolve('@tarojs/taro')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isClientTaroFacade(importer: string | undefined): boolean {
|
|
65
|
+
return importer !== undefined && normalizeModuleId(importer) === normalizedClientTaroApiPath
|
|
66
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { packageRequire } from '../../utils/packages.ts'
|
|
2
|
+
|
|
3
|
+
const apiLoader: (source: string) => string = packageRequire('@tarojs/plugin-framework-react/dist/api-loader')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Applies Taro React's standard source-to-source API loader. It imports the framework lifecycle hooks, assigns them to
|
|
7
|
+
* the facade's `taro` object, and emits matching named exports; keeping the hook inventory owned by Taro avoids drift.
|
|
8
|
+
*/
|
|
9
|
+
export function injectTaroFrameworkApis(source: string): string {
|
|
10
|
+
return apiLoader(source)
|
|
11
|
+
}
|
|
@@ -5,10 +5,24 @@ import { WeappTailwindcss } from 'weapp-tailwindcss/vite'
|
|
|
5
5
|
import type { VitePluginTaroTarget } from '../../../options.ts'
|
|
6
6
|
import { packageRequire } from '../../utils/packages.ts'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/*
|
|
9
|
+
* CSS output order for WX:
|
|
10
|
+
*
|
|
11
|
+
* weapp-tailwindcss output hooks
|
|
12
|
+
* → vpt:wx-style-finalizer
|
|
13
|
+
* → vpt:wx native companion emission
|
|
14
|
+
*
|
|
15
|
+
* All three generateBundle hooks retain hook-level `order: 'post'` and therefore execute in registration order. The
|
|
16
|
+
* upstream plugin normally also uses plugin-level `enforce: 'post'`, which would move it behind both VPT plugins and
|
|
17
|
+
* break this sequence. `alignWxGenerateBundleOrder` removes only that broader phase from upstream output hooks.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Tailwind belongs to VPT, not necessarily to the application. Resolving from VPT keeps strict package managers and
|
|
21
|
+
// bundled development from looking for Tailwind in the application's node_modules.
|
|
10
22
|
const tailwindcssBasedir = path.dirname(packageRequire.resolve('tailwindcss/package.json'))
|
|
11
23
|
|
|
24
|
+
// Both upstream generation and VPT's final whole-file pass use one conversion policy. If these options diverge, the
|
|
25
|
+
// second pass can preserve browser units or reinterpret syntax that the first pass generated.
|
|
12
26
|
const wxStyleOptions = {
|
|
13
27
|
cssCalc: false,
|
|
14
28
|
autoprefixer: false,
|
|
@@ -16,84 +30,106 @@ const wxStyleOptions = {
|
|
|
16
30
|
px2rpx: true
|
|
17
31
|
} as const
|
|
18
32
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** Completes the final compatibility pass required by generated WXSS. */
|
|
22
|
-
export async function adaptWxss(source: string): Promise<string> {
|
|
23
|
-
return (await transformWxss(source)).css
|
|
24
|
-
}
|
|
33
|
+
// The handler is immutable and reusable across builds; only each emitted asset's source is replaced.
|
|
34
|
+
const transformWxStyle = createStyleHandler(wxStyleOptions)
|
|
25
35
|
|
|
26
|
-
/** Creates the target-aware Tailwind
|
|
36
|
+
/** Creates the target-aware Tailwind pipeline. */
|
|
27
37
|
export function createCssPlugins(target: VitePluginTaroTarget): PluginOption[] {
|
|
28
38
|
const wx = target === 'wx'
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
const tailwindPlugins =
|
|
41
|
+
WeappTailwindcss({
|
|
42
|
+
// VPT is a custom Vite compiler. Using Taro's adapter would import Taro-specific CSS ownership rules.
|
|
32
43
|
appType: 'weapp-vite',
|
|
33
|
-
// WX
|
|
34
|
-
//
|
|
35
|
-
// by vpt. The web generator consumes the imports before that resolver runs, so H5 keeps the
|
|
36
|
-
// upstream default.
|
|
44
|
+
// WX generation rewrites Tailwind's split package imports before Vite tries to resolve them in the app.
|
|
45
|
+
// Without this, strict workspaces fail on imports such as `tailwindcss/theme.css`.
|
|
37
46
|
rewriteCssImports: wx,
|
|
38
|
-
|
|
39
|
-
// directory explicitly so bundled development and strict package managers resolve split CSS imports equally.
|
|
47
|
+
platform: wx ? 'weapp' : 'web',
|
|
40
48
|
tailwindcssBasedir,
|
|
41
49
|
generator: {
|
|
42
50
|
target: wx ? 'weapp' : 'web'
|
|
43
|
-
// webCompat: {
|
|
44
|
-
// preset: 'legacy-web'
|
|
45
|
-
// }
|
|
46
51
|
},
|
|
47
52
|
cssOptions: {
|
|
48
53
|
...wxStyleOptions,
|
|
54
|
+
// Browser output still needs vendor prefixes; WXSS does not support or need that browser pass.
|
|
49
55
|
autoprefixer: !wx
|
|
50
56
|
},
|
|
51
57
|
logLevel: 'warn'
|
|
52
|
-
}) ?? []
|
|
53
|
-
|
|
58
|
+
}) ?? []
|
|
59
|
+
|
|
60
|
+
return [
|
|
61
|
+
...(wx ? tailwindPlugins.map(alignWxGenerateBundleOrder) : tailwindPlugins),
|
|
62
|
+
wx ? createWxStyleFinalizer() : undefined
|
|
54
63
|
]
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
/**
|
|
58
|
-
*
|
|
67
|
+
* Finalizes the one global stylesheet after upstream Tailwind generation.
|
|
59
68
|
*
|
|
60
|
-
* `
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* This plugin runs after the upstream finalizer, repeats only the compatibility transform, and restores the captured
|
|
66
|
-
* global asset to WeChat's required `app.wxss` path. Exact path correlation leaves Page WXSS companions untouched.
|
|
67
|
-
* Remove it when upstream both completes adaptation and preserves the bundler-selected filename.
|
|
69
|
+
* `cssCodeSplit: false` makes the compiler style global, but upstream can name it `.css` or `.wxss` depending on build
|
|
70
|
+
* mode. This hook converts its complete final contents once and gives it the root `app.wxss` identity required by
|
|
71
|
+
* WeChat. Running earlier loses CSS from dynamic chunks; running after native companion emission would also see Page
|
|
72
|
+
* and native-component WXSS files that must remain opaque.
|
|
68
73
|
*/
|
|
69
|
-
function
|
|
74
|
+
function createWxStyleFinalizer(): Plugin {
|
|
70
75
|
return {
|
|
71
|
-
name: 'vpt:
|
|
72
|
-
enforce: 'post',
|
|
76
|
+
name: 'vpt:wx-style-finalizer',
|
|
73
77
|
generateBundle: {
|
|
74
78
|
order: 'post',
|
|
75
79
|
async handler(_, bundle) {
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
(
|
|
80
|
-
output.type === 'asset' &&
|
|
81
|
-
(output.fileName.replaceAll('\\', '/').endsWith('.css') ||
|
|
82
|
-
output.names.some((name) => name.replaceAll('\\', '/').endsWith('.css')))
|
|
83
|
-
)
|
|
84
|
-
if (!globalStyleAsset) return
|
|
85
|
-
|
|
86
|
-
// Both finalizers use a post-ordered generateBundle hook. Array order places this hook after the
|
|
87
|
-
// upstream finalizer, where the single Vite global style asset has its final contents and filename.
|
|
88
|
-
const source =
|
|
89
|
-
typeof globalStyleAsset.source === 'string'
|
|
90
|
-
? globalStyleAsset.source
|
|
91
|
-
: new TextDecoder().decode(globalStyleAsset.source)
|
|
92
|
-
if (source.length > 0) {
|
|
93
|
-
globalStyleAsset.source = await adaptWxss(source)
|
|
80
|
+
const styles = Object.values(bundle).filter(isStyleAsset)
|
|
81
|
+
// More than one compiler style means cssCodeSplit was re-enabled. Choosing one would silently lose CSS.
|
|
82
|
+
if (styles.length > 1) {
|
|
83
|
+
throw new Error('WX builds require one global compiler-emitted stylesheet')
|
|
94
84
|
}
|
|
95
|
-
|
|
85
|
+
// CSS is optional; applications without styles do not need an empty app.wxss.
|
|
86
|
+
if (styles.length === 0) return
|
|
87
|
+
|
|
88
|
+
const [style] = styles
|
|
89
|
+
const source = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source)
|
|
90
|
+
// generateBundle exposes the final asset as mutable so conversion and native placement remain atomic.
|
|
91
|
+
// Without the compatibility pass, browser-only selectors, escaped classes, rem and @property can reach
|
|
92
|
+
// WeChat. Without the rename, bundled development writes paths such as src/app.wxss, which WeChat does
|
|
93
|
+
// not load as the application's global stylesheet.
|
|
94
|
+
style.source = (await transformWxStyle(source)).css
|
|
95
|
+
style.fileName = 'app.wxss'
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Adapts upstream plugin descriptors without mutating `weapp-tailwindcss` or patching node_modules.
|
|
103
|
+
*
|
|
104
|
+
* Vite first groups whole plugins by `enforce`, then orders individual hooks. Upstream's output plugins specify both
|
|
105
|
+
* `enforce: 'post'` and `generateBundle.order: 'post'`. The plugin-level phase overrides their earlier registration and
|
|
106
|
+
* places them after VPT's normal plugins, so VPT observes incomplete CSS. Making all of VPT post-enforced would fix that
|
|
107
|
+
* one hook while unnecessarily reordering resolution and transforms.
|
|
108
|
+
*
|
|
109
|
+
* For upstream plugins that actually own generateBundle, clone the descriptor without plugin-level enforcement. Keep
|
|
110
|
+
* hook-level `order: 'post'`: it still waits for ordinary bundle generation, while registration order becomes the sole
|
|
111
|
+
* tie-breaker between upstream generation, VPT finalization and native output. H5 descriptors remain untouched.
|
|
112
|
+
*/
|
|
113
|
+
function alignWxGenerateBundleOrder(pluginOption: PluginOption): PluginOption {
|
|
114
|
+
// PluginOption permits nested arrays. Preserve their shape while adapting every concrete plugin recursively.
|
|
115
|
+
if (Array.isArray(pluginOption)) return pluginOption.map(alignWxGenerateBundleOrder)
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
!pluginOption ||
|
|
119
|
+
typeof pluginOption !== 'object' ||
|
|
120
|
+
!('enforce' in pluginOption) ||
|
|
121
|
+
pluginOption.enforce !== 'post' ||
|
|
122
|
+
!('generateBundle' in pluginOption) ||
|
|
123
|
+
pluginOption.generateBundle === undefined
|
|
124
|
+
) {
|
|
125
|
+
return pluginOption
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Clone rather than mutate: upstream may retain or reuse the descriptor returned by its factory.
|
|
129
|
+
return { ...pluginOption, enforce: undefined }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Selects only the compiler stylesheet; native WXSS assets are emitted by the later WX hook. */
|
|
133
|
+
function isStyleAsset(output: Rolldown.OutputBundle[string]): output is Rolldown.OutputAsset {
|
|
134
|
+
return output.type === 'asset' && /\.(?:css|wxss)$/.test(output.fileName)
|
|
135
|
+
}
|
|
@@ -41,10 +41,6 @@ function createH5TargetPlugin(options: VitePluginTaroOptions): Plugin {
|
|
|
41
41
|
{
|
|
42
42
|
find: /^@tarojs\/components\/dist\/components$/,
|
|
43
43
|
replacement: packageRequire.resolve('@tarojs/components/dist/components')
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
find: /^@tarojs\/taro$/,
|
|
47
|
-
replacement: packageRequire.resolve('@tarojs/plugin-platform-h5/dist/runtime/apis')
|
|
48
44
|
}
|
|
49
45
|
]
|
|
50
46
|
},
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
writeHmrFile
|
|
23
23
|
} from './hmr-files.ts'
|
|
24
24
|
import { PatchPublisher } from './patch-publisher.ts'
|
|
25
|
-
import { publishWxDevStyle } from './publish-wx-dev-style.ts'
|
|
26
25
|
|
|
27
26
|
export type WxDevHost = Readonly<{
|
|
28
27
|
close: () => Promise<void>
|
|
@@ -170,7 +169,6 @@ export async function createWxDevHost({
|
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
return dev(rolldownOptions, rolldownOptions.output, {
|
|
173
|
-
onAdditionalAssets: (output) => publishWxDevStyle(output, server.config.build.outDir),
|
|
174
172
|
onHmrUpdates: async (result) => {
|
|
175
173
|
if (result instanceof Error) {
|
|
176
174
|
logWxError(server.config.logger, 'wx HMR update failed', result)
|
|
@@ -206,7 +204,6 @@ export async function createWxDevHost({
|
|
|
206
204
|
logWxError(server.config.logger, 'wx dev build failed', result)
|
|
207
205
|
return
|
|
208
206
|
}
|
|
209
|
-
await publishWxDevStyle(result, server.config.build.outDir)
|
|
210
207
|
// A fresh build identity per complete physical build; the App runtime reads it
|
|
211
208
|
// from hmr/info.js before any module registers.
|
|
212
209
|
await startFreshBuild()
|
|
@@ -121,8 +121,7 @@ export function createPlacer() {
|
|
|
121
121
|
// into every physical chunk filename; content identity alone is sufficient beneath that root.
|
|
122
122
|
return `${location.root}/assets/[hash].js`
|
|
123
123
|
},
|
|
124
|
-
// Keep generic assets independent of
|
|
125
|
-
// mutation and owns the exact global `app.wxss` identity without confusing native Page companions.
|
|
124
|
+
// Keep generic assets independent of native output identities assigned after bundling.
|
|
126
125
|
assetFileNames: 'assets/[name]-[hash][extname]'
|
|
127
126
|
},
|
|
128
127
|
// Rolldown rejects strict entry signatures when code-splitting groups disable recursive dependency capture.
|
|
@@ -46,8 +46,11 @@ function createWxPlugin(options: VitePluginTaroOptions): Plugin {
|
|
|
46
46
|
|
|
47
47
|
build: {
|
|
48
48
|
modulePreload: false,
|
|
49
|
+
// Mini Program styles are intentionally global. This guarantees one compiler stylesheet for the CSS
|
|
50
|
+
// finalizer; enabling splitting would require Page ownership and must not be silently flattened.
|
|
49
51
|
cssCodeSplit: false,
|
|
50
|
-
//
|
|
52
|
+
// Preserve readable source for the final WX compatibility pass; browser minification can emit syntax
|
|
53
|
+
// unsupported by WeChat and would make the subsequent whole-file conversion harder to reason about.
|
|
51
54
|
cssMinify: false,
|
|
52
55
|
|
|
53
56
|
// No base64 assets: Taro warns on image srcs above ~2KB, and inlined
|
|
@@ -123,6 +126,12 @@ function createWxPlugin(options: VitePluginTaroOptions): Plugin {
|
|
|
123
126
|
},
|
|
124
127
|
|
|
125
128
|
generateBundle: {
|
|
129
|
+
/*
|
|
130
|
+
* This hook is registered after createCssPlugins() and shares hook-level `order: 'post'` with the adapted
|
|
131
|
+
* upstream hooks and VPT style finalizer. Registration order therefore guarantees that app.wxss is complete
|
|
132
|
+
* before native Page/component companions are emitted. Without this order, the CSS finalizer could consume
|
|
133
|
+
* incomplete Tailwind output or mistake native WXSS companions for additional compiler styles.
|
|
134
|
+
*/
|
|
126
135
|
order: 'post',
|
|
127
136
|
async handler(_, bundle) {
|
|
128
137
|
const subpackages = placer.getSubpackages(bundle)
|
package/src/node/vite-plugin.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { createWxTargetPlugins } from './plugins/wx/plugins.ts'
|
|
|
11
11
|
export default function vitePluginTaro(options: VitePluginTaroOptions): PluginOption[] {
|
|
12
12
|
return [
|
|
13
13
|
createConditionalDirectivePlugin(options.target),
|
|
14
|
-
createClientTaroPlugin(),
|
|
14
|
+
createClientTaroPlugin(options.target),
|
|
15
15
|
...createCssPlugins(options.target),
|
|
16
16
|
...react(),
|
|
17
17
|
...(options.target === 'wx' ? createWxTargetPlugins(options) : []),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/*
|
|
2
|
+
* This physical module is the shared facade, not the generic Taro implementation. Its own `@tarojs/taro` request is
|
|
3
|
+
* resolved by the client plugin to the selected platform APIs, while application requests resolve back to this facade.
|
|
4
|
+
* React's API loader then extends this same object with framework lifecycle hooks.
|
|
5
|
+
*/
|
|
6
|
+
import taro from '@tarojs/taro'
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// @ts-expect-error @tarojs/taro declares export= types, but the facade also exposes its runtime named exports.
|
|
8
|
+
// Re-export platform APIs while preserving object identity for the framework loader's lifecycle assignments.
|
|
9
|
+
// @ts-expect-error @tarojs/taro uses export= types while Rolldown exposes its runtime properties as named exports.
|
|
10
10
|
export * from '@tarojs/taro'
|
|
11
|
-
export default
|
|
11
|
+
export default taro
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
type DevOutputFile = Readonly<{
|
|
2
|
-
type: string;
|
|
3
|
-
fileName: string;
|
|
4
|
-
source?: string | Uint8Array;
|
|
5
|
-
}>;
|
|
6
|
-
type DevOutput = Readonly<{
|
|
7
|
-
output: readonly DevOutputFile[];
|
|
8
|
-
}>;
|
|
9
|
-
/** Publishes Vite bundled-dev's source-addressed global WXSS at WeChat's required root path. */
|
|
10
|
-
export declare function publishWxDevStyle(output: DevOutput, outDir: string): Promise<void>;
|
|
11
|
-
export {};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { writeFile } from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { adaptWxss } from '../../css/plugins.js';
|
|
4
|
-
/** Publishes Vite bundled-dev's source-addressed global WXSS at WeChat's required root path. */
|
|
5
|
-
export async function publishWxDevStyle(output, outDir) {
|
|
6
|
-
// WX disables CSS splitting, so the only non-empty WXSS asset is the application stylesheet; Page companions are empty.
|
|
7
|
-
const globalStyle = output.output.find((file) => file.type === 'asset' && file.fileName.endsWith('.wxss') && file.source && file.source.length > 0);
|
|
8
|
-
if (!globalStyle?.source)
|
|
9
|
-
return;
|
|
10
|
-
const source = typeof globalStyle.source === 'string' ? globalStyle.source : new TextDecoder().decode(globalStyle.source);
|
|
11
|
-
await writeFile(path.join(outDir, 'app.wxss'), await adaptWxss(source));
|
|
12
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { writeFile } from 'node:fs/promises'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { adaptWxss } from '../../css/plugins.ts'
|
|
4
|
-
|
|
5
|
-
type DevOutputFile = Readonly<{
|
|
6
|
-
type: string
|
|
7
|
-
fileName: string
|
|
8
|
-
source?: string | Uint8Array
|
|
9
|
-
}>
|
|
10
|
-
|
|
11
|
-
type DevOutput = Readonly<{
|
|
12
|
-
output: readonly DevOutputFile[]
|
|
13
|
-
}>
|
|
14
|
-
|
|
15
|
-
/** Publishes Vite bundled-dev's source-addressed global WXSS at WeChat's required root path. */
|
|
16
|
-
export async function publishWxDevStyle(output: DevOutput, outDir: string): Promise<void> {
|
|
17
|
-
// WX disables CSS splitting, so the only non-empty WXSS asset is the application stylesheet; Page companions are empty.
|
|
18
|
-
const globalStyle = output.output.find(
|
|
19
|
-
(file) => file.type === 'asset' && file.fileName.endsWith('.wxss') && file.source && file.source.length > 0
|
|
20
|
-
)
|
|
21
|
-
if (!globalStyle?.source) return
|
|
22
|
-
|
|
23
|
-
const source =
|
|
24
|
-
typeof globalStyle.source === 'string' ? globalStyle.source : new TextDecoder().decode(globalStyle.source)
|
|
25
|
-
await writeFile(path.join(outDir, 'app.wxss'), await adaptWxss(source))
|
|
26
|
-
}
|