どういうことかというと、
- 特定のpages/[slug].astroの中で
- getStaticPaths()から複数のページを返しつつ
- とあるslugの場合のみ、<script>を使ったコンポーネントを利用してる
- はずなのに、すべてのslugのHTMLで<script>が出力されてしまう
というケース。
問題のコード
簡略化するとこういう感じ。
---
import V1OnlyScript from "../components/v1-only-script.astro";
export const getStaticPaths = () => ([
  { params: { slug: "v1-1", } }
  // ...
  { params: { slug: "v2-1", } }
  { params: { slug: "v2-2", } }
  // ...
]);
const { params: { slug } } = Astro;
---
{slug.startsWith("v1") && <V1OnlyScript />}
{slug.startsWith("v2") && <p>0JS</p>}3つのHTMLが出力されるけど、slug: v1-*のページでだけ、<script>が出力されてほしい。
が、実際には、slug: v2-*のページでも、<script>が出力されてしまう。
バグではなく仕様
直感的じゃないし、バグでは?って最初は思ったけど、どうやら仕様らしい。
https://docs.astro.build/en/guides/troubleshooting/#an-unexpected-script-or-style-is-included https://docs.astro.build/en/guides/client-side-scripts/#script-bundling
.astroファイルにおける<script>は、処理されるルールが決まってて、そのせいでこうなる。
ワークアラウンド
いくつか考えてみたが、どれもすっきりしない。
is:inlineにする案
その名の通り、インライン化してしまう。
そうすれば、それぞれのページで必要なところだけで出力される。
が、もちろん、そのアセットはサイト単位で見た場合に重複することになる。
publicディレクトリなんかに逃がしてsrcで参照するようにすれば、この問題は解決できるけど、コロケーションできない不都合は残る。
異なる.astroファイルに分ける案
[slug].astroを、[slugV1].astroと[slugV2].astroに分けるってこと。
---
import V1OnlyScript from "../components/v1-only-script.astro";
export const getStaticPaths = () => ([
  { params: { slugV1: "v1-1", } }
]);
const { params: { slugV1 } } = Astro;
---
<V1OnlyScript />と
---
export const getStaticPaths = () => ([
  { params: { slugV2: "v2-1", } }
  { params: { slugV2: "v2-2", } }
]);
const { params: { slugV2 } } = Astro;
---
<p>0JS</p>に分けてしまうと、想定通りの出力にはなる。
が、共通部のコードをコンポーネントに切り出すなどの手間は必要。
今回はこの方法を採用したけど、もっといいやり方はないもんだろうか。