🚀 从 Windi CSS 迁移到 Tailwind CSS v4 完整实践指南

📌 迁移背景

  • Windi CSS 已停止维护(最后更新于 2022 年),存在稳定性与兼容性风险
  • Tailwind CSS 作为行业标准,提供长期支持、活跃生态及更完善的工具链

重要提示:迁移前请务必备份整个项目!

🔍 迁移准备

  1. 了解 Tailwind CSS v4 新特性:

    • 增强的 JIT 引擎性能
    • 改进的暗黑模式支持
    • 全新的 @reference 指令
    • 更智能的类名推导机制
  2. 备份关键文件:

    • windi.config.ts
    • postcss.config.js
    • 所有包含 Windi CSS 导入的文件
  3. 准备安装包:

    bash

    sql 复制代码
    pnpm install tailwindcss@4 @tailwindcss/postcss autoprefixer --save-dev

🛠️ 迁移过程

1. 替换依赖与清理旧配置

bash

perl 复制代码
# 卸载 Windi CSS
pnpm remove windicss vite-plugin-windicss windicss-analysis

# 安装 Tailwind CSS v4
pnpm install tailwindcss@4 @tailwindcss/postcss autoprefixer --save-dev

清理工作:

  1. 删除 @/plugins/windi.css 文件

  2. 移除所有 Windi CSS 导入语句:

    javascript

    arduino 复制代码
    // 删除以下导入
    import 'virtual:windi.css'
    import 'virtual:windi-devtools'

2. 配置文件迁移

从 windi.config.ts 到 tailwind.config.js:

javascript

javascript 复制代码
// 根目录创建 tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: 'class',
  content: ['./src/**/*.{vue,html,jsx,tsx}'],
  theme: {
    extend: {
      backgroundColor: {
        'v-dark': 'var(--dark-bg-color)',
      },
    },
  },
  plugins: [
    function({ addComponents }) {
      const range = (size, startAt = 1) => 
        Array.from(Array(size).keys()).map(i => i + startAt);
      
      const obj = {};
      range(50).forEach(i => {
        obj[`.border-top-${i}`] = { borderTopWidth: `${i}px` };
        obj[`.border-left-${i}`] = { borderLeftWidth: `${i}px` };
        obj[`.border-right-${i}`] = { borderRightWidth: `${i}px` };
        obj[`.border-bottom-${i}`] = { borderBottomWidth: `${i}px` };
      });
      
      addComponents({
        '.hover-trigger': {
          display: 'flex',
          height: '100%',
          padding: '1px 10px 0',
          cursor: 'pointer',
          alignItems: 'center',
          transition: 'background var(--transition-time-02)',
          '&:hover': {
            backgroundColor: 'var(--top-header-hover-color)',
          },
        },
        '.dark .hover-trigger:hover': {
          backgroundColor: 'var(--el-bg-color-overlay)',
        },
        ...obj
      });
    },
  ],
}

3. 样式文件迁移

创建 src/styles/tailwind.css:

css

less 复制代码
@tailwind base;
@reference "tailwindcss"; /* Tailwind v4 核心指令 */
@tailwind components;
@tailwind utilities;

/* 自定义工具类 */
.hover-trigger {
  @apply flex h-full px-[10px] pt-1 cursor-pointer items-center 
         transition-[background] duration-[var(--transition-time-02)];
}

.hover-trigger:hover {
  @apply bg-[var(--top-header-hover-color)];
}

.dark .hover-trigger:hover {
  @apply bg-[var(--el-bg-color-overlay)];
}

/* 边框工具类 (示例) */
.border-top-1 { border-top-width: 1px; }
.border-left-1 { border-left-width: 1px; }
/* ...扩展到需要的尺寸 */

在 main.ts 中引入:

typescript

arduino 复制代码
import '@/styles/tailwind.css';

4. PostCSS 配置更新

javascript

yaml 复制代码
// postcss.config.js
module.exports = {
  plugins: {
    '@tailwindcss/postcss': {
      config: './tailwind.config.js'
    },
    autoprefixer: {},
    'postcss-px-to-viewport': {
      viewportWidth: 1920,
      unitPrecision: 5,
      viewportUnit: 'vw',
      selectorBlackList: [],
      minPixelValue: 1,
      mediaQuery: false
    }
  }
}

⚠️ 迁移常见问题及解决方案

1. 工具类识别问题

现象 :迁移后 Tailwind 无法识别 pt-1 等工具类
解决方案:

  1. 确保 tailwind.css 中包含 @reference "tailwindcss";
  2. 检查 content 配置是否覆盖所有文件路径
  3. 重启开发服务器清除缓存

2. 自定义工具类不生效

解决方案:

javascript

css 复制代码
// 在 tailwind.config.js 中正确使用 addComponents
plugins: [
  function({ addComponents }) {
    addComponents({
      '.my-class': {
        padding: '2rem',
        '&:hover': {
          color: '#fff'
        }
      }
    })
  }
]

3. 暗黑模式切换异常

解决方案:

javascript

java 复制代码
// 确保配置了 darkMode: 'class'
module.exports = {
  darkMode: 'class',
  // ...
}

// 在HTML根元素切换类名
document.documentElement.classList.toggle('dark');

4. 依赖冲突问题

解决方案:

bash

bash 复制代码
# 清除 node_modules 和 lock 文件
rm -rf node_modules
rm pnpm-lock.yaml

# 重新安装依赖
pnpm install
相关推荐
亿元程序员1 小时前
太牛了!这AI做出来的游戏,居然还能变现!
前端
hellice2 小时前
闪传 FlashDrop 实战:我用 300 行 Node 代码做了个「4 位取件码」临时文件中转站
前端·产品
用户0829773260052 小时前
RTX 5500 MIG 踩坑记录:切分之后模型跑不起来,排错整整一下午
前端
Lank_M2 小时前
AI 放大后的图更清楚,但它不能当原图入库
前端
Swot2 小时前
SvelteKit 数据流研究:`+page.js` 和 `+page.server.js` 到底谁在跑,数据又去了哪儿
前端·后端
用户4147679304152 小时前
Windows 触摸屏上 Swiper 轮播滑不动?可能是内部滚动容器抢走了你的手势
前端
张明君644512 小时前
从一个 Referer 引发的 403,到 SSR 服务失稳:Astro 流式渲染与缓存失效分析
前端
律宏阔2 小时前
微信小程序 + Taro + TDesign 去掉 [&&&],让普通 Tailwind 类接管局部样式
前端·微信小程序·taro
费曼学习法2 小时前
把 3 个内部服务封装成 MCP Server 的工程复盘:进程模型、超时与错误契约
前端
ruanno_top2 小时前
给标签页加 roving tabindex,整组反而键盘进不去了
vue.js