ESLint で Vue.js プロジェクトを守る設定ガイド

Vue.js プロジェクトの開発において、コードの品質を保つことは非常に重要です。特にチーム開発では、一貫性のあるコードスタイルと、潜在的なバグを事前に発見する仕組みが必要になります。この記事では、ESLint を使って Vue.js プロジェクトを効果的に管理し、開発チームの生産性を向上させる方法を段階的に解説していきます。
初心者の方でも理解できるよう、基本的な設定から実際の運用まで、具体的なコード例とともに詳しくご紹介します。また、実際の開発現場でよく遭遇するエラーとその解決方法も含めて、即座に活用できる実践的な内容となっています。
ESLint と Vue.js の関係性
ESLint が Vue.js プロジェクトにもたらすメリット
ESLint は、JavaScript のコード品質を保つためのリンターツールです。Vue.js プロジェクトで ESLint を活用することで、以下のような具体的なメリットが得られます。
# | メリット | 具体的な効果 |
---|---|---|
1 | コード品質の向上 | 潜在的なバグや問題のあるコードパターンを事前に発見 |
2 | チーム開発の効率化 | 統一されたコーディングスタイルでレビュー時間を短縮 |
3 | 保守性の向上 | 一貫したコード構造により、後から参加したメンバーも理解しやすい |
4 | Vue.js 特有の問題回避 | テンプレート記法やリアクティブシステムでの誤用を防止 |
これらのメリットは、プロジェクトの規模が大きくなるほど、その効果を実感できるでしょう。
Vue.js 特有のコード品質課題
Vue.js プロジェクトでは、従来の JavaScript アプリケーションとは異なる特有の課題があります。
テンプレート構文での課題
Vue.js のテンプレート構文では、HTML と JavaScript が混在するため、以下のような問題が発生しやすくなります。
vue<template>
<!-- 問題のあるコード例 -->
<div v-if="user.name && user.age > 18">
{{ user.name.toUpperCase() }}
</div>
</template>
上記のコードでは、user.name
が空文字列の場合に意図しない動作をする可能性があります。
コンポーネント設計での課題
Vue.js コンポーネントでは、プロップスやイベントの定義が曖昧になりがちです。
vue<script>
export default {
// 問題のあるコード例
props: ['userData', 'config'],
methods: {
handleClick() {
this.$emit('click', this.userData);
},
},
};
</script>
このような課題を解決するために、ESLint の Vue.js 専用ルールが効果的に機能します。
基本設定の構築
ESLint と Vue.js 用プラグインのインストール
まず、Vue.js プロジェクトで ESLint を使用するために必要なパッケージをインストールします。
bashyarn add -D eslint eslint-plugin-vue @vue/eslint-config-recommended
Vue 3 を使用している場合は、さらに以下のパッケージも追加します。
bashyarn add -D @vue/eslint-config-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
インストールが完了したら、パッケージの依存関係を確認しましょう。
bashyarn list --depth=0 | grep eslint
基本的な.eslintrc 設定ファイルの作成
プロジェクトのルートディレクトリに.eslintrc.js
ファイルを作成します。
javascriptmodule.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
rules: {
// カスタムルールは後で追加
},
};
この基本設定では、以下の要素を含んでいます:
root: true
: このファイルを設定のルートとして扱うenv
: 実行環境の指定(Node.js、ブラウザ、ES2021)extends
: 基本的な推奨ルールセットの継承parserOptions
: JavaScript の解析オプション
Vue.js 推奨ルールセットの適用
Vue.js プロジェクトでは、段階的にルールを適用することをお勧めします。以下の表に、各設定レベルの特徴をまとめました。
# | 設定レベル | 対象 | 適用タイミング |
---|---|---|---|
1 | plugin:vue/vue3-essential | 基本的なエラー防止 | プロジェクト開始時 |
2 | plugin:vue/vue3-strongly-recommended | 可読性向上 | 開発チームが慣れてから |
3 | plugin:vue/vue3-recommended | 統一性とベストプラクティス | 本格運用時 |
まずはvue3-essential
から始めて、チームが慣れてきたら段階的に厳しいルールに移行しましょう。
javascript// 段階的な設定例
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential', // 第1段階
// 'plugin:vue/vue3-strongly-recommended', // 第2段階
// 'plugin:vue/vue3-recommended' // 第3段階
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
rules: {
'no-console':
process.env.NODE_ENV === 'production'
? 'warn'
: 'off',
'no-debugger':
process.env.NODE_ENV === 'production'
? 'warn'
: 'off',
},
};
Vue.js 特化ルールの活用
vue/recommended 設定の詳細
plugin:vue/vue3-recommended
を適用すると、以下のような Vue.js 特有のルールが有効になります。
主要なルールとその効果
javascript// .eslintrc.jsでの詳細設定例
module.exports = {
extends: ['plugin:vue/vue3-recommended'],
rules: {
// コンポーネント名の規則
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
],
// プロップス定義の強制
'vue/require-prop-types': 'error',
// 未使用変数の検出
'vue/no-unused-vars': 'error',
// テンプレート内での複数ルート要素の制御
'vue/no-multiple-template-root': 'off', // Vue 3では許可
// 属性の順序統一
'vue/attributes-order': [
'error',
{
order: [
'DEFINITION',
'LIST_RENDERING',
'CONDITIONALS',
'RENDER_MODIFIERS',
'GLOBAL',
'UNIQUE',
'TWO_WAY_BINDING',
'OTHER_DIRECTIVES',
'OTHER_ATTR',
'EVENTS',
'CONTENT',
],
},
],
},
};
テンプレート構文でのルール適用
Vue.js テンプレートでよく発生するエラーとその対処法を見てみましょう。
エラー例 1: 未定義変数の使用
vue<template>
<!-- エラー: 'userName' is not defined -->
<div>{{ userName }}</div>
</template>
<script>
export default {
data() {
return {
username: 'John', // 'userName'ではなく'username'
};
},
};
</script>
エラーメッセージ:
perl✗ 1:11 error 'userName' is not defined vue/no-undef-properties
解決方法:
vue<template>
<div>{{ username }}</div>
</template>
<script>
export default {
data() {
return {
username: 'John',
};
},
};
</script>
エラー例 2: 不適切なディレクティブ使用
vue<template>
<!-- エラー: v-forとv-ifの同時使用 -->
<li
v-for="item in items"
v-if="item.active"
:key="item.id"
>
{{ item.name }}
</li>
</template>
エラーメッセージ:
perl✗ 2:5 error This 'v-if' should be moved to the wrapper element vue/no-use-v-if-with-v-for
解決方法:
vue<template>
<template v-for="item in items" :key="item.id">
<li v-if="item.active">
{{ item.name }}
</li>
</template>
</template>
コンポーネント設計のためのルール
Vue.js コンポーネントの設計を改善するためのルール設定です。
javascript// .eslintrc.jsでのコンポーネント設計ルール
module.exports = {
rules: {
// プロップスのデフォルト値を強制
'vue/require-default-prop': 'error',
// イベント名のケースを統一
'vue/custom-event-name-casing': ['error', 'kebab-case'],
// コンポーネントの命名規則
'vue/component-definition-name-casing': [
'error',
'PascalCase',
],
// プロップスの型チェック強化
'vue/prop-name-casing': ['error', 'camelCase'],
// 不要なv-bindの検出
'vue/no-useless-v-bind': 'error',
},
};
良いコンポーネント設計の例:
vue<template>
<div class="user-card">
<h3>{{ userData.name }}</h3>
<p>{{ userData.email }}</p>
<button @click="handleEdit">編集</button>
</div>
</template>
<script>
export default {
name: 'UserCard',
props: {
userData: {
type: Object,
required: true,
default: () => ({}),
},
editable: {
type: Boolean,
default: false,
},
},
emits: ['edit-user'],
methods: {
handleEdit() {
this.$emit('edit-user', this.userData.id);
},
},
};
</script>
TypeScript + Vue での設定強化
@typescript-eslint/parser との連携
TypeScript を使用する Vue.js プロジェクトでは、より厳密な型チェックと ESLint ルールの適用が可能になります。
javascript// .eslintrc.js(TypeScript対応版)
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'@vue/typescript/recommended',
'plugin:vue/vue3-recommended',
'@vue/eslint-config-typescript',
],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2021,
sourceType: 'module',
},
rules: {
// TypeScript固有のルール
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type':
'off',
'@typescript-eslint/no-unused-vars': 'error',
},
};
Vue SFC での TypeScript 対応
Single File Component(SFC)で TypeScript を使用する場合の設定例です。
vue<template>
<div class="todo-item">
<input
type="checkbox"
:checked="todo.completed"
@change="toggleTodo"
/>
<span :class="{ completed: todo.completed }">
{{ todo.text }}
</span>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
interface Todo {
id: number;
text: string;
completed: boolean;
}
export default defineComponent({
name: 'TodoItem',
props: {
todo: {
type: Object as PropType<Todo>,
required: true,
},
},
emits: {
'toggle-todo': (id: number) => typeof id === 'number',
},
methods: {
toggleTodo(): void {
this.$emit('toggle-todo', this.todo.id);
},
},
});
</script>
型安全性を高めるルール群
TypeScript と Vue.js を組み合わせた場合に有効なルール設定です。
javascriptmodule.exports = {
rules: {
// 型定義の強制
'@typescript-eslint/explicit-module-boundary-types':
'error',
// any型の使用を制限
'@typescript-eslint/no-explicit-any': 'error',
// 未使用の変数を検出
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
// Vue固有の型安全性ルール
'vue/no-setup-props-destructure': 'error',
'vue/component-api-style': ['error', ['script-setup']],
// Composition APIでの型安全性
'vue/no-ref-as-operand': 'error',
'vue/no-watch-after-await': 'error',
},
};
エラー例: プロップスの型定義不備
vue<!-- エラーが発生するコード -->
<script setup lang="ts">
// エラー: Props interface is missing
const props = defineProps(['message']);
</script>
エラーメッセージ:
lua✗ 3:15 error Missing props type definition @typescript-eslint/explicit-module-boundary-types
解決方法:
vue<script setup lang="ts">
interface Props {
message: string;
count?: number;
}
const props = defineProps<Props>();
</script>
実践的なワークフロー構築
VSCode との統合設定
開発効率を最大化するための VSCode 設定を構築しましょう。
.vscode/settings.json
json{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"eslint.workingDirectories": ["."],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"vetur.validation.template": false,
"vetur.validation.script": false,
"vetur.validation.style": false
}
.vscode/extensions.json
json{
"recommendations": [
"dbaeumer.vscode-eslint",
"Vue.volar",
"Vue.vscode-typescript-vue-plugin"
]
}
これらの設定により、保存時に自動的に ESLint ルールが適用され、開発体験が大幅に向上します。
Git Hooks での自動チェック
コミット前に自動的に ESLint チェックを実行する設定を行います。
lint-staged と husky のインストール
bashyarn add -D husky lint-staged
package.json の設定
json{
"scripts": {
"lint": "eslint --ext .js,.vue,.ts src/",
"lint:fix": "eslint --ext .js,.vue,.ts src/ --fix",
"prepare": "husky install"
},
"lint-staged": {
"*.{js,vue,ts}": ["eslint --fix", "git add"]
}
}
pre-commit フックの設定
bashnpx husky add .husky/pre-commit "npx lint-staged"
この設定により、問題のあるコードはコミットされることなく、チーム全体のコード品質が保たれます。
CI/CD パイプラインでの品質管理
GitHub Actions を使用した CI/CD パイプラインでの ESLint チェック設定例です。
.github/workflows/ci.yml
yamlname: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run ESLint
run: yarn lint
- name: Run ESLint with output
run: yarn lint --format=json --output-file=eslint-report.json
continue-on-error: true
- name: Upload ESLint report
uses: actions/upload-artifact@v3
if: always()
with:
name: eslint-report
path: eslint-report.json
トラブルシューティング
よくあるエラーと解決方法
エラー 1: Parser 設定関連
go✗ Parsing error: Unexpected token <
原因: Vue SFC ファイルのパーサー設定が不適切
解決方法:
javascript// .eslintrc.js
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser', // TypeScript使用時
ecmaVersion: 2021,
sourceType: 'module',
},
};
エラー 2: プラグイン依存関係
arduino✗ ESLint couldn't find the plugin "eslint-plugin-vue"
原因: 必要なプラグインがインストールされていない
解決方法:
bashyarn add -D eslint-plugin-vue
エラー 3: 設定ファイルの競合
csharp✗ ESLint configuration in .eslintrc.js is invalid
原因: 複数の設定ファイルが競合している
解決方法:
.eslintrc.js
以外の設定ファイル(.eslintrc.json
など)を削除package.json
内のeslintConfig
設定を削除
エラー 4: Vue 3 Composition API 関連
perl✗ 'ref' is not defined no-undef
原因: Composition API の自動インポート設定不備
解決方法:
javascript// .eslintrc.js
module.exports = {
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
};
パフォーマンス最適化のコツ
大規模プロジェクトで ESLint のパフォーマンスを向上させる方法です。
1. キャッシュの活用
bash# .eslintcacheファイルを利用
yarn lint --cache --cache-location .eslintcache
2. 並列処理の活用
json{
"scripts": {
"lint": "eslint --ext .js,.vue,.ts src/ --max-warnings 0 --cache"
}
}
3. 不要なファイルの除外
javascript// .eslintrc.js
module.exports = {
ignorePatterns: [
'dist/',
'node_modules/',
'*.d.ts',
'public/',
'.nuxt/',
'coverage/',
],
};
4. ルールの最適化
javascriptmodule.exports = {
rules: {
// 重いルールを無効化または調整
'import/no-cycle': 'off', // 循環依存チェックは重い
'vue/no-unused-components': 'warn', // エラーではなく警告に
},
};
まとめ
ESLint を Vue.js プロジェクトに導入することで、コードの品質向上とチーム開発の効率化を実現できます。この記事で解説した内容を段階的に適用することで、以下の効果が期待できます。
# | 効果 | 具体的な改善点 |
---|---|---|
1 | 開発速度の向上 | 自動修正機能により手動修正時間を削減 |
2 | バグの早期発見 | 実行前に潜在的な問題を検出 |
3 | コードレビューの効率化 | スタイルの統一によりレビュー時間を短縮 |
4 | 新人教育のサポート | ベストプラクティスを自動的に学習 |
重要なのは、一度にすべてのルールを適用するのではなく、チームの成熟度に合わせて段階的に導入することです。まずは基本的な設定から始めて、徐々に厳密なルールへと移行していきましょう。
また、エラーが発生した際は、この記事のトラブルシューティングセクションを参考に、適切な対処を行ってください。継続的な改善により、より良い開発環境を構築できるはずです。
関連リンク
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来
- review
人類はなぜ地球を支配できた?『サピエンス全史 上巻』ユヴァル・ノア・ハラリが解き明かす驚愕の真実
- review
え?世界はこんなに良くなってた!『FACTFULNESS』ハンス・ロスリングが暴く 10 の思い込みの正体
- review
瞬時に答えが出る脳に変身!『ゼロ秒思考』赤羽雄二が贈る思考力爆上げトレーニング
- review
関西弁のゾウに人生変えられた!『夢をかなえるゾウ 1』水野敬也が教えてくれた成功の本質
- review
「なぜ私の考えは浅いのか?」の答えがここに『「具体 ⇄ 抽象」トレーニング』細谷功