vite-plugin-taro 0.4.0 → 0.4.2

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.
@@ -5,6 +5,7 @@ import { dev, viteReporterPlugin } from 'rolldown/experimental';
5
5
  import { once } from '../../../utils/once.js';
6
6
  import { resolvePackageFile } from '../../../utils/packages.js';
7
7
  import { appShellFileName } from '../module.js';
8
+ import { emptyOutputDirectory } from './empty-output-directory.js';
8
9
  import { hmrControlPath, hmrInfoFileName, hmrPatchesFileName, renderHmrInfo, renderInitialHmrPatches, writeHmrFile } from './hmr-files.js';
9
10
  import { PatchPublisher } from './patch-publisher.js';
10
11
  /**
@@ -191,11 +192,25 @@ export async function createWxDevHost({ server, options }) {
191
192
  implement: await bundleRuntimeSource(),
192
193
  lazy: false
193
194
  };
195
+ const emptyOutputDirectoryPlugin = {
196
+ name: 'vpt:wx-empty-output-directory',
197
+ renderStart: {
198
+ order: 'pre',
199
+ // DevEngine bypasses Vite's build-only output preparation. Clear stale files before every complete
200
+ // physical render while retaining the directory watched by WeChat DevTools.
201
+ handler: () => emptyOutputDirectory(server.config.build.outDir)
202
+ }
203
+ };
194
204
  const reportInitialBuildPlugin = {
195
205
  name: 'vpt:wx-report-initial-build',
196
206
  buildEnd: settleInitialBuild
197
207
  };
198
- rolldownOptions.plugins = [rolldownOptions.plugins, reportInitialBuildPlugin, createViteReporter(server)];
208
+ rolldownOptions.plugins = [
209
+ emptyOutputDirectoryPlugin,
210
+ rolldownOptions.plugins,
211
+ reportInitialBuildPlugin,
212
+ createViteReporter(server)
213
+ ];
199
214
  disableViteOxcSourcemap(rolldownOptions.plugins);
200
215
  return rolldownOptions;
201
216
  };
@@ -0,0 +1,2 @@
1
+ /** Empties an output directory without replacing the directory itself or deleting Git metadata. */
2
+ export declare function emptyOutputDirectory(directory: string): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ /** Empties an output directory without replacing the directory itself or deleting Git metadata. */
4
+ export async function emptyOutputDirectory(directory) {
5
+ await fs.mkdir(directory, { recursive: true });
6
+ const entries = await fs.readdir(directory);
7
+ await Promise.all(entries
8
+ .filter((entry) => entry !== '.git')
9
+ .map((entry) => fs.rm(path.join(directory, entry), { force: true, recursive: true })));
10
+ }
@@ -36,6 +36,7 @@ export const pageShellPath = resolvePackageFile('dist/runtime/wx/native/page.js'
36
36
  const shellModuleIds = new Set([appShellPath, componentShellPath, pageShellPath]);
37
37
  const capsuleModuleIds = new Set([appCapsulePath, componentCapsulePath, pageCapsulePath]);
38
38
  const amphibiousModuleIds = new Set([bootstrapPath, rolldownRuntimeId]);
39
+ const transportModuleIds = new Set([transportPath]);
39
40
  /** Returns the one explicit lifecycle role owned by a chunk. */
40
41
  export function getWxEntryRole(chunk) {
41
42
  const ownsShell = containsModule(chunk, shellModuleIds);
@@ -47,7 +48,7 @@ export function getWxEntryRole(chunk) {
47
48
  }
48
49
  /** Tests whether a chunk contains the physical transport implementation. */
49
50
  export function isTransportModule(chunk) {
50
- return chunk.moduleIds.includes(transportPath);
51
+ return containsModule(chunk, transportModuleIds);
51
52
  }
52
53
  /**
53
54
  * Classifies one final output chunk by execution domain. Entry role is deliberately independent: explicit capsule entries
@@ -10,7 +10,7 @@ export async function compileNativeComponentInterface({ code, id, sourcemap, add
10
10
  nativeComponents.forEach((source) => {
11
11
  addWatchFile(source.folder);
12
12
  source.assets.forEach((asset) => {
13
- addWatchFile(path.join(source.folder, asset.relativePath));
13
+ addWatchFile(normalizeModuleId(path.join(source.folder, asset.relativePath)));
14
14
  });
15
15
  });
16
16
  const assetBytes = nativeComponents.reduce((sourceTotal, source) => {
@@ -1,3 +1,3 @@
1
- import { type PluginObject } from '@babel/core';
1
+ import { type PluginObj } from '@babel/core';
2
2
  /** Wraps System.register as an inert CommonJS capsule tuple with canonical final dependency IDs. */
3
- export declare function wrapCapsulePlugin(fileName: string): PluginObject;
3
+ export declare function wrapCapsulePlugin(fileName: string): PluginObj;
@@ -1,3 +1,3 @@
1
1
  export declare const packageRequire: NodeJS.Require;
2
- /** Resolves a file shipped by this package. */
2
+ /** Resolves a file shipped by this package as a portable Vite module ID. */
3
3
  export declare function resolvePackageFile(...segments: string[]): string;
@@ -1,8 +1,9 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import path from 'node:path';
3
+ import { normalizeModuleId } from './modules.js';
3
4
  export const packageRequire = createRequire(import.meta.url);
4
5
  const packageRoot = path.dirname(packageRequire.resolve('vite-plugin-taro/package.json'));
5
- /** Resolves a file shipped by this package. */
6
+ /** Resolves a file shipped by this package as a portable Vite module ID. */
6
7
  export function resolvePackageFile(...segments) {
7
- return path.join(packageRoot, ...segments);
8
+ return normalizeModuleId(path.join(packageRoot, ...segments));
8
9
  }
@@ -1,5 +1,5 @@
1
1
  import { type PluginItem } from '@babel/core';
2
- import generate from '@babel/generator';
2
+ import { generate } from '@babel/generator';
3
3
  import { type Rolldown } from 'vite';
4
4
  export type AstTransformResult = {
5
5
  code: string;
@@ -1,5 +1,5 @@
1
1
  import { transformSync } from '@babel/core';
2
- import generate from '@babel/generator';
2
+ import { generate } from '@babel/generator';
3
3
  import { transformWithOxc } from 'vite';
4
4
  import { esTarget } from './constant.js';
5
5
  /** Replaces each placeholder with a Babel AST expression while transforming the module through Oxc. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-taro",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
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",
@@ -51,14 +51,13 @@
51
51
  "node": "^22.18.0 || >=24.11.0"
52
52
  },
53
53
  "dependencies": {
54
- "@babel/core": "^8.0.1",
55
- "@babel/generator": "^8.0.0",
56
- "@babel/plugin-transform-dynamic-import": "^8.0.1",
57
- "@babel/plugin-transform-modules-commonjs": "^8.0.1",
58
- "@babel/plugin-transform-modules-systemjs": "^8.0.1",
54
+ "@babel/core": "^7.29.7",
55
+ "@babel/generator": "^7.29.8",
56
+ "@babel/plugin-transform-dynamic-import": "^7.29.7",
57
+ "@babel/plugin-transform-modules-commonjs": "^7.29.7",
58
+ "@babel/plugin-transform-modules-systemjs": "^7.29.8",
59
59
  "@rolldown/plugin-babel": "^0.2.3",
60
60
  "@tailwindcss-mangle/engine": "0.2.0",
61
- "@weapp-tailwindcss/postcss": "3.2.8",
62
61
  "@tarojs/components": "^4.2.0",
63
62
  "@tarojs/helper": "^4.2.0",
64
63
  "@tarojs/plugin-platform-h5": "^4.2.0",
@@ -67,6 +66,7 @@
67
66
  "@tarojs/runtime": "^4.2.0",
68
67
  "@tarojs/taro": "^4.2.0",
69
68
  "@vitejs/plugin-react": "^6.0.5",
69
+ "@weapp-tailwindcss/postcss": "3.2.8",
70
70
  "babel-plugin-transform-taroapi": "^4.2.0",
71
71
  "picocolors": "^1.1.1",
72
72
  "react-reconciler": "0.33.0",
@@ -74,8 +74,8 @@
74
74
  "rolldown": "~1.2.2",
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.4.0",
78
- "@tarojs/react": "npm:vite-plugin-taro-react@0.4.0"
77
+ "@tarojs/plugin-framework-react": "npm:vite-plugin-taro-plugin-framework-react@0.4.2",
78
+ "@tarojs/react": "npm:vite-plugin-taro-react@0.4.2"
79
79
  },
80
80
  "peerDependencies": {
81
81
  "react": "^19.0.0",
@@ -83,6 +83,8 @@
83
83
  "vite": "^8.2.0"
84
84
  },
85
85
  "devDependencies": {
86
+ "@types/babel__core": "^7.20.5",
87
+ "@types/babel__generator": "^7.27.0",
86
88
  "@types/node": "^26.1.1",
87
89
  "@types/react": "^19.2.17",
88
90
  "@types/react-dom": "^19.2.3",
@@ -0,0 +1,20 @@
1
+ declare module '@babel/plugin-transform-dynamic-import' {
2
+ import type { PluginTarget } from '@babel/core'
3
+
4
+ const transformDynamicImport: PluginTarget
5
+ export default transformDynamicImport
6
+ }
7
+
8
+ declare module '@babel/plugin-transform-modules-commonjs' {
9
+ import type { PluginTarget } from '@babel/core'
10
+
11
+ const transformModulesCommonjs: PluginTarget
12
+ export default transformModulesCommonjs
13
+ }
14
+
15
+ declare module '@babel/plugin-transform-modules-systemjs' {
16
+ import type { PluginTarget } from '@babel/core'
17
+
18
+ const transformModulesSystemjs: PluginTarget
19
+ export default transformModulesSystemjs
20
+ }
@@ -1,5 +1,5 @@
1
1
  import type { types as BabelTypes } from '@babel/core'
2
- import { type NodePath, type PluginObject, types } from '@babel/core'
2
+ import { type NodePath, type PluginObj, types } from '@babel/core'
3
3
  import babel from '@rolldown/plugin-babel'
4
4
  import type { HtmlTagDescriptor, Plugin, PluginOption } from 'vite'
5
5
  import type { VitePluginTaroOptions } from '../../../options.ts'
@@ -127,7 +127,7 @@ function createH5SupportPlugins(): PluginOption[] {
127
127
  }
128
128
 
129
129
  /** Keeps Stencil-injected Taro component styles before application stylesheets. */
130
- function rewriteStencilStyleInsertion(): PluginObject {
130
+ function rewriteStencilStyleInsertion(): PluginObj {
131
131
  return {
132
132
  name: 'vpt:rewrite-stencil-style-insertion',
133
133
  visitor: {
@@ -9,6 +9,7 @@ import type { VitePluginTaroOptions } from '../../../../options.ts'
9
9
  import { once } from '../../../utils/once.ts'
10
10
  import { resolvePackageFile } from '../../../utils/packages.ts'
11
11
  import { appShellFileName } from '../module.ts'
12
+ import { emptyOutputDirectory } from './empty-output-directory.ts'
12
13
  import {
13
14
  type HmrInfo,
14
15
  hmrControlPath,
@@ -252,12 +253,26 @@ export async function createWxDevHost({
252
253
  lazy: false
253
254
  }
254
255
 
256
+ const emptyOutputDirectoryPlugin: Plugin = {
257
+ name: 'vpt:wx-empty-output-directory',
258
+ renderStart: {
259
+ order: 'pre',
260
+ // DevEngine bypasses Vite's build-only output preparation. Clear stale files before every complete
261
+ // physical render while retaining the directory watched by WeChat DevTools.
262
+ handler: () => emptyOutputDirectory(server.config.build.outDir)
263
+ }
264
+ }
255
265
  const reportInitialBuildPlugin: Plugin = {
256
266
  name: 'vpt:wx-report-initial-build',
257
267
  buildEnd: settleInitialBuild
258
268
  }
259
269
 
260
- rolldownOptions.plugins = [rolldownOptions.plugins, reportInitialBuildPlugin, createViteReporter(server)]
270
+ rolldownOptions.plugins = [
271
+ emptyOutputDirectoryPlugin,
272
+ rolldownOptions.plugins,
273
+ reportInitialBuildPlugin,
274
+ createViteReporter(server)
275
+ ]
261
276
  disableViteOxcSourcemap(rolldownOptions.plugins)
262
277
  return rolldownOptions
263
278
  }
@@ -0,0 +1,14 @@
1
+ import fs from 'node:fs/promises'
2
+ import path from 'node:path'
3
+
4
+ /** Empties an output directory without replacing the directory itself or deleting Git metadata. */
5
+ export async function emptyOutputDirectory(directory: string): Promise<void> {
6
+ await fs.mkdir(directory, { recursive: true })
7
+ const entries = await fs.readdir(directory)
8
+
9
+ await Promise.all(
10
+ entries
11
+ .filter((entry) => entry !== '.git')
12
+ .map((entry) => fs.rm(path.join(directory, entry), { force: true, recursive: true }))
13
+ )
14
+ }
@@ -1,4 +1,4 @@
1
- import { type PluginObject, types } from '@babel/core'
1
+ import { type PluginObj, types } from '@babel/core'
2
2
  import type { Plugin } from 'vite'
3
3
  import { memoize } from '../../../utils/memoize.ts'
4
4
  import { transformWithBabel } from '../../../utils/transform.ts'
@@ -81,7 +81,7 @@ export function createWxReactRefreshTransforms(): Plugin[] {
81
81
  * explicit member access is precise. The hook itself is created on `global` by the dev
82
82
  * runtime chunk (see dev-runtime.ts).
83
83
  */
84
- function rewriteReactDevtoolsHookGlobal(): PluginObject {
84
+ function rewriteReactDevtoolsHookGlobal(): PluginObj {
85
85
  return {
86
86
  name: 'vpt:wx-react-devtools-hook-global',
87
87
  visitor: {
@@ -124,7 +124,7 @@ function rewriteReactDevtoolsHookGlobal(): PluginObject {
124
124
  * replay captures it; the patched commit hooks then track every later mount, including the
125
125
  * remounts on re-execution.
126
126
  */
127
- function injectRefreshGlobalHook(): PluginObject {
127
+ function injectRefreshGlobalHook(): PluginObj {
128
128
  return {
129
129
  name: 'vpt:wx-refresh-global-hook-injection',
130
130
  visitor: {
@@ -153,7 +153,7 @@ function injectRefreshGlobalHook(): PluginObject {
153
153
  * Only the exact known protocol names are rewritten, one by one, so unrelated `window`
154
154
  * accesses are never touched and future protocol additions are deliberate.
155
155
  */
156
- function rewriteRefreshRuntimeWindowAccess(): PluginObject {
156
+ function rewriteRefreshRuntimeWindowAccess(): PluginObj {
157
157
  /**
158
158
  * Refresh protocol globals that must land on the WeChat `global`:
159
159
  * - `__registerBeforePerformReactRefresh`: assigned at module scope; in web, the HMR
@@ -186,7 +186,7 @@ function rewriteRefreshRuntimeWindowAccess(): PluginObject {
186
186
  }
187
187
 
188
188
  /** Boundary modules: remove the generated `if (!window.$RefreshReg$) throw Error(...)` guard. */
189
- function removeRefreshPreambleGuard(): PluginObject {
189
+ function removeRefreshPreambleGuard(): PluginObj {
190
190
  return {
191
191
  name: 'vpt:wx-refresh-preamble-guard',
192
192
  visitor: {
@@ -63,6 +63,7 @@ export type WxExecutionKind = 'native' | 'capsule' | 'amphibious'
63
63
  const shellModuleIds: ReadonlySet<string> = new Set([appShellPath, componentShellPath, pageShellPath])
64
64
  const capsuleModuleIds: ReadonlySet<string> = new Set([appCapsulePath, componentCapsulePath, pageCapsulePath])
65
65
  const amphibiousModuleIds: ReadonlySet<string> = new Set([bootstrapPath, rolldownRuntimeId])
66
+ const transportModuleIds: ReadonlySet<string> = new Set([transportPath])
66
67
 
67
68
  /** Returns the one explicit lifecycle role owned by a chunk. */
68
69
  export function getWxEntryRole(chunk: WxChunk): WxEntryRole | undefined {
@@ -76,7 +77,7 @@ export function getWxEntryRole(chunk: WxChunk): WxEntryRole | undefined {
76
77
 
77
78
  /** Tests whether a chunk contains the physical transport implementation. */
78
79
  export function isTransportModule(chunk: WxChunk): boolean {
79
- return chunk.moduleIds.includes(transportPath)
80
+ return containsModule(chunk, transportModuleIds)
80
81
  }
81
82
 
82
83
  /**
@@ -26,7 +26,7 @@ export async function compileNativeComponentInterface({
26
26
  addWatchFile(source.folder)
27
27
 
28
28
  source.assets.forEach((asset) => {
29
- addWatchFile(path.join(source.folder, asset.relativePath))
29
+ addWatchFile(normalizeModuleId(path.join(source.folder, asset.relativePath)))
30
30
  })
31
31
  })
32
32
 
@@ -1,8 +1,8 @@
1
- import { type PluginObject, types } from '@babel/core'
1
+ import { type PluginObj, types } from '@babel/core'
2
2
  import { resolveChunkReference } from '../../../utils/modules.ts'
3
3
 
4
4
  /** Wraps System.register as an inert CommonJS capsule tuple with canonical final dependency IDs. */
5
- export function wrapCapsulePlugin(fileName: string): PluginObject {
5
+ export function wrapCapsulePlugin(fileName: string): PluginObj {
6
6
  return {
7
7
  name: 'vpt:wrap-capsule',
8
8
  visitor: {},
@@ -1,4 +1,4 @@
1
- import { type PluginObject, type PluginTarget, types } from '@babel/core'
1
+ import { type PluginObj, type PluginTarget, types } from '@babel/core'
2
2
  import transformModulesCommonjs from '@babel/plugin-transform-modules-commonjs'
3
3
  import type { Rolldown } from 'vite'
4
4
  import { resolveChunkReference } from '../../../utils/modules.ts'
@@ -29,7 +29,7 @@ export function renderNative({
29
29
  function connectNativeCapsulesPlugin(
30
30
  fileName: string,
31
31
  chunks: Readonly<Record<string, Rolldown.RenderedChunk>>
32
- ): PluginObject {
32
+ ): PluginObj {
33
33
  return {
34
34
  name: 'vpt:connect-native-capsules',
35
35
  visitor: {
@@ -1,10 +1,11 @@
1
1
  import { createRequire } from 'node:module'
2
2
  import path from 'node:path'
3
+ import { normalizeModuleId } from './modules.ts'
3
4
 
4
5
  export const packageRequire = createRequire(import.meta.url)
5
6
  const packageRoot = path.dirname(packageRequire.resolve('vite-plugin-taro/package.json'))
6
7
 
7
- /** Resolves a file shipped by this package. */
8
+ /** Resolves a file shipped by this package as a portable Vite module ID. */
8
9
  export function resolvePackageFile(...segments: string[]): string {
9
- return path.join(packageRoot, ...segments)
10
+ return normalizeModuleId(path.join(packageRoot, ...segments))
10
11
  }
@@ -1,5 +1,5 @@
1
1
  import { type PluginItem, transformSync } from '@babel/core'
2
- import generate from '@babel/generator'
2
+ import { generate } from '@babel/generator'
3
3
  import { type Rolldown, transformWithOxc } from 'vite'
4
4
  import { esTarget } from './constant.ts'
5
5