Vite + React + Cloudflare Pages + Contentful で アプリを立ち上げるまで

2023.05.12

ベルリンオフィスの小西です。

Vite + React でアプリを立ち上げ、ヘッドレス CMS として Contentful を接続し、Cloudflare Pages にデプロイしてみました。

1. Contentful の準備

Contentful へのユーザー登録は終わっている前提で、簡単なコンテンツモデルを作成して記事を投稿してみます。

Contentful自体の説明や細かい説明方法は本記事では割愛しますので、気になる方はこちら↓をお読みください。

[初心者向け]Contentfulの全体像・記事投稿の流れ・便利な機能をまとめてみた

▼コンテンツモデルの作成

今回は samplePost という ID でモデルを作成します。

▼入力フィールドの追加

  • ID = title で [ショートテキスト]形式のフィールドを、
  • ID = thumbnail で [Media] 形式のフィールドを

追加します。

上記で作成したモデルに対し、記事を公開します。

その後、Contentful のダッシュボードで [Settings] > [API keys] > [Add API key] から トークンを発行し、[Space ID] と [Content Delivery API - access token] をコピーしておきます。

2. ローカルで Vite + React の構築

2-1. Viteプロジェクトの立ち上げ

ガイドに沿ってアプリを立ち上げます。

% npm create vite@latest           
✔ Project name: … my-first-vite-pjt
✔ Select a framework: › React
✔ Select a variant: › TypeScript

Scaffolding project in /Users/ryokonishi/dev/vite/my-first-vite-pjt...

Done. Now run:

  cd my-first-vite-pjt
  npm install
  npm run dev

爆速で素体ができあがりました。

2-2. コードの修正

試しにトップページに Contentful の記事データを表示してみます。

まずは環境変数を設定します。

.env ファイルをルートディレクトリに作成します。先ほど Contentful からコピーしたキーを入力してください。

VITE_CONTENTFUL_SPACE_ID=1234XXXXX
VITE_CONTENTFUL_ACCESS_TOKEN=1234XXXXX

src/App.tsx を下記のコードに差し替えてください。

import { useState, useEffect } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

type entryItem = {
  title: string
  thumbnail: {
    title: string
    url: string
  }
}

function App() {
  const [entry, setEntry] = useState()
  const contentfulEndpoint = `https://graphql.contentful.com/content/v1/spaces/${import.meta.env.VITE_CONTENTFUL_SPACE_ID}/`

  const query = `
  {
    sampleModel(id:"7lbRXLuIUv8IhSl95oATgo"){
      title
      thumbnail {
        title
        url
      }
    }
  }
  `;

  useEffect(() => {
    window
      .fetch(contentfulEndpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN}`,
        },
        body: JSON.stringify({ query }),
      })
      .then((response) => response.json())
      .then(({ data, errors }) => {
        if (errors) {
          console.error(errors);
        }

        setEntry(data.sampleModel);
      });
  }, []);

  return (

      <div>
        <a href="https://vitejs.dev" target="_blank" rel="noopener">
          <img src="{viteLogo}" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank" rel="noopener">
          <img src="{reactLogo}" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      {entry
        ? <div>
            <h2>{entry.title}</h2>
            <img src="{entry.thumbnail.url}" alt="{entry.thumbnail.title}" width="400" />
          </div>
        : 'Loading...'
      }

      <p>
        Click on the Vite and React logos to learn more
      </p>

  )
}

export default App

2-3. (備考)コードに追加した箇所について

const query = ... では 投げる GraphQL クエリを記述しています。今回は単一の記事を id 指定で取得しているため、ご自身の Contentful 記事の ID に差し替えてください。

画像などのアセット(下記例では thumbnail がそれにあたる)は、他に description , size , width , height なども取得できます。

const query = `
{
  sampleModel(id:"7lbRXLuIUv8IhSl95oATgo"){
    title
    thumbnail {
      title
      url
    }
  }
}
`;

上記の例では ID を指定して単一記事を取得しましたが、記事の一覧を取得したい場合は Collection オブジェクトを利用します。 items の中には全記事のデータが配列として返ってきます。

 const query = `
  {
    sampleModelCollection {
      items {
        title
        thumbnail {
          title
          url
        }
      }
    }
  }
  `;

下記はGraphQL エンドポイントを介して Contentful へリクエストする箇所です。 Bearer で先ほど生成したトークンをヘッダーにセットします。

useEffect(() => {
    window
      .fetch(contentfulEndpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN}`,
        },
        body: JSON.stringify({ query }),
      })
      .then((response) => response.json())
      .then(({ data, errors }) => {
        if (errors) {
          console.error(errors);
        }

        setEntry(data.sampleModel);
      });
  }, []);

なお、GraphQL の IDE である GraphiQL を使用して、Contentful のスキーマを探索できます。

GraphiQL サーバーは下記 URL をブラウザで開きます。

<code>https://graphql.contentful.com/content/v1/spaces/YOUR_CONTENTFUL_SPACE_ID/explore?access_token=YOUR_CONTENTFUL_ACCESS_TOKEN</code>

<img src="https://d1tlzifd8jdoy4.cloudfront.net/wp-content/uploads/2023/05/scr_2023-05-11_1522-960x546.png" alt="" width="960" height="546" class="alignnone size-large wp-image-1074292" />

GraphQL が少し過剰という方には、REST API エンドポイントも Contentful から用意されています。

<code>https://cdn.contentful.com</code>

2-4. アプリの確認

上記のコード変更を行った後に再度ローカルホストにアクセスすると、Contentful から設定した記事が確認できると思います。

<img src="https://d1tlzifd8jdoy4.cloudfront.net/wp-content/uploads/2023/05/Screenshot_2023-05-11_at_20.14.37-960x806.png" alt="" width="960" height="806" class="alignnone size-large wp-image-1074296" />

3. Cloudflare Pages へのデプロイ

Cloudflare Pagesは、Vite 3 のプロジェクトをネイティブにサポートしています。

Cloudflare Pages 自体の説明は省きます。詳細は↓

Jamstackホスティング決定版? Cloudflare Pagesを試してみたよ!

3-1. Wrangler CLI でデプロイする場合

まずビルド。

% npm run build

> my-first-vite-pjt@0.0.0 build
> tsc && vite build

vite v4.3.5 building for production...
✓ 34 modules transformed.
dist/index.html                   0.46 kB │ gzip:  0.30 kB
dist/assets/react-35ef61ed.svg    4.13 kB │ gzip:  2.14 kB
dist/assets/index-d526a0c5.css    1.42 kB │ gzip:  0.74 kB
dist/assets/index-f1047168.js   143.84 kB │ gzip: 46.39 kB
✓ built in 1.17s

でその後 wrangler でデプロイします。 dist ディレクトリをアップロードしています。

% wrangler login
% npx wrangler pages publish dist                                   
✔ Enter the name of your new project: … konishi-vite-sample
✔ Enter the production branch name: … production
✨ Successfully created the 'konishi-vite-sample' project.
?  Uploading... (5/5)

✨ Success! Uploaded 5 files (2.71 sec)

✨ Deployment complete! Take a peek over at https://xxxxxxxx.konishi-vite-sample.pages.dev

上記ですでに Pages プロジェクトが立ち上がっています。(上記の例だとビルドはローカルで行っているため、環境変数やビルドコマンドの設定も不要です)

発行された Pages URL にアクセスしてみます。

成功!

wrangler pages コマンドは本記事執筆時点で beta のため、うまくいかない場合は次に書くコンソールからの操作で進めてください。

3-2. コンソールからデプロイする場合

Cloudflare のコンソール上でも Pages プロジェクトは作成できます。

Githubリポジトリを作成し、上記までのコードの変更を push します。

% git init
% git add .
% git commit -m "Initial commit"
% gh repo create
% git push

あとは Cloudflare コンソールから、

Pages > [Create a project] > [Connect to Git] で先ほど作成したリポジトリを選択し、

  • [Build command] として  npm run build と入力
  • [Build output directory] として dist と入力
  • [Environment variables (advanced)] > [Add variable] >  NODE_VERSION として 14.18 を選択

してデプロイするだけです。簡単!

さいごに

CMS とコードを行ったり来たりする開発でも、高速に変更が反映される Vite なら快適に進められます。一式の立ち上げに費用や複雑な設定も必要ないので、個人的な検証環境はこれで十分かなと思いました。

参考