RailsとVue.jsを組み合わせたアプリケーション開発では、ページのDOMが完全にロードされてからVueインスタンスをマウントすることが重要です。特にRailsのビューでjavascript_pack_tagやvite_javascript_tagを使う際にこの問題は顕著になります。この記事では、DOMのロード完了を待ってからVueアプリケーションをマウントする方法と、そうしない場合の違いについて解説します。
DOMContentLoaded を使用する理由
document.addEventListener('DOMContentLoaded', () => {
const calendarEl = document.getElementById('weekly-calendar');
if (calendarEl) {
createApp(WeeklyCalendar).mount(calendarEl);
}
});
上記のコードでは、DOMContentLoaded イベントリスナーを使用しています。このイベントは、HTMLドキュメントが完全に読み込まれ、解析された後に発生しますが、画像やスタイルシートなどは待ちません。このイベントを待つことで、Vueコンポーネントをマウントする際に、必要なDOM要素が確実に存在することを保証します。
即時マウントとの違い
const app = createApp(WeeklyCalendar);
app.mount('#weekly-calendar');
こちらは即座にVueアプリケーションをマウントしようとするコードです。これが正常に機能するためには、このスクリプトが実行される時点でDOM要素#weekly-calendarが存在している必要があります。通常、これを保証するためにはスクリプトを</body>タグの直前に配置することが一般的です。
実際にはどちらの方法を使うべき?
ViteやWebpackなどのモダンなフロントエンドツールを使用している場合、type="module"を使用したモジュールスクリプトは、デフォルトでdefer属性が適用されるため、DOMが準備できるまでスクリプトの実行が遅延されます。このため、DOMContentLoaded イベントを待つ必要はなく、上記の即時マウントコードで十分です。
しかし、スクリプトが早期に実行される可能性がある場合や、スクリプトのロードと実行のタイミングを明示的に制御したい場合は、DOMContentLoadedイベントリスナーを使用した方が安全です。
まとめ
RailsとVue.jsを組み合わせて開発する際は、Vueインスタンスをマウントするタイミングに注意が必要です。DOMが完全にロードされたことを確認してからマウント処理を行うことで、予期せぬエラーを避け、アプリケーションの安定性を高めることができます。
[補足]コード解説
document.addEventListener('DOMContentLoaded', () => {
const calendarEl = document.getElementById('weekly-calendar');
if (calendarEl) {
createApp(WeeklyCalendar).mount(calendarEl);
}
});
-
document: これはHTMLドキュメント全体を指します。ブラウザ内で表示されるページをJavaScriptが操作するときのエントリーポイントです。 -
addEventListener: これは、特定のイベントが発生したときに実行される関数をドキュメントに追加するメソッドです。これを使って、イベントリスナーを設定します。 -
DOMContentLoaded: このイベントは、ページ全体のHTMLが完全に読み込まれ、DOMツリーが構築された後に発生しますが、スタイルシート、画像、サブフレームの読み込みは待ちません。このイベントは、ページのロードが完了してDOM操作が安全に行えることを示すために使用されます。 -
() => {}: これはアロー関数と呼ばれ、短い関数を定義するためのJavaScriptの構文です。addEventListenerの第二引数に渡され、DOMContentLoadedイベントが発生したときに実行されます。 -
const calendarEl = document.getElementById('weekly-calendar');: この行では、idが'weekly-calendar'であるHTML要素をドキュメントから取得し、その要素への参照をcalendarElという定数に代入しています。 -
if (calendarEl) {...}: ここで、calendarElが実際に存在するかどうかをチェックしています。つまり、getElementByIdがnullを返さなかった場合(要素が見つかった場合)、カッコ内のコードが実行されます。 -
createApp(WeeklyCalendar).mount(calendarEl);: これはVue 3の構文で、WeeklyCalendarというVueコンポーネントを初期化しています。createAppはVueアプリケーションインスタンスを作成し、mountメソッドはそのアプリケーションを指定されたDOM要素(この場合はcalendarEl)にマウント(つまり、描画やDOMに反映)します。
簡単にいうと、このコードはページのHTMLが完全にロードされたら実行され、idが'weekly-calendar'のHTML要素を見つけ、その要素にWeeklyCalendarコンポーネントをマウントします。これにより、コンポーネントが表示されるべき場所にVueアプリケーションが表示されることが保証されます。