跳到主要内容

从 v4 迁移到 v5

v5 最大的变化不是 API 名字,而是职责边界变了。

在 v4 里,很多项目会先让 Tailwind 官方插件生成 CSS,再由 weapp-tailwindcss 做小程序转义。v5 改成由 WeappTailwindcss 接管 Tailwind CSS 生成链路:同一份 Tailwind 输入,在小程序端生成小程序可用的选择器和样式;在 H5/Web 端生成浏览器可用的 Tailwind CSS。

所以迁移时别急着到处改类名。先把构建链路理顺。

先看结论

大多数项目要做这几件事:

  1. 升级 weapp-tailwindcss 到 v5。
  2. 删除 postinstall: "weapp-tw patch"
  3. 小程序构建里移除 Tailwind 官方生成插件。
  4. 注册 WeappTailwindcss
  5. 检查 Tailwind CSS 3/4 的入口和扫描范围。
  6. H5/Web 构建不要再简单禁用 WeappTailwindcss;Taro 项目要同时覆盖 H5 和小程序构建。
  7. 跑一次小程序构建,再测一行新增任意值 class。

不用强制一起升级到 Tailwind CSS 4。weapp-tailwindcss@5 同时支持 Tailwind CSS 3 和 4。存量项目想稳一点,可以先保留 Tailwind CSS 3,只迁移 weapp-tailwindcss

1. 升级依赖

继续使用 Tailwind CSS 3:

pnpm add -D weapp-tailwindcss@5 tailwindcss@3

使用 Tailwind CSS 4:

pnpm add -D weapp-tailwindcss@5 tailwindcss@4

如果这些包只服务小程序构建,可以删掉:

pnpm remove tailwindcss-patch @tailwindcss/vite @tailwindcss/postcss

如果同一个仓库里还有独立的 Web 应用,Web 应用可以继续使用 @tailwindcss/vite@tailwindcss/postcss。限制只针对同一次小程序构建:不要让官方 Tailwind 插件和 WeappTailwindcss 同时生成 Tailwind CSS。

2. 删除安装后 patch

删掉 package.json 里的旧脚本:

package.json
{
"scripts": {
// 删除
"postinstall": "weapp-tw patch"
}
}

v5 的生成链路会在构建时处理 Tailwind 运行时,不需要安装后 patch。保留这个脚本通常不会带来收益,排查问题时反而会多一个干扰项。

3. 清理 Tailwind 官方生成插件

小程序构建里不要再注册这些插件:

postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
'@tailwindcss/postcss': {},
},
}
vite.config.ts
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
plugins: [
tailwindcss(),
],
})

业务 PostCSS 插件可以留,比如 autoprefixer、框架自己的 PostCSS 插件、压缩插件等。要删的是 Tailwind CSS 的生成入口。

4. 检查 Tailwind CSS 入口

Tailwind CSS 3 继续使用 @tailwind 指令:

src/app.css
@tailwind base;
@tailwind components;
@tailwind utilities;

tailwind.config.* 里要覆盖模板和脚本文件:

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{html,js,ts,jsx,tsx,vue,wxml,axml,ttml,mpx,uts,uvue}',
'!./src/uni_modules/**/*',
'!./node_modules/**/*',
'!./dist/**/*',
'!./unpackage/**/*',
],
}

Tailwind CSS 4 使用 CSS-first 入口:

src/app.css
@import "tailwindcss";
@source "./**/*.{html,js,ts,jsx,tsx,vue,wxml,axml,ttml,mpx,uts,uvue}";
@source not "./uni_modules";
@source not "../node_modules";
@source not "../dist";
@source not "../unpackage";

Tailwind CSS 4 的入口请放在纯 .css 文件里。不要把 @import "tailwindcss" 直接写到 scsslesssass 文件中。业务预处理样式可以引入这个 CSS 文件,但 Tailwind 入口本身最好保持简单。

5. 注册 WeappTailwindcss

Vite 项目:

vite.config.ts
import { defineConfig } from 'vite'
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'

export default defineConfig({
plugins: [
WeappTailwindcss({
rem2rpx: true,
}),
],
})

uni-app Vite 项目里,放在 uni() 后面:

vite.config.ts
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'

export default defineConfig({
plugins: [
uni(),
WeappTailwindcss({
rem2rpx: true,
}),
],
})

Webpack 项目:

webpack.config.js
const { WeappTailwindcss } = require('weapp-tailwindcss/webpack')

module.exports = {
plugins: [
new WeappTailwindcss({
rem2rpx: true,
}),
],
}

Taro、Mpx、uni-app Webpack 这类项目的挂载位置各不相同,按对应框架页复制完整写法即可。迁移时要抓住一个点:Tailwind 生成交给 WeappTailwindcss,不要再从 PostCSS 或官方 Vite 插件生成第二份 Tailwind CSS。

Taro 迁移要覆盖 H5 和小程序

Taro 迁移时不要只在小程序链路注册插件。v5 的 WeappTailwindcss 会根据 TARO_ENV=h5 自动切到 Web 目标,所以 H5 构建也应该保留插件。

Webpack 项目里,mini.webpackChainh5.webpackChain 都注册一次:

config/index.[jt]s
const path = require('node:path')
const { WeappTailwindcss } = require('weapp-tailwindcss/webpack')

const weappTailwindcssOptions = {
rem2rpx: true,
cssEntries: [
path.resolve(__dirname, '../src/app.css'),
],
}

function registerWeappTailwindcss(chain) {
chain.merge({
plugin: {
install: {
plugin: WeappTailwindcss,
args: [weappTailwindcssOptions],
},
},
})
}

module.exports = {
mini: {
webpackChain(chain) {
registerWeappTailwindcss(chain)
},
},
h5: {
webpackChain(chain) {
registerWeappTailwindcss(chain)
},
},
}

Vite 项目里,把插件放在 config/indexcompiler.vitePlugins。不要只写单独的 vite.config.ts,因为它通常只在小程序运行时被加载,H5 不会走这份配置。

config/index.ts
import path from 'node:path'
import type { Plugin } from 'vite'
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'

export default {
compiler: {
type: 'vite',
vitePlugins: [
WeappTailwindcss({
rem2rpx: true,
cssEntries: [
path.resolve(__dirname, '../src/app.css'),
],
}),
] as Plugin[],
},
}

6. 什么时候写 cssEntries

普通 Vite 项目通常不用写。入口 CSS 被 Vite 引入后,v5 会尝试自动识别。

这些情况建议显式写:

  • Tailwind CSS 4 项目里有多个 CSS-first 入口。
  • 入口 CSS 没有被框架直接引入。
  • Webpack、Gulp、自定义构建。
  • 构建日志提示没有找到 Tailwind CSS 入口。
  • uni-app x + Tailwind CSS 4,尤其是 HBuilderX 项目。
vite.config.ts
import path from 'node:path'
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'

WeappTailwindcss({
rem2rpx: true,
cssEntries: [
path.resolve(__dirname, 'src/app.css'),
],
})

cssEntries 写绝对路径,指向包含 @import "tailwindcss"@tailwind 指令的 CSS 入口。多个入口就都写进去。

7. H5/Web 构建不要一刀切禁用

v4 项目里经常有这段:

vite.config.ts
const isH5 = process.env.UNI_PLATFORM === 'h5'

WeappTailwindcss({
disabled: isH5,
})

迁移到 v5 后,先删掉这种 H5/Web 禁用逻辑:

vite.config.ts
WeappTailwindcss({
rem2rpx: true,
})

v5 会根据常见环境变量自动切换目标。例如 UNI_PLATFORM=h5/app/app-plusUNI_UTS_PLATFORM=h5/web/web-*TARO_ENV=h5MPX_CLI_MODE=webMPX_CURRENT_TARGET_MODE=web 会走 Web 目标,输出浏览器可用的 Tailwind CSS,而不是小程序转义后的选择器。UNI_UTS_PLATFORM=app-android/app-ios/app-harmony 这类 uni-app x 原生 App 目标不会被当成 Web,也不需要新增 target: 'app'

如果你在自定义构建里需要明确指定,也可以写:

vite.config.ts
WeappTailwindcss({
generator: {
target: 'web',
},
})

disabled 仍然有用,但它适合“完全跳过插件”的构建,例如某些 RN、Harmony 或独立原生构建。对 uni-app、uni-app x、Taro、Mpx 的 H5/Web 目标,通常不需要禁用。

8. uni-app x 和 HBuilderX

uni-app x 建议使用 uniAppX 预设:

vite.config.ts
import path from 'node:path'
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { uniAppX } from 'weapp-tailwindcss/presets'
import { WeappTailwindcss } from 'weapp-tailwindcss/vite'

export default defineConfig({
plugins: [
uni(),
WeappTailwindcss(
uniAppX({
base: __dirname,
cssEntries: [
path.resolve(__dirname, 'main.css'),
],
rem2rpx: true,
}),
),
],
})

Tailwind CSS 3 的 uni-app x 项目可以不写 cssEntries,前提是入口能被构建链路识别。Tailwind CSS 4 建议显式写 cssEntries,指向纯 CSS 入口。

HBuilderX 本地运行时可以按目标分别验证:

pnpm dev:mp-weixin
pnpm dev:android:emulator
pnpm dev:ios:simulator

如果用仓库里的本地 e2e,则是:

pnpm e2e:hbuilderx:local:app
pnpm e2e:hbuilderx:local:android
pnpm e2e:hbuilderx:local:ios

iOS 模拟器需要完整 Xcode。xcode-select -p 应指向 /Applications/Xcode.app/Contents/Developerxcodebuild -checkFirstLaunchStatus 应返回 0。

9. 验证迁移是否真的成功

只看构建成功还不够。迁移后至少测一条新增类。

在页面里临时写:

<view class="mt-[11px] w-[173px] rounded-[13px] bg-[#102938] p-4 text-[#f7fbff]">
v5 check
</view>

然后跑对应目标:

pnpm dev:mp-weixin

H5/Web 项目再跑一次 HMR:启动 dev server 后,连续改几次任意值 class,确认 CSS 会刷新。例如把 bg-[#102938] 依次改成 bg-[#0f5132]bg-[#7c2d12]bg-[#4338ca]。如果第一遍有样式,后续新增任意值 class 没有样式,通常是入口扫描或 HMR 依赖没有接上。

App 端不要只看 manifest.json。uni-app x 的 Android 产物可以检查 .uvue/app-android/** 里是否出现转换后的类名;iOS 在 HBuilderX 不同版本下输出位置会不同,可以检查 app-ios/app-service.jsunpackage/cache/.app-ios/sourcemap/app-service.js.map。例如:

bg-[#102938] -> bg-_b_h102938_B
text-[#f7fbff] -> text-_b_hf7fbff_B
w-[173px] -> w-_b173px_B

常见问题

现象优先检查
完全没有样式CSS 入口是否被构建器引入,或是否需要配置 cssEntries
Tailwind CSS 3 类名没生成tailwind.config.*content 是否包含页面、组件和脚本
Tailwind CSS 4 类名没生成CSS 入口里的 @source 是否覆盖源码,是否排除了 dist / unpackage
样式重复或顺序怪小程序构建里是否还注册了 tailwindcss / @tailwindcss/postcss / @tailwindcss/vite
安装后还在 patchpackage.json 是否还保留 postinstall: "weapp-tw patch"
JS 字符串里的类名没转这个类是否先被 Tailwind 扫描到了;v5 不会猜普通字符串
H5 样式变成小程序转义类检查 Web 目标环境变量,必要时显式设置 generator.target: 'web'
uni-app x App 样式缺失检查是否启用 uniAppX 预设,Tailwind CSS 4 是否配置了 cssEntries

迁移后可以删掉的东西

  • tailwindcss-patch
  • postinstall: "weapp-tw patch"
  • 小程序构建里的 @tailwindcss/vite
  • 小程序构建里的 @tailwindcss/postcss
  • 小程序构建里的 tailwindcss PostCSS 插件
  • 只为 H5/Web 写的 disabled: isH5 逻辑

不要急着删业务 PostCSS 插件、框架插件、Tailwind 配置文件。它们是否保留,取决于项目本身。

继续看