
Nuxt Content v3 + Nuxt Hub を使って爆速で個人ブログを作って公開する
#Nuxt.js
#Vue.js
#Cloudflare
#Tailwind CSS
2025 年 1 月にリリースされた Nuxt Content v3 とNuxt Hubを使って個人ブログを爆速で作っていきます。
ブログはソフトウェア開発者のセルフマーケティングで使える最良のメディアのひとつだ。実際、自分のキャリアを大事に考えるすべてのソフトウェア開発者は、ブログの作成に投資すべきだと私は強く思っている。
ジョン・ソンメズ. SOFT SKILLS ソフトウェア開発者の人生マニュアル 第2版 (p.186).
はじめに
はじめまして、フリーランスのエンジニアとして働いているつきやまです。
Vue, Nuxt, CSS が好きです。
技術以外だと最近はポケポケと短歌を嗜んでいます。
この度、個人ブログを作る運びとなり、本記事は記念すべき一本目の記事です。
せっかくなので一本目の記事は本ブログのような個人ブログを爆速で作る方法の記事を書こうと思います。
記事のテーマとして個人ブログを爆速で作ると掲げているので、ブログの根幹となる機能の解説しかしません。
(=細かな機能やUIについては解説しないです)
Nuxt Content は 2025 年 1 月に v3 がリリースされました。
v3 の主な機能は公式ブログにまとめられています。
事前準備
さっそく実装に入りたいところですが、実装に入る前に各種アカウント作成をする必要があるので作成がまだの方は作成をお願いします。
(すでにアカウントお持ちの方は飛ばしてください。)
本記事では Nuxt Hub を利用してデプロイを行います。
Nuxt Hub を利用する際に必要なアカウント類の登録を行います。
GitHub
GitHub アカウントと公開するサービスのリポジトリを用意をお願いします。
Cloudflare
Cloudflare Pages にホスティングするのでアカウントの作成をお願いします。
Nuxt Hub
Nuxt Hub を用いて Cloudflare にデプロイするのでアカウント作成をお願いします。
環境構築
Nuxt インストール
$ npm create nuxt sample-blog
プロジェクト名は任意の名前をつけてください。
インストールが済んだらディレクトリを移動して、開発サーバーを起動してみましょう。
cd sample-blog
npm run dev
localhost:3000
にアクセスして Welcome ページが表示されていれば完了です。
デプロイの際にGitHubリポジトリと紐づける必要があるのでリポジトリの作成・紐付けも行います。
Nuxt Content インストール
npx nuxi module add content
Nuxt Hub インストール
npx nuxi module add hub
Tailwind CSS (Nice to Have)
(Tailwind CSS はインストールしなくても問題ないです。)
npm install tailwindcss @tailwindcss/vite
~/assets/css/tailwind.css
を新規作成します。
@import "tailwindcss";
nuxt.config.ts
に Tailwind CSS の記述を追加します。
import tailwindcss from '@tailwindcss/vite'
export default defineNuxtConfig({
// ...
css: ['~/assets/css/tailwind.css'],
vite: {
plugins: [tailwindcss()],
},
})
デプロイしてみる
一通りの環境構築を終えたのでこの段階で一旦デプロイしてみましょう。
デプロイコマンド
npx nuxthub deploy
デプロイコマンドを実行するといくつか質問されます
基本的にデフォルトの回答で大丈夫だと思います。
region だけ Asia Pacific
を選びました。
$ npx nuxthub deploy
NuxtHub CLI
ℹ No project is linked with the NUXT_HUB_PROJECT_KEY environment variable.
│
◇ Deploy ~/projects/sample-blog to NuxtHub?
│ Yes
│
◇ Select a project
│ Create a new project
│
◇ Project name
│ sample-blog
│
◇ Select a region for the storage
│ Asia Pacific
│
◇ Production branch (git)
│ main
✔ Project sample-blog created
✔ Connected to tsukiyama-3 team.
✔ Linked to sample-blog project.
問題なければビルドが走ります。
ビルドに成功するとデプロイ先の URL が表示されるのでアクセスしてみましょう。
Welcome ページが表示されていたら完了です。
実装
環境構築も終えたのでいよいよ実装に入っていきます。
コレクション定義
v3 では従来のファイルベースの管理から SQL のデータベースシステムに移行しました。
ファイル管理の方法が変わったからといって内部でいい感じに .sqlite
ファイルを生成してくれているので使う際に特に意識する必要はないと思います。
Nuxt Content v3 ではコレクションを定義してコンテンツを管理します。
コレクションとは、関連するコンテンツのグループです。
コレクションの定義はcontent.config.ts
で行います。content.config.ts
を新規作成します。
コレクションには任意でスキーマの定義もできます。
import { defineContentConfig, defineCollection, z } from '@nuxt/content'
export default defineContentConfig({
collections: {
blog: defineCollection({
type: "page",
source: "blog/*.md",
// スキーマ定義
schema: z.object({
title: z.string(),
description: z.string(),
image: z.string(),
published: z.boolean(),
})
}),
},
})
コンテンツ作成
コンテンツはルート直下に/content
を作成して管理します。
ためしに~/content/blog/
配下にいくつか以下のようにマークダウンファイルを作成してみます。
---
title: 4月1日の記事
description: 4月1日の記事です。
image: https://picsum.photos/584/328
published: true
---
# タイトル
パラグラフ
TOP ページ
~/pages/index
を作成します。
<script setup lang="ts">
const { data } = await useAsyncData('blog', () =>
queryCollection('blog').all(),
)
</script>
<template>
<div>
<ul class="space-y-8">
<li
v-for="article in data"
:key="article.path"
class="list-none divide-y divide-gray-300 hover:opacity-70"
>
<NuxtLink
:to="article.path"
class="gap-x-4"
>
<div class="space-y-1 text-blue-600 underline">
<h3 class="text-base md:text-xl font-bold">{{ article.title }}</h3>
<p class="text-sm md:text-base opacity-80">
{{ article.description }}
</p>
</div>
</NuxtLink>
</li>
</ul>
</div>
</template>
コンテンツの取得はqueryCollection
を用います。published
がtrue
の記事を取得するように絞り込んでいます。
app.vue
も修正します。
<template>
<div>
<NuxtPage />
</div>
</template>
画面確認すると/content
配下に配置した記事が表示されていると思います。
記事ページ
記事ページとしてpages/blog/[...slug]/index.vue
を作成します。
<!-- pages/blog/[...slug]/index.vue -->
<script setup lang="ts">
const route = useRoute()
const { data } = await useAsyncData(route.path, () =>
queryCollection('blog').path(route.path).first(),
)
</script>
<template>
<div class="max-w-[800px] mx-auto">
<article
v-if="data"
id="article"
class="space-y-12"
>
<div class="space-y-4">
<img
ref="image"
:src="data.image"
alt=""
width="584"
height="328"
class="mx-auto"
>
<h1 class="font-bold text-xl md:text-3xl">
{{ data.title }}
</h1>
<p class="opacity-80 text-sm md:text-base">
{{ data.description }}
</p>
</div>
<ContentRenderer
:value="data"
class="space-y-8"
/>
</article>
<div v-else>
<h1>記事が見つかりませんでした</h1>
</div>
</div>
</template>
画面を確認してみるとマークダウンで書いた記事が表示されていると思います。
公開する
Nuxt Hub のダッシューボードから Git リポジトリを紐づけることによって、main
ブランチにpushするだけでデプロイできるようになります。簡単ですね。main
ではないブランチにpushするとプレビュー環境が作られます。嬉しいですね。
ダッシュボード
> 該当プロジェクト
> Settings
> General
> Git repository
> Link repository
(Nuxt Content を Cloudflare Pages にホスティングする場合は、D1データベースに紐付ける必要があるのですが、その辺は Nuxt Hub がいい感じにしてくれているっぽいです。)
おわりに
本記事ではNuxt Contentを使って爆速で個人ブログを作ることをテーマになるべく寄り道をせずに最低限のステップだけを紹介しました。
細かい機能やUIについてはご自身の好みでカスタマイズしていってください。
本ブログのコードは公開しています。
本記事で実装しているコードとは一部異なりますが気になる箇所があればご覧ください。
(誤字脱字や内容の誤りなどがありましたらコメントやIssueを建てていただけるとありがたいです。)
今後も主にフロントエンドにまつわる記事を書いていく予定ですので、お見知り置きを。