【Astroの基本】スクリプトの最適化の仕組みやJSの記述方法について

【Astroの基本】スクリプトの最適化の仕組みやJSの記述方法について

Astroでは、ReactやVue、Svelteやその他のフレームワークがサポートされており、自身の慣れ親しんだフレームワークを使用して開発を行うことができます。

しかしAstroで静的サイトを組む場合のほとんどは、JavaScriptで十分という場合が多いですよね。

今回の記事では、

  • scriptタグを使用してJavaScriptを記述する方法
  • Astroのscript最適化の仕組み

について解説していきます。

検証環境

当記事で紹介する方法は、以下のバージョンで動作確認を行っています。

検証環境のバージョン情報

Astro
Astro 5.1.3

バージョンの違いによっては、この記事の通りに動作しない可能性がありますので、ご理解いただけますと幸いです。

Astroでscriptを使用する方法

Astroでは、ファイル内にscriptタグを追加することで、クライアントサイドのJavaScriptを記述することができます。

今回の記事ではJavaScriptで書いていますが、TypeScriptもデフォルトでサポートされています。

src/pages/index.astro
Astro
    ---
import Layout from '@/layouts/Layout.astro';
---
 
<Layout>
  <h1>TOPページ</h1>
</Layout>
 
<script>
  console.log("これはTOPページです");
</script>
  

このようにして、.astroファイル内にJavaScriptを埋め込むことが可能です。

埋め込まれたscriptは、Astroによって最適化の処理が行われます。

また、src属性を使用してローカルのJavaScriptファイルを読み込んだり、外部ライブラリを読み込むことも可能です。

ローカルのJavaScriptファイルを読み込む

src/pages/index.astro
Astro
    <script src="../scripts/local.js"></script>
  

このようにして、ローカルのJavaScriptファイルを読み込むことができます。

この場合、Astroの最適化を適用するために、JSファイルはsrcディレクトリ内に配置する必要があります。

外部のスクリプトを読み込む

CDNや外部ライブラリを読み込む場合は、以下のように記述します。

src/pages/index.astro
Astro
    <!-- publicディレクトリに配置したスクリプトを読み込む -->
<script is:inline src="/my-script.js"></script>
 
<!-- 外部のスクリプトを読み込む -->
<script is:inline src="https://my-analytics.com/script.js"></script>
  

外部のスクリプトの場合は、Astro側でのバンドルと最適化の処理は必要ないので、is:inline属性を追加します。

こうすることで、Astroで処理されることなくそのままの形で読み込むことができます。

また、プロジェクト内にスクリプトを置く場合は、publicディレクトリに配置してください。

publicディレクトリを参照する場合は、/public/my-script.jsではなく/my-script.jsと記述することができます。

Astroのスクリプトの最適化について

ここからは、Astro側でスクリプトがどのように最適化されるかについて解説していきます。

type=“module”属性が付与される

Astroでは、スクリプト最適化の際にscriptタグにtype="module"属性を自動で付与します。

type="module"属性が付与されたスクリプトは、ページの読み込みが完了してから実行されます。

つまり、スクリプトの読み込みが非同期になり、ページのレンダリングをブロックすることがなくなるのでパフォーマンス向上につながります。

内部的にはdefer属性がついた状態と同じになりますね。

type="module"がついたスクリプトは非同期に読み込まれるので、async属性を追加する必要はありません。もしasync属性を追加すると、ページの読み込みを待たずに即座に実行されてしまいます。

スクリプトが複数回使われている場合、一度だけ読み込まれる

Astroでは、同じスクリプトがページ内で複数回使われている場合、一度だけ読み込まれるように最適化されます。

例えば、以下のようなコンポーネントがあるとします。

src/components/AlertBtn.astro
Astro
    ---
const { message } = Astro.props;
---
 
<button class="alert-btn" data-message={message}>
  <slot />
</button>
 
<script>
  const btns = document.querySelectorAll('.alert-btn');
 
  btns.forEach(btn => {
    btn.addEventListener('click', (event) => {
      alert(event.target.dataset.message);
    });
  });
</script>
  

ボタンをクリックすると、data-message属性の値がアラートで表示されるというシンプルなコンポーネントです。

script内では、querySelectorAllでクリックイベントを登録しています。しかし、このスクリプトは1度だけ読み込まれれば十分ですね。

このコンポーネントを1つのページ内で複数回使用してみます。

src/pages/index.astro
Astro
    ---
import AlertBtn from '@/components/AlertBtn.astro';
---
 
<main>
  <AlertBtn message="アラートメッセージ01">ボタン01</AlertBtn>
  <AlertBtn message="アラートメッセージ02">ボタン02</AlertBtn>
  <AlertBtn message="アラートメッセージ03">ボタン03</AlertBtn>
</main>
  

これをコンパイルするとどうなるかを確認するために、ビルドを実行しastro previewで本番環境と同じ状態を再現します。

コンパイル後のHTMLを見ると、以下のようになっています。

HTML
    <main>
  <button class="alert-btn" data-message="アラートメッセージ01" data-astro-cid-XXXXXX>ボタン01</button>
  <script type="module">
    const a = document.querySelectorAll(".alert-btn");
    a.forEach((t) => {
      t.addEventListener("click", (e) => {
        alert(e.target.dataset.message);
      });
    });
  </script>
  <button class="alert-btn" data-message="アラートメッセージ02" data-astro-cid-XXXXXX>ボタン02</button>
  <button class="alert-btn" data-message="アラートメッセージ03" data-astro-cid-XXXXXX>ボタン03</button>
</main>
  

スクリプトは1度だけ読み込まれ、2個目以降のボタンにはスクリプトが挿入されていませんね。

これでAstroのscriptの最適化がどのように行われるかがわかりました。

is:inlineを付与するとどうなる?

scriptis:inlineを付与すると最適化が行われないと説明しましたが、実際に試してみましょう。

ここではシンプルに、is:inlineを付与したスクリプトを追加してみます。

src/components/SimpleBtn.astro
Astro
    <button>
  <slot />
</button>
 
<script is:inline>
  console.log("このスクリプトは最適化されません");
</script>
  

このコンポーネントを使用して、ページ内に複数回配置してみます。

src/pages/index.astro
Astro
    ---
import SimpleBtn from '@/components/SimpleBtn.astro';
---
 
<main>
  <SimpleBtn>ボタン01</SimpleBtn>
  <SimpleBtn>ボタン02</SimpleBtn>
  <SimpleBtn>ボタン03</SimpleBtn>
</main>
  

ビルドを実行し、コンパイル後のHTMLを確認してみます。

HTML
    <main>
  <button>ボタン01</button>
  <script>
    console.log("このスクリプトは最適化されません");
  </script>
  <button>ボタン02</button>
  <script>
    console.log("このスクリプトは最適化されません");
  </script>
  <button>ボタン03</button>
  <script>
    console.log("このスクリプトは最適化されません");
  </script>
</main>
  

するとscriptタグは最適化されず、そのままの形で出力されているのが確認できました。

また、コンポーネントを呼び出した数だけスクリプトが挿入されていますね。

【まとめ】Astroのscriptタグの最適化の仕組みについて

今回は、AstroでJavaScriptを記述する方法と、Astroのスクリプト最適化の仕組みについて解説しました。

Astroでは、.astroファイル内でscriptタグを使用してJavaScriptを書くことができます。

また、TypeScriptもデフォルトでサポートされているので、TypeScriptでの開発も可能ですね。

Astroのスクリプト最適化については、

  • type="module"属性が付与される
  • 同じスクリプトが複数回使われている場合は一度だけ読み込まれる

というように、ページの読み込み速度を向上させるための工夫がされています。

今回の記事が参考になれば幸いです!