前言
本文记录在 Vue 3 + Vite + TypeScript 项目中接入 Tailwind CSS v4 的完整步骤,并配置 Prettier + ESLint + VS Code,让 Tailwind 类名警告在保存时自动修复(排序、简写、冲突检测等)。
技术栈版本参考:
- Tailwind CSS v4
@tailwindcss/vite
eslint-plugin-tailwindcss v4
prettier-plugin-tailwindcss
若项目同时使用 Ant Design Vue,建议不引入 Preflight,避免与组件库全局样式冲突。
安装依赖
统一使用 pnpm(避免与 npm 混装导致 node_modules/.ignored 警告):
1
| pnpm add -D tailwindcss @tailwindcss/vite
|
自动修复相关:
1 2 3
| pnpm add -D prettier prettier-plugin-tailwindcss \ eslint @eslint/js typescript-eslint eslint-plugin-vue vue-eslint-parser \ eslint-plugin-tailwindcss globals
|
在 package.json 中补充脚本:
1 2 3 4 5 6 7
| { "scripts": { "lint": "eslint .", "lint:fix": "eslint . --fix", "format": "prettier --write ." } }
|
可选:锁定包管理器,根目录 .npmrc:
1
| package-manager-strict=true
|
package.json 中指定:
1
| "packageManager": "pnpm@11.0.8"
|
Vite 接入 Tailwind v4
vite.config.ts 注册官方 Vite 插件:
1 2 3 4 5 6 7
| import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import tailwindcss from '@tailwindcss/vite'
export default defineConfig({ plugins: [tailwindcss(), vue()], })
|
全局样式
src/style.css
Tailwind v4 推荐在 CSS 入口文件中引入,并通过 @config 关联 JS/TS 配置文件。
与 Ant Design Vue 共存时,只引入 theme + utilities,不引入 Preflight:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @import "tailwindcss/theme" layer(theme); @import "tailwindcss/utilities" layer(utilities); @config "../tailwind.config.ts";
@theme { --color-brand: #36b8a7; --color-brand-hover: #2ea890; --color-brand-dark: #2ba08c; --color-accent-blue: #4d9ff6; --color-accent-teal: #45b7a4; --color-surface-page: #f3f3f3; --color-surface-stat: #e7edf6; --color-surface-muted: #7f8795; --max-width-content: 1200px; --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif; }
*, *::before, *::after { box-sizing: border-box; }
|
在 src/main.ts 中引入:
tailwind.config.ts
项目根目录创建配置文件,负责 content 扫描路径 与 theme.extend:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import type { Config } from 'tailwindcss'
export default { content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], theme: { extend: { colors: { brand: { DEFAULT: '#36b8a7', hover: '#2ea890', dark: '#2ba08c', }, accent: { blue: '#4d9ff6', teal: '#45b7a4', }, surface: { page: '#f3f3f3', stat: '#e7edf6', muted: '#7f8795', }, }, maxWidth: { content: '1200px', }, fontFamily: { sans: [ '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'PingFang SC', 'Microsoft YaHei', 'sans-serif', ], }, }, }, } satisfies Config
|
使用语义化类名示例:
1
| <div class="max-w-content bg-surface-page text-brand">...</div>
|
@theme 中的 CSS 变量与 theme.extend 保持同步,便于在设计 token 与工具类之间统一。
Prettier:保存时自动排序 class
根目录 prettier.config.js:
1 2 3 4 5 6 7 8 9
| export default { plugins: ['prettier-plugin-tailwindcss'], tailwindStylesheet: './src/style.css', semi: false, singleQuote: true, trailingComma: 'all', printWidth: 100, }
|
.prettierignore 示例:
1 2 3
| dist node_modules pnpm-lock.yaml
|
命令行格式化:
ESLint:Tailwind 规则
根目录 eslint.config.js(Flat Config):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import js from '@eslint/js' import pluginVue from 'eslint-plugin-vue' import tailwind from 'eslint-plugin-tailwindcss' import tseslint from 'typescript-eslint' import globals from 'globals'
export default tseslint.config( { ignores: ['dist/**', 'node_modules/**', 'public/**', '.cursor/**'], }, js.configs.recommended, ...tseslint.configs.recommended, ...pluginVue.configs['flat/essential'], tailwind.configs.recommended, { files: ['**/*.{vue,js,ts,mjs}'], languageOptions: { ecmaVersion: 'latest', sourceType: 'module', globals: { ...globals.browser, ...globals.node }, }, settings: { tailwindcss: { cssConfigPath: 'src/style.css', attributes: ['class', ':class', 'className'], }, }, }, { files: ['**/*.vue'], languageOptions: { parserOptions: { parser: tseslint.parser }, }, }, )
|
要点:
- Tailwind v4 使用
cssConfigPath 指向 src/style.css,而不是旧的 tailwind.config.js 路径
tailwind.configs.recommended 启用官方推荐规则
- 可自动修复:类名排序、简写、冲突类名等
命令行:
VS Code:保存时自动修复
.vscode/settings.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, "eslint.validate": ["javascript", "typescript", "vue"], "tailwindCSS.experimental.configFile": "tailwind.config.ts", "tailwindCSS.lint.suggestCanonicalClasses": "warning", "tailwindCSS.validate": true, "css.validate": false, "tailwindCSS.includeLanguages": { "vue": "html" }, "tailwindCSS.classAttributes": ["class", "className", ":class", "ui"] }
|
推荐扩展 .vscode/extensions.json:
1 2 3 4 5 6 7 8
| { "recommendations": [ "Vue.volar", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "bradlc.vscode-tailwindcss" ] }
|
保存 .vue 文件时的执行顺序:
- Prettier → 排序 Tailwind class
- ESLint fixAll → 修复可自动修复的 Tailwind 规则
修改配置后建议 重载 VS Code 窗口。
验证
1 2 3 4
| pnpm dev pnpm run build pnpm lint:fix pnpm format
|
在 Vue 文件中故意写乱 class 顺序,保存后应被 Prettier 自动排序;冲突类名(如同时写 p-2 和 p-4)会由 ESLint 提示并可通过 fix 修复。
总结
| 层级 |
文件 |
作用 |
| 构建 |
vite.config.ts |
@tailwindcss/vite 插件 |
| 主题 |
tailwind.config.ts + @theme |
设计 token、content 扫描 |
| 入口 |
src/style.css |
引入 Tailwind 层、@config |
| 排序 |
prettier.config.js |
保存时 class 排序 |
| 校验 |
eslint.config.js |
Tailwind 规则 + --fix |
| 编辑器 |
.vscode/settings.json |
保存时 format + fixAll |
注意
Tailwind v4 重要约定:! 后缀
v4 中 !important 修饰符写在类名末尾,不要再用 v3 的前缀写法:
1 2 3 4 5
| <!-- ❌ v3 --> <a-button class="!h-10 hover:!bg-brand" />
<!-- ✅ v4 --> <a-button class="h-10! hover:bg-brand-hover!" />
|