Astro で起動スクリプトを作成する


私の状況と必要性を説明させてください.私は素晴らしい静的サイト ジェネレーターである Astro のこのブログを運営しているので、Markdown ファイルを HTML 出力に変換します.

それらは静的ですが、ビルド時に何かを評価するために、それらの背後にいくつかのロジックを含めることができます.

問題の説明



たとえば、サブスクライバーの数は Sendy API から取得され、背後にサーバーがないため、リアルタイムで取得できません.

もちろん、JavaScript を使用してすべてのリクエストをフェッチすることもできますが、これにより、すべての訪問者に対して API が呼び出されることになります.

これを行う別の方法は、私が始めた Astro ロジックに導入することです.
このような Stats.astro コンポーネントを使用できます.

---
const response = await fetch(`${PUBLIC_SENDY_ENDPOINT}api/subscribers/active-subscriber-count.php`,
{
  method: "POST",
  body: new URLSearchParams(
    `api_key=${PUBLIC_SENDY_API_KEY}&list_id=${PUBLIC_SENDY_LIST_ID}`
  ),
}
);
const subscribers = await response.text();
---
{subscribers} are subscribed to the newsletter


上記は API を要求し、必要な応答を返します.

ただし、これには重大な欠点があります.このコンポーネントを含むすべてのページに対して実行されます.

私の場合、これはこのコンポーネントをレンダリングする必要がある 700 以上のページであり、Web サイトの構築にかかる分でこの数が変わる可能性はほとんどありません.

では、他に何ができるでしょうか?

統一された起動スクリプト



ビルド時間の前に実行できるスクリプトが必要だと考え始めました.

これに対する正式なサポートはまだありませんが (チームはこれについて何かを検討しています)、ビルドの前に実行される単純なノード スクリプトを使用しました.

私がそれをどのようにまとめたか見てみましょう.

まず、このスクリプトを src ディレクトリの外に配置することが重要です. Astro は、インポートしたすべてのモジュールを評価しますが、管理が少し面倒になります.
scripts ディレクトリを作成し、その中に collect.mjs ファイルを作成しました. ( mjs ファイルは es6 モジュール ファイルです)

このファイルは、サブスクライバーをフェッチし、サーバー上のプレーンな JSON ファイルに保存する役割を果たします.その後、Astro はその JSON ファイルからこの情報を取得できます.

私たちは現在 Astro の外にいるので、見逃している便利なものがいくつかあります.
  • フェッチは利用できなくなりました
  • 環境変数に簡単にアクセスできない

  • しかし、幸いなことに、Nate (Astro core) は、使用できるものがいくつかあると述べました.フェッチ部分では、Astro ポリフィルを利用できます.

    import { polyfill } from '@astropub/webapi';
    
    polyfill(globalThis, {
      exclude: 'window document',
    });
    


    次は環境変数です.これは Vite が私たちを助けることができるものです.

    import { loadEnv } from 'vite';
    const { PUBLIC_SENDY_ENDPOINT, PUBLIC_SENDY_API_KEY, PUBLIC_SENDY_LIST_ID } =
      loadEnv('production', process.cwd(), '');
    


    これらの変数をこのドキュメントで使用できるようになりました.

    サブスクライバーをフェッチし、Astro 側の JSON ファイルに保存する関数を作成しましょう.

    import fs from 'fs';
    
    const fetchSubscribers = async () => {
      const response = await fetch(
        `${PUBLIC_SENDY_ENDPOINT}api/subscribers/active-subscriber-count.php`,
        {
          method: 'POST',
          body: new URLSearchParams(
            `api_key=${PUBLIC_SENDY_API_KEY}&list_id=${PUBLIC_SENDY_LIST_ID}`
          ),
        }
      );
      const allSubscribers = await response.text();
    
      fs.writeFile(
        '_cache/subscribers.json',
        JSON.stringify({ subscribers: allSubscribers }),
        (err) => {
          if (err) throw err;
          console.log(`>>> ${file} cached successfully`);
        }
      );
    };
    


    この関数は、API からサブスクライバーを取得し、_cache/subscribers.json ファイルに保存します.
    このようにして、Astro はこのファイルから読み取ることができます.

    あとは、この関数を次のように呼び出すだけです.

    fetchSubscribers();
    


    これを package.json ファイルに追加して、すばやく実行できます.

    {
      "name": "@example/starter",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "dev": "astro dev",
        "collect": "node --experimental-modules scripts/collect.mjs",
        "start": "astro dev",
        "build": "npm run collect && astro build",
      }
    }
    


    これで、スクリプトを単独で実行するオプションが用意されました.これにより、作成したばかりのファイルが実行されます.
    または、最初にスクリプトを実行する npm run build コマンドを実行できます.

    サブスクライバーをキャッシュからロードする



    購読コンポーネントの既存の実装を変更して、キャッシュされたファイルから購読者数をロードするだけです.

    ---
    import fs from "fs";
    
    const readCache = () => {
      if (fs.existsSync(CACHE_FILE_PATH)) {
        const cacheFile = fs.readFileSync("_cache/subscribers.json");
        return JSON.parse(cacheFile);
      }
    };
    const cachedSubscribers = await readCache();
    const subscribers = cachedSubscribers.subscribers;
    ---
    {subscribers} loaded from cache
    


    これで、ビルドごとに 1 回だけ API から読み取るように変換されました.これにより、API がより簡単になり、リクエストであふれなくなります.

    この記事を楽しんでいただければ幸いです.このプロセスについてご質問やご提案がありましたら、お知らせください.

    読んでくれてありがとう、接続しましょう!



    私のブログを読んでいただきありがとうございます.メール ニュースレターを購読して、Facebook に接続してください.