Integrating ESLint & Prettier in DevContainers

Introduction

Consistent code quality across distributed teams requires identical linting and formatting configurations. This section defines how to integrate ESLint and Prettier within DevContainer environments, ensuring CI/CD parity through locked dependencies and centralized configuration.

Sections

1. Dependency Pinning & Lock Files

Use package-lock.json or yarn.lock to guarantee ESLint and Prettier versions are identical across all developer machines and CI runners. Commit lock files to Git to enforce deterministic dependency resolution.

Pin ESLint to specific major versions (e.g., eslint@^8.40.0). Pin Prettier to exact versions when possible (e.g., prettier@3.0.0) to prevent formatting divergence. Document all plugin dependencies explicitly.

2. Configuration Management

Define .eslintrc.json and .prettierrc in the workspace root with explicit rule sets. Avoid inline configurations in package.json to maintain clarity. Reference the configuration files in VS Code settings for consistent IDE behavior.

Use ESLint extends to inherit from community configs (eslint-config-airbnb, eslint-config-standard) and override with team-specific rules. Ensure Prettier configuration matches ESLint output format to prevent conflicting rule violations.

3. Formatter Integration & Conflict Resolution

Configure Prettier as the default formatter in VS Code via customizations.vscode.settings. Disable conflicting ESLint formatting rules using eslint-config-prettier. Run Prettier before ESLint in CI pipelines to establish single source of truth for formatting.

Define postCreateCommand to install dependencies and validate configuration syntax before allowing development workflows.

4. CI Pipeline Integration

Execute ESLint and Prettier checks in GitHub Actions or similar CI systems using identical package-lock.json. Fail CI on linting errors or formatting mismatches. Generate detailed reports for human review.

Use --fix flag conservatively in CI—prefer manual fixing by developers to maintain code ownership. Reserve auto-fix for formatting-only rules (Prettier).

Code Blocks

.eslintrc.json with airbnb config

{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true,
    "jest": true
  },
  "extends": [
    "airbnb-base",
    "prettier"
  ],
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "rules": {
    "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
    "no-console": ["warn", { "allow": ["warn", "error"] }],
    "import/no-extraneous-dependencies": [
      "error",
      { "devDependencies": ["**/*.test.js", "**/test/**"] }
    ]
  }
}

.prettierrc with formatting standards

{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "arrowParens": "always",
  "bracketSpacing": true
}

devcontainer.json VS Code settings for linting

{
  "customizations": {
    "vscode": {
      "settings": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
        "editor.formatOnSave": true,
        "eslint.validate": ["javascript", "typescript"],
        "[javascript]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true
        },
        "[typescript]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true
        }
      },
      "extensions": [
        "dbaeumer.vscode-eslint@3.0.10",
        "esbenp.prettier-vscode@10.1.0"
      ]
    }
  }
}

GitHub Actions CI with linting checks

name: Lint

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18.17.0'
          cache: 'npm'
      
      - run: npm ci
      - run: npx prettier --check .
      - run: npm run lint

Common Pitfalls

  • Mismatched Prettier & ESLint configs: ESLint rules conflicting with Prettier formatting cause infinite format loops. Use eslint-config-prettier to disable formatting rules.
  • Floating dependency versions: Omitting package-lock.json from Git causes format divergence between developer machines and CI. Always commit lock files.
  • Missing --fix guards: Running eslint --fix or prettier --write without review masks code quality issues. Reserve auto-fix for CI-only formatting phases.
  • Ignoring file patterns: Forgetting to configure .eslintignore or .prettierignore causes redundant checks on generated/vendor code. Maintain ignore lists explicitly.
  • IDE vs CLI divergence: VS Code settings not matching CLI ESLint config cause confusion. Validate customizations.vscode matches .eslintrc.json.

FAQ

How do I prevent ESLint and Prettier conflicts? Use eslint-config-prettier to disable ESLint’s formatting rules. Run Prettier before ESLint in CI. Disable editor.formatOnSave for ESLint and use Prettier exclusively for formatting.

Should I use —fix in CI pipelines? Prefer manual fixing to maintain code ownership. Use --fix only for truly automatic fixes (trailing semicolons, quotes). Report mismatches and fail CI so developers fix issues consciously.