ESLint × Monorepo での管理方法と注意点

モノレポ(Monorepo)環境での開発が普及する中、ESLint の設定管理は従来の単一プロジェクトとは異なる複雑な課題を抱えています。複数のパッケージが共存し、異なる技術スタックが混在する環境では、設定の継承、競合、パフォーマンスなど、様々な問題が発生します。
この記事では、モノレポ環境での ESLint 管理の効率的な解決策を段階的に解説していきます。基本的な設定戦略から実際の運用課題まで、実践的な内容をお届けし、大規模なプロジェクトでも安定して運用できる方法をご紹介します。
モノレポと ESLint の基本関係
モノレポ環境特有の ESLint 課題
モノレポ環境では、単一プロジェクトでは発生しない特有の課題があります。
主要な課題一覧
# | 課題 | 発生理由 | 影響度 |
---|---|---|---|
1 | 設定継承の複雑化 | 複数階層の設定ファイルが相互作用 | 高 |
2 | パフォーマンス劣化 | 大量のファイルとパッケージの処理 | 高 |
3 | 技術スタック混在 | React/Vue/Node.js などが共存 | 中 |
4 | 設定競合 | 異なるパッケージ間でのルール衝突 | 中 |
5 | 開発体験の不統一 | パッケージごとに異なるエラー表示 | 低 |
従来の単一プロジェクト管理との違い
単一プロジェクトの場合
dirproject/
├── .eslintrc.js (root: true)
├── src/
│ ├── components/
│ └── utils/
└── package.json
この構成では、一つの .eslintrc.js
ですべてのファイルを管理できます。
モノレポの場合
dirmonorepo/
├── .eslintrc.js (root: true, 共通設定)
├── packages/
│ ├── web-app/
│ │ ├── .eslintrc.js (React設定)
│ │ ├── src/
│ │ └── package.json
│ ├── api-server/
│ │ ├── .eslintrc.js (Node.js設定)
│ │ ├── src/
│ │ └── package.json
│ └── shared-lib/
│ ├── .eslintrc.js (ライブラリ設定)
│ ├── src/
│ └── package.json
└── package.json
この構成では、複数の設定ファイルが階層的に存在し、それぞれが異なる目的を持ちます。
設定継承と分離のバランス
モノレポでは、共通設定と個別設定のバランスが重要です。
良いバランスの例
javascript// monorepo/.eslintrc.js (ルートレベル)
module.exports = {
root: true,
extends: ['eslint:recommended'],
env: {
es2021: true,
},
parserOptions: {
ecmaVersion: 2021,
},
rules: {
// 全パッケージ共通のルール
'no-console': 'warn',
'prefer-const': 'error',
},
overrides: [
{
files: ['**/*.test.js', '**/*.spec.js'],
env: {
jest: true,
},
rules: {
'no-console': 'off',
},
},
],
};
javascript// packages/web-app/.eslintrc.js (個別設定)
module.exports = {
// root: true を設定しない(親設定を継承)
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
env: {
browser: true,
},
settings: {
react: {
version: 'detect',
},
},
rules: {
// React固有のルール
'react/prop-types': 'error',
'react-hooks/exhaustive-deps': 'warn',
},
};
基本的な設定戦略
ルートレベルでの共通設定
ルートレベルの設定は、モノレポ全体で適用される基盤となる重要な設定です。
基本構成の設計原則
javascript// monorepo/.eslintrc.js
module.exports = {
root: true, // 必須:上位ディレクトリへの探索を停止
extends: [
'eslint:recommended',
'@company/eslint-config', // 社内共通設定があれば
],
env: {
es2021: true,
node: true, // 全般的に Node.js 環境を想定
},
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
plugins: [
'import', // 必須プラグイン
],
rules: {
// 全パッケージで統一すべき基本ルール
'no-unused-vars': 'error',
'no-console': 'warn',
'prefer-const': 'error',
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal'],
'newlines-between': 'always',
},
],
},
ignorePatterns: [
// 全体で無視するパターン
'node_modules/',
'dist/',
'build/',
'coverage/',
'*.d.ts',
],
};
パッケージレベルでの個別設定
各パッケージでは、そのパッケージ特有の要件に応じた設定を追加します。
React パッケージの設定例
javascript// packages/web-app/.eslintrc.js
module.exports = {
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
],
env: {
browser: true,
},
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/react-in-jsx-scope': 'off', // React 17+
'react/prop-types': 'error',
'jsx-a11y/anchor-is-valid': 'error',
},
overrides: [
{
files: ['**/*.tsx'],
rules: {
'react/prop-types': 'off', // TypeScript使用時
},
},
],
};
Node.js パッケージの設定例
javascript// packages/api-server/.eslintrc.js
module.exports = {
extends: [
'plugin:node/recommended',
'plugin:security/recommended',
],
env: {
node: true,
browser: false, // 明示的にブラウザ環境を無効化
},
rules: {
'no-console': 'off', // サーバーサイドではconsoleを許可
'node/no-process-env': 'off', // 環境変数の使用を許可
'security/detect-object-injection': 'warn',
},
};
設定ファイルの階層構造設計
効率的な階層構造を設計するための原則です。
推奨される階層パターン
dirmonorepo/
├── .eslintrc.js (レベル1: 全体基盤設定)
├── packages/
│ ├── frontend/
│ │ ├── .eslintrc.js (レベル2: 技術領域別設定)
│ │ ├── web-app/
│ │ │ ├── .eslintrc.js (レベル3: 個別プロジェクト設定)
│ │ │ └── src/
│ │ └── mobile-app/
│ │ ├── .eslintrc.js
│ │ └── src/
│ └── backend/
│ ├── .eslintrc.js (レベル2: 技術領域別設定)
│ ├── api-server/
│ │ └── src/
│ └── worker/
│ └── src/
└── tools/
├── .eslintrc.js (レベル2: ツール固有設定)
└── scripts/
レベル 2 設定の例(技術領域別)
javascript// packages/frontend/.eslintrc.js
module.exports = {
extends: [
'plugin:import/recommended',
'plugin:prettier/recommended',
],
env: {
browser: true,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
rules: {
// フロントエンド共通のルール
'no-alert': 'error',
'no-confirm': 'error',
},
};
技術スタック別の管理手法
React/Vue/Node.js 混在環境での設定
異なるフレームワークが混在する環境では、適切な分離と共通化が重要です。
共通ベース設定の作成
javascript// eslint-config/base.js (共通設定)
module.exports = {
extends: ['eslint:recommended'],
env: {
es2021: true,
},
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
plugins: ['import', 'unicorn'],
rules: {
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal'],
'newlines-between': 'always',
alphabetize: { order: 'asc' },
},
],
'unicorn/prefer-module': 'error',
'prefer-const': 'error',
},
};
フレームワーク固有設定の作成
javascript// eslint-config/react.js
const base = require('./base');
module.exports = {
...base,
extends: [
...base.extends,
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
env: {
...base.env,
browser: true,
},
settings: {
react: { version: 'detect' },
},
rules: {
...base.rules,
'react/prop-types': 'error',
'react-hooks/exhaustive-deps': 'warn',
},
};
javascript// eslint-config/vue.js
const base = require('./base');
module.exports = {
...base,
extends: [...base.extends, 'plugin:vue/vue3-recommended'],
parser: 'vue-eslint-parser',
parserOptions: {
...base.parserOptions,
parser: '@typescript-eslint/parser',
},
env: {
...base.env,
browser: true,
},
rules: {
...base.rules,
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
],
},
};
TypeScript/JavaScript 共存パターン
TypeScript と JavaScript が混在する環境での設定例です。
ファイル拡張子による分岐設定
javascript// packages/mixed-project/.eslintrc.js
module.exports = {
extends: ['eslint:recommended'],
env: {
es2021: true,
node: true,
},
overrides: [
{
// TypeScript ファイル用設定
files: ['**/*.ts', '**/*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'@typescript-eslint/recommended-requiring-type-checking',
],
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-function-return-type':
'warn',
'@typescript-eslint/no-explicit-any': 'warn',
},
},
{
// JavaScript ファイル用設定
files: ['**/*.js', '**/*.jsx'],
env: {
es2021: true,
},
rules: {
'no-unused-vars': 'error',
'no-undef': 'error',
},
},
],
};
フロントエンド/バックエンド分離戦略
技術領域による明確な分離戦略です。
よくあるエラーと解決方法
エラー例 1: ブラウザ API の Node.js 環境での誤用
bash✗ 15:3 error 'document' is not defined no-undef
✗ 16:3 error 'window' is not defined no-undef
原因: フロントエンド用のコードがバックエンド環境で実行されている
javascript// 問題のあるコード(バックエンドパッケージ内)
function handleClick() {
document
.getElementById('button')
.addEventListener('click', () => {
window.location.href = '/dashboard';
});
}
解決方法:
javascript// packages/backend/.eslintrc.js
module.exports = {
env: {
node: true,
browser: false, // 明示的に無効化
},
rules: {
'no-undef': 'error',
},
};
エラー例 2: Node.js API のブラウザ環境での誤用
bash✗ 8:17 error 'process' is not defined no-undef
✗ 9:17 error 'Buffer' is not defined no-undef
解決方法:
javascript// packages/frontend/.eslintrc.js
module.exports = {
env: {
browser: true,
node: false, // Node.js環境を無効化
},
globals: {
// 必要に応じて特定のグローバル変数のみ許可
process: 'readonly', // 環境変数アクセス用
},
};
パフォーマンス最適化
大規模モノレポでの実行時間短縮
大規模なモノレポでは、ESLint の実行時間が大幅に増加する問題があります。
パフォーマンス問題の例
bash# 問題のある実行例
$ yarn lint
✓ Linting 15,000 files...
⚠ Completed in 180.5s (3 minutes)
# 最適化後の実行例
$ yarn lint
✓ Linting 2,500 files (changed files only)...
✓ Completed in 12.3s
実行時間短縮の戦略
json// package.json - 効率的なlintスクリプト
{
"scripts": {
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx .",
"lint:changed": "eslint --cache $(git diff --name-only --diff-filter=AM HEAD~1 | grep -E '\\.(js|jsx|ts|tsx)$' | tr '\\n' ' ')",
"lint:package": "eslint --cache packages/$PACKAGE/src",
"lint:parallel": "concurrently \"yarn lint:frontend\" \"yarn lint:backend\"",
"lint:frontend": "eslint --cache packages/frontend",
"lint:backend": "eslint --cache packages/backend"
}
}
キャッシュ戦略と並列実行
効率的なキャッシュ戦略の実装例です。
ESLint キャッシュの最適化
javascript// .eslintrc.js
module.exports = {
// ... 他の設定
cache: true,
cacheLocation: '.eslintcache',
// ファイル変更時のみ再実行
};
bash# .gitignore
.eslintcache
node_modules/
並列実行の設定
json// package.json
{
"scripts": {
"lint:all": "concurrently --names \"web,api,shared\" \"yarn workspace web-app lint\" \"yarn workspace api-server lint\" \"yarn workspace shared-lib lint\""
},
"devDependencies": {
"concurrently": "^7.6.0"
}
}
変更検知による差分実行
Git 連携による効率的な差分実行の実装です。
変更ファイル検知スクリプト
javascript// scripts/lint-changed.js
const { execSync } = require('child_process');
const path = require('path');
function getChangedFiles() {
try {
const changedFiles = execSync(
'git diff --name-only HEAD~1',
{
encoding: 'utf8',
}
)
.split('\n')
.filter((file) => file.match(/\.(js|jsx|ts|tsx)$/))
.filter((file) => file.length > 0);
return changedFiles;
} catch (error) {
console.warn('Git diff failed, linting all files');
return [];
}
}
function lintChangedFiles() {
const changedFiles = getChangedFiles();
if (changedFiles.length === 0) {
console.log('No JavaScript/TypeScript files changed');
return;
}
console.log(
`Linting ${changedFiles.length} changed files...`
);
console.log(changedFiles.map((f) => ` ${f}`).join('\n'));
try {
execSync(
`npx eslint --cache ${changedFiles.join(' ')}`,
{
stdio: 'inherit',
}
);
} catch (error) {
process.exit(1);
}
}
lintChangedFiles();
json// package.json
{
"scripts": {
"lint:changed": "node scripts/lint-changed.js"
}
}
運用とメンテナンス
設定変更の影響範囲管理
モノレポでは設定変更の影響範囲を正確に把握することが重要です。
影響範囲分析ツールの作成
javascript// scripts/analyze-eslint-impact.js
const fs = require('fs');
const path = require('path');
const glob = require('glob');
function findEslintConfigs() {
const configs = glob.sync('**/.eslintrc.{js,json,yaml}', {
ignore: ['node_modules/**'],
});
return configs.map((configPath) => {
const fullPath = path.resolve(configPath);
const directory = path.dirname(fullPath);
return {
path: configPath,
directory,
affectedFiles: glob.sync('**/*.{js,jsx,ts,tsx}', {
cwd: directory,
ignore: ['node_modules/**'],
}),
};
});
}
function analyzeConfigHierarchy() {
const configs = findEslintConfigs();
console.log('ESLint Configuration Hierarchy:');
configs.forEach((config, index) => {
console.log(`${index + 1}. ${config.path}`);
console.log(
` Affected files: ${config.affectedFiles.length}`
);
console.log(` Directory: ${config.directory}`);
console.log('');
});
}
analyzeConfigHierarchy();
設定変更時のチェックリスト
# | チェック項目 | 実行方法 | 重要度 |
---|---|---|---|
1 | 影響範囲の確認 | node scripts/analyze-eslint-impact.js | 高 |
2 | 全パッケージでの lint 実行 | yarn lint:all | 高 |
3 | CI/CD パイプラインでのテスト | yarn test:ci | 高 |
4 | チーム内での設定レビュー | プルリクエストでの確認 | 中 |
5 | 段階的ロールアウト | パッケージ単位での適用 | 中 |
新パッケージ追加時の自動設定
新しいパッケージを追加する際の自動化戦略です。
パッケージテンプレートの作成
bash# scripts/create-package.sh
#!/bin/bash
PACKAGE_NAME=$1
PACKAGE_TYPE=$2 # frontend, backend, shared
if [ -z "$PACKAGE_NAME" ]; then
echo "Usage: ./create-package.sh <package-name> <package-type>"
exit 1
fi
PACKAGE_DIR="packages/$PACKAGE_NAME"
# ディレクトリ作成
mkdir -p "$PACKAGE_DIR/src"
# package.json 作成
cat > "$PACKAGE_DIR/package.json" << EOF
{
"name": "@monorepo/$PACKAGE_NAME",
"version": "1.0.0",
"private": true,
"scripts": {
"lint": "eslint src --ext .js,.jsx,.ts,.tsx",
"lint:fix": "yarn lint --fix",
"test": "jest"
}
}
EOF
# ESLint設定ファイル作成
case $PACKAGE_TYPE in
"frontend")
cp templates/.eslintrc.frontend.js "$PACKAGE_DIR/.eslintrc.js"
;;
"backend")
cp templates/.eslintrc.backend.js "$PACKAGE_DIR/.eslintrc.js"
;;
"shared")
cp templates/.eslintrc.shared.js "$PACKAGE_DIR/.eslintrc.js"
;;
*)
echo "Unknown package type: $PACKAGE_TYPE"
exit 1
;;
esac
echo "Package $PACKAGE_NAME created successfully!"
テンプレート設定ファイル
javascript// templates/.eslintrc.frontend.js
module.exports = {
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
env: {
browser: true,
},
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/prop-types': 'error',
},
};
チーム間での設定合意形成
大規模開発チームでの設定合意形成のプロセスです。
設定変更プロセス
mermaidgraph TD
A["設定変更提案"] --> B["技術検討"]
B --> C["影響範囲分析"]
C --> D["チーム内議論"]
D --> E{合意形成}
E -->|合意| F["段階的適用"]
E -->|非合意| G["再検討"]
F --> H["効果測定"]
H --> I["本格運用"]
G --> D
設定提案テンプレート
markdown# ESLint 設定変更提案
## 概要
[変更内容の概要]
## 背景・目的
[なぜこの変更が必要か]
## 変更内容
```javascript
// 変更前
// 既存の設定
// 変更後
// 新しい設定
```
影響範囲
- 影響を受けるパッケージ: [パッケージ名]
- 影響を受けるファイル数: [ファイル数]
- 修正が必要なファイル: [リスト]
移行計画
- [ステップ 1]
- [ステップ 2]
- [ステップ 3]
リスク評価
- 高リスク: [内容]
- 中リスク: [内容]
- 低リスク: [内容]
bash
## 実際の問題と解決事例
### よくある設定競合と対処法
モノレポ環境で頻繁に発生する設定競合の具体例と解決方法です。
**問題事例1: パーサー競合エラー**
```bash
✗ Error: Cannot read config file: /path/to/monorepo/packages/web-app/.eslintrc.js
✗ Error: You have used a rule which requires parserServices to be generated.
原因:
javascript// packages/web-app/.eslintrc.js (問題のある設定)
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'@typescript-eslint/recommended-requiring-type-checking',
],
// parserOptions.project が設定されていない
rules: {
'@typescript-eslint/no-floating-promises': 'error',
},
};
解決方法:
javascript// packages/web-app/.eslintrc.js (修正後)
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json', // 必須設定
tsconfigRootDir: __dirname,
},
extends: [
'@typescript-eslint/recommended-requiring-type-checking',
],
rules: {
'@typescript-eslint/no-floating-promises': 'error',
},
};
問題事例 2: 設定継承の無限ループ
bash✗ Error: Configuration for rule "import/order" is invalid
✗ Error: Circular dependency detected in extends chain
原因:
javascript// packages/frontend/.eslintrc.js
module.exports = {
extends: ['../shared/.eslintrc.js'], // 相対パス参照
};
// packages/shared/.eslintrc.js
module.exports = {
extends: ['../frontend/.eslintrc.js'], // 循環参照
};
解決方法:
javascript// eslint-config/base.js (共通設定を分離)
module.exports = {
extends: ['eslint:recommended'],
rules: {
'no-unused-vars': 'error',
},
};
// packages/frontend/.eslintrc.js
module.exports = {
extends: ['../../eslint-config/base.js'],
rules: {
// フロントエンド固有のルール
},
};
// packages/shared/.eslintrc.js
module.exports = {
extends: ['../../eslint-config/base.js'],
rules: {
// 共有ライブラリ固有のルール
},
};
パフォーマンス問題の診断と改善
大規模モノレポで発生するパフォーマンス問題の診断方法です。
パフォーマンス分析スクリプト
javascript// scripts/eslint-performance.js
const { performance } = require('perf_hooks');
const { ESLint } = require('eslint');
const glob = require('glob');
async function analyzePerformance() {
const eslint = new ESLint({
cache: true,
cacheLocation: '.eslintcache',
});
const patterns = [
'packages/web-app/src/**/*.{js,jsx,ts,tsx}',
'packages/api-server/src/**/*.{js,ts}',
'packages/shared-lib/src/**/*.{js,ts}',
];
for (const pattern of patterns) {
const files = glob.sync(pattern);
console.log(
`\nAnalyzing ${files.length} files in ${pattern}:`
);
const startTime = performance.now();
const results = await eslint.lintFiles(files);
const endTime = performance.now();
const duration = endTime - startTime;
const errorsCount = results.reduce(
(sum, result) => sum + result.errorCount,
0
);
const warningsCount = results.reduce(
(sum, result) => sum + result.warningCount,
0
);
console.log(` Duration: ${duration.toFixed(2)}ms`);
console.log(
` Files/sec: ${(
files.length /
(duration / 1000)
).toFixed(2)}`
);
console.log(
` Errors: ${errorsCount}, Warnings: ${warningsCount}`
);
}
}
analyzePerformance().catch(console.error);
パフォーマンス改善例
改善前:
bash$ node scripts/eslint-performance.js
Analyzing 1,247 files in packages/web-app/src/**/*.{js,jsx,ts,tsx}:
Duration: 45,230.55ms
Files/sec: 27.58
Errors: 156, Warnings: 89
Analyzing 834 files in packages/api-server/src/**/*.{js,ts}:
Duration: 32,123.22ms
Files/sec: 25.97
Errors: 23, Warnings: 12
改善後:
bash$ node scripts/eslint-performance.js
Analyzing 1,247 files in packages/web-app/src/**/*.{js,jsx,ts,tsx}:
Duration: 8,456.33ms
Files/sec: 147.45
Errors: 156, Warnings: 89
Analyzing 834 files in packages/api-server/src/**/*.{js,ts}:
Duration: 5,234.11ms
Files/sec: 159.33
Errors: 23, Warnings: 12
改善手法:
javascript// .eslintrc.js (最適化版)
module.exports = {
root: true,
cache: true, // キャッシュ有効化
cacheLocation: '.eslintcache',
// 不要なプラグインを削除
plugins: [
'import', // 必要最小限
],
// パフォーマンスの良いルールセットを使用
extends: [
'eslint:recommended', // 軽量な基本セット
],
// 重いルールを無効化
rules: {
'import/no-cycle': 'off', // 重い循環依存チェックを無効化
'import/no-unused-modules': 'off', // 重い未使用モジュールチェックを無効化
},
// ignorePatterns を活用してファイル数を削減
ignorePatterns: [
'node_modules/',
'dist/',
'build/',
'coverage/',
'**/*.d.ts',
'packages/*/lib/',
],
};
スケーリング時の課題対応
モノレポの規模拡大に伴う課題と対応策です。
段階的な課題と対応
フェーズ | パッケージ数 | 主要課題 | 対応策 |
---|---|---|---|
小規模 | 3-5 個 | 基本設定の統一 | 共通.eslintrc.js の作成 |
中規模 | 6-15 個 | パフォーマンス劣化 | キャッシュ有効化、並列実行 |
大規模 | 16-50 個 | 設定管理の複雑化 | 設定継承の階層化 |
超大規模 | 50+個 | CI/CD 時間の増大 | 差分実行、分散処理 |
超大規模環境での対応例
javascript// scripts/distributed-lint.js
const {
Worker,
isMainThread,
parentPort,
workerData,
} = require('worker_threads');
const os = require('os');
const glob = require('glob');
if (isMainThread) {
// メインスレッド: ワーカーの管理
async function distributedLint() {
const allFiles = glob.sync(
'packages/*/src/**/*.{js,jsx,ts,tsx}'
);
const numWorkers = os.cpus().length;
const chunkSize = Math.ceil(
allFiles.length / numWorkers
);
const workers = [];
const promises = [];
for (let i = 0; i < numWorkers; i++) {
const start = i * chunkSize;
const end = Math.min(
start + chunkSize,
allFiles.length
);
const files = allFiles.slice(start, end);
if (files.length === 0) continue;
const worker = new Worker(__filename, {
workerData: { files },
});
const promise = new Promise((resolve, reject) => {
worker.on('message', resolve);
worker.on('error', reject);
});
workers.push(worker);
promises.push(promise);
}
const results = await Promise.all(promises);
// 結果の集約
const totalErrors = results.reduce(
(sum, result) => sum + result.errors,
0
);
const totalWarnings = results.reduce(
(sum, result) => sum + result.warnings,
0
);
console.log(`Total errors: ${totalErrors}`);
console.log(`Total warnings: ${totalWarnings}`);
workers.forEach((worker) => worker.terminate());
}
distributedLint().catch(console.error);
} else {
// ワーカースレッド: ESLintの実行
const { ESLint } = require('eslint');
const { files } = workerData;
async function lintFiles() {
const eslint = new ESLint({ cache: true });
const results = await eslint.lintFiles(files);
const errors = results.reduce(
(sum, result) => sum + result.errorCount,
0
);
const warnings = results.reduce(
(sum, result) => sum + result.warningCount,
0
);
parentPort.postMessage({ errors, warnings });
}
lintFiles().catch(console.error);
}
まとめ
モノレポ環境での ESLint 管理は、単一プロジェクトとは大きく異なる複雑な課題を抱えています。しかし、適切な設定戦略と運用手法を採用することで、これらの課題は効果的に解決できます。
重要なポイントの再確認
設定継承の階層化により、共通ルールと個別要件のバランスを取ることができます。技術スタック別の管理手法を導入することで、React、Vue、Node.js などの異なる環境でも統一された開発体験を提供できます。
パフォーマンス最適化については、キャッシュ活用と並列実行により大幅な高速化が可能です。変更検知による差分実行を組み合わせることで、大規模プロジェクトでも実用的な実行時間を実現できます。
運用面では、設定変更の影響範囲管理と新パッケージ追加の自動化により、継続的な改善サイクルを構築できます。チーム間での合意形成プロセスを確立することで、組織全体での品質向上につながります。
実際の問題解決においては、設定競合やパフォーマンス問題への対処法を習得することで、安定した運用が可能になります。スケーリング時の課題への準備も重要で、段階的な対応策を講じることで、プロジェクトの成長に対応できます。
モノレポでの ESLint 管理は継続的な改善が必要な分野です。定期的な設定見直しとチーム内での知識共有により、より効率的で品質の高い開発環境を構築していくことができるでしょう。
関連リンク
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来
- review
人類はなぜ地球を支配できた?『サピエンス全史 上巻』ユヴァル・ノア・ハラリが解き明かす驚愕の真実
- review
え?世界はこんなに良くなってた!『FACTFULNESS』ハンス・ロスリングが暴く 10 の思い込みの正体
- review
瞬時に答えが出る脳に変身!『ゼロ秒思考』赤羽雄二が贈る思考力爆上げトレーニング
- review
関西弁のゾウに人生変えられた!『夢をかなえるゾウ 1』水野敬也が教えてくれた成功の本質