Skip to main content

ESLint Plugin

The eslint-plugin-react-compiler package provides ESLint rules that surface problematic React code found by the React Compiler, helping you catch violations of the Rules of React before compilation.

Installation

npm install --save-dev eslint eslint-plugin-react-compiler

Configuration

Flat Config (ESLint 8+)

For modern ESLint flat config:
eslint.config.mjs
import reactCompiler from 'eslint-plugin-react-compiler';
import react from 'eslint-plugin-react';

export default [
  {
    plugins: {
      'react-compiler': reactCompiler,
    },
    rules: {
      'react-compiler/react-compiler': 'error',
    },
  },
];
eslint.config.mjs
import reactCompiler from 'eslint-plugin-react-compiler';
import react from 'eslint-plugin-react';

export default [
  // Your existing config
  {
    ...react.configs.flat.recommended,
    settings: { react: { version: 'detect' } },
  },
  // Add React Compiler recommended config
  reactCompiler.configs.recommended,
];

Legacy Config (.eslintrc)

For .eslintrc configuration:
{
  "plugins": ["react-compiler"],
  "rules": {
    "react-compiler/react-compiler": "error"
  }
}

Rule Configuration

Error Level

Configure the rule severity:
export default [
  {
    rules: {
      // Error - blocks CI/commits
      'react-compiler/react-compiler': 'error',
      
      // Warning - shows in editor but doesn't fail
      // 'react-compiler/react-compiler': 'warn',
      
      // Off - disable the rule
      // 'react-compiler/react-compiler': 'off',
    },
  },
];

Rule Options

The rule accepts the same configuration options as the Babel plugin:
eslint.config.mjs
export default [
  {
    rules: {
      'react-compiler/react-compiler': [
        'error',
        {
          environment: {
            // Compiler environment options
            validateHooksUsage: true,
            validateRefAccessDuringRender: true,
            validateNoSetStateInRender: true,
          },
        },
      ],
    },
  },
];

What It Checks

The ESLint plugin runs the React Compiler on your code and reports React-specific errors. It validates:

Rules of Hooks

// ✗ Bad - conditional hook call
function Component({ condition }) {
  if (condition) {
    useState(0); // Error: Hooks cannot be called conditionally
  }
}

// ✓ Good
function Component({ condition }) {
  const [state, setState] = useState(0);
  if (condition) {
    setState(1);
  }
}

setState During Render

// ✗ Bad - unconditional setState in render
function Component() {
  const [count, setCount] = useState(0);
  setCount(count + 1); // Error: setState called during render
  return <div>{count}</div>;
}

// ✓ Good - setState in event handler
function Component() {
  const [count, setCount] = useState(0);
  const handleClick = () => setCount(count + 1);
  return <button onClick={handleClick}>{count}</button>;
}

Ref Access During Render

// ✗ Bad - accessing ref.current in render
function Component() {
  const ref = useRef(null);
  const value = ref.current; // Error: ref.current accessed during render
  return <div>{value}</div>;
}

// ✓ Good - access ref in effect or event handler
function Component() {
  const ref = useRef(null);
  useEffect(() => {
    console.log(ref.current);
  });
  return <div ref={ref}>Content</div>;
}

Exhaustive Dependencies

// ✗ Bad - missing dependency
function Component({ userId }) {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, []); // Error: Missing dependency 'userId'
}

// ✓ Good - complete dependencies
function Component({ userId }) {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]);
}

Component Mutations

// ✗ Bad - mutating props
function Component({ items }) {
  items.push('new'); // Error: Mutating props
  return <List items={items} />;
}

// ✓ Good - creating new array
function Component({ items }) {
  const newItems = [...items, 'new'];
  return <List items={newItems} />;
}

Integration with Existing Setup

With eslint-plugin-react-hooks

Use both plugins together:
eslint.config.mjs
import reactHooks from 'eslint-plugin-react-hooks';
import reactCompiler from 'eslint-plugin-react-compiler';

export default [
  {
    plugins: {
      'react-hooks': reactHooks,
      'react-compiler': reactCompiler,
    },
    rules: {
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn',
      'react-compiler/react-compiler': 'error',
    },
  },
];

With TypeScript

eslint.config.mjs
import tseslint from '@typescript-eslint/eslint-plugin';
import reactCompiler from 'eslint-plugin-react-compiler';

export default [
  {
    files: ['**/*.ts', '**/*.tsx'],
    plugins: {
      '@typescript-eslint': tseslint,
      'react-compiler': reactCompiler,
    },
    rules: {
      'react-compiler/react-compiler': 'error',
    },
  },
];

File-Based Configuration

eslint.config.mjs
import reactCompiler from 'eslint-plugin-react-compiler';

export default [
  {
    // Strict checking for new code
    files: ['src/features/**/*.{js,jsx,ts,tsx}'],
    rules: {
      'react-compiler/react-compiler': 'error',
    },
  },
  {
    // Warnings for legacy code
    files: ['src/legacy/**/*.{js,jsx,ts,tsx}'],
    rules: {
      'react-compiler/react-compiler': 'warn',
    },
  },
];

Editor Integration

VS Code

Install the ESLint extension:
  1. Install ESLint extension
  2. Add to .vscode/settings.json:
.vscode/settings.json
{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

WebStorm / IntelliJ IDEA

  1. Go to Settings → Languages & Frameworks → JavaScript → Code Quality Tools → ESLint
  2. Enable “Automatic ESLint configuration”
  3. Set “Run eslint —fix on save”

Vim / Neovim

Use ALE or coc-eslint:
.vimrc
" ALE
let g:ale_linters = {'javascript': ['eslint']}
let g:ale_fixers = {'javascript': ['eslint']}

" Or with coc.nvim
" :CocInstall coc-eslint

CI/CD Integration

GitHub Actions

.github/workflows/lint.yml
name: Lint

on: [push, pull_request]

jobs:
  eslint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run lint

GitLab CI

.gitlab-ci.yml
lint:
  stage: test
  image: node:18
  script:
    - npm ci
    - npm run lint

Pre-commit Hook

Use husky and lint-staged:
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": "eslint --fix"
  }
}

Troubleshooting

”No files matching the pattern were found”

Ensure your ESLint config includes the correct file patterns:
eslint.config.mjs
export default [
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    // ...
  },
];

“Failed to load plugin ‘react-compiler’”

Verify the plugin is installed:
npm list eslint-plugin-react-compiler
Reinstall if necessary:
npm install --save-dev eslint-plugin-react-compiler

High Memory Usage

For large codebases, increase Node memory:
package.json
{
  "scripts": {
    "lint": "NODE_OPTIONS='--max-old-space-size=4096' eslint ."
  }
}

Slow Linting

Use ESLint cache:
eslint --cache --cache-location node_modules/.cache/eslint .
Or in package.json:
{
  "scripts": {
    "lint": "eslint --cache ."
  }
}

Ignoring Violations

File-Level

/* eslint-disable react-compiler/react-compiler */
function LegacyComponent() {
  // Non-compliant code
}
/* eslint-enable react-compiler/react-compiler */

Line-Level

function Component() {
  // eslint-disable-next-line react-compiler/react-compiler
  if (condition) useState(0);
}

.eslintignore

.eslintignore
# Ignore legacy code
src/legacy/

# Ignore build output
build/
dist/

# Ignore dependencies
node_modules/

Best Practices

Gradual Adoption

  1. Start with warnings:
    rules: { 'react-compiler/react-compiler': 'warn' }
    
  2. Fix violations incrementally
  3. Switch to errors:
    rules: { 'react-compiler/react-compiler': 'error' }
    

Team Workflow

  1. Local Development: Show warnings in editor
  2. Pre-commit: Block commits with errors
  3. CI/CD: Fail builds on errors
  4. Code Review: Require fixes before merge

Documentation

Document exceptions:
// eslint-disable-next-line react-compiler/react-compiler
// Reason: Third-party library requires this pattern
// TODO: Refactor when library v2.0 is available
legacyAPI.method();

Next Steps

Configuration

Configure compiler validation options

Babel Plugin

Set up code transformation

How It Works

Understand the validation process

Contributing

Contribute to the ESLint plugin