コンテンツにスキップ

Nuxt.jsとSanity.ioを使用してCloudflare Pagesにブログを構築する

Last reviewed: about 2 years ago

このチュートリアルでは、Nuxt.jsとSanity.ioを使用してブログアプリケーションを構築し、Cloudflare Pagesにデプロイします。Nuxt.jsは、フロントエンドフレームワークVue.jsに基づいて構築された強力な静的サイトジェネレーターです。Sanity.ioは、データベースを維持することなくアプリケーションのデータを管理するために構築されたヘッドレスCMSツールです。

前提条件

  • コンピュータに最新の npmがインストールされていること
  • Sanity.ioアカウント

新しいSanityプロジェクトの作成

まず、Sanityのテンプレートの1つであるブログテンプレートを使用して新しいSanityプロジェクトを作成します。構成をカスタマイズしたい場合は、スキーマを変更するか、カスタムテンプレートを選択できます。

Sanityのインストールとデータセットの設定

npmから@sanity/cliクライアントをインストールし、ターミナルでsanity initを実行して新しいSanityプロジェクトを作成します:

Sanityクライアントのインストールと新しいプロジェクトの作成
npm install -g @sanity/cli && sanity init

Sanityプロジェクトを作成するとき、あらかじめ定義されたスキーマの1つを使用することができます。スキーマは、Sanityデータセット内のデータの形状を説明します。新しいプロジェクトを開始する場合は、スキーマを最初から初期化することもできますが、今回はBlogスキーマを選択します。

スキーマの確認

プロジェクトが作成されたら、フォルダに移動してスタジオをローカルで起動します:

Sanityスタジオの起動
cd my-sanity-project
sanity start

Sanityスタジオは、データセットの新しいレコードを作成する場所です。デフォルトでは、ローカルでスタジオを実行するとlocalhost:3333で利用可能になります。今すぐそこに行き、著者レコードを作成してください。ここでブログ投稿も作成できます。

Sanityプロジェクトダッシュボードでのブログ投稿の作成

データセットのデプロイ

スタジオのデプロイの準備ができたら、sanity deployを実行してスタジオのユニークなURLを選択します。これにより、あなた(またはブログの管理に招待した他の誰か)がyoururl.sanity.studioドメインでスタジオにアクセスできるようになります。

スタジオのデプロイ
sanity deploy

Sanityスタジオをデプロイしたら:

  1. Sanityの管理パネルにアクセスします(manage.sanity.io)。
  2. プロジェクトを見つけます。
  3. APIを選択します。
  4. プロジェクトの許可されたCORSオリジンとしてhttp://localhost:3000を追加します。

これにより、NuxtアプリケーションからSanityデータセットに送信されるリクエストが許可リストに追加されます。

SanityプロジェクトのCORS設定

新しいNuxt.jsプロジェクトの作成

次に、Nuxt.jsプロジェクトを作成します。新しいターミナルで、create-nuxt-appを使用して新しいNuxtプロジェクトをセットアップします:

新しいNuxt.jsプロジェクトの作成
npx create-nuxt-app blog

重要なことに、セットアッププロセスを進める際に**Universal (SSR / SSG)のレンダリングモードとStatic (Static/JAMStack hosting)**のデプロイターゲットを選択してください。

プロジェクトが完了したら、cdで新しいプロジェクトに移動し、yarn dev(またはnpmをパッケージマネージャーとして選択した場合はnpm run dev)を実行してローカル開発サーバーを起動します:

Nuxt.js開発サーバーの起動
cd blog
yarn dev

Sanity.ioの統合

Nuxt.jsアプリケーションが設定されたら、Sanityの@sanity/nuxtプラグインをNuxtプロジェクトに追加します:

@nuxt/sanityの追加
yarn add @nuxtjs/sanity @sanity/client

Nuxt.jsアプリケーションでプラグインを設定するには、いくつかの設定詳細を提供する必要があります。最も簡単な方法は、スタジオからアプリケーションディレクトリにsanity.jsonフォルダをコピーすることです(他の方法もあります:@nuxt/sanityのドキュメントを参照)。

sanity.jsonの追加
cp ../my-sanity-project/sanity.json .

最後に、Nuxt設定で@nuxtjs/sanityビルドモジュールとして追加します:

nuxt.config.js
{
buildModules: ["@nuxtjs/sanity"];
}

コンポーネントの設定

アプリケーションにSanityが設定されたので、ブログをレンダリングするために使用を開始できます。これから、Sanity APIからデータを取得してレンダリングするためのいくつかのページを設定します。Nuxtに不慣れな場合は、Nuxtガイドを確認することをお勧めします。これにより、Nuxtを使用したアプリケーション構築の基本概念を学ぶことができます。

インデックスページの設定

まず、ルートルート(/)を訪れたときにレンダリングされるindexページを更新します。pages/index.vueで:

pages/index.vue
<template>
<div class="container">
<div>
<h1 class="title">私のブログ</h1>
</div>
<div class="posts">
<div v-for="post in posts" :key="post._id">
<h2><a v-bind:href="post.slug.current" v-text="post.title" /></h2>
</div>
</div>
</div>
</template>
<script>
import { groq } from "@nuxtjs/sanity";
export default {
async asyncData({ $sanity }) {
const query = groq`*[_type == "post"]`;
const posts = await $sanity.fetch(query);
return { posts };
},
};
</script>
<style>
.container {
margin: 2rem;
min-height: 100vh;
}
.posts {
margin: 2rem 0;
}
</style>

Vue SFC(シングルファイルコンポーネント)は、JavaScript、HTML、CSSを1つのファイルにまとめることを可能にする独自のVue機能です。pages/index.vueでは、Vueコンポーネントを表すtemplateタグが提供されています。

重要なことに、v-forは、配列posts内の各postに対してHTMLをレンダリングするようにVueに指示するためのディレクティブとして使用されます:

v-forディレクティブの確認
<div v-for="post in posts" :key="post._id">
<h2><a v-bind:href="post.slug.current" v-text="post.title" /></h2>
</div>

そのposts配列を埋めるために、asyncData関数が使用され、これはNuxtによって提供され、ページのデータを埋めるために非同期呼び出し(例えば、ネットワークリクエスト)を行います。

$sanityオブジェクトは、NuxtとSanity.jsの統合によって提供され、Sanityデータセットへのリクエストを行う方法です。$sanity.fetchを呼び出し、クエリを渡すことで、Sanityデータセットから特定のデータを取得し、それをページのデータとして返すことができます。

Sanityを使用したことがない場合、GROQ(Sanityがデータセットとインターフェースするために提供するGRaph Oriented Query言語)に不慣れかもしれません。GROQは、Sanity APIにデータセットから取得したいデータを指示するための強力な言語です。最初のクエリでは、Sanityに_typeの値がpostであるすべてのオブジェクトを取得するように指示します:

基本的なGROQクエリ
const query = groq`*[_type == "post"]`;
const posts = await $sanity.fetch(query);

ブログ投稿ページの設定

indexページは、データセット内の各ブログ投稿のリンクをレンダリングし、slug値を使用してブログ投稿のURLを設定します。たとえば、「Hello World」というブログ投稿を作成し、スラッグをhello-worldに設定した場合、私のNuxtアプリケーションは/hello-worldページへのリクエストを処理し、Sanityから対応するブログ投稿を取得できるはずです。

Nuxtは、pages内に_slug.vueという形式の新しいファイルを作成することで、これらの種類のページをサポートしています。ページのasyncData関数内で、params引数を使用してスラッグを参照できます:

pages/_slug.vue
<script>
export default {
async asyncData({ params, $sanity }) {
console.log(params); // { slug: "hello-world" }
},
};
</script>

そのことを考慮に入れて、pages/_slug.vueを構築して、受信したslug値を取得し、Sanityにクエリを行って一致するブログ投稿を見つけ、ブログ投稿のpostタイトルをレンダリングします:

pages/_slug.vue
<template>
<div class="container">
<div v-if="post">
<h1 class="title" v-text="post.title" />
<div class="content"></div>
</div>
<h4><a href="/">← 戻る</a></h4>
</div>
</template>
<script>
import { groq } from "@nuxtjs/sanity";
export default {
async asyncData({ params, $sanity }) {
const query = groq`*[_type == "post" && slug.current == "${params.slug}"][0]`;
const post = await $sanity.fetch(query);
return { post };
},
};
</script>
<style>
.container {
margin: 2rem;
min-height: 100vh;
}
.content {
margin: 2rem 0;
max-width: 38rem;
}
p {
margin: 1rem 0;
}
</style>

たとえば、/hello-worldを訪れると、Nuxtは受信したスラッグhello-worldを取得し、Sanityに_typepostで、スラッグが/hello-worldに一致するオブジェクトを取得するためのGROQクエリを行います。そのセットから、配列の最初のオブジェクトを取得し(JavaScriptで見られる配列インデックス演算子[0]を使用)、それをページデータのpostとして設定します。

ブログ投稿のコンテンツをレンダリングする

ブログのpostタイトルをレンダリングしましたが、ブログ投稿自体のコンテンツがまだ欠けています。これをレンダリングするために、SanityのPortable Text形式を受け取り、Vueコンポーネントとしてレンダリングするsanity-blocks-vue-componentパッケージをインポートします。

まず、npmパッケージをインストールします:

sanity-blocks-vue-componentパッケージの追加
yarn add sanity-blocks-vue-component

パッケージがインストールされたら、plugins/sanity-blocks.jsを作成し、コンポーネントをインポートしてVueコンポーネントblock-contentとして登録します:

plugins/sanity-blocks.js
import Vue from "vue";
import BlockContent from "sanity-blocks-vue-component";
Vue.component("block-content", BlockContent);

Nuxt設定のnuxt.config.jsで、そのファイルをpluginsディレクティブの一部としてインポートします:

nuxt.config.js
{
plugins: ["@/plugins/sanity-blocks.js"];
}

pages/_slug.vueでは、<block-content>コンポーネントを使用してコンテンツをレンダリングできます。これはカスタムHTMLコンポーネントの形式を取り、3つの引数を受け取ります::blocksは何をレンダリングするかを示し(この場合はchild)、v-forchildを取得するイテレータを受け入れ(この場合はpost.body)、:keyはVueが状態のレンダリングを追跡するために各投稿にユニークな値を提供します:すなわち、_id値です。

pages/_slug.vue
<template>
<div class="container">
<div v-if="post">
<h1 class="title" v-text="post.title" />
<div class="content">
<block-content
:blocks="child"
v-for="child in post.body"
:key="child._id"
/>
</div>
</div>
<h4><a href="/">← 戻る</a></h4>
</div>
</template>
<script>
import { groq } from "@nuxtjs/sanity";
export default {
async asyncData({ params, $sanity }) {
const query = groq`*[_type == "post" && slug.current == "${params.slug}"][0]`;
const post = await $sanity.fetch(query);
return { post };
},
};
</script>
<style>
.container {
margin: 2rem;
min-height: 100vh;
}
.content {
margin: 2rem 0;
max-width: 38rem;
}
p {
margin: 1rem 0;
}
</style>

pages/index.vueでは、block-contentコンポーネントを使用して、ブログ投稿コンテンツの最初のブロックを取得し、要約をレンダリングできます:

pages/index.vue
<template>
<div class="container">
<div>
<h1 class="title">私のブログ</h1>
</div>
<div class="posts">
<div v-for="post in posts" :key="post._id">
<h2><a v-bind:href="post.slug.current" v-text="post.title" /></h2>
<div class="summary">
<block-content
:blocks="post.body[0]"
v-bind:key="post.body[0]._id"
v-if="post.body.length"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { groq } from "@nuxtjs/sanity";
export default {
async asyncData({ $sanity }) {
const query = groq`*[_type == "post"]`;
const posts = await $sanity.fetch(query);
return { posts };
},
};
</script>
<style>
.container {
margin: 2rem;
min-height: 100vh;
}
.posts {
margin: 2rem 0;
}
.summary {
margin-top: 0.5rem;
}
</style>

ブログスキーマ内には、プロジェクトに追加できる他の多くの要素があります。ヘッドレスCMSを使用して構築する理解を深めるために、次のいずれかを考慮してください:

  • pages/authors.vueを作成し、著者のリストをレンダリングします(pages/index.vueに似ていますが、_type == "author"のオブジェクト用です)
  • Sanityのドキュメントを読み、GROQでの参照の使用を確認し、ブログ投稿ページに著者情報をレンダリングします

Cloudflare Pagesでの公開

Cloudflare Pagesでプロジェクトを公開するのは2ステップのプロセスです。まず、プロジェクトをGitHubにプッシュし、その後Cloudflare PagesダッシュボードでそのGitHubリポジトリに基づいて新しいプロジェクトを設定します。Pagesは、公開するたびにサイトの新しいバージョンをデプロイし、新しいプルリクエストを開くたびにプレビューデプロイを設定します。

プロジェクトをGitHubにプッシュするには、新しいリポジトリを作成し、ローカルGitリポジトリをGitHubにプッシュする手順に従います。

プロジェクトをGitHubにプッシュしたら、サイトをPagesにデプロイします:

  1. Cloudflareダッシュボードにログインし、アカウントを選択します。
  2. アカウントホームで、Workers & Pages > アプリケーションを作成 > Pages > Gitに接続を選択します。
  3. 作成した新しいGitHubリポジトリを選択し、ビルドとデプロイの設定セクションで、_Nuxt_を選択します。Pagesは自動的に正しいフィールドを設定します。

サイトがデプロイされると、プロダクションで表示するためのユニークなURLが送信されます。

Sanity.ioのデータが変更されたときにプロジェクトを自動的にデプロイするには、Deploy Hooksを使用できます。Pagesプロジェクト > 設定で新しいDeploy Hook URLを作成します。Sanityプロジェクトの設定ページで、Webhooksセクションを見つけ、以下のようにDeploy Hook URLを追加します:

SanityのダッシュボードでDeploy Hook URLを追加

これで、Sanity.ioデータセットに変更を加えると、SanityはユニークなDeploy Hook URLにリクエストを送信し、新しいCloudflare Pagesデプロイが開始されます。これにより、新しいブログ投稿を追加したり、既存の投稿を編集したりする際に、Pagesアプリケーションが最新の状態に保たれます。

結論

このガイドを完了することで、Nuxt、Sanity.io、およびCloudflare Pagesを使用して独自のブログを正常にデプロイしました。両方のコードベースのソースコードはGitHubで見つけることができます:

このチュートリアルを楽しんでいただけたなら、Cloudflare Workersを使用して既存のサイトを拡張する方法について学ぶことに興味があるかもしれません。Pages Functionsを使用してフロントエンド用のAPIを構築するチュートリアルを参照して、詳細を学んでください。