前端工程化工具链:ESLint、Prettier、Tailwind CSS
ESLint
ESLint 是 JavaScript 和 TypeScript 的代码检查工具,用于发现和修复代码中的问题。
安装与配置
# 安装 ESLint
npm install -D eslint
# 初始化配置(交互式)
npx eslint --init
# 或手动安装推荐的配置
npm install -D eslint @eslint/js typescript-eslintESLint v9+ 扁平配置
ESLint v9 使用新的扁平配置文件 eslint.config.js。
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import vue from 'eslint-plugin-vue';
import react from 'eslint-plugin-react';
import importPlugin from 'eslint-plugin-import';
import unusedImports from 'eslint-plugin-unused-imports';
export default [
// 全局配置
{
files: ['**/*.{js,mjs,cjs,ts,jsx,tsx,vue}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
browser: true,
es2021: true,
node: true,
},
},
},
// JavaScript 推荐规则
js.configs.recommended,
// TypeScript 推荐规则
...tseslint.configs.recommended,
// Vue 推荐规则
...vue.configs['flat/recommended'],
// React 配置(如果使用 React)
{
files: ['**/*.{jsx,tsx}'],
...react.configs.flat.recommended,
settings: {
react: {
version: 'detect',
},
},
},
// 导入规则
{
plugins: {
import: importPlugin,
'unused-imports': unusedImports,
},
rules: {
'import/order': ['error', {
groups: [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
],
'newlines-between': 'always',
}],
'import/no-duplicates': 'error',
'unused-imports/no-unused-imports': 'error',
},
},
// 自定义规则
{
rules: {
// 通用规则
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-debugger': 'warn',
'no-unused-vars': 'off', // 使用 TypeScript 的规则
// TypeScript 规则
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
}],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'warn',
// Vue 规则
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'warn',
'vue/require-default-prop': 'off',
'vue/attribute-hyphenation': ['error', 'always'],
'vue/v-on-event-hyphenation': ['error', 'always'],
// React 规则
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
},
},
// 忽略文件
{
ignores: [
'dist/**',
'node_modules/**',
'coverage/**',
'*.min.js',
'.output/**',
],
},
];常用规则分类
// 代码质量规则
rules: {
// 错误处理
'nothrowliteralerror': 'error',
'no-unsafe-finally': 'error',
// 最佳实践
'curly': ['error', 'multi-line'],
'eqeqeq': ['error', 'always'],
'no-eval': 'error',
'no-implied-eval': 'error',
'no-new-func': 'error',
'no-return-await': 'error',
// 变量
'no-shadow': 'error',
'no-use-before-define': ['error', { functions: false }],
// 函数
'consistent-return': 'error',
'no-func-assign': 'error',
// 类
'no-class-assign': 'error',
'no-const-assign': 'error',
// 模块化
'no-duplicate-imports': 'error',
}运行 ESLint
# 检查所有文件
npx eslint .
# 检查特定目录
npx eslint src/
# 检查特定文件
npx eslint src/main.ts src/App.vue
# 自动修复
npx eslint . --fix
npx eslint src/ --fix
# 输出格式
npx eslint . --format json
npx eslint . --format stylish
# 使用缓存
npx eslint . --cache --cache-location .eslintcache与 IDE 集成
// .vscode/settings.json
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.options": {
"extensions": [".js", ".jsx", ".ts", ".tsx", ".vue"]
}
}Prettier
Prettier 是代码格式化工具,确保代码风格统一。
安装与配置
# 安装 Prettier
npm install -D prettier
# 安装 ESLint 与 Prettier 的集成
npm install -D eslint-config-prettier eslint-plugin-prettierPrettier 配置
// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"htmlWhitespaceSensitivity": "css",
"jsxSingleQuote": false,
"bracketSameLine": false,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"semi": true,
"singleAttributePerLine": false,
"vueIndentScriptAndStyle": true
}// .prettierignore
dist
node_modules
coverage
public
*.min.js
*.min.css
pnpm-lock.yaml
yarn.lock
package-lock.json与 ESLint 集成
// eslint.config.js
import prettier from 'eslint-plugin-prettier/recommended';
export default [
// 其他配置...
// Prettier 配置(必须放在最后)
prettier,
// 或者手动配置
{
plugins: {
prettier: prettierPlugin,
},
rules: {
'prettier/prettier': 'error',
// 关闭与 Prettier 冲突的规则
'arrow-body-style': 'off',
'prefer-arrow-callback': 'off',
},
},
];// 使用 eslint-config-prettier 关闭冲突规则
import eslintConfigPrettier from 'eslint-config-prettier';
export default [
// 其他配置...
// 放在最后,关闭所有与 Prettier 冲突的 ESLint 规则
eslintConfigPrettier,
];运行 Prettier
# 格式化所有文件
npx prettier --write .
# 格式化特定目录
npx prettier --write src/
# 检查格式(不修改文件)
npx prettier --check .
npx prettier --check src/
# 格式化特定文件
npx prettier --write src/main.ts与 Git 集成
// package.json
{
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint . --fix",
"lint:check": "eslint ."
},
"lint-staged": {
"*.{js,jsx,ts,tsx,vue}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,scss,md}": [
"prettier --write"
]
}
}# 安装 lint-staged 和 husky
npm install -D lint-staged husky
# 初始化 husky
npx husky init
# 在 .husky/pre-commit 中添加
npx lint-stagedTailwind CSS
Tailwind CSS 是一个功能优先的 CSS 框架,通过实用类快速构建自定义设计。
安装与配置
# 安装 Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
# 初始化配置
npx tailwindcss init -p配置文件
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
// 内容文件(用于扫描使用的类)
content: [
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx}',
],
// 主题配置
theme: {
// 扩展默认主题
extend: {
// 颜色
colors: {
'primary': {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49',
},
'secondary': '#ff6b6b',
'accent': '#ffd93d',
},
// 字体
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
'serif': ['Merriweather', 'serif'],
'mono': ['Fira Code', 'monospace'],
},
// 字体大小
fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem' }],
'sm': ['0.875rem', { lineHeight: '1.25rem' }],
'base': ['1rem', { lineHeight: '1.5rem' }],
'lg': ['1.125rem', { lineHeight: '1.75rem' }],
'xl': ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1' }],
},
// 间距
spacing: {
'18': '4.5rem',
'88': '22rem',
'128': '32rem',
},
// 边框半径
borderRadius: {
'4xl': '2rem',
'5xl': '2.5rem',
},
// 阴影
boxShadow: {
'inner-lg': 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
'glow': '0 0 20px rgba(14, 165, 233, 0.5)',
},
// 动画
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.3s ease-out',
'bounce-slow': 'bounce 2s infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
// 断点
screens: {
'xs': '475px',
'3xl': '1920px',
},
// 过渡时间
transitionDuration: {
'2000': '2000ms',
'3000': '3000ms',
},
},
},
// 插件
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/container-queries'),
],
// 黑暗模式
darkMode: 'class', // 或 'media'
// 未来警告
future: {
hoverOnlyWhenSupported: true,
},
};基础样式
/* src/styles/main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* 自定义基础样式 */
@layer base {
html {
font-family: 'Inter', system-ui, sans-serif;
}
h1 {
@apply text-4xl font-bold text-gray-900 dark:text-white;
}
h2 {
@apply text-3xl font-semibold text-gray-800 dark:text-gray-100;
}
h3 {
@apply text-2xl font-medium text-gray-700 dark:text-gray-200;
}
a {
@apply text-primary-600 hover:text-primary-700 underline;
}
button {
@apply px-4 py-2 rounded-lg font-medium transition-colors;
}
}
/* 自定义组件 */
@layer components {
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-colors;
}
.btn-primary {
@apply btn bg-primary-600 text-white hover:bg-primary-700;
}
.btn-secondary {
@apply btn bg-gray-200 text-gray-900 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600;
}
.btn-outline {
@apply btn border-2 border-primary-600 text-primary-600 hover:bg-primary-600 hover:text-white;
}
.card {
@apply bg-white rounded-lg shadow-md p-6 dark:bg-gray-800;
}
.input {
@apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-gray-700 dark:border-gray-600;
}
.container-custom {
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
}
}
/* 自定义工具类 */
@layer utilities {
.text-gradient {
@apply bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent;
}
.glass {
@apply bg-white/10 backdrop-blur-lg border border-white/20;
}
.hide-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
}常用类名示例
<!-- 布局 -->
<div class="flex items-center justify-between">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="container mx-auto px-4">
<div class="space-y-4">
<div class="divide-y divide-gray-200">
<!-- 间距 -->
<div class="m-4 p-4">
<div class="mx-auto my-4">
<div class="mt-4 mb-4 ml-4 mr-4">
<div class="pt-4 pb-4 pl-4 pr-4">
<div class="gap-4 space-x-4 space-y-4">
<!-- 尺寸 -->
<div class="w-full w-1/2 w-64 h-full h-screen h-96">
<div class="min-w-0 min-h-screen max-w-7xl max-h-96">
<!-- 颜色 -->
<div class="bg-red-500 text-white border-blue-300">
<div class="bg-gradient-to-r from-purple-500 to-pink-500">
<div class="text-gray-900 text-opacity-50">
<!-- 排版 -->
<div class="text-lg font-bold italic underline uppercase tracking-wide">
<div class="text-left text-center text-right">
<div class="leading-tight leading-normal leading-loose">
<!-- 边框 -->
<div class="border border-2 border-red-500 rounded-lg rounded-full">
<div class="border-t border-b border-l-0 border-r-0">
<div class="divide-y divide-gray-200">
<!-- 效果 -->
<div class="shadow-lg shadow-xl shadow-inner">
<div class="opacity-50 opacity-75">
<div class="transition-all duration-300 ease-in-out">
<div class="transform scale-110 rotate-45 translate-x-4">
<!-- 响应式 -->
<div class="w-full md:w-1/2 lg:w-1/3 xl:w-1/4">
<div class="text-sm md:text-base lg:text-lg">
<div class="hidden md:block lg:flex xl:grid">
<!-- 状态 -->
<div class="hover:bg-blue-700 focus:ring-2 active:bg-blue-800">
<div class="disabled:opacity-50 disabled:cursor-not-allowed">
<div class="group-hover:text-white">
<div class="peer-checked:bg-blue-500">
<!-- 黑暗模式 -->
<div class="bg-white dark:bg-gray-800">
<div class="text-black dark:text-white">
<!-- 交互 -->
<div class="cursor-pointer cursor-not-allowed">
<div class="select-none select-text">
<div class="resize-y resize-none">响应式设计
<!-- 移动优先设计 -->
<div class="
w-full
sm:w-1/2
md:w-1/3
lg:w-1/4
xl:w-1/5
">
<!-- 隐藏/显示 -->
<div class="hidden md:block">桌面端显示</div>
<div class="block md:hidden">移动端显示</div>
<!-- 响应式间距 -->
<div class="p-4 md:p-6 lg:p-8">
<div class="space-y-4 md:space-y-6 lg:space-y-8">
<!-- 响应式网格 -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">与框架集成
// Vite + Tailwind CSS
// vite.config.ts
export default defineConfig({
css: {
postcss: {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
});// 使用 @tailwindcss/vite 插件(Tailwind v4+)
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [tailwindcss()],
});JIT 模式
Tailwind CSS v3+ 默认启用 JIT(Just-In-Time)模式,按需生成样式。
// tailwind.config.js
module.exports = {
// 内容文件(用于扫描使用的类)
content: [
'./src/**/*.{vue,js,ts,jsx,tsx}',
],
// ...
}插件推荐
# 表单样式
npm install -D @tailwindcss/forms
# 排版样式
npm install -D @tailwindcss/typography
# 宽高比
npm install -D @tailwindcss/aspect-ratio
# 容器查询
npm install -D @tailwindcss/container-queries
# 滚动条
npm install -D tailwind-scrollbar
# 动画
npm install -D tailwindcss-animate// tailwind.config.js
module.exports = {
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/container-queries'),
require('tailwind-scrollbar'),
],
}综合配置示例
Vue 3 项目
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import vue from 'eslint-plugin-vue';
import prettier from 'eslint-plugin-prettier/recommended';
import eslintConfigPrettier from 'eslint-config-prettier';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
...vue.configs['flat/recommended'],
prettier,
eslintConfigPrettier,
{
rules: {
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
];// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"vueIndentScriptAndStyle": true
}// package.json
{
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"lint": "eslint . --fix",
"format": "prettier --write ."
},
"lint-staged": {
"*.{vue,js,ts}": ["eslint --fix", "prettier --write"]
}
}React 项目
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettier from 'eslint-plugin-prettier/recommended';
import eslintConfigPrettier from 'eslint-config-prettier';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.{jsx,tsx}'],
...react.configs.flat.recommended,
plugins: {
'react-hooks': reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
'react/react-in-jsx-scope': 'off',
},
},
prettier,
eslintConfigPrettier,
];完整项目模板
# 创建项目
npm create vite@latest my-app -- --template vue-ts
cd my-app
# 安装开发工具
npm install -D eslint @eslint/js typescript-eslint eslint-plugin-vue
npm install -D prettier eslint-plugin-prettier eslint-config-prettier
npm install -D tailwindcss postcss autoprefixer @tailwindcss/forms @tailwindcss/typography
npm install -D lint-staged husky
# 初始化配置
npx tailwindcss init -p
npx husky init
# 创建配置文件
touch eslint.config.js .prettierrc .prettierignore
# 配置 lint-staged
# 在 package.json 中添加 lint-staged 配置// package.json
{
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"lint": "eslint . --fix",
"format": "prettier --write .",
"prepare": "husky"
},
"lint-staged": {
"*.{vue,js,ts}": ["eslint --fix", "prettier --write"],
"*.{json,css,md}": ["prettier --write"]
}
}# .husky/pre-commit
npx lint-staged