この記事は、ニフティグループ Advent Calendar 2023 5日目の記事です。
はじめに
こんにちは、最近はひょんなことから見つけた古のWebページに衝撃を受けている宮本です。jQueryが生まれる前の時代のページともなると流石に趣が違いますね。
さて、今回はAstroの機能のひとつについてご紹介したいと思います。
Astroって?
AstroはJavaScriptを使ったモダンWebフレームワークの一つです。JS製のWebフレームワークというとNext.jsが有名ですが、Astroはコンテンツが多い静的サイトに特化している点でかなり特徴的です。どのくらい特徴的かというと、Astro単体だとReactのstateにあたる機能が一切存在せず、クライアント側のDOM動作はほぼ素のJavaScriptやjQueryになるくらい特徴的です。
まだAstroを触ったことがない方は、ぜひ公式サイトをご覧ください。
https://docs.astro.build/ja/concepts/why-astro/
同じレイアウトで異なるJSとCSSを読み込みたい
前述の通り、純粋なAstroの場合は細かいDOM操作はほぼ素のJavaScriptやjQuery頼りになります。拡張としてReactやSvelteのコンポーネントを部分的に導入することもできますが、単純な操作の場合は意外と昔ながらの方法でも十分に感じます。
さて、そうなると出てくるのが「レイアウトが同じだけど、このページだけ〜するから特定のJSライブラリをscriptタグで読み込みたい」という悩みです。もちろんscriptタグで読み込まずとも、Astroなのでnpmやyarnのようなパッケージ管理ソフト経由でjQueryなどをインストールし、内部でまとめてビルドしてしまうこともできます。こちらの方がだいぶスマートに感じます。
しかし、場合によっては昔ながらのscriptタグでの読み込みがしたい場合もあります。あるんです。たとえば、ただのhtmlだった既存のページを大量にAstro化する場合など……。また、この場合はJSが元々外部ファイルとして作成されている場合もあります。
CSSも同様に、時と場合によっては同じレイアウトで異なるCSSを読み込みたくなります。Astroにはデフォルトで簡単にスタイルをコンポーネント内で閉じる機能があるので、今後はそうした機能を使っていきたいですね。
複数のCSSやJSを読み込む場合には、読み込み順序を間違えると正常なページ表示にならない可能性もあります。これもCSSやJSファイル自体を修正しようとすると、程度にもよりますがなかなか大変だと思います。可能であれば、読み込み順を変えて対応してしまいたいです。
そうなってくるとレイアウトを新しく作る必要がありそうですが、ほとんど一緒なのに読み込むJS、CSSが違うだけでわざわざ新しいレイアウトは作りたくありません。特にそれを使うのが1~2ページだと、なんとも残念な気分になります。ということで、レイアウトは増やすことなく自由にJSとCSSファイルを読み込めるようにします。
ページごとにJSとCSSを読み込めるようにする
同じレイアウトでも自由に読み込むJS/CSSを制御できるようにしたレイアウトの例がこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
--- import Header from "./Header.astro" import Footer from "./Footer.astro" const { title } = Astro.props --- <html> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <title>{title}</title> <slot name="OverrideHead"> <link rel="stylesheet" type="text/css" href="/css/base.css" /> <slot name="AppendHead"> </slot> </head> <body> <Header /> <slot /> <Footer /> <slot name="OverrideFoot"> <script is:inline src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <slot name="AppendFoot"> </slot> </body> </html> |
名無しのslotはページ側の内容を表示するためですが、それ以外の名前付きslotの役割は以下のようになっています。
- AppendHead slot: head要素の最下部に自由に読み込めるタグを追加できるslot
- AppendFoot slot: body要素の最下部に自由に読み込めるタグを追加できるslot
- OverrideHead slot: head要素内で読み込むCSS/JSを全て上書きするslot
- OverrideFoot slot: body要素の最下部で読み込むタグを完全に上書きするslot
AppendHead/Footではほぼ基本的なslotタグの使い方です。OverrideHead/Footでは、slotのフォールバックコンテンツ機能を使っています。あらかじめ用意したslotに挿入がない場合はLayout側で指定した要素をそのまま表示、Layoutの呼び出し側で指定があればそちらを表示してくれます。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
--- import Layout from "@layout/Layout.astro" --- <Layout title="ページ内で読み込むJS/CSSを追加する"> <Fragment slot="AppendHead"> {/* Layoutで指定した/css/base.cssに加えて以下を読み込む */} <link rel="stylesheet" type="text/css" href="/css/content.css" /> </Fragment> <p>ページ内で読み込むJS/CSSを追加する例</p> <Fragment slot="AppendFoot"> {/* Layoutで指定したjQueryに加えて次のファイルを読み込む */} <script is:inline src="/js/hoge.js"></script> </Fragment> </Layout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--- import Layout from "@layout/Layout.astro" --- <Layout title="ページ内で読み込むJS/CSSを全て制御する"> <Fragment slot="OverrideHead"> {/* Layoutのcssの読み込み順序を完全に上書き */} <link rel="stylesheet" type="text/css" href="/css/content.css" /> <link rel="stylesheet" type="text/css" href="/css/base.css" /> </Fragment> <p>ページ内で読み込むJS/CSSを全て制御する例</p> <Fragment slot="OverrideFoot"> <script is:inline src="/js/hoge.js"></script> {/* ここに追加しない限りjQueryの読み込みは行われない */} </Fragment> </Layout> |
さいごに
今回はAstroのLayout機能で柔軟にCSS/JSの読み込みを制御する方法を紹介させていただきました。一からAstroを使って新規にWebサイトを作成する場合はあまり必要ないかもしれませんが、既存のサイトをAstroに書き換える際には役に立つかもしれません。
明日は、@yukiex さんの EMとしてISUCONに参加するようになって です。
お楽しみに!