eslint-plugin-vueからVue.jsを学ぶ
はじめに
eslint-plugin-vue には Vue.js のコーディングルールが数多く詰まっています。
本記事では、その一部ルールを取り上げ、ルールの背景となる「なぜ」を紐解きながら、Vue.js について学習していきましょう。
そもそもeslint-plugin-vueとは
ご存じの方も多いかもしれませんが、eslint-plugin-vue は Vue.js 公式の ESLint プラグインです。
公式ドキュメントによると、.vue ファイルの <template> と <script> 部分、さらに .js ファイル内の Vue.js コードを ESLint でチェックできるようにしてくれます。
This plugin allows us to check the
<template>and<script>of.vuefiles with ESLint, as well as Vue.js code in.jsfiles.
(和訳)このプラグインを使用すると、ESLint で
.vueファイルの<template>と<script>、および.jsファイル内の Vue.js コードをチェックできます。
取り上げるルール
eslint-plugin-vue には多くのルールがあります(2024/11/23 時点で 137 個)。
本記事では以下の 3 つをピックアップし、それぞれのルールの背景やルールから学べる点を考察します。
- vue/no-v-html
- vue/no-async-in-computed-properties
- vue/no-lifecycle-after-await
1. vue/no-v-html:v-html の使用禁止(または制限)

ルールの内容
公式より抜粋:
This rule reports all uses of v-html directive
(和訳)このルールは、v-htmlディレクティブのすべての使用を報告します。
ルールの背景
v-html は任意の HTML を挿入できるため、XSS 攻撃の温床になり得ます。
v-html について Vue.js 公式ドキュメントでは、以下のように注意喚起しています。
セキュリティーに関する注意
ウェブサイト上で任意の HTML を動的にレンダリングすることは、XSS 攻撃につながりやすいため、非常に危険です。信頼できるコンテンツにのみv-htmlを使用し、ユーザーが提供するコンテンツには 絶対に 使用しないでください。
Vue.js は {{ }} 内のデータを自動的にエスケープしますが、v-html を使うとこれをバイパスしてしまいます。
ルールからの学び
- 外部から取り込むデータは常にサニタイズするなど、セキュアなコーディングを心がける。
- 生 HTML を挿入したい場合は、
DOMPurifyなどでサニタイズしてから描画するなど、十分な対策を取る。
改善例
<template>
<div>{{ sanitizedContent }}</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import DOMPurify from 'dompurify';
const props = defineProps({ rawHtmlContent: String });
const sanitizedContent = computed(() => DOMPurify.sanitize(props.rawHtmlContent));
</script>
2. vue/no-async-in-computed-properties:算出プロパティ内での非同期処理禁止

ルールの内容
公式より抜粋(今回は算出プロパティに着目)
Computed properties and functions should be synchronous.
(和訳)算出プロパティや関数は同期的であるべきです。
ルールの背景
computed() はあくまで純粋なゲッター関数を意図しており、非同期処理を入れると更新タイミングが予測困難になり、依存関係の追跡も困難になります。
公式ドキュメントでも、算出プロパティのゲッター関数の副作用を伴う処理を含めることへの注意喚起があります。
getter 関数は副作用のないものでなければならない
算出プロパティにおける getter 関数は計算のみを行い、副作用がないようにすることが重要です。例えば、算出プロパティの getter の内部で他のステートを変更したり、非同期リクエストを実行したり、DOM を変更したりしないようにしましょう!
ルールからの学び
- 非同期処理は
onMountedやwatch、methods内で行い、その結果をrefに格納してから算出プロパティで参照する。 - 算出プロパティはあくまでも純粋な計算ロジックに徹し、副作用や非同期処理を避ける。
改善例
<template>
<div>{{ data }}</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const data = ref(null);
onMounted(async () => {
const response = await fetch('https://api.example.com/data');
data.value = await response.json();
});
</script>
3. vue/no-lifecycle-after-await:await 後のライフサイクルフック登録禁止

ルールの内容
公式より抜粋:
This rule reports the lifecycle hooks after await expression.
(和訳)このルールは、await式の後にライフサイクルフックがある場合に報告します。
ルールの背景
Vue コンポーネントインスタンスには描画されるまでにライフサイクルという概念が存在します。
各ライフサイクルのタイミングは公式のライフサイクルダイアグラムをご覧ください。
ライフサイクルダイアグラム

ライフサイクルでの各処理は setup() 内で onMounted のようなライフサイクルフックとして記述できます。
ライフサイクルフックはコールバック関数で記述され、Vue コンポーネントインスタンスに登録されます。
await 式で処理タイミングがズレるとライフサイクルフック登録が行えず、うまく機能しなくなってしまいます。
ルールからの学び
- ライフサイクルフック(
onMountedなど)はsetup関数内で同期的に登録する。 - 非同期処理が必要な場合は、ライフサイクルフック内で
awaitを用いて実行する。
改善例
<script setup lang="ts">
import { onMounted } from 'vue';
async function initializeApp() {
// 非同期処理
}
onMounted(async () => {
await initializeApp();
// 続きの初期化処理
});
</script>
まとめ
eslint-plugin-vue のルールを通じて、セキュリティ上の注意点やステート管理方法、ライフサイクルに関する正しい扱い方など、Vue.js における「なぜ」を学ぶことができました。
他にも多くのルールが存在するため、時間があるときに eslint-plugin-vue を覗いてみましょう!Vue.js でのコーディングに関するさまざまな発見があるはずです👊
Discussion