StoryblokとAstro
Storyblokはブロックと呼ばれる再利用可能なコンポーネントを作成してコンテンツを管理するコンポーネントベースのヘッドレスCMSです。
Astroとの連携
セクションタイトル: Astroとの連携このセクションでは、Storyblok integrationを利用してStoryblokとAstroを接続します。
必須要件
セクションタイトル: 必須要件始めるには、以下の手順を行っている必要があります。
- 
Astroプロジェクト - もしAstroプロジェクトをまだ持っていない場合は、自動CLIでAstroをインストールを見ると、すぐに使い始めることができます。 
- 
Storyblokアカウントとスペース - もしアカウントを持っていない場合は、無料で登録してスペースを作成します。 
- 
Storyblok APIトークン - Storyblokスペースの設定内のアクセストークンタブからAPIトークンを生成できます。 - Preview token - これは開発中にドラフトもしくは未公開バージョンのコンテンツを取得するために使います。
- Public token - これは製品版でビルド時に公開済みのコンテンツを取得するために使います。
 
クレデンシャルをセットアップする
セクションタイトル: クレデンシャルをセットアップするAstroへStoryblokのクレデンシャルを追加するために、.envファイルをプロジェクトのルートディレクトリに作成して環境変数に追加します。
STORYBLOK_PREVIEW_TOKEN=YOUR_PREVIEW_TOKENSTORYBLOK_PUBLIC_TOKEN=YOUR_PUBLIC_TOKENこれで、プロジェクトでこれらの環境変数を利用できます。
ルートディレクトリは以下のように作成したファイル含まれているはずです。
├── src/├── .env├── astro.config.mjs└── package.json依存関係をインストールする
セクションタイトル: 依存関係をインストールするAstroとStoryblokスペースを接続するために、次の中から好みのパッケージマネージャの1つのコマンドを実行して公式のStoryblok integrationをインストールします。
npm install @storyblok/astropnpm add @storyblok/astroyarn add @storyblok/astroStoryblokを設定する
セクションタイトル: Storyblokを設定するAstro設定ファイルにStoryblokとの接続が含まれるように以下のように修正します。
import { defineConfig } from 'astro/config';import storyblok from '@storyblok/astro';import { loadEnv } from 'vite';
const env = loadEnv(import.meta.env.MODE, process.cwd(), 'STORYBLOK');
export default defineConfig({  integrations: [    storyblok({      accessToken:        import.meta.env.MODE === 'development'          ? env.STORYBLOK_PREVIEW_TOKEN          : env.STORYBLOK_PUBLIC_TOKEN,      components: {        // Add your components here      },      apiOptions: {        // Choose your Storyblok space region        region: 'us',      },    })  ],});Storyblokとの接続には以下のプロパティを持つオブジェクトを必要とします。
- 
accessToken- これは、前述で追加したStoryblok APIトークンへの参照です。この例では開発時はpreview tokenを使い、製品版ではpublic tokenを使います。Astro設定ファイルは環境変数をサポートしないため、環境変数をロードするためにViteの loadEnv()関数を使います。
- 
components- Storyblokのコンポーネント名をローカルコンポーネントへのパスへマッピングするオブジェクトです。StoryblokコンポーネントをAstroへ描画するときに必須となります。このコンポネントパスは srcディレクトリからの相対パスです。
- 
apiOptions- Storyblok API optionsを含むオブジェクトです。デフォルトのリージョンは euです。もしStoryblokがUSリージョンで作成された場合は、region:usと設定する必要があります。
ブロックをAstroコンポーネントに接続する
セクションタイトル: ブロックをAstroコンポーネントに接続するブロックをAstroへ接続するために、srcディレクトリにstoryblokという名のフォルダーを作成します。このフォルダーには全てのStoryblokのブロックライブラリに対応するAstroコンポネントが含まれます。
例えば、以下のフィールドを持つblogPostというブロックコンテンツがブロックライブラリにある場合を解説します。
- title- テキストフィールド
- description- テキストフィールド
- content- リッチテキストフィールド
目標は、このフィールドを使ってコンテンツに描画するようなAstroコンポーネントを作成する事です。これを実現するために、以下のようにsrc/storyblokディレクトリにBlogPost.astroというファイルを作成します。
---import { storyblokEditable, renderRichText } from '@storyblok/astro'
const { blok } = Astro.propsconst content = renderRichText(blok.content)---
<article {...storyblokEditable(blok)}>  <h1>{blok.title}</h1>  <p>{blok.description}</p>  <Fragment set:html={content} /></article>blokプロパティーにはStoryblokから受信するデータがが含まれます。StoryblokのblogPostブロックで定義したフィールドの値が含まれます。
コンテンツを描画するためには、インテグレーションは以下のようなユーティリティ関数を提供しています。
- storyblokEditable- Stroyblokでこれらを編集可能にするために、必要に応じて要素へ属性を追加します。
- renderRichText- リッチテキストフィールドをHTMLに変換します。
ルートディレクトリは以下のように作成したファイル含まれているはずです。
├── src/│   └── storyblok/│       └── BlogPost.astro├── .env├── astro.config.mjs└── package.json最後に、blogPostブロックをBlogPostコンポーネントへ接続するために、Astro設定ファイルのコンポーネントオブジェクトにプロパティを追加します。キーはブロック名で、値はコンポーネントへのパスです。
import { defineConfig } from 'astro/config';import storyblok from '@storyblok/astro';import { loadEnv } from 'vite';
const env = loadEnv(import.meta.env.MODE, process.cwd(), 'STORYBLOK');
export default defineConfig({  integrations: [    storyblok({      accessToken:        import.meta.env.MODE === 'development'          ? env.STORYBLOK_PREVIEW_TOKEN          : env.STORYBLOK_PUBLIC_TOKEN,      components: {        blogPost: 'storyblok/BlogPost',      },      apiOptions: {        region: 'us',      },    })  ],});データを取得する
セクションタイトル: データを取得するセットアップしたものをテストするために、blogPostコンテンツでtest-postという名前のストーリーをStoryblokで作成します。
Astroでは、以下のコンテンツのtest-post.astroという名前のページをsrc/pagesに作成します。
---import { useStoryblokApi } from '@storyblok/astro'import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro'
const storyblokApi = useStoryblokApi()
const { data } = await storyblokApi.get("cdn/stories/test-post", {  version: import.meta.env.DEV ? "draft" : "published",});
const content = data.story.content;---<StoryblokComponent blok={content} />データ問い合わせをするために、useStoryblokApiフックを利用します。これは連携設定を利用して新しいクライアントインスタンスを初期化します。
コンテンツを描画するために、ストーリーのcontentプロパティをblokとしてStoryblokComponentへ渡します。このコンポーネントはcontentプロパティ内で定義されたブロックを描画します。この例では、BlogPostコンポーネントを描画します。
ブログをAstroとStoryblokで作る
セクションタイトル: ブログをAstroとStoryblokで作る連携のセットアップが終われば、AstroとStoryblokを使ったブログを作成できます。
必須要件
セクションタイトル: 必須要件- 
Storyblokスペース - 子のチュートリアルでは、新しいスペースを作ることをお勧めします。もしすでにブロックを含むスペースがある場合は、そのまま利用できますが、ブロック名とコンテンツタイプに合わせコードを修正する必要があります。 
- 
Storyblokと連携したAstroプロジェクト - 連携するためのセットアップ方法を知るにはAstroとの連携を参照ください。 
ブロックライブラリを作成する
セクションタイトル: ブロックライブラリを作成するBlokを作成するためには、Storyblokアプリのライブラリをブロックをクリックします。+ 新規ブロックボタンをクリックして以下のブロックを作成します。
- 
blogPost- 以下のフィールドを持つコンテンツタイプブロックです。- title- テキストフィールド
- description- テキストフィールド
- content- リッチテキストフィールド
 
- 
blogPostList- 空のNestable Blokです。
- 
page- 以下のフィールドを持つコンテンツタイプブロックです。- body- ネスト可能なBlokフィールド
 
コンテンツを作成する
セクションタイトル: コンテンツを作成するコンテンツを追加するために、コンテンツタブをクリックしてコンテンツセクションへ移動します。前のステップで作成したブロックライブラリを使って以下のストーリーを追加します。
- 
home-pageブロックを使ったコンテンツタイプを持つストーリーです。bodyフィールド内にはblogPostListブロックを追加します。
- 
blog/no-javascript- ブログフォルダー内のblogPostコンテンツタイプを持つストーリーです。title: No JavaScriptdescription: A sample blog postcontent: Hi there! This blog post doesn't use JavaScript.
- 
blog/astro-is-amazing- ブログフォルダー内のblogPostコンテンツタイプを持つストーリーです。title: Astro is amazingdescription: We love Astrocontent: Hi there! This blog post was build with Astro.
これでコンテンツの準備は整いました。Astroプロジェクトに切り替えてブログの構築を始めましょう。
ブロックをコンポーネントへ接続する
セクションタイトル: ブロックをコンポーネントへ接続する新しく作成したブロックをAstroコンポーネントへ接続するには、srcディレクトリにstoryblokと呼ばれるフォルダを作成して以下のファイルを追加します。
Page.astroは、pageブロックのbodyプロパティ内の全てのブロックを再帰的に描画するネスト可能なBlokコンテンツタイプのコンポーネントです。また、親要素にstoryblokEditableを追加し、Storyblokでページを編集できるようにします。
---import { storyblokEditable } from '@storyblok/astro'import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro'const { blok } = Astro.props---
<main {...storyblokEditable(blok)}>  {    blok.body?.map((blok) => {      return <StoryblokComponent blok={blok} />    })  }</main>BlogPost.astroはblogPostブロックのtitleとdescriptionとcontentプロパティを描画します。
リッチテキストフィールドプロパティのcontentをHTMLに変換するためにrenderRichText関数を利用します。
---import { storyblokEditable, renderRichText } from '@storyblok/astro'const { blok } = Astro.propsconst content = renderRichText(blok.content)---<article {...storyblokEditable(blok)}>  <h1>{blok.title}</h1>  <p>{blok.description}</p>  <Fragment set:html={content} /></article>BlogPostList.astroはブログ記事のリストプレビューを描画するNestable Blokコンテンツタイプです。
これはuseStoryblokApiフックを利用してblogPostのコンテンツタイプのストーリー全てを取得します。クエリパラメータのversionを利用して、開発モードではストーリーのドラフトを、製品番ビルドの時は公開されたバージョンを取得します。
---import { useStoryblokApi } from '@storyblok/astro'
const storyblokApi = useStoryblokApi();const { data } = await storyblokApi.get('cdn/stories', {  version: import.meta.env.DEV ? "draft" : "published",  content_type: 'blogPost',})const posts = data.stories.map(story => {  return {    title: story.content.title,    date: new Date(story.published_at).toLocaleDateString("en-US", {dateStyle: "full"}),    description: story.content.description,    slug: story.full_slug,  }})---<h1>My blog</h1><ul>  {posts.map(post => (    <li>      <time>{post.date}</time>      <a href={post.slug}>{post.title}</a>      <p>{post.description}</p>    </li>  ))}</ul>最後に、astro.config.mjsファイルのcomponentsプロパティに作成したコンポーネントを追加します。各キーはStoryblok内のブロック名で、値はsrcからのコンポーネントの相対パスです。
import { defineConfig } from 'astro/config';import storyblok from '@storyblok/astro';import { loadEnv } from 'vite';
const env = loadEnv(import.meta.env.MODE, process.cwd(), 'STORYBLOK');
export default defineConfig({  integrations: [    storyblok({      accessToken:        import.meta.env.MODE === 'development'          ? env.STORYBLOK_PREVIEW_TOKEN          : env.STORYBLOK_PUBLIC_TOKEN,      components: {        blogPost: 'storyblok/BlogPost',        blogPostList: 'storyblok/BlogPostList',        page: 'storyblok/Page',      },      apiOptions: {        region: 'us',      },    })  ],});ページを生成する
セクションタイトル: ページを生成する静的サイトジェネレーター
セクションタイトル: 静的サイトジェネレーターAstroのデフォルト静的モードを利用している場合、動的ルーティングとgetStaticPaths()関数を使えます。この関数はビルド時に呼ばれて、ページとなるパスのリストをせいせいします。
src/pagesに[…slug].astroという以下のファイルを作成します。
---import { useStoryblokApi } from '@storyblok/astro'import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro'
export async function getStaticPaths() {  const storyblokApi = useStoryblokApi()  const { data } = await storyblokApi.get("cdn/stories", {    version: import.meta.env.DEV ? "draft" : "published",  });  const pages = data.stories.map(story => {    return {      params: {        slug: story.full_slug === 'home' ? undefined : story.full_slug      },      props: {        content: story.content      }    }  })  return pages}const { content } = Astro.props---<html lang="en">  <head>    <title>Storyblok & Astro</title>  </head>  <body>    <StoryblokComponent blok={content} />  </body></html>これはStoryblok APIから取得したスラッグとコンテンツを含む各ストーリーのページを生成します。もしストーリーのスラッグがhomeだった場合、undefinedのスラッグを返し/ルーティングを生成します。
サーバーサイドレンダリング
セクションタイトル: サーバーサイドレンダリングプロジェクトでSSRを有効にする場合、Storyblokデータを取得するために動的ルーティングで slug パラメータが利用されます。
---import { useStoryblokApi } from '@storyblok/astro'import StoryblokComponent from '@storyblok/astro/StoryblokComponent.astro'const storyblokApi = useStoryblokApi()const slug = Astro.params.slug === undefined ? "home" : Astro.params.sluglet content;try {  const { data } = await storyblokApi.get(`cdn/stories/${slug}`, {    version: import.meta.env.DEV ? "draft" : "published",  });  content = data.story.content} catch (error) {  return Astro.redirect('/404')}---<html lang="en">  <head>    <title>Storyblok & Astro</title>  </head>  <body>    <StoryblokComponent blok={content} />  </body></html>このファイルは動的なslugパラメータと一致するページデータをStoryblokから取得して描画します。
もし見つからない場合は、404ページへリダイレクトします。
サイトを公開する
セクションタイトル: サイトを公開するウェブサイトをデプロイするために、デプロイガイドへアクセスして好みのホスティングプロバイダーにあわせた説明に従ってください。
Storyblokの変更時に再ビルドする
セクションタイトル: Storyblokの変更時に再ビルドするもしプロジェクトがAstroのデフォルトである静的モードを使っている場合、コンテンツを変更した時に新しいビルドを行うトリガーをするためのWebhookをセットアップする必要があります。もしNetlifyかVercelをホスティングプロバイダーとして使っている場合、コンテンツイベントから新しいビルドをトリガーするためにWebhook機能を使えます。
Netlify
セクションタイトル: NetlifyNetlifyのWebhookをセットアップするためには以下の手順が必要です。
- 
ダッシュボードに行き、Build & deployをクリックします。 
- 
Continuous Deploymentタブから、Build hooks セクションを探しAdd build hookをクリックします。 
- 
Webhookの名前を指定してビルド時にトリガーされるブランチを選択します。Saveをクリックし生成されたURLをコピーします。 
Vercel
セクションタイトル: VercelVercelのWebhookをセットアップするためには以下の手順が必要です。
- 
ダッシュボードへ行き、Settingsをクリックします。 
- 
Gitタブから、Deploy Hooksセクションを見つけます。 
- 
Webhookの名前を指定してビルド時にトリガーされるブランチを選択します。Addをクリックして生成されたURLをコピーします。 
StoryblokにWebhookを追加する
セクションタイトル: StoryblokにWebhookを追加するStoryblokスペースのSettingsから、Webhooksタブをクリックします。Story published & unpublishedボックスにWebhook URLをペーストします。保存を押してWebhookを作成します。
これで、新しいストーリーを公開しても、新しいビルドがトリガーされブログが更新されます。
公式リソース
セクションタイトル: 公式リソース- StoryblokはプロジェクトにStoryblokを追加する Astro Integrationを提供しています。
コミュニティリソース
セクションタイトル: コミュニティリソース- 追加してください!
 
		