👛

AstroでmicroCMSのデータを事前にJSONとして取得しておく

2024/05/12に公開

完成品から

scripts/fetchdata.js
import fs from 'fs';
import { createClient } from "microcms-js-sdk";
import dotenv from 'dotenv';
dotenv.config();

const client = createClient({
    serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
    apiKey: process.env.MICROCMS_API_KEY,
});

const getAllContents = async (endpoint, queries = {}) => {
    return await client.getAllContents({ endpoint, queries });
};

async function fetchData() {
    const data = await getAllContents("projects");
    fs.writeFileSync('src/assets/data/projects.json', JSON.stringify(data));
    console.log("Created projects.json");
}

fetchData().catch(err => console.error('Data fetch failed:', err));
package.json
{
    "scripts": {
        "dev": "astro dev",
        "build": "npm run fetch-data && astro build",
        "fetch-data": "node scripts/fetchdata.js",
    },
}

ディレクトリ構成

src
├── scripts
│   └── fetchdata.js
├── assets
│   └── data
│       └── projects.json
├── pages
│   └── index.astro
│   └── [id].astro
└── .env

なぜ先にCMSデータを取得しておくのか

開発環境においてAstroはCMSからのデータからページを作る場合、ページ遷移のたびにデータをCMSからFetchして遷移先を生成します。データが複雑になるとfetch()に時間がかかり、ページ生成速度が遅くなるほか、CMSサービスのデータ転送量やコンテンツ取得回数もそれだけかさんでしまうことになります。

ローカルにCMSデータを事前にJSONとして落としておき、それを参照してページ生成等を行うようにすれば、データの取得は一度で済ませることができます。

結果として開発中のページ生成スピードの大幅な向上と、データ転送量がリミットを超えてしまう、といったハプニングを防ぐことになるのです。

技術仕様

  • astro@4.8.2
  • dotenv@16.4.5
  • microcms-js-sdk@3.1.0

dotenvとmicrocms-js-sdkのインストール

パッケージマネージャーはyarnを使っています(お好みで)
プロジェクトルートでターミナルを開き以下を叩く。

yarn add dotenv microcms-js-sdk

.envのセットアップ

envファイルをプロジェクトルートに生成し、microCMSからデータを取得するための、serviceDomainとapiKeyをに記述しておきます。
microCMSの具体的な使い方は公式を参照してください
https://blog.microcms.io/astro-microcms-introduction/

.env

MICROCMS_SERVICE_DOMAIN=<YOUR_SERVICE_DOMAIN> # .microcms.io は含まない値
MICROCMS_API_KEY=<YOUR_KEY_VALUE>

fetchdata.jsをつくる

ルートにscriptsフォルダを作成、その中にデータを取得するためのロジックをかいたfetchdata.jsを置きます。

scripts/fetchdata.js
import fs from 'fs';
import { createClient } from "microcms-js-sdk";
import dotenv from 'dotenv';
dotenv.config();

const client = createClient({
    serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
    apiKey: process.env.MICROCMS_API_KEY,
});

const getAllContents = async (endpoint, queries = {}) => {
    return await client.getAllContents({ endpoint, queries });
};

async function fetchData() {
    const data = await getAllContents("projects"); //"projects"の部分は指定したいエンドポイントに書き換えてください
    fs.writeFileSync('src/assets/data/projects.json', JSON.stringify(data));
    console.log("Created projects.json");
}

fetchData().catch(err => console.error('Data fetch failed:', err));

dataフォルダを作る

srcにassetsフォルダをなければ作成、その中にdataフォルダを作成します。この中にfetchdata.jsにて取得し生成されたJSONファイルが格納されます。

package.jsonにロジックを追加

fetchdata.jsをパッケージマネージャーから走らせるためのロジックを追加します。これによってJSONデータを新たに生成したり、更新することができます。

package.json
{
    "scripts": {
        "dev": "astro dev",
+       "build": "npm run fetch-data && astro build",
-       "build": "astro build",
+       "fetch-data": "node scripts/fetchdata.js",
    },
}

これで以下のように叩くとprojects.jsonsrc/assets/dataに生成されているはずです。

yarn fetch-data

使い方

Astroのコードフェンスでimportし、あとは通常通り使うことができます。

src/pages/index.astro
---
import projectsData from "../assets/data/projects.json";
---
<ul>
    {projectsData.map((project)=>{
        <li>
            <h1>{project.title}</h1>
            <p>{project.info}</p>
        </li>
        })
    }
</ul>

[id].astroも同様です。

src/pages/[id].astro
---
import projectsData from "../assets/data/projects.json";

//プロジェクトの個別ページ生成
export async function getStaticPaths() {
  return projectsData.map((content, index) => ({
    params: {
      id: content.id,
    },
    props: {
      project: projectsData.find(({ id }) => id === content.id),
    }
  }));
};
const { project } = Astro.props;
---
<h1>{project.title}</h1>
<p>{project.info}</p>

おわりに

Astroだけではなく、その他のJSフレームワークでも使用可能かと思います(実際SvelteKitでも同様の形でデータをローカルにキャッシュすることができました)。

Discussion