ESLint

ESLint 是 JavaScript 和 TypeScript 的代码检查工具,用于发现和修复代码中的问题。

安装与配置

# 安装 ESLint
npm install -D eslint

# 初始化配置(交互式)
npx eslint --init

# 或手动安装推荐的配置
npm install -D eslint @eslint/js typescript-eslint

ESLint 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-prettier

Prettier 配置

// .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-staged

Tailwind 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