Astro製のブログにCloudinaryを導入する
はじめに
このブログと技術ブログは、Astro の Content Collection を使ってマークダウンでブログを書いていて、記事は GitHub で管理してます。
Astro の Image コンポーネントを使うために、ブログ記事の画像も src/assets/images/配下に配置していました。しかし、ローカルで画像を管理したくないなと思ったので Cloudinary を導入してみました。
Astro での Cloudinary の導入方法について、この記事では紹介します。
Cloudinary の詳しいオプションなどは解説しないのと、Cloudinary のアカウントが既にあるのを前提に説明します。
まだの方は下記 URL からアカウントを作成してください。

Astro Cloudinary のインストール
Astro で使える Cloudinary のコンポーネントが用意されてます。下記コマンドで Astro Cloudinary をインストールしましょう。
npm install astro-cloudinary
インストールできたら、プロジェクトのルートに.env
ファイルを作成して、Cloudinary のアカウント情報を記述します。
PUBLIC_CLOUDINARY_CLOUD_NAME="<Your Cloud Name>"
アカウント名は、Cloudinary のダッシュボードの Home の Product Environment の Cloud name から確認できます。
Cloudinary 画像と動画の使用
Cloudinary の画像と動画を使うには、astro-cloudinary
のコンポーネントを使います。ブログ内の MDX でコンポーネントを使えるように[...slug].astro
を下記のように書きましょう。
---
import type { CollectionEntry } from "astro:content";
import MarkdownBody from "@/components/MarkdownBody.astro";
import Figure from "@/components/markdown/Figure.astro";
import { getSortedBlogs } from "@/utils/content-utils";
interface Props {
entry: CollectionEntry<"blog">;
}
export async function getStaticPaths() {
const blogEntries = await getSortedBlogs();
return blogEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry }
}));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Layout>
<MarkdownBody>
<Content components={{ img: Figure }} />
</MarkdownBody>
</Layout>
これで、マークダウンで画像を使うと、Figure
コンポーネントが使われるようになりました。
それでは、Cloudinary の画像と動画を使うためにFigure
コンポーネントを作成します。
---
import { Image } from "astro:assets";
import type { ImageMetadata } from "astro";
import { CldImage } from 'astro-cloudinary';
import { CldVideoPlayer } from 'astro-cloudinary';
interface Props {
title: string;
src: ImageMetadata | string;
alt: string;
};
const { title, src, alt } = Astro.props;
const cloudName = import.meta.env.PUBLIC_CLOUDINARY_CLOUD_NAME;
const isStringSrc = typeof src === 'string';
const isCloudinaryImage = isStringSrc && src.startsWith(`https://res.cloudinary.com/${cloudName}/image/`);
const isCloudinaryVideo = isStringSrc && src.startsWith(`https://res.cloudinary.com/${cloudName}/video/`);
---
<figure class="figure">
<div class="figure__img">
{ isCloudinaryVideo ? (
<CldVideoPlayer src={src as string} width="1200" height="675" />
) : isCloudinaryImage ? (
<CldImage src={src as string} alt={alt} width={1200} height={675} />
) : (
<Image src={src as ImageMetadata} alt={alt} width="1200" height="675" />
)
}
</div>
{ title && (
<figcaption class="figcaption">
<Fragment set:html={title} />
</figcaption>
)}
</figure>
ここでは、isCloudinaryImage
やisCloudinaryVideo
で、Cloudinary の画像と動画かどうかを判定しています。Cloudinary の画像と動画の場合はCldImage
やCldVideoPlayer
コンポーネントを使用し src に画像 URL を渡してます。
Cloudinary の画像ではない場合は、Astro のImage
コンポーネントを使っています。
ここでは、cloudName を環境変数から取得しています。本番環境で参照する際は、.env の PUBLIC_CLOUDINARY_CLOUD_NAME を設定してください。このブログでは Cloudflare でデプロイしているので、設定の「変数とシークレット」で環境変数を設定しています。
使用例
最後に使用例を見てみましょう
画像

動画

まとめ
Astro 製のブログに Cloudinary を導入してみました。これで気軽に画像の投稿や動作例の動画をブログに投稿できるようになったので、より良いコンテンツが作れそうです。
みなさんも、ぜひ使ってみてください!
招待リンク
以下のリンクから Cloudinary のアカウントを作ると、わたしのアカウントの Credit が増えます。ここまで読んだ方は、以下のリンクからアカウントを作ってくれると(わたしが)気軽に Cloudinary を使えるようになれるので嬉しいです。
Cloudinary Direct invitation link