<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CDN - 株式会社yep</title>
	<atom:link href="https://www.ye-p.co.jp/blog_tag/cdn/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ye-p.co.jp</link>
	<description>株式会社yepのコーポレートサイト</description>
	<lastBuildDate>Wed, 16 Sep 2026 06:05:03 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://www.ye-p.co.jp/wp-content/uploads/2026/06/cropped-アセット-1-32x32.png</url>
	<title>CDN - 株式会社yep</title>
	<link>https://www.ye-p.co.jp</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Next.js+Hono+Imgixで実現！動的OGP生成</title>
		<link>https://www.ye-p.co.jp/blog/374-2</link>
		
		<dc:creator><![CDATA[kumaki]]></dc:creator>
		<pubDate>Mon, 28 Jul 2025 00:48:49 +0000</pubDate>
				<guid isPermaLink="false">https://www.ye-p.co.jp/blog/374-2</guid>

					<description><![CDATA[<p>Imgixとは Imgixとは画像をリアルタイムに変換・最適化・配信出来るCDNサービスです URLパラメータで画像の加工が出来るためアプリ・Webにて柔軟な実装が可能です https://www.imgix.com/j [&#8230;]</p>
<p>The post <a href="https://www.ye-p.co.jp/blog/374-2">Next.js+Hono+Imgixで実現！動的OGP生成</a> first appeared on <a href="https://www.ye-p.co.jp">株式会社yep</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2>Imgixとは</h2>
<p>Imgixとは画像をリアルタイムに変換・最適化・配信出来るCDNサービスです<br />
URLパラメータで画像の加工が出来るためアプリ・Webにて柔軟な実装が可能です</p>
<p><a href="https://www.imgix.com/jp" target="_blank">https://www.imgix.com/jp</a></p>
<h3>プランについて</h3>
<p>Imgixでは様々なプランを用意しています<br />
またどのようなプロジェクトにはどのプランが良いか例も記載してあるのでプラン選びがしやすいです</p>
<ul>
<li>STARTER
<ul>
<li>料金：月額25ドル</li>
</ul>
</li>
<li>BASIC
<ul>
<li>料金：月額75ドル</li>
</ul>
</li>
<li>GROWTH
<ul>
<li>料金：月額300ドル</li>
</ul>
</li>
<li>ENTERPRISE
<ul>
<li>料金：お問い合わせにより変動</li>
</ul>
</li>
</ul>
<p>またFreeトライアルが存在するので試しに使いたい人は初めにFreeトライアルから始めるのが良いです<br />
30日または100クレジットまで使用できます</p>
<p><a href="https://www.imgix.com/jp/pricing" target="_blank">https://www.imgix.com/jp/pricing</a></p>
<h3>ストレージについて</h3>
<p>Imgixは様々なストレージサービスに対応しており既存の画像リソースをそのまま使って最適化配信が可能です<br />
公式はGoogle Cloud Storageを推奨しています</p>
<p><a href="https://docs.imgix.com/ja-JP/getting-started/setup/creating-sources" target="_blank">https://docs.imgix.com/ja-JP/getting-started/setup/creating-sources</a></p>
<h2>実装</h2>
<p>記載しているコードはImgixを使用したOGP実装をメインにしています<br />
もし全体像を確認したい場合は下記Githubリポジトリからご確認してください</p>
<p><a href="https://github.com/roll1226/next-hono-imgix" target="_blank">https://github.com/roll1226/next-hono-imgix</a></p>
<h3>使用技術</h3>
<p>タイトルにあるように</p>
<ul>
<li>フロントエンドにはNext.jsを使用</li>
<li>バックエンドにはHonoを使用
<ul>
<li>HonoのRCP機能を利用してNext.jsのRoute Handlersをハイジャックする形で使用</li>
</ul>
</li>
</ul>
<h3>Imgix処理の実装</h3>
<p>今回は下記画像をベースにしてOGP画像を生成されるようにしていきます</p>
<p><img decoding="async" alt="ベースのOGP画像" data-entity-type="file" data-entity-uuid="a1c4b206-906e-47c3-9f8f-61458fa00cc9" src="https://www.ye-p.co.jp/wp-content/files/inline-images/ogp%20%281%29.jpg" width="500" /></p>
<p>Freeトライアルだとクレジットの上限が決まっているためsandboxを使用してURLパラメータを決めていきます</p>
<p><a href="https://sandbox.imgix.com/create" target="_blank">https://sandbox.imgix.com/create</a></p>
<p>URLパラメータが決まったらコードに落とし込んでいきます</p>
<h4>./src/lib/imgix.ts</h4>
<blockquote>
<p>import { format } from &#8220;date-fns&#8221;;<br />
const imgixUrlCache = new Map&lt;string, string&gt;();</p>
<p>// テキスト長に応じてフォントサイズを動的調整<br />
const getOptimalFontSize = (text: string): string =&gt; {<br />
&nbsp; const length = text.length;<br />
&nbsp; if (length &lt;= 10) return &#8220;56&#8221;;<br />
&nbsp; if (length &lt;= 15) return &#8220;52&#8221;;<br />
&nbsp; if (length &lt;= 20) return &#8220;48&#8221;;<br />
&nbsp; if (length &lt;= 25) return &#8220;44&#8221;;<br />
&nbsp; return &#8220;40&#8221;;<br />
};</p>
<p>// テキスト長に応じてパディングも調整<br />
const getOptimalPadding = (text: string): string =&gt; {<br />
&nbsp; const length = text.length;<br />
&nbsp; if (length &lt;= 15) return &#8220;60&#8221;;<br />
&nbsp; if (length &lt;= 25) return &#8220;80&#8221;;<br />
&nbsp; return &#8220;100&#8221;;<br />
};</p>
<p>export const generateImgixOgpUrl = (title: string, createdAt: Date): string =&gt; {<br />
&nbsp; const cacheKey = `${title}:${createdAt}`;</p>
<p>&nbsp; if (imgixUrlCache.has(cacheKey)) {<br />
&nbsp; &nbsp; return imgixUrlCache.get(cacheKey)!;<br />
&nbsp; }</p>
<p>&nbsp; const imgixDomain = process.env.IMGIX_URL || &#8220;your-imgix-domain.imgix.net&#8221;;<br />
&nbsp; const baseImage = &#8220;yep/ogp.jpg&#8221;;</p>
<p>&nbsp; const fontSize = getOptimalFontSize(title);<br />
&nbsp; const padding = getOptimalPadding(title);</p>
<p>&nbsp; // 投稿日のフォーマット<br />
&nbsp; const formattedDate = format(createdAt, &#8220;yyyy/MM/dd&#8221;);</p>
<p>&nbsp; const params = new URLSearchParams({<br />
&nbsp; &nbsp; txt: title, // タイトルテキスト<br />
&nbsp; &nbsp; &#8220;txt-size&#8221;: fontSize, // 動的にフォントサイズを設定<br />
&nbsp; &nbsp; &#8220;txt-color&#8221;: &#8220;333333&#8221;, // テキストカラー<br />
&nbsp; &nbsp; &#8220;txt-align&#8221;: &#8220;center,middle&#8221;, // 中央揃え<br />
&nbsp; &nbsp; &#8220;txt-pad&#8221;: padding, // パディングを動的に設定<br />
&nbsp; &nbsp; &#8220;txt-font&#8221;: &#8220;Hiragino Sans W6&#8221;, // 日本語に適したフォント<br />
&nbsp; &nbsp; &#8220;txt-fit&#8221;: &#8220;max&#8221;, // テキストを領域内に自動収束<br />
&nbsp; &nbsp; &#8220;txt-width&#8221;: &#8220;1000&#8221;, // テキスト幅を少し狭めて確実に収める<br />
&nbsp; &nbsp; &#8220;txt-line-height&#8221;: &#8220;1.5&#8221;, // 日本語に適した行間<br />
&nbsp; &nbsp; &#8220;txt-shad&#8221;: &#8220;2&#8221;, // 少し影を付けて可読性向上<br />
&nbsp; &nbsp; w: &#8220;1200&#8221;, // OGP画像の幅<br />
&nbsp; &nbsp; h: &#8220;630&#8221;, // OGP画像の高さ<br />
&nbsp; &nbsp; fit: &#8220;crop&#8221;, // 画像をクロップしてフィット<br />
&nbsp; &nbsp; auto: &#8220;format&#8221;, // 自動フォーマット<br />
&nbsp; &nbsp; q: &#8220;90&#8221;, // 画質を高めに設定<br />
&nbsp; });</p>
<p>&nbsp; // 投稿日をblendで左下に追加<br />
&nbsp; const dateImageUrl =<br />
&nbsp; &nbsp; &#8220;https://assets.imgix.net/~text&#8221; +<br />
&nbsp; &nbsp; `?txt=${encodeURIComponent(formattedDate)}` + // 日付テキスト<br />
&nbsp; &nbsp; `&amp;txt-size=24` + // フォントサイズ<br />
&nbsp; &nbsp; `&amp;txt-color=666666` + // 日付のテキストカラー<br />
&nbsp; &nbsp; `&amp;txt-font=${encodeURIComponent(&#8220;Hiragino Sans W6&#8221;)}` + // フォント<br />
&nbsp; &nbsp; `&amp;txt-align=left,bottom` + // 左下に配置<br />
&nbsp; &nbsp; `&amp;txt-pad=40` + // パディング<br />
&nbsp; &nbsp; `&amp;w=1200` + // OGP画像の幅<br />
&nbsp; &nbsp; `&amp;h=630`; // OGP画像の高さ</p>
<p>&nbsp; params.set(&#8220;blend&#8221;, encodeURIComponent(dateImageUrl));<br />
&nbsp; params.set(&#8220;blend-mode&#8221;, &#8220;normal&#8221;);</p>
<p>&nbsp; const url = `https://${imgixDomain}/${baseImage}?${params.toString()}`;</p>
<p>&nbsp; if (imgixUrlCache.size &gt;= 100) {<br />
&nbsp; &nbsp; const firstKey = imgixUrlCache.keys().next().value;<br />
&nbsp; &nbsp; if (firstKey) {<br />
&nbsp; &nbsp; &nbsp; imgixUrlCache.delete(firstKey);<br />
&nbsp; &nbsp; }<br />
&nbsp; }<br />
&nbsp; imgixUrlCache.set(cacheKey, url);</p>
<p>&nbsp; return url;<br />
};</p>
</blockquote>
<h3>バック側の実装</h3>
<p>Honoでの実装になりますがバリデーション部分はTypescriptだけで完結出来るように Drizzle + drizzle-zod + Hono + Zod Validator の組み合わせで実装していきます</p>
<h4>./src/app/api/[[&#8230;route]]/post.ts</h4>
<blockquote>
<p>import { db } from &#8220;@/db&#8221;;<br />
import { posts } from &#8220;@/db/schema&#8221;;<br />
import { generateImgixOgpUrl } from &#8220;@/lib/imgix&#8221;;<br />
import { zValidator } from &#8220;@hono/zod-validator&#8221;;<br />
import { eq } from &#8220;drizzle-orm&#8221;;<br />
import { Hono } from &#8220;hono/tiny&#8221;;<br />
import { z } from &#8220;zod&#8221;;</p>
<p>const schema = z.object({<br />
&nbsp;&nbsp;id: z.string().regex(/^d+$/, &#8220;Invalid ID format&#8221;),<br />
});</p>
<p>const app = new Hono().get(<br />
&nbsp;&nbsp;&#8220;/ogp/:id&#8221;,<br />
&nbsp;&nbsp;zValidator(&#8220;param&#8221;, schema),<br />
&nbsp;&nbsp;async (c) =&gt; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const { id } = c.req.param();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const numericId = parseInt(id);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (isNaN(numericId)) return c.json({ error: &#8220;Invalid ID&#8221; }, 400);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const resPosts = await db<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.select()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.from(posts)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.where(eq(posts.id, numericId));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const post = resPosts.at(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!post) return c.json({ error: &#8220;Post not found&#8221; }, 404);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const ogpUrl = generateImgixOgpUrl(post.title, post.createdAt);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return c.json({<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ogpUrl,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: post.title,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description: post.description,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;} catch (error) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.error(&#8220;Failed to generate OGP:&#8221;, error);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return c.json({ error: &#8220;Failed to generate OGP&#8221; }, 500);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
);</p>
<p>export default app;</p>
</blockquote>
<h4>./src/app/api/[[&#8230;route]]/route.ts</h4>
<blockquote>
<p>import { Hono } from &#8220;hono&#8221;;<br />
import { handle } from &#8220;hono/vercel&#8221;;<br />
import post from &#8220;./post&#8221;;</p>
<p>export const dynamic = &#8220;force-dynamic&#8221;;<br />
export const revalidate = 0;</p>
<p>const app = new Hono()<br />
&nbsp;&nbsp;.basePath(&#8220;/api&#8221;)<br />
&nbsp;&nbsp;.route(&#8220;/posts&#8221;, post);</p>
<p>export type AppType = typeof app;<br />
export const GET = handle(app);<br />
export const POST = handle(app);<br />
export const PUT = handle(app);<br />
export const DELETE = handle(app);</p>
</blockquote>
<h3>フロント側の実装</h3>
<p>バックエンドが実装出来たらフロントエンド側で呼び出せるようにServerActions機能を利用して実装をしています</p>
<h4>./src/app/api-access.ts</h4>
<blockquote>
<p>import { client } from &#8220;@/lib/hono&#8221;;<br />
import { GetParams } from &#8220;./api/[[&#8230;route]]/post&#8221;;</p>
<p>export const getHonoOgpById = async (params: GetParams) =&gt; {<br />
&nbsp; try {<br />
&nbsp; &nbsp; const res = await client.api.posts.ogp[&#8220;:id&#8221;].$get({<br />
&nbsp; &nbsp; &nbsp; param: { id: params.id },<br />
&nbsp; &nbsp; });<br />
&nbsp; &nbsp; if (!res.ok) {<br />
&nbsp; &nbsp; &nbsp; if (res.status === 404) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; return null; // 404の場合はnullを返す（OGPが見つからない）<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; throw new Error(`HTTP error! status: ${res.status}`);<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return res.json();<br />
&nbsp; } catch (error) {<br />
&nbsp; &nbsp; console.error(`Failed to fetch OGP ${params.id}:`, error);<br />
&nbsp; &nbsp; if (error instanceof Error &amp;&amp; error.message.includes(&#8220;404&#8221;)) {<br />
&nbsp; &nbsp; &nbsp; return null;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; throw new Error(&#8220;OGPデータの取得に失敗しました&#8221;);<br />
&nbsp; }<br />
};</p>
</blockquote>
<h4>./src/app/server-action.ts</h4>
<blockquote>
<p>&#8220;use server&#8221;;<br />
import { getHonoOgpById } from &#8220;./api-access&#8221;;</p>
<p>export const getOgp = async (id: string) =&gt; {<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return await getHonoOgpById({ id });<br />
&nbsp;&nbsp;} catch (error) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;console.error(`Server action error (getOgp ${id}):`, error);<br />
&nbsp;&nbsp;&nbsp;&nbsp;throw error;<br />
&nbsp;&nbsp;}<br />
};</p>
</blockquote>
<h4>./src/app/posts/[id]/page.tsx</h4>
<blockquote>
<p>import { getOgp, getPost } from &#8220;@/app/server-action&#8221;;<br />
import { Metadata } from &#8220;next&#8221;;</p>
<p>type PostPageProps = {<br />
&nbsp;&nbsp;params: Promise&lt;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;id: string;<br />
&nbsp;&nbsp;}&gt;;<br />
};</p>
<p>export const generateMetadata = async ({<br />
&nbsp;&nbsp;params,<br />
}: PostPageProps): Promise&lt;Metadata&gt; =&gt; {<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;const { id } = await params;<br />
&nbsp;&nbsp;&nbsp;&nbsp;const ogpData = await getOgp(id);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;if (!ogpData) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: &#8220;投稿が見つかりません&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8220;指定された投稿は存在しないか、削除された可能性があります。&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;return {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: ogpData.title,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description: ogpData.description || &#8220;投稿の詳細を表示しています&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;openGraph: {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: `${ogpData.title} | yep demo post`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description: ogpData.description || &#8220;投稿の詳細を表示しています&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;images: [<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url: ogpData.ogpUrl,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;width: 1200,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;height: 630,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alt: ogpData.title,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;twitter: {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;card: &#8220;summary_large_image&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: `${ogpData.title} | yep demo post`,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description: ogpData.description || &#8220;投稿の詳細を表示しています&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;images: [ogpData.ogpUrl],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />
&nbsp;&nbsp;&nbsp;&nbsp;};<br />
&nbsp;&nbsp;} catch (error) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;console.error(&#8220;Error generating metadata:&#8221;, error);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title: &#8220;エラーが発生しました&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description: &#8220;メタデータの生成中にエラーが発生しました。&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;};<br />
&nbsp;&nbsp;}<br />
};</p>
<p>const PostPage = async ({ params }: PostPageProps) =&gt; {<br />
&nbsp;&nbsp;try {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;return &lt;p&gt;通常はここに投稿データが表示される&lt;/p&gt;;<br />
&nbsp;&nbsp;} catch (error) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;console.error(&#8220;Error loading post:&#8221;, error);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return &lt;p&gt;エラーが発生しました&lt;/p&gt;;<br />
&nbsp;&nbsp;}<br />
};</p>
<p>export default PostPage;</p>
</blockquote>
<h3>デモページ</h3>
<p>コードだけではわからない部分があるので実際に動作するページ用意しました<br />
Freeトライアルの上限が来るまでは動作してくれますので、是非動かしてみてください</p>
<p><a href="https://next-hono-imgix.vercel.app/" target="_blank">https://next-hono-imgix.vercel.app/</a></p>
<p>下記の形でOGPが動的に生成されます</p>
<p><img decoding="async" alt="OGPサンプル" data-entity-type="file" data-entity-uuid="6587d855-3e43-4abe-a9e4-9aa8fb7ae8b7" src="https://www.ye-p.co.jp/wp-content/files/inline-images/ogp.jpg" width="500" /></p>
<h2>まとめ</h2>
<p>今回はOGP生成にImgixを使用していきました<br />
OGPだけでなく画像をメイン押し出したサイト（予約サイトやメディアサイトなど）でパフォーマンスを向上させつつクリック率やクリックスルー率などを上げられる可能性もあります<br />
また、レシート発行のような業務に使用される場面でも活躍するかもしれないです<br />
使い方次第で無限の可能性があるImgixを是非一度触ってみてください</p><p>The post <a href="https://www.ye-p.co.jp/blog/374-2">Next.js+Hono+Imgixで実現！動的OGP生成</a> first appeared on <a href="https://www.ye-p.co.jp">株式会社yep</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
