tech.sinayaka.com

GatsbyからAstroに移行したら、つまずきポイントが7つあった

2026-06-02
2026-07-18
8分
1422語
Web技術 AstroGatsbyNetlifyMDX
目次

    Gatsby製のブログサイトをAstroに移行した。

    ビルドが遅い。それだけの理由だった。記事30本程度で2〜3分かかっていたのが、Astroにしたら7秒になった。それだけで移行した甲斐があったと思っている。

    ただ、思ったより罠が多かった。同じような移行を考えている人のために、踏んだ地雷を全部書いておく。

    1. slug がAstro 5の予約フィールドと衝突する

    GatsbyのMarkdownフロントマターでは slug フィールドをURLに使うのが一般的だ。

    slug: "what-is-endorphin"

    AstroのContent Collectionsでも同じように使おうとして schemaslug: z.string().optional() を定義したが、Astro 5では slug が内部で自動生成される予約フィールドと衝突し、entry.data.slugundefined になるケースが発生した。

    対策はシンプルで、ディレクトリ名からスラッグを導出するユーティリティ関数を作った。

    export function deriveSlug(entry: any): string {
      if (entry.data?.slug) return entry.data.slug;
      // 例: "2025/0105-what-is-endorphin" → "what-is-endorphin"
      const dir = entry.id.split('/').slice(-2, -1)[0] || '';
      return dir.replace(/^\d{4}[-_]?/, '');
    }

    2. lazyLoadImage プラグインが記事内画像を壊す

    tech.sinayaka.com(同じくAstroで動いているテックブログ)から設定を流用したとき、lazyLoadImage というrehypeプラグインを引き継いだ。このプラグインはスクロール連動の遅延ロードを実現するもので、画像の src/spinner.gif に差し替えて元のパスを data-src に保存する。

    問題は、MDX内の相対パス指定の画像(![画像](./asahi.jpg) のような書き方)を使っている場合だ。

    Astroはビルド時に相対パス画像を /_astro/asahi.HASH.webp のような最適化済みURLに変換するが、このrehypeプラグインが変換前の相対パスdata-src に保存してしまう。結果として本番環境で画像が404になる。

    解決策:元サイト(Gatsby)が画像遅延ロードを使っていないなら、素直にプラグインを外す。

    // astro.config.js
    markdown: {
      rehypePlugins: [], // lazyLoadImageを除去
    }

    3. Netlifyの環境変数はビルド前に設定しないと反映されない

    AstroはSSG(静的サイト生成)なので、import.meta.env.PUBLIC_MAILFORM_URL のような環境変数はビルド実行時にHTMLへ焼き込まれる。Netlifyでデプロイした後に環境変数を追加しても、再ビルドするまで反映されない

    さらに、Netlifyの環境変数には「スコープ」設定がある。

    • Builds → ビルド時に使える(Astroはこれが必要)
    • Runtime → サーバー関数などの実行時のみ
    • All scopes → 両方

    「All scopes」か「Builds」を選んでいないと、Astroのビルド中に変数が見えず空文字で焼き込まれる。

    4. お問い合わせフォームの no-corsContent-Type の罠

    GASへのフォーム送信に fetch を使っているが、こんな書き方をしていた。

    // ❌ バグ:Content-Type がヘッダーとして送信されない
    const postparam = {
      method: "POST",
      mode: "no-cors",
      "Content-Type": "application/x-www-form-urlencoded", // トップレベルは無視される
      body: JSON.stringify(forms)
    };

    Content-Typeheaders オブジェクトの中に書かないと送信されない。さらに mode: 'no-cors' の場合、Content-Type: application/x-www-form-urlencoded と宣言してJSONボディを送るとGASがパースに失敗する。

    動いていた別サイトのコードを調べたら、実は Content-Type がトップレベルに書かれたバグを含んだまま動いていた。ヘッダーが送られないことで text/plain 扱いになり、GASが e.postData.contents をそのまま読めていたという皮肉な結果だった。

    // ✅ Content-Type なしで送ると text/plain になりGASが読める
    await fetch(url, {
      method: 'POST',
      mode: 'no-cors',
      body: JSON.stringify({ site: 'example.com', name, email, message }),
    });

    5. OGP画像のURLにスラッシュが足りない

    export const SITE_URL = 'https://example.com';  // 末尾スラッシュなし
    export const SITE_IMAGE = 'thumbnail.png';       // 先頭スラッシュなし
    <!-- 結果 -->
    <meta property="og:image" content="https://example.comthumbnail.png">

    ドメインとファイル名がくっついてLINEでURLを貼ってもアイコンが出ない、という症状になる。どちらかにスラッシュを追加するだけで直る。

    export const SITE_IMAGE = '/thumbnail.png';  // 先頭スラッシュを追加

    6. SVGファビコンはLINEとChromeの一部で使えない

    Astroのスターターは <link rel="icon" type="image/svg+xml" href="/favicon.svg"> だけが設定されていることが多い。SVGファビコンはSafariの一部やLINEのリンクプレビューで表示されないため、PNG・ICO形式も追加しておく必要がある。

    <link rel="icon" type="image/x-icon" href="/favicon.ico">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">

    7. CommonMarkの日本語太字問題

    MDXで **コルチゾール(ストレスホルモン)** のように書くと、閉じる ** の直前が全角括弧 の場合に太字として認識されないことがある。

    原因はCommonMarkの仕様で、** が「right-flanking delimiter」として認定されるには直前がUnicode句読点でないか、直後がUnicode句読点または空白である必要がある。全角括弧はUnicode句読点なので条件を満たさない。

    remark-cjk-friendly を入れると解決する。

    pnpm add remark-cjk-friendly
    // astro.config.js
    import remarkCjkFriendly from 'remark-cjk-friendly';
    
    markdown: {
      remarkPlugins: [remarkCjkFriendly, ...],
    }

    まとめ

    問題原因解決策
    entry.data.slug が undefinedAstro 5の予約フィールド衝突ディレクトリ名からslugを導出
    記事内画像が404lazyLoadImageが相対パスを保存プラグインを外す
    フォームURLが空SSGのビルド時焼き込みNetlifyのスコープを「Builds」に
    フォームが届かないContent-Type誤設定no-corsではJSON bodyをそのまま送る
    OGP画像のURLが壊れているスラッシュ欠落SITE_IMAGEの先頭に/を追加
    LINEにアイコンが出ないSVGファビコン非対応PNG/ICOも追加
    日本語の太字が効かないCommonMarkの仕様remark-cjk-friendlyを追加

    Gatsbyの資産はほぼそのまま移行できたが、細かいところでこれだけ詰まった。特に2・3・4は「動いているはずなのになぜ?」という類で時間を食った。同じ轍を踏む人が減れば幸いだ。




    Copyright 2026
    サイトマップ