vite-plugin-taro 0.5.12 → 0.5.14

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 (91) hide show
  1. package/dist/node/plugins/client/client-taro.d.ts +1 -1
  2. package/dist/node/plugins/client/client-taro.js +2 -1
  3. package/dist/node/plugins/h5/create-stencil-client-adapter.d.ts +1 -1
  4. package/dist/node/plugins/h5/create-stencil-client-adapter.js +2 -1
  5. package/dist/node/plugins/h5/plugins.js +22 -1
  6. package/dist/node/plugins/h5/resolver/module-resolver.js +2 -1
  7. package/dist/node/plugins/tailwind/tailwind-css.d.ts +1 -0
  8. package/dist/node/plugins/tailwind/tailwind-css.js +3 -0
  9. package/dist/node/plugins/wx/dev/create-hmr-results-stream.d.ts +23 -0
  10. package/dist/node/plugins/wx/dev/create-hmr-results-stream.js +57 -0
  11. package/dist/node/plugins/wx/dev/create-style-capture.d.ts +42 -0
  12. package/dist/node/plugins/wx/dev/create-style-capture.js +125 -0
  13. package/dist/node/plugins/wx/dev/dev-host.d.ts +5 -1
  14. package/dist/node/plugins/wx/dev/dev-host.js +170 -47
  15. package/dist/node/plugins/wx/dev/hmr-files.d.ts +10 -0
  16. package/dist/node/plugins/wx/dev/hmr-files.js +12 -0
  17. package/dist/node/plugins/wx/dev/host-actions.d.ts +16 -0
  18. package/dist/node/plugins/wx/dev/host-actions.js +58 -0
  19. package/dist/node/plugins/wx/dev/patch-publisher.d.ts +2 -2
  20. package/dist/node/plugins/wx/dev/patch-publisher.js +17 -1
  21. package/dist/node/plugins/wx/dev/plugins.d.ts +25 -2
  22. package/dist/node/plugins/wx/dev/plugins.js +61 -9
  23. package/dist/node/plugins/wx/dev/react-refresh.js +6 -2
  24. package/dist/node/plugins/wx/dev/runtime-reports.d.ts +27 -0
  25. package/dist/node/plugins/wx/dev/runtime-reports.js +45 -0
  26. package/dist/node/plugins/wx/dev/wx-dev-options.d.ts +10 -5
  27. package/dist/node/plugins/wx/dev/wx-dev-options.js +47 -24
  28. package/dist/node/plugins/wx/module.d.ts +1 -1
  29. package/dist/node/plugins/wx/module.js +2 -1
  30. package/dist/node/plugins/wx/native/compile-native-component-interface.js +2 -1
  31. package/dist/node/plugins/wx/native/create-native-component-output.js +2 -0
  32. package/dist/node/plugins/wx/native/native-component-assets.d.ts +1 -1
  33. package/dist/node/plugins/wx/native/native-component-assets.js +3 -3
  34. package/dist/node/plugins/wx/native/native-component-interface.js +2 -1
  35. package/dist/node/plugins/wx/output/files.d.ts +1 -1
  36. package/dist/node/plugins/wx/output/files.js +6 -1
  37. package/dist/node/plugins/wx/plugins.js +13 -6
  38. package/dist/node/plugins/wx/resolve/resolver.d.ts +2 -1
  39. package/dist/node/plugins/wx/resolve/resolver.js +34 -19
  40. package/dist/node/plugins/wx/styles/plugins.d.ts +3 -0
  41. package/dist/node/plugins/wx/styles/plugins.js +111 -0
  42. package/dist/node/plugins/wx/styles/transform-wx-style.d.ts +8 -0
  43. package/dist/node/plugins/wx/styles/transform-wx-style.js +9 -0
  44. package/dist/node/plugins/wx/styles/utils.d.ts +39 -0
  45. package/dist/node/plugins/wx/styles/utils.js +95 -0
  46. package/dist/node/utils/modules.d.ts +1 -1
  47. package/dist/node/utils/modules.js +4 -3
  48. package/dist/node/utils/packages.js +2 -2
  49. package/dist/node/utils/vite.d.ts +17 -0
  50. package/dist/node/utils/vite.js +43 -0
  51. package/dist/node/vite-plugin.js +0 -2
  52. package/package.json +4 -3
  53. package/src/node/plugins/client/client-taro.ts +2 -2
  54. package/src/node/plugins/h5/create-stencil-client-adapter.ts +2 -2
  55. package/src/node/plugins/h5/plugins.ts +22 -1
  56. package/src/node/plugins/h5/resolver/module-resolver.ts +2 -1
  57. package/src/node/plugins/tailwind/tailwind-css.ts +4 -0
  58. package/src/node/plugins/wx/dev/create-hmr-results-stream.ts +71 -0
  59. package/src/node/plugins/wx/dev/create-style-capture.ts +179 -0
  60. package/src/node/plugins/wx/dev/dev-host.ts +198 -63
  61. package/src/node/plugins/wx/dev/hmr-files.ts +13 -0
  62. package/src/node/plugins/wx/dev/host-actions.ts +88 -0
  63. package/src/node/plugins/wx/dev/patch-publisher.ts +19 -2
  64. package/src/node/plugins/wx/dev/plugins.ts +67 -10
  65. package/src/node/plugins/wx/dev/react-refresh.ts +6 -2
  66. package/src/node/plugins/wx/dev/runtime-reports.ts +70 -0
  67. package/src/node/plugins/wx/dev/wx-dev-options.ts +53 -32
  68. package/src/node/plugins/wx/module.ts +2 -4
  69. package/src/node/plugins/wx/native/compile-native-component-interface.ts +2 -1
  70. package/src/node/plugins/wx/native/create-native-component-output.ts +2 -0
  71. package/src/node/plugins/wx/native/native-component-assets.ts +3 -4
  72. package/src/node/plugins/wx/native/native-component-interface.ts +2 -1
  73. package/src/node/plugins/wx/output/files.ts +6 -1
  74. package/src/node/plugins/wx/plugins.ts +16 -6
  75. package/src/node/plugins/wx/resolve/resolver.ts +36 -19
  76. package/src/node/plugins/wx/styles/plugins.ts +125 -0
  77. package/src/node/plugins/wx/styles/transform-wx-style.ts +11 -0
  78. package/src/node/plugins/wx/styles/utils.ts +119 -0
  79. package/src/node/utils/modules.ts +4 -3
  80. package/src/node/utils/packages.ts +2 -2
  81. package/src/node/utils/vite.ts +67 -0
  82. package/src/node/vite-plugin.ts +0 -2
  83. package/dist/node/plugins/css/plugins.d.ts +0 -4
  84. package/dist/node/plugins/css/plugins.js +0 -119
  85. package/dist/node/plugins/wx/dev/create-wx-dev-mode.d.ts +0 -6
  86. package/dist/node/plugins/wx/dev/create-wx-dev-mode.js +0 -9
  87. package/dist/node/utils/serialized-task-queue.d.ts +0 -13
  88. package/dist/node/utils/serialized-task-queue.js +0 -25
  89. package/src/node/plugins/css/plugins.ts +0 -135
  90. package/src/node/plugins/wx/dev/create-wx-dev-mode.ts +0 -14
  91. package/src/node/utils/serialized-task-queue.ts +0 -32
@@ -0,0 +1,111 @@
1
+ import { WeappTailwindcss } from 'weapp-tailwindcss/vite';
2
+ import { transformVitePlugin } from '../../../utils/vite.js';
3
+ import { tailwindcssBasedir } from '../../tailwind/tailwind-css.js';
4
+ import { transformWxStyle, wxStyleOptions } from './transform-wx-style.js';
5
+ /*
6
+ * WX style output order:
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. `alignGenerateBundleOrder` removes only that broader phase from upstream output hooks.
15
+ */
16
+ /** Creates the complete WX Tailwind and global-style pipeline. */
17
+ export function createWxStylePlugins() {
18
+ const tailwindPlugins = WeappTailwindcss({
19
+ // VPT is a custom Vite compiler.
20
+ // Using Taro's adapter would import Taro-specific CSS ownership rules which we don't need.
21
+ appType: 'weapp-vite',
22
+ // WX generation rewrites Tailwind's split package imports before Vite tries to resolve them in the app.
23
+ // Without this, strict workspaces fail on imports such as `tailwindcss/theme.css`.
24
+ rewriteCssImports: true,
25
+ platform: 'weapp',
26
+ tailwindcssBasedir,
27
+ generator: {
28
+ target: 'weapp'
29
+ },
30
+ cssOptions: wxStyleOptions,
31
+ logLevel: 'warn'
32
+ }) ?? [];
33
+ return [transformVitePlugin(tailwindPlugins, alignGenerateBundleOrder), createWxStyleFinalizer(transformWxStyle)];
34
+ }
35
+ /**
36
+ * Finalizes the one global stylesheet after upstream Tailwind generation.
37
+ *
38
+ * `cssCodeSplit: false` makes the compiler style global, but upstream can name it `.css` or `.wxss` depending on build
39
+ * mode. This hook converts its complete final contents once and renames that compiler asset to `assets/global.wxss`. An
40
+ * application without styles receives an empty global asset at the same stable path. Running earlier loses CSS from
41
+ * dynamic chunks; running after native companion emission would also see Page and native-component WXSS files that must
42
+ * remain opaque.
43
+ */
44
+ function createWxStyleFinalizer(transformStyle) {
45
+ /*
46
+ * DevEngine can omit an unchanged stylesheet from later complete output generations. Absence therefore has two meanings:
47
+ * the first clean output genuinely has no styles, or a later output is reusing the physical stylesheet already on disk.
48
+ * The Vite server creates a fresh plugin instance on a clean start, so this one lifecycle bit distinguishes those cases and
49
+ * resets naturally on restart. Deliberately retain no CSS bytes or graph projection here: memory remains O(1), changed CSS
50
+ * still arrives as a normal asset, and the dev host remains the only owner of incremental style preparation.
51
+ */
52
+ let hasFinalizedOutput = false;
53
+ return {
54
+ name: 'vpt:wx-style-finalizer',
55
+ generateBundle: {
56
+ order: 'post',
57
+ async handler(_, bundle) {
58
+ const styles = Object.values(bundle).filter(isStyleAsset);
59
+ // Multiple compiler styles mean cssCodeSplit was re-enabled. Choosing one would silently lose CSS.
60
+ if (styles.length > 1) {
61
+ throw new Error('WX builds support at most one compiler-emitted stylesheet');
62
+ }
63
+ if (styles.length === 0) {
64
+ /*
65
+ * A clean first output must materialize the stable import target imported by app.wxss. On later complete
66
+ * outputs, DevEngine's physical writer preserves files omitted from the bundle; emitting the same empty
67
+ * placeholder would instead overwrite valid unchanged WXSS. Emit nothing in that later case. A source or
68
+ * configuration change that really removes all styles is already published as empty by ordinary style HMR,
69
+ * while a clean server restart reaches this first-output branch and also clears any stale prior file.
70
+ */
71
+ if (!hasFinalizedOutput) {
72
+ this.emitFile({ type: 'asset', fileName: 'assets/global.wxss', source: '' });
73
+ }
74
+ hasFinalizedOutput = true;
75
+ return;
76
+ }
77
+ const [style] = styles;
78
+ const source = typeof style.source === 'string' ? style.source : new TextDecoder().decode(style.source);
79
+ const transformedResult = await transformStyle(source);
80
+ // Preserve the compiler stylesheet as the real global asset so its bundle metadata and ownership remain
81
+ // intact. Only its finalized contents and stable WXSS identity change.
82
+ style.source = transformedResult.css;
83
+ style.fileName = 'assets/global.wxss';
84
+ hasFinalizedOutput = true;
85
+ }
86
+ }
87
+ };
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.
100
+ */
101
+ function alignGenerateBundleOrder(plugin) {
102
+ if (plugin.enforce !== 'post' || plugin.generateBundle === undefined) {
103
+ return plugin;
104
+ }
105
+ // Clone rather than mutate: upstream may retain or reuse the descriptor returned by its factory.
106
+ return { ...plugin, enforce: undefined };
107
+ }
108
+ /** Selects only the compiler stylesheet; native WXSS assets are emitted by the later WX hook. */
109
+ function isStyleAsset(output) {
110
+ return output.type === 'asset' && /\.(?:css|wxss)$/.test(output.fileName);
111
+ }
@@ -0,0 +1,8 @@
1
+ export declare const wxStyleOptions: {
2
+ readonly cssCalc: false;
3
+ readonly autoprefixer: false;
4
+ readonly rem2rpx: true;
5
+ readonly px2rpx: true;
6
+ };
7
+ /** Shared finalization policy for complete builds and host-owned style HMR. */
8
+ export declare const transformWxStyle: import("@weapp-tailwindcss/postcss").StyleHandler;
@@ -0,0 +1,9 @@
1
+ import { createStyleHandler } from '@weapp-tailwindcss/postcss';
2
+ export const wxStyleOptions = {
3
+ cssCalc: false,
4
+ autoprefixer: false,
5
+ rem2rpx: true,
6
+ px2rpx: true
7
+ };
8
+ /** Shared finalization policy for complete builds and host-owned style HMR. */
9
+ export const transformWxStyle = createStyleHandler(wxStyleOptions);
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Creates an auxiliary style request without replacing the physical Rolldown graph module.
3
+ *
4
+ * `weapp-vite-sidecar` is an upstream protocol marker, not a cache-busting nonce. `weapp-tailwindcss` detects the query
5
+ * key, strips the complete query when resolving the physical CSS pipeline file, and excludes this synthetic request from
6
+ * transformed-source candidate collection. That lets the request use the latest candidate state without feeding generated
7
+ * CSS back into Tailwind's source memory. The descriptive `style` value is stable; upstream treats the presence of the key
8
+ * as the protocol contract.
9
+ */
10
+ export declare function createTailwindSidecarId(rootId: string): string;
11
+ /** Selects imported style modules whose Vite development output owns a runtime CSS payload. */
12
+ export declare function isGlobalStyleRequest(id: string): boolean;
13
+ /**
14
+ * Creates the ordered style plan for one completed HMR transaction.
15
+ *
16
+ * `entryIds` carries semantic cascade ownership from the WX resolver: the App capsule first, followed by Page capsules in
17
+ * configured route order. Each entry is traversed depth-first. Static imports retain source order and precede dynamic imports;
18
+ * dynamic branches are included because WX cannot inject lazy CSS at browser runtime. A style follows its dependencies,
19
+ * matching evaluation order.
20
+ *
21
+ * Graph IDs may contain queries while `hasStyle` reads physical IDs. Normalization lets aliases share one captured style.
22
+ * JavaScript and non-runtime CSS requests remain traversal nodes but do not enter the plan. All mutable traversal state is
23
+ * transaction-local, so import additions and removals need no invalidation bookkeeping. Complexity is O(modules + edges),
24
+ * with O(modules + styles) temporary memory.
25
+ */
26
+ export declare function createGraphStylePlan(entryIds: readonly string[], getModuleInfo: (moduleId: string) => Readonly<{
27
+ importedIds: readonly string[];
28
+ dynamicallyImportedIds: readonly string[];
29
+ }> | null, hasStyle: (styleId: string) => boolean): readonly string[];
30
+ /** Renders one immutable graph plan after any Tailwind roots in that same plan have been refreshed. */
31
+ export declare function composeGraphStyleCss(styleIds: readonly string[], getStyleCss: (styleId: string) => string): string;
32
+ /**
33
+ * Extracts Vite's final CSS payload from the development module without evaluating its browser HMR code.
34
+ *
35
+ * Remove this parser when either Vite exposes a supported plugin-container API that returns final CSS directly, or
36
+ * `weapp-tailwindcss` exposes generated root CSS after candidate updates. Until then the sidecar receives Vite's JavaScript
37
+ * style module, so this function isolates the version-specific `__vite__css` serialization contract.
38
+ */
39
+ export declare function extractViteCss(moduleCode: string, rootId: string): string;
@@ -0,0 +1,95 @@
1
+ import { isCSSRequest } from 'vite';
2
+ import { normalizeModuleId } from '../../../utils/modules.js';
3
+ const nonRuntimeStyleQueries = ['direct', 'inline', 'inline-css', 'raw', 'style-attr', 'transform-only', 'url'];
4
+ /**
5
+ * Creates an auxiliary style request without replacing the physical Rolldown graph module.
6
+ *
7
+ * `weapp-vite-sidecar` is an upstream protocol marker, not a cache-busting nonce. `weapp-tailwindcss` detects the query
8
+ * key, strips the complete query when resolving the physical CSS pipeline file, and excludes this synthetic request from
9
+ * transformed-source candidate collection. That lets the request use the latest candidate state without feeding generated
10
+ * CSS back into Tailwind's source memory. The descriptive `style` value is stable; upstream treats the presence of the key
11
+ * as the protocol contract.
12
+ */
13
+ export function createTailwindSidecarId(rootId) {
14
+ return `${rootId}?weapp-vite-sidecar=style`;
15
+ }
16
+ /** Selects imported style modules whose Vite development output owns a runtime CSS payload. */
17
+ export function isGlobalStyleRequest(id) {
18
+ if (!isCSSRequest(id)) {
19
+ return false;
20
+ }
21
+ const queryStart = id.indexOf('?');
22
+ if (queryStart < 0) {
23
+ return true;
24
+ }
25
+ const fragmentStart = id.indexOf('#', queryStart);
26
+ const query = id.slice(queryStart + 1, fragmentStart < 0 ? undefined : fragmentStart);
27
+ const parameters = new URLSearchParams(query);
28
+ return (!parameters.has('weapp-vite-sidecar') && nonRuntimeStyleQueries.every((parameter) => !parameters.has(parameter)));
29
+ }
30
+ /**
31
+ * Creates the ordered style plan for one completed HMR transaction.
32
+ *
33
+ * `entryIds` carries semantic cascade ownership from the WX resolver: the App capsule first, followed by Page capsules in
34
+ * configured route order. Each entry is traversed depth-first. Static imports retain source order and precede dynamic imports;
35
+ * dynamic branches are included because WX cannot inject lazy CSS at browser runtime. A style follows its dependencies,
36
+ * matching evaluation order.
37
+ *
38
+ * Graph IDs may contain queries while `hasStyle` reads physical IDs. Normalization lets aliases share one captured style.
39
+ * JavaScript and non-runtime CSS requests remain traversal nodes but do not enter the plan. All mutable traversal state is
40
+ * transaction-local, so import additions and removals need no invalidation bookkeeping. Complexity is O(modules + edges),
41
+ * with O(modules + styles) temporary memory.
42
+ */
43
+ export function createGraphStylePlan(entryIds, getModuleInfo, hasStyle) {
44
+ // These local collections collapse cycles, shared modules, and aliases without retaining derived topology between batches.
45
+ const visitedModuleIds = new Set();
46
+ const visitedStyleIds = new Set();
47
+ const styleIds = [];
48
+ const visit = (moduleId) => {
49
+ if (visitedModuleIds.has(moduleId)) {
50
+ return;
51
+ }
52
+ visitedModuleIds.add(moduleId);
53
+ const moduleInfo = getModuleInfo(moduleId);
54
+ if (!moduleInfo) {
55
+ return;
56
+ }
57
+ moduleInfo.importedIds.forEach(visit);
58
+ moduleInfo.dynamicallyImportedIds.forEach(visit);
59
+ const styleId = normalizeModuleId(moduleId);
60
+ if (hasStyle(styleId) && !visitedStyleIds.has(styleId)) {
61
+ visitedStyleIds.add(styleId);
62
+ styleIds.push(styleId);
63
+ }
64
+ };
65
+ entryIds.forEach(visit);
66
+ return styleIds;
67
+ }
68
+ /** Renders one immutable graph plan after any Tailwind roots in that same plan have been refreshed. */
69
+ export function composeGraphStyleCss(styleIds, getStyleCss) {
70
+ return styleIds.map(getStyleCss).join('\n');
71
+ }
72
+ /**
73
+ * Extracts Vite's final CSS payload from the development module without evaluating its browser HMR code.
74
+ *
75
+ * Remove this parser when either Vite exposes a supported plugin-container API that returns final CSS directly, or
76
+ * `weapp-tailwindcss` exposes generated root CSS after candidate updates. Until then the sidecar receives Vite's JavaScript
77
+ * style module, so this function isolates the version-specific `__vite__css` serialization contract.
78
+ */
79
+ export function extractViteCss(moduleCode, rootId) {
80
+ const assignmentPrefix = 'const __vite__css = ';
81
+ const assignmentStart = moduleCode.indexOf(assignmentPrefix);
82
+ if (assignmentStart < 0) {
83
+ throw new Error(`Vite CSS transform for ${rootId} did not expose __vite__css`);
84
+ }
85
+ // Vite serializes the payload with JSON.stringify on one assignment line. Parse that literal so quotes, escapes, and
86
+ // embedded CSS newlines are decoded by JSON rather than by a second, subtly different unescaping implementation.
87
+ const valueStart = assignmentStart + assignmentPrefix.length;
88
+ const lineEnd = moduleCode.indexOf('\n', valueStart);
89
+ const serializedCss = moduleCode.slice(valueStart, lineEnd < 0 ? moduleCode.length : lineEnd);
90
+ const css = JSON.parse(serializedCss);
91
+ if (typeof css !== 'string') {
92
+ throw new Error(`Vite CSS transform for ${rootId} exposed a non-string __vite__css value`);
93
+ }
94
+ return css;
95
+ }
@@ -14,7 +14,7 @@ export declare function resolveAppComponentPath({ appPath, projectRoot }: AppCom
14
14
  export declare function resolvePageComponentPath({ pagePath, projectRoot }: PageComponentPathOptions): string;
15
15
  /** Creates a portable import for one configured Page component. */
16
16
  export declare function createPageComponentImportPath(options: PageComponentPathOptions): string;
17
- /** Normalizes a file-backed Vite module ID for stable comparisons. */
17
+ /** Converts a file-backed Vite request ID to its normalized physical path for stable comparisons. */
18
18
  export declare function normalizeModuleId(id: string): string;
19
19
  /** Converts a local file path into Vite's portable file-system import form. */
20
20
  export declare function toViteFileImportPath(filePath: string): string;
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { normalizePath } from 'vite';
2
3
  /** Resolves a final relative reference to the canonical output chunk ID used by the WX module registry. */
3
4
  export function resolveChunkReference(importerChunkId, reference) {
4
5
  if (!reference.startsWith('./') && !reference.startsWith('../')) {
@@ -18,11 +19,11 @@ export function resolvePageComponentPath({ pagePath, projectRoot }) {
18
19
  export function createPageComponentImportPath(options) {
19
20
  return toViteFileImportPath(resolvePageComponentPath(options));
20
21
  }
21
- /** Normalizes a file-backed Vite module ID for stable comparisons. */
22
+ /** Converts a file-backed Vite request ID to its normalized physical path for stable comparisons. */
22
23
  export function normalizeModuleId(id) {
23
- return id.replaceAll('\\', '/').replace(/\?.*$/, '');
24
+ return normalizePath(id.replace(/\?.*$/, ''));
24
25
  }
25
26
  /** Converts a local file path into Vite's portable file-system import form. */
26
27
  export function toViteFileImportPath(filePath) {
27
- return `/@fs/${normalizeModuleId(path.resolve(filePath))}`;
28
+ return `/@fs/${normalizePath(path.resolve(filePath))}`;
28
29
  }
@@ -1,9 +1,9 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import path from 'node:path';
3
- import { normalizeModuleId } from './modules.js';
3
+ import { normalizePath } from 'vite';
4
4
  export const packageRequire = createRequire(import.meta.url);
5
5
  const packageRoot = path.dirname(packageRequire.resolve('vite-plugin-taro/package.json'));
6
6
  /** Resolves a file shipped by this package as a portable Vite module ID. */
7
7
  export function resolvePackageFile(...segments) {
8
- return normalizeModuleId(path.join(packageRoot, ...segments));
8
+ return normalizePath(path.join(packageRoot, ...segments));
9
9
  }
@@ -0,0 +1,17 @@
1
+ import type { HookHandler, Plugin, PluginOption } from 'vite';
2
+ type TransformHook = HookHandler<NonNullable<Plugin['transform']>>;
3
+ export type TransformHookResult = Awaited<ReturnType<TransformHook>>;
4
+ export type AsyncTransformHook = (this: ThisParameterType<TransformHook>, ...args: Parameters<TransformHook>) => Promise<TransformHookResult>;
5
+ export type TransformHookWrapper = (transform: AsyncTransformHook) => AsyncTransformHook;
6
+ export type PluginMapper = (plugin: Plugin) => Plugin;
7
+ /** Transforms every concrete plugin while preserving nested arrays, falsy options, and promised options. */
8
+ export declare function transformVitePlugin(pluginOptions: PluginOption[], mapPlugin: PluginMapper): PluginOption[];
9
+ /**
10
+ * Clones a Vite transform hook with middleware that controls execution of the original handler.
11
+ *
12
+ * Function and object hook forms retain their original plugin context. Object metadata such as `order` and `filter` is copied
13
+ * unchanged, and the input descriptor is never mutated. The wrapper receives the normalized asynchronous transform with its
14
+ * complete plugin context, code, ID, and metadata signature, and returns the handler that continues Vite's plugin pipeline.
15
+ */
16
+ export declare function wrapPluginTransform(plugin: Plugin, wrapper: TransformHookWrapper): Plugin;
17
+ export {};
@@ -0,0 +1,43 @@
1
+ /** Transforms every concrete plugin while preserving nested arrays, falsy options, and promised options. */
2
+ export function transformVitePlugin(pluginOptions, mapPlugin) {
3
+ return pluginOptions.map((option) => transformPluginOption(option, mapPlugin));
4
+ }
5
+ function transformPluginOption(option, mapPlugin) {
6
+ if (option instanceof Promise) {
7
+ return option.then((resolvedOption) => transformPluginOption(resolvedOption, mapPlugin));
8
+ }
9
+ if (Array.isArray(option)) {
10
+ return transformVitePlugin(option, mapPlugin);
11
+ }
12
+ return isPlugin(option) ? mapPlugin(option) : option;
13
+ }
14
+ function isPlugin(option) {
15
+ return (option !== null &&
16
+ option !== false &&
17
+ option !== undefined &&
18
+ typeof option === 'object' &&
19
+ !Array.isArray(option) &&
20
+ 'name' in option);
21
+ }
22
+ /**
23
+ * Clones a Vite transform hook with middleware that controls execution of the original handler.
24
+ *
25
+ * Function and object hook forms retain their original plugin context. Object metadata such as `order` and `filter` is copied
26
+ * unchanged, and the input descriptor is never mutated. The wrapper receives the normalized asynchronous transform with its
27
+ * complete plugin context, code, ID, and metadata signature, and returns the handler that continues Vite's plugin pipeline.
28
+ */
29
+ export function wrapPluginTransform(plugin, wrapper) {
30
+ const { transform } = plugin;
31
+ if (!transform) {
32
+ throw new Error(`${plugin.name} must expose a transform hook`);
33
+ }
34
+ const isTransformFunction = typeof transform === 'function';
35
+ const handler = isTransformFunction ? transform : transform.handler;
36
+ const wrappedHandler = wrapper(async function (code, id, meta) {
37
+ return handler.call(this, code, id, meta);
38
+ });
39
+ return {
40
+ ...plugin,
41
+ transform: isTransformFunction ? wrappedHandler : { ...transform, handler: wrappedHandler }
42
+ };
43
+ }
@@ -1,7 +1,6 @@
1
1
  import react from '@vitejs/plugin-react';
2
2
  import { createClientTaroPlugin } from './plugins/client/client-taro.js';
3
3
  import { createConditionalDirectivePlugin } from './plugins/conditional/conditional-directives.js';
4
- import { createCssPlugins } from './plugins/css/plugins.js';
5
4
  import { createH5TargetPlugins } from './plugins/h5/plugins.js';
6
5
  import { createWxTargetPlugins } from './plugins/wx/plugins.js';
7
6
  /** Creates the Vite plugins for one Taro target. */
@@ -9,7 +8,6 @@ export default function vitePluginTaro(options) {
9
8
  return [
10
9
  createConditionalDirectivePlugin(options.target),
11
10
  createClientTaroPlugin(options.target),
12
- ...createCssPlugins(options.target),
13
11
  ...react(),
14
12
  ...(options.target === 'wx' ? createWxTargetPlugins(options) : []),
15
13
  ...(options.target === 'h5' ? createH5TargetPlugins(options) : [])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-taro",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
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",
@@ -73,10 +73,11 @@
73
73
  "react-reconciler": "0.33.0",
74
74
  "react-refresh": "^0.18.0",
75
75
  "rolldown": "1.2.3",
76
+ "rxjs": "^7.8.2",
76
77
  "tailwindcss": "^4.3.3",
77
78
  "weapp-tailwindcss": "^5.2.11",
78
- "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.12",
79
- "@tarojs/react": "npm:vite-plugin-taro-react@0.5.12"
79
+ "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.5.14",
80
+ "@tarojs/react": "npm:vite-plugin-taro-react@0.5.14"
80
81
  },
81
82
  "peerDependencies": {
82
83
  "react": "^19.0.0",
@@ -1,4 +1,4 @@
1
- import type { Plugin } from 'vite'
1
+ import { normalizePath, type Plugin } from 'vite'
2
2
  import type { VitePluginTaroTarget } from '../../../options.ts'
3
3
  import { normalizeModuleId } from '../../utils/modules.ts'
4
4
  import { resolvePackageFile } from '../../utils/packages.ts'
@@ -21,7 +21,7 @@ import { injectTaroFrameworkApis } from './inject-taro-framework-apis.ts'
21
21
  export const clientTaroApiId = 'virtual:taro/api'
22
22
 
23
23
  const clientTaroApiPath = resolvePackageFile('dist/runtime/client/taro/api.js')
24
- const normalizedClientTaroApiPath = normalizeModuleId(clientTaroApiPath)
24
+ const normalizedClientTaroApiPath = normalizePath(clientTaroApiPath)
25
25
 
26
26
  const clientTaroComponentId = 'virtual:taro/components'
27
27
 
@@ -1,6 +1,6 @@
1
1
  import type { WalkerEnter } from 'oxc-walker'
2
2
  import type { RolldownMagicString } from 'rolldown'
3
- import type { Plugin } from 'vite'
3
+ import { normalizePath, type Plugin } from 'vite'
4
4
  import { normalizeModuleId } from '../../utils/modules.ts'
5
5
  import { transformWithOxcWalker } from '../../utils/oxc-transform.ts'
6
6
  import { packageRequire } from '../../utils/packages.ts'
@@ -8,7 +8,7 @@ import { packageRequire } from '../../utils/packages.ts'
8
8
  const stencilClientPath = packageRequire.resolve('@stencil/core/internal/client', {
9
9
  paths: [packageRequire.resolve('@tarojs/components/package.json')]
10
10
  })
11
- const normalizedStencilClientPath = normalizeModuleId(stencilClientPath)
11
+ const normalizedStencilClientPath = normalizePath(stencilClientPath)
12
12
 
13
13
  /**
14
14
  * Creates the compiler-owned adaptation of Stencil's client style insertion.
@@ -1,17 +1,38 @@
1
1
  import babel, { defineRolldownBabelPreset } from '@rolldown/plugin-babel'
2
2
  import type { HtmlTagDescriptor, Plugin, PluginOption } from 'vite'
3
+ import { WeappTailwindcss } from 'weapp-tailwindcss/vite'
3
4
  import type { VitePluginTaroOptions } from '../../../options.ts'
4
5
  import { esTarget } from '../../utils/constant.ts'
5
6
  import { toViteFileImportPath } from '../../utils/modules.ts'
6
7
  import { packageRequire } from '../../utils/packages.ts'
7
8
  import { clientTaroApiId } from '../client/client-taro.ts'
9
+ import { tailwindcssBasedir } from '../tailwind/tailwind-css.ts'
8
10
  import { h5AppPath } from './constant.ts'
9
11
  import { createStencilClientAdapter } from './create-stencil-client-adapter.ts'
10
12
  import { createModuleResolver } from './resolver/module-resolver.ts'
11
13
 
12
14
  /** Creates the plugins that own the H5 target. */
13
15
  export function createH5TargetPlugins(options: VitePluginTaroOptions): PluginOption[] {
14
- return [...createH5SupportPlugins(), createH5TargetPlugin(options)]
16
+ return [
17
+ WeappTailwindcss({
18
+ appType: 'weapp-vite',
19
+ rewriteCssImports: false,
20
+ platform: 'web',
21
+ tailwindcssBasedir,
22
+ generator: {
23
+ target: 'web'
24
+ },
25
+ cssOptions: {
26
+ cssCalc: false,
27
+ autoprefixer: true,
28
+ rem2rpx: true,
29
+ px2rpx: true
30
+ },
31
+ logLevel: 'warn'
32
+ }),
33
+ ...createH5SupportPlugins(),
34
+ createH5TargetPlugin(options)
35
+ ]
15
36
  }
16
37
 
17
38
  /** Configures H5 resolution and supplies the specialized physical application entry. */
@@ -1,3 +1,4 @@
1
+ import { normalizePath } from 'vite'
1
2
  import type { VitePluginTaroOptions } from '../../../../options.ts'
2
3
  import { normalizeModuleId, resolveAppComponentPath } from '../../../utils/modules.ts'
3
4
  import { appComponentId } from '../../client/constant.ts'
@@ -24,7 +25,7 @@ export function createModuleResolver(options: VitePluginTaroOptions) {
24
25
  projectRoot: string
25
26
  sourcemap?: boolean
26
27
  }) {
27
- if (normalizeModuleId(id) === normalizeModuleId(h5AppPath)) {
28
+ if (normalizeModuleId(id) === normalizePath(h5AppPath)) {
28
29
  return transformH5App({ code, id, options, projectRoot, sourcemap })
29
30
  }
30
31
  }
@@ -0,0 +1,4 @@
1
+ import path from 'node:path'
2
+ import { packageRequire } from '../../utils/packages.ts'
3
+
4
+ export const tailwindcssBasedir = path.dirname(packageRequire.resolve('tailwindcss/package.json'))
@@ -0,0 +1,71 @@
1
+ import type { DevOptions } from 'rolldown/experimental'
2
+ import { buffer, debounceTime, filter, type SchedulerLike, Subject } from 'rxjs'
3
+
4
+ type HmrUpdatesResult = Parameters<NonNullable<DevOptions['onHmrUpdates']>>[0]
5
+ type HmrUpdates = Exclude<HmrUpdatesResult, Error>
6
+
7
+ /**
8
+ * Adapts Rolldown's non-awaited HMR callback into lossless quiet-window publications.
9
+ *
10
+ * Debouncing the result stream itself would retain only the final callback and lose incremental patch factories that later
11
+ * patches provably do not reproduce. Instead, the debounced view is only a closing notifier for `buffer`: every callback is
12
+ * retained in arrival order, and one configured quiet period emits the complete window to the host's existing serialized
13
+ * writer. This first stream migration deliberately does not own physical state; `publish` and `reportError` remain synchronous
14
+ * admission callbacks so the dev host can enqueue both through its single writer.
15
+ *
16
+ * DevEngine failures are values, not Observable errors. They represent transient editor generations and carry no executable
17
+ * patch, so the stream reports the final error but otherwise removes them. Successful callbacks on either side remain ordered
18
+ * and lossless; Rolldown generated each against its unpublished client frontier, and the host delivers every retained payload.
19
+ * Completing the returned Subject flushes its current buffer synchronously, allowing host shutdown to await the resulting
20
+ * serialized task rather than silently dropping an admitted patch.
21
+ *
22
+ * Complexity is O(updates + changed files) per emitted window, with one retained reference per callback until the quiet edge.
23
+ */
24
+ export function createHmrResultsStream(
25
+ settleMilliseconds: number,
26
+ scheduler: SchedulerLike,
27
+ publish: (result: HmrUpdates) => void,
28
+ reportError: (error: Error) => void
29
+ ): Subject<HmrUpdatesResult> {
30
+ /*
31
+ * This hot Subject is the sole mutable boundary between Rolldown's non-awaited callback and RxJS. Each next preserves one
32
+ * compiler generation by reference and in arrival order. buffer owns the temporary lossless window; debounceTime observes the
33
+ * same Subject only to decide when that window closes. Replacing this with a debounced scalar would discard patch factories,
34
+ * while letting callback Promises mutate host state directly would overlap publications. Completion flushes the final window
35
+ * before shutdown, after which the Subject is never reused.
36
+ */
37
+ const results = new Subject<HmrUpdatesResult>()
38
+
39
+ results
40
+ .pipe(
41
+ buffer(results.pipe(debounceTime(settleMilliseconds, scheduler))),
42
+ filter((window) => window.length > 0)
43
+ )
44
+ .subscribe((window) => {
45
+ /*
46
+ * An Error is one source generation that produced no executable delta; it does not invalidate successful Rolldown
47
+ * callbacks already admitted on either side of it. Dropping the whole quiet window would therefore discard real
48
+ * patch factories, while starting a complete build would compile the same known-invalid editor contents. Keep the
49
+ * old runtime running, report only the latest diagnostic from a repeated parser burst, and continue below with the
50
+ * successful callback values exactly as if the temporary invalid save had never produced an HMR payload.
51
+ */
52
+ const lastFailure = window.findLast((result): result is Error => result instanceof Error)
53
+ if (lastFailure) {
54
+ reportError(lastFailure)
55
+ }
56
+ const successfulWindow = window.filter((result): result is HmrUpdates => !(result instanceof Error))
57
+ if (successfulWindow.length > 0) {
58
+ /*
59
+ * flatMap preserves callback arrival order and each callback's internal Rolldown order. Updates must not be
60
+ * deduplicated: later undelivered patches are deltas and do not reproduce factories from earlier sequences.
61
+ * changedFiles is opaque DevEngine metadata and has no identity semantics in the host, so preserving its raw
62
+ * concatenation is both cheaper and more faithful than maintaining a second Set-based interpretation here.
63
+ */
64
+ publish({
65
+ updates: successfulWindow.flatMap((result) => result.updates),
66
+ changedFiles: successfulWindow.flatMap((result) => result.changedFiles)
67
+ })
68
+ }
69
+ })
70
+ return results
71
+ }