vite-plugin-taro 0.5.1 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.en.md +16 -16
  2. package/README.md +17 -16
  3. package/dist/node/plugins/client/client-taro.d.ts +4 -2
  4. package/dist/node/plugins/client/client-taro.js +43 -4
  5. package/dist/node/plugins/client/inject-taro-framework-apis.d.ts +5 -0
  6. package/dist/node/plugins/client/inject-taro-framework-apis.js +9 -0
  7. package/dist/node/plugins/css/plugins.d.ts +1 -3
  8. package/dist/node/plugins/css/plugins.js +91 -58
  9. package/dist/node/plugins/h5/create-stencil-client-adapter.d.ts +24 -0
  10. package/dist/node/plugins/h5/create-stencil-client-adapter.js +80 -0
  11. package/dist/node/plugins/h5/plugins.js +11 -54
  12. package/dist/node/plugins/wx/dev/dev-host.js +0 -3
  13. package/dist/node/plugins/wx/placement/placer.js +1 -2
  14. package/dist/node/plugins/wx/plugins.js +10 -1
  15. package/dist/node/vite-plugin.js +1 -1
  16. package/dist/runtime/client/taro/api.d.ts +2 -3
  17. package/dist/runtime/client/taro/api.js +9 -8
  18. package/package.json +12 -12
  19. package/src/node/plugins/client/client-taro.ts +52 -4
  20. package/src/node/plugins/client/inject-taro-framework-apis.ts +11 -0
  21. package/src/node/plugins/css/plugins.ts +89 -53
  22. package/src/node/plugins/h5/create-stencil-client-adapter.ts +109 -0
  23. package/src/node/plugins/h5/plugins.ts +11 -76
  24. package/src/node/plugins/wx/dev/dev-host.ts +0 -3
  25. package/src/node/plugins/wx/placement/placer.ts +1 -2
  26. package/src/node/plugins/wx/plugins.ts +10 -1
  27. package/src/node/vite-plugin.ts +1 -1
  28. package/src/runtime/client/taro/api.ts +9 -9
  29. package/dist/node/plugins/wx/dev/publish-wx-dev-style.d.ts +0 -11
  30. package/dist/node/plugins/wx/dev/publish-wx-dev-style.js +0 -12
  31. 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
- Documentation website: <https://vite-plugin-taro.netlify.app>
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://vite-plugin-taro.netlify.app/guides/automatic-subpackages/)
35
- - [Native WeChat components](https://vite-plugin-taro.netlify.app/guides/native-components/)
36
- - [Hot module replacement](https://vite-plugin-taro.netlify.app/guides/hot-module-replacement/)
37
- - [Skyline mode](https://vite-plugin-taro.netlify.app/guides/skyline-mode/)
38
- - [Migrate from Taro CLI](https://vite-plugin-taro.netlify.app/guides/migrate-from-taro/)
39
- - [Configuration reference](https://vite-plugin-taro.netlify.app/references/configuration/)
40
- - [Repository management](https://vite-plugin-taro.netlify.app/references/repository-management/)
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
- 文档网站:<https://vite-plugin-taro.netlify.app>
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://vite-plugin-taro.netlify.app/guides/automatic-subpackages/)
35
- - [微信原生组件](https://vite-plugin-taro.netlify.app/guides/native-components/)
36
- - [开发者工具热更新](https://vite-plugin-taro.netlify.app/guides/hot-module-replacement/)
37
- - [Skyline 模式](https://vite-plugin-taro.netlify.app/guides/skyline-mode/)
38
- - [从 Taro CLI 迁移](https://vite-plugin-taro.netlify.app/guides/migrate-from-taro/)
39
- - [配置参考](https://vite-plugin-taro.netlify.app/references/configuration/)
40
- - [仓库维护](https://vite-plugin-taro.netlify.app/references/repository-management/)
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 target-neutral Taro facade plugin. */
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,58 @@
1
+ import { normalizeModuleId } from '../../utils/modules.js';
1
2
  import { 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, resolvePackageFile('dist/runtime/client/taro/api.js')],
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 target-neutral Taro facade plugin. */
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 platformTaroId = resolvePlatformTaroId(target);
12
30
  return {
13
31
  name: 'vpt:client-taro',
14
32
  enforce: 'pre',
15
- resolveId(id) {
33
+ async resolveId(id, importer) {
34
+ if (id === '@tarojs/taro') {
35
+ if (!isClientTaroFacade(importer)) {
36
+ return clientTaroApiPath;
37
+ }
38
+ // Delegate the platform backend to Vite instead of returning an absolute dependency path. H5 marks this
39
+ // backend as an optimization root, so delegation lets Vite substitute its prebundled facade. Removing it
40
+ // bypasses CommonJS interop and exposes backend details such as base64-js directly to the browser.
41
+ return this.resolve(platformTaroId, importer, { skipSelf: true });
42
+ }
16
43
  return clientTaroModules.get(id);
44
+ },
45
+ // Taro's framework loader transforms source code, so apply it only to the shared physical facade.
46
+ transform(code, id) {
47
+ if (normalizeModuleId(id) === normalizedClientTaroApiPath) {
48
+ return injectTaroFrameworkApis(code);
49
+ }
17
50
  }
18
51
  };
19
52
  }
53
+ function resolvePlatformTaroId(target) {
54
+ return target === 'h5' ? '@tarojs/plugin-platform-h5/dist/runtime/apis' : '@tarojs/taro';
55
+ }
56
+ function isClientTaroFacade(importer) {
57
+ return importer !== undefined && normalizeModuleId(importer) === normalizedClientTaroApiPath;
58
+ }
@@ -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
- /** Completes the final compatibility pass required by generated WXSS. */
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
- // Keep the Vite plugin and the compatibility finalizer on identical WX conversion settings. A difference here can
6
- // make the second pass preserve browser units or apply a transformation that the first pass did not expect.
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
- const transformWxss = createStyleHandler(wxStyleOptions);
15
- /** Completes the final compatibility pass required by generated WXSS. */
16
- export async function adaptWxss(source) {
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
- ...(WeappTailwindcss({
24
- appType: 'weapp-vite',
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
- * Completes WXSS adaptation that weapp-tailwindcss leaves pending after rewriting split Tailwind imports.
56
+ * Finalizes the one global stylesheet after upstream Tailwind generation.
50
57
  *
51
- * `rewriteCssImports: true` makes the early Vite transform generate the Tailwind CSS, but the non-web generator
52
- * also defers CSS adaptation. The generated asset is consequently browser-shaped
53
- * CSS containing values and syntax such as `rem`, escaped class selectors, and `@property`. It is then recorded as a
54
- * processed Vite asset, so the upstream output finalizer does not perform the missing complete WXSS adaptation.
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 createWxssCompatibilityFinalizer() {
63
+ function createWxStyleFinalizer() {
61
64
  return {
62
- name: 'vpt:wxss-compatibility-finalizer',
63
- enforce: 'post',
65
+ name: 'vpt:wx-style-finalizer',
64
66
  generateBundle: {
65
67
  order: 'post',
66
68
  async handler(_, bundle) {
67
- // With cssCodeSplit: false the global style is the only asset with a logical
68
- // .css source name, even when an earlier hook already changed its final suffix.
69
- const globalStyleAsset = Object.values(bundle).find((output) => output.type === 'asset' &&
70
- (output.fileName.replaceAll('\\', '/').endsWith('.css') ||
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
- globalStyleAsset.fileName = 'app.wxss';
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
+ }
@@ -0,0 +1,24 @@
1
+ import type { Plugin } from 'vite';
2
+ /**
3
+ * Creates the compiler-owned adaptation of Stencil's client style insertion.
4
+ *
5
+ * Taro components inject their styles through this internal client. Its default insertion point places those styles
6
+ * after application CSS, allowing component defaults to override application rules. The adapter is registered in both
7
+ * Vite's application pipeline and the independent dependency-optimization build: removing either registration leaves
8
+ * production or development with an unadapted client. This explicit dual registration removes the former optimization
9
+ * exclusion while keeping one transformation implementation.
10
+ */
11
+ export declare function createStencilClientAdapter(): Plugin;
12
+ /** Applies the shared Stencil adaptation in either the application or dependency-optimization pipeline. */
13
+ export declare function adaptStencilClient(code: string, id: string): Promise<{
14
+ code: string;
15
+ map: {
16
+ version: number;
17
+ sources: string[];
18
+ names: string[];
19
+ sourceRoot?: string | undefined;
20
+ sourcesContent?: string[] | undefined;
21
+ mappings: string;
22
+ file: string;
23
+ } | null | undefined;
24
+ } | undefined>;
@@ -0,0 +1,80 @@
1
+ import { transformAsync, types } from '@babel/core';
2
+ import { normalizeModuleId } from '../../utils/modules.js';
3
+ import { packageRequire } from '../../utils/packages.js';
4
+ const stencilClientPath = packageRequire.resolve('@stencil/core/internal/client', {
5
+ paths: [packageRequire.resolve('@tarojs/components/package.json')]
6
+ });
7
+ const normalizedStencilClientPath = normalizeModuleId(stencilClientPath);
8
+ /**
9
+ * Creates the compiler-owned adaptation of Stencil's client style insertion.
10
+ *
11
+ * Taro components inject their styles through this internal client. Its default insertion point places those styles
12
+ * after application CSS, allowing component defaults to override application rules. The adapter is registered in both
13
+ * Vite's application pipeline and the independent dependency-optimization build: removing either registration leaves
14
+ * production or development with an unadapted client. This explicit dual registration removes the former optimization
15
+ * exclusion while keeping one transformation implementation.
16
+ */
17
+ export function createStencilClientAdapter() {
18
+ return {
19
+ name: 'vpt:h5-stencil-client',
20
+ transform: adaptStencilClient
21
+ };
22
+ }
23
+ /** Applies the shared Stencil adaptation in either the application or dependency-optimization pipeline. */
24
+ export async function adaptStencilClient(code, id) {
25
+ if (normalizeModuleId(id) !== normalizedStencilClientPath) {
26
+ return;
27
+ }
28
+ const transformed = await transformAsync(code, {
29
+ babelrc: false,
30
+ configFile: false,
31
+ filename: stencilClientPath,
32
+ plugins: [rewriteStencilStyleInsertion],
33
+ sourceFileName: stencilClientPath,
34
+ sourceMaps: true
35
+ });
36
+ if (transformed?.code === undefined || transformed.code === null) {
37
+ throw new Error(`Failed to adapt Stencil client: ${stencilClientPath}`);
38
+ }
39
+ return {
40
+ code: transformed.code,
41
+ map: transformed.map
42
+ };
43
+ }
44
+ /** Keeps Stencil-injected Taro component styles before application stylesheets. */
45
+ function rewriteStencilStyleInsertion() {
46
+ return {
47
+ name: 'vpt:rewrite-stencil-style-insertion',
48
+ visitor: {
49
+ CallExpression(callPath) {
50
+ if (!isStencilStyleInsertBeforeCall(callPath)) {
51
+ return;
52
+ }
53
+ callPath
54
+ .get('arguments.1')
55
+ .replaceWith(types.conditionalExpression(types.callExpression(types.memberExpression(types.identifier('scopeId'), types.identifier('startsWith')), [types.stringLiteral('sc-taro-')]), createStyleQuery('style,link[rel="stylesheet"]'), createStyleQuery('link')));
56
+ }
57
+ }
58
+ };
59
+ }
60
+ /** Identifies Stencil's default component-style insertion call. */
61
+ function isStencilStyleInsertBeforeCall(callPath) {
62
+ const { callee, arguments: callArguments } = callPath.node;
63
+ return (types.isMemberExpression(callee) &&
64
+ types.isIdentifier(callee.object, { name: 'styleContainerNode' }) &&
65
+ types.isIdentifier(callee.property, { name: 'insertBefore' }) &&
66
+ types.isIdentifier(callArguments[0], { name: 'styleElm' }) &&
67
+ isStyleQuery(callArguments[1], 'link'));
68
+ }
69
+ /** Identifies one style-container querySelector call. */
70
+ function isStyleQuery(node, selector) {
71
+ return (types.isCallExpression(node) &&
72
+ types.isMemberExpression(node.callee) &&
73
+ types.isIdentifier(node.callee.object, { name: 'styleContainerNode' }) &&
74
+ types.isIdentifier(node.callee.property, { name: 'querySelector' }) &&
75
+ types.isStringLiteral(node.arguments[0], { value: selector }));
76
+ }
77
+ /** Creates one style-container querySelector call. */
78
+ function createStyleQuery(selector) {
79
+ return types.callExpression(types.memberExpression(types.identifier('styleContainerNode'), types.identifier('querySelector')), [types.stringLiteral(selector)]);
80
+ }
@@ -1,10 +1,10 @@
1
- import { types } from '@babel/core';
2
1
  import babel from '@rolldown/plugin-babel';
3
2
  import { esTarget } from '../../utils/constant.js';
4
3
  import { toViteFileImportPath } from '../../utils/modules.js';
5
4
  import { packageRequire } from '../../utils/packages.js';
6
5
  import { clientTaroApiId } from '../client/client-taro.js';
7
6
  import { h5AppPath } from './constant.js';
7
+ import { createStencilClientAdapter } from './create-stencil-client-adapter.js';
8
8
  import { createModuleResolver } from './resolver/module-resolver.js';
9
9
  /** Creates the plugins that own the H5 target. */
10
10
  export function createH5TargetPlugins(options) {
@@ -21,12 +21,6 @@ function createH5TargetPlugin(options) {
21
21
  resolve: {
22
22
  mainFields: ['main:h5', 'browser', 'module', 'jsnext:main', 'jsnext'],
23
23
  alias: [
24
- {
25
- find: /^@stencil\/core\/internal\/client$/,
26
- replacement: packageRequire.resolve('@stencil/core/internal/client', {
27
- paths: [packageRequire.resolve('@tarojs/components/package.json')]
28
- })
29
- },
30
24
  {
31
25
  find: /^@tarojs\/components$/,
32
26
  replacement: packageRequire.resolve('@tarojs/components/lib/react')
@@ -34,15 +28,19 @@ function createH5TargetPlugin(options) {
34
28
  {
35
29
  find: /^@tarojs\/components\/dist\/components$/,
36
30
  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
31
  }
42
32
  ]
43
33
  },
44
34
  optimizeDeps: {
45
- exclude: ['@stencil/core/internal/client']
35
+ // The compiler-owned H5 app and Taro facade are injected after Vite's initial HTML scan. Prebundle
36
+ // the facade's platform backend as one boundary so its CommonJS implementation details receive
37
+ // interop without duplicating their package list. ReactDOM needs the same treatment for the H5 app.
38
+ include: ['@tarojs/plugin-platform-h5/dist/runtime/apis', 'react-dom/client'],
39
+ // Dependency optimization is its own Rolldown build and does not run application transform plugins.
40
+ // Register the same adapter there so optimized Taro components cannot embed Stencil's original client.
41
+ rolldownOptions: {
42
+ plugins: [createStencilClientAdapter()]
43
+ }
46
44
  },
47
45
  build: {
48
46
  target: esTarget
@@ -93,11 +91,7 @@ function createH5IndexHtmlTags() {
93
91
  /** Creates H5-only Babel transforms for Stencil CSS ordering and Taro API imports. */
94
92
  function createH5SupportPlugins() {
95
93
  return [
96
- babel({
97
- include: /[\\/]@stencil[\\/]core[\\/]internal[\\/]client[\\/]index\.js(?:\?.*)?$/,
98
- exclude: [],
99
- plugins: [rewriteStencilStyleInsertion]
100
- }),
94
+ createStencilClientAdapter(),
101
95
  babel({
102
96
  plugins: [
103
97
  [
@@ -111,43 +105,6 @@ function createH5SupportPlugins() {
111
105
  })
112
106
  ];
113
107
  }
114
- /** Keeps Stencil-injected Taro component styles before application stylesheets. */
115
- function rewriteStencilStyleInsertion() {
116
- return {
117
- name: 'vpt:rewrite-stencil-style-insertion',
118
- visitor: {
119
- CallExpression(callPath) {
120
- if (!isStencilStyleInsertBeforeCall(callPath)) {
121
- return;
122
- }
123
- callPath
124
- .get('arguments.1')
125
- .replaceWith(types.conditionalExpression(types.callExpression(types.memberExpression(types.identifier('scopeId'), types.identifier('startsWith')), [types.stringLiteral('sc-taro-')]), createStyleQuery('style,link[rel="stylesheet"]'), createStyleQuery('link')));
126
- }
127
- }
128
- };
129
- }
130
- /** Identifies Stencil's default component-style insertion call. */
131
- function isStencilStyleInsertBeforeCall(callPath) {
132
- const { callee, arguments: callArguments } = callPath.node;
133
- return (types.isMemberExpression(callee) &&
134
- types.isIdentifier(callee.object, { name: 'styleContainerNode' }) &&
135
- types.isIdentifier(callee.property, { name: 'insertBefore' }) &&
136
- types.isIdentifier(callArguments[0], { name: 'styleElm' }) &&
137
- isStyleQuery(callArguments[1], 'link'));
138
- }
139
- /** Identifies one style-container querySelector call. */
140
- function isStyleQuery(node, selector) {
141
- return (types.isCallExpression(node) &&
142
- types.isMemberExpression(node.callee) &&
143
- types.isIdentifier(node.callee.object, { name: 'styleContainerNode' }) &&
144
- types.isIdentifier(node.callee.property, { name: 'querySelector' }) &&
145
- types.isStringLiteral(node.arguments[0], { value: selector }));
146
- }
147
- /** Creates one style-container querySelector call. */
148
- function createStyleQuery(selector) {
149
- return types.callExpression(types.memberExpression(types.identifier('styleContainerNode'), types.identifier('querySelector')), [types.stringLiteral(selector)]);
150
- }
151
108
  /** Creates H5 Taro compile-time constants. */
152
109
  function createH5Defines() {
153
110
  return {
@@ -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 stylesheet conventions. The CSS adapter sees Tailwind's final
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.