What tools and processes do you use for maintaining code quality? (ESLint, Prettier, Husky, CI/CD, etc.)
5 minintermediatereactbest-practicestoolsprocessesmaintainingcode
Quick Answer
Key aspects: ESLint Configuration; Prettier Configuration; Husky Git Hooks; TypeScript Configuration; Jest Testing Configuration; CI/CD Pipeline (GitHub Actions).
Detailed Answer
What tools and processes do you use for maintaining code quality? (ESLint, Prettier, Husky, CI/CD, etc.)
Answer:
1. ESLint Configuration:
// .eslintrc.json
{
"extends": [
"eslint:recommended",
"@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"@typescript-eslint",
"react",
"react-hooks",
"jsx-a11y",
"import"
],
"rules": {
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"jsx-a11y/anchor-is-valid": "error",
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index"
],
"newlines-between": "always"
}
]
},
"settings": {
"react": {
"version": "detect"
},
"import/resolver": {
"typescript": {
"alwaysTryTypes": true
}
}
}
}
2. Prettier Configuration:
// .prettierrc
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "avoid",
"endOfLine": "lf",
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"proseWrap": "preserve"
}
// .prettierignore
node_modules/
dist/
build/
.next/
coverage/
*.min.js
*.min.css
package-lock.json
yarn.lock
3. Husky Git Hooks:
// package.json
{
"scripts": {
"lint": "eslint src --ext .ts,.tsx --max-warnings 0",
"lint:fix": "eslint src --ext .ts,.tsx --fix",
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
"type-check": "tsc --noEmit",
"test": "jest",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
"build": "tsc && vite build",
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm run type-check && npm run test"
}
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{js,jsx,json,css,md}": [
"prettier --write"
]
}
}
4. TypeScript Configuration:
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "DOM.Iterable", "ES6"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": "src",
"paths": {
"@/*": ["*"],
"@/components/*": ["components/*"],
"@/hooks/*": ["hooks/*"],
"@/utils/*": ["utils/*"],
"@/types/*": ["types/*"]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"build"
]
}
5. Jest Testing Configuration:
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/index.tsx',
'!src/setupTests.ts',
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
testMatch: [
'<rootDir>/src/**/__tests__/**/*.{ts,tsx}',
'<rootDir>/src/**/*.{test,spec}.{ts,tsx}',
],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
};
// src/setupTests.ts
import '@testing-library/jest-dom';
import { configure } from '@testing-library/react';
// Configure testing library
configure({ testIdAttribute: 'data-testid' });
// Mock IntersectionObserver
global.IntersectionObserver = class IntersectionObserver {
constructor() {}
disconnect() {}
observe() {}
unobserve() {}
};
// Mock ResizeObserver
global.ResizeObserver = class ResizeObserver {
constructor() {}
disconnect() {}
observe() {}
unobserve() {}
};
6. CI/CD Pipeline (GitHub Actions):
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
quality-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Type checking
run: npm run type-check
- name: Linting
run: npm run lint
- name: Format checking
run: npm run format:check
- name: Run tests
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
build:
needs: quality-checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- name: Deploy to production
run: |
# Deployment commands here
echo "Deploying to production..."
7. Additional Quality Tools:
// package.json - Additional dev dependencies
{
"devDependencies": {
"@commitlint/cli": "^17.0.0",
"@commitlint/config-conventional": "^17.0.0",
"commitizen": "^4.2.4",
"cz-conventional-changelog": "^3.3.0",
"husky": "^8.0.0",
"lint-staged": "^13.0.0",
"npm-run-all": "^4.1.5",
"plop": "^3.0.0",
"size-limit": "^8.0.0",
"@size-limit/preset-small-lib": "^8.0.0"
}
}
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'ci',
'build',
'revert'
]
]
}
};
// .size-limit.json
[
{
"path": "dist/index.js",
"limit": "10 KB"
},
{
"path": "dist/index.css",
"limit": "2 KB"
}
]
8. VS Code Configuration:
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"emmet.includeLanguages": {
"typescript": "html",
"typescriptreact": "html"
},
"files.associations": {
"*.css": "tailwindcss"
}
}
// .vscode/extensions.json
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss",
"ms-vscode.vscode-typescript-next",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense",
"ms-vscode.vscode-json"
]
}
9. Automated Code Generation:
// plopfile.js
module.exports = function (plop) {
plop.setGenerator('component', {
description: 'Create a new React component',
prompts: [
{
type: 'input',
name: 'name',
message: 'Component name:',
},
{
type: 'confirm',
name: 'withProps',
message: 'Include props interface?',
default: true,
},
{
type: 'confirm',
name: 'withTests',
message: 'Include test file?',
default: true,
},
],
actions: [
{
type: 'add',
path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.tsx',
templateFile: 'templates/component.hbs',
},
{
type: 'add',
path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.test.tsx',
templateFile: 'templates/component.test.hbs',
skip: (data) => !data.withTests,
},
{
type: 'add',
path: 'src/components/{{pascalCase name}}/index.ts',
templateFile: 'templates/index.hbs',
},
],
});
};
10. Best Practices Summary:
Code Quality Tools:
- ESLint: Catch bugs and enforce coding standards
- Prettier: Consistent code formatting
- TypeScript: Type safety and better developer experience
- Husky: Git hooks for pre-commit checks
- lint-staged: Run linters only on staged files
- Jest: Unit testing with coverage reports
- Commitlint: Enforce conventional commit messages
Processes:
- Pre-commit hooks: Automatic linting and formatting
- CI/CD pipeline: Automated testing and deployment
- Code reviews: Peer review process with quality gates
- Automated testing: Unit, integration, and E2E tests
- Performance monitoring: Bundle size limits and performance budgets
- Documentation: Automated API documentation generation
Quality Metrics:
- Code coverage thresholds (80%+)
- Bundle size limits
- Performance budgets
- Accessibility compliance
- Security vulnerability scanning
- Dependency audit and updates