はじめに
こんにちは、でぃーすけです。
今回は、Nuxt3とmicroCMSを使ってJamstackブログを作成するチュートリアルになります。
また弊社で公開している nuxt-microcms-module
もNuxt3に対応しましたのでそちらの使用方法も併せてご紹介いたします。
環境について
- Node.js v16.19.1
- Nuxt v3.2.3
- nuxt-microcms-module v3.0.0
※ 2023/5/31 追記:Nuxt v3.5.0以上でクライアントサイドの環境変数が読み込めない現象が起きています。こちらのチュートリアルはv3.4.3以下でお試しいただけると幸いです。
※ 2023/6/14 追記:nuxt-microcms-moduleのv3.0.2で上記の問題に対応しております。Nuxt.jsの最新バージョンをお使いの方はmicroCMSのモジュールについてもアップデートをお願いします。
Nuxtとは
https://nuxt.com/
ReactでいうNext.jsのように、Vue.jsを使用したフロントエンドとバックエンドの両方の機能を提供するフレームワークになります。
とても優秀なフレームワークであることは言うまでもないのですが、v3にアップデートされ特に優れていると感じたポイントをいくつか紹介します。
1. 自動インポート
Vue.jsやNuxt.jsが提供している組み込みのAPIはもちろん、components
composables
utils
ディレクトリに作成されたファイルも自動インポートの対象になります。
これにより、TypeScriptの型サポートを受けつつ効率的に開発することができます。
2. 型の自動生成
上記で自動インポート可能になった関数群の型や便利なエイリアスを含むtsconfig.json
、server ディレクトリに作成したAPIルートの型までも自動生成します。
この他にも、ルートごとにレンダリングモードを変更したり、新しいサーバーエンジン「Nitro」、モジュールシステムによる機能追加の容易さなど、とても完成度の高いフレームワークになっています。
ゴール
この記事では以下のような記事一覧ページと記事詳細ページを作成するまでをゴールとします。
Nuxtのセットアップ
まずはNuxtのセットアップを行います。
npx nuxi init microcms-blog
コンソールの指示通り、該当ディレクトリに移動して依存ライブラリのインストールをしましょう。
cd microcms-blog
npm install
セットアップができたところで一度開発サーバーを起動してみます。
npm run dev
http://localhost:3000/ にウェルカムページが表示されます。
(めちゃくちゃかっこいいですね・・・!)
microCMSの準備
microCMSでAPIを用意します。今回はmicroCMSのブログテンプレートを利用して進めていきます。
APIの作成
アカウント登録がまだの方はこちらのドキュメントを参考に、登録を行ってください。
はじめに
APIキーとサービスドメイン
あわせてAPIのエンドポイントと、APIキーも用意しておきましょう。ブログ一覧画面のAPIプレビューから確認するのがレスポンスの中身も確認できるので手軽で便利です。
取得したAPIキーとAPIのサービスドメイン名は環境変数ファイル.env
に記載しておきます。
MICROCMS_SERVICE_DOMAIN=サービスドメイン名
MICROCMS_API_KEY=APIキー
microCMSモジュールの導入
microCMSのコンテンツの取得を簡単に扱える nuxt-microcms-module
を導入します。
https://github.com/microcmsio/nuxt-microcms-module
npm install nuxt-microcms-module
次にConfigurationにモジュールを追加します。
// nuxt.config.ts
export default defineNuxtConfig({
+ modules: ["nuxt-microcms-module"],
+ microCMS: {
+ serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
+ apiKey: process.env.MICROCMS_API_KEY,
+ },
});
microCMSモジュールを追加すると、設定ファイルのキーにmicroCMS
というオプションを指定できるようになります。
このオプションには serviceDomain
、apiKey
、target
を指定でき、このうちtarget
のみオプショナルな値で、server
またはall
を指定できます。
この target
はmicroCMSへのリクエストをどこからするのかを指定するものでall
を指定した場合はAPIキーがクライアント側でも使用することができます。
(APIキーの権限を適切に設定した上でクライアント側で使用ください)
今回はJamstackブログを作成しますのでtarget
はデフォルトのserver
にしておきAPIキーは隠蔽します。
そして、nuxt-microcms-module
からは3つのGET関数が提供されます。
useMicroCMSGetList
useMicroCMSGetListDetail
useMicroCMSGetObject
// インターフェース
type useMicroCMSGetList = <T>(
args: {
endpoint: string;
queries?: MicroCMSQueries;
},
fetchOptions?: FetchOptions
) => Promise<AsyncData<MicroCMSListResponse<T>>>;
type useMicroCMSGetListDetail = <T>(
args: {
endpoint: string;
contentId: string;
queries?: MicroCMSQueries;
},
fetchOptions?: FetchOptions
) => Promise<AsyncData<T & MicroCMSListContent>>;
type useMicroCMSGetObject = <T>(
args: {
endpoint: string;
queries?: MicroCMSQueries;
},
fetchOptions?: FetchOptions
) => Promise<AsyncData<T & MicroCMSObjectContent>>;
// FetchOptionsはNuxt3が提供するuseFetchの第2引数と同じです。
// AsyncDataはuseFetchの戻り値です。
// https://nuxt.com/docs/api/composables/use-fetch
microCMSで取得できるコンテンツの型情報を作成
次はmicroCMSで取得できるコンテンツの型情報をあらかじめ作成しておきましょう。
カテゴリーAPIは以下のように、
// types/category.ts
export type Category = {
name?: string;
};
ブログAPIは以下のように定義します。
// types/blog.ts
import type { MicroCMSImage, MicroCMSListContent } from "microcms-js-sdk";
import { Category } from "./Category";
export type Blog = {
title?: string;
content?: string;
eyecatch?: MicroCMSImage;
category: (MicroCMSListContent & Category) | null;
};
記事一覧ページの作成
最初に記事一覧のページを作成しましょう。
Nuxtはv3でもv2と同様にpages
ディレクトリ内のVueファイルがルーティングに対応します。
(このpages
ディレクトリがオプショナルである点はv3からの特徴になります!)
ただ、初期状態のままだとpages
ディレクトリに作成したVueファイルが表示されないため、エントリーポイントであるapp.vue
を修正する必要があります。
// app.vue
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
今回はlayouts
ディレクトリを使用しないので、NuxtLayout
が機能していないですがたとえばエラーページではレイアウトを変更したりする際に便利です。
https://nuxt.com/docs/guide/directory-structure/layouts
そしてNuxtPageが、pages
ディレクトリに配置したそれぞれのVueファイルを表示するコンポーネントです。
https://nuxt.com/docs/api/components/nuxt-page
これでpages
ディレクトリを使う準備ができたので早速作っていきます。
今回は記事一覧ページをTOPに表示しようと思うのでpages/index.vue
を作成します。
そして、先ほど導入したmicroCMSモジュールから提供されるuseMicroCMSGetList
を使ってブログAPIのコンテンツを取得しましょう。
// pages/index.vue
<template>
</template>
<script setup lang="ts">
import { Blog } from "~~/types/Blog";
const { data } = await useMicroCMSGetList<Blog>({
endpoint: "blogs",
});
console.log(data)
</script>
コンソールにmicroCMSのコンテンツデータが表示されていれば成功です!
次に表示部分を作成していきましょう。
まずは見た目は気にせずHTMLのみで組んでいきます。
<template>
<h1>Nuxt3 Jamstack Blogs</h1>
<ul>
<li v-for="blog in data?.contents" :key="blog.id">
<NuxtLink :to="`/${blog.id}`">
<img
:src="blog.eyecatch?.url"
:width="blog.eyecatch?.width"
:height="blog.eyecatch?.height"
alt=""
/>
<div>
<div>
{{ blog.category?.name }}
</div>
<div>
{{ blog.title }}
</div>
<div>
{{ blog.publishedAt ?? blog.createdAt }}
</div>
</div>
</NuxtLink>
</li>
</ul>
</template>
以下のように表示されていれば成功です。(ブラウザによって多少見た目が変わる可能性はあります)
記事詳細ページの作成
次に記事詳細ページを用意していきます。
先ほどのpages
ディレクトリにpages/[id].vue
を追加で作成します。
Nuxtでは[]
で囲んだ部分が動的ルーティングとなり、そのページファイルで利用できます。
このページではuseMicroCMSGetListDetail
を使用して詳細データを取得しましょう。
// pages/[id].vue
<template>
</template>
<script setup lang="ts">
import { Blog } from "~~/types/blog";
const { params } = useRoute();
const { data } = await useMicroCMSGetListDetail{
endpoint: "blogs",
contentId: Array.isArray(params.id) ? params.id[0] : params.id,
});
console.log(data)
</script>
Nuxtから提供されているuseRoute
を使用して、現在表示されるページの[id]
部分を取得します。
ここでもコンソールを確認してデータが表示されていれば成功です。
表示部分も作成していきましょう。
<template>
<template v-if="data">
<h1>
{{ data.title }}
</h1>
<img
:src="data.eyecatch?.url"
:width="data.eyecatch?.width"
:height="data.eyecatch?.height"
alt=""
/>
<div>
<div>
{{ data.category?.name }}
</div>
<div>
{{ data.publishedAt ?? data.createdAt }}
</div>
</div>
<div v-html="data.content"></div>
</template>
</template>
以下のように表示されていれば成功です。
見た目を整える
microCMSで取得したデータの表示は完了しましたが、現状だとデフォルトの表示で少し味気ないですよね。
今回はTailwindCSSを使って少しだけ整えてみましょう。
TailwindCSSモジュールの導入
まずはNuxtでTailwindCSSを使えるようにするために便利なモジュールを導入しましょう。
以下のようにインストールをして、
npm install -D @nuxtjs/tailwindcss
Nuxtの設定ファイルに追加しましょう。
// nuxt.config.ts
export default defineNuxtConfig({
- modules: ["nuxt-microcms-module"],
+ modules: ["nuxt-microcms-module", "@nuxtjs/tailwindcss"],
microCMS: {
serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
apiKey: process.env.MICROCMS_API_KEY,
},
});
そして、詳細ページのようなコンテンツの見た目の調整には@tailwindcss/typography
というTailwindCSSプラグインが便利ですのでこちらもインストールします。
npm install -D @tailwindcss/typography
先ほどの設定ファイルにこちらも追加します。
// nuxt.config.ts
+ import tailwindTypography from "@tailwindcss/typography";
export default defineNuxtConfig({
modules: ["nuxt-microcms-module", "@nuxtjs/tailwindcss"],
microCMS: {
serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
apiKey: process.env.MICROCMS_API_KEY,
},
+ tailwindcss: {
+ config: {
+ content: [],
+ plugins: [tailwindTypography],
+ },
+ },
});
dayjsを用いた日付表示
microCMSではISO8601形式のUTC(協定世界時)で日時データを返却しているため、フロントエンド側で適切な変換が必要となります。
また、その際に人間が読み取りやすい形式のフォーマットにも変換しようと思います。
まずは日付の変換に便利な dayjs
をインストールします。
npm install dayjs
先述の通り、utils
ディレクトリに作成したファイルも自動インポートの対象になりますので、utils/dateFormat.ts
を作成してそこで日時変換をする関数を定義します。
// utils/dateFormat.ts
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
dayjs.extend(utc);
dayjs.extend(timezone);
export const dateFormat = (date: string) =>
dayjs.utc(date).tz("Asia/Tokyo").format("YYYY年MM月DD日");
これでグローバルにdateFormat
関数を呼ぶことができるようになりました。
全体レイアウト
全体のレイアウトを調整するためルートにあるapp.vue
を編集していきます。
// app.vue
<template>
<NuxtLayout>
+ <div class="mx-auto max-w-7xl px-5 sm:px-8 lg:px-10">
+ <div class="mx-auto max-w-3xl py-10 md:py-16">
<NuxtPage />
+ </div>
+ </div>
</NuxtLayout>
</template>
記事一覧ページ
さきほどの一覧ページのVueファイルを編集していきます。
// pages/index.vue
<template>
<h1 class="text-center font-sans text-4xl font-semibold">
Nuxt3 Jamstack Blogs
</h1>
<ul class="mt-16 grid grid-cols-1 gap-8">
<li v-for="blog in data?.contents" :key="blog.id">
<NuxtLink
:to="`/${blog.id}`"
class="flex flex-col gap-4 sm:transition-shadow sm:hover:shadow md:flex-row md:items-center lg:gap-6"
>
<img
:src="blog.eyecatch?.url"
:width="blog.eyecatch?.width"
:height="blog.eyecatch?.height"
class="md:w-1/3 md:flex-none"
alt=""
/>
<div class="md:p-2.5 md:pr-0">
<div
class="inline-block rounded border-2 border-indigo-600 px-1.5 py-0.5 text-sm font-semibold text-indigo-600"
>
{{ blog.category?.name }}
</div>
<div class="mt-2 text-lg font-semibold md:text-xl">
{{ blog.title }}
</div>
<div class="mt-1 text-sm text-gray-700">
{{ dateFormat(blog.publishedAt ?? blog.createdAt) }}
</div>
</div>
</NuxtLink>
</li>
</ul>
</template>
以下のような表示になっていれば成功です。
記事詳細ページ
次は詳細ページです。
// pages/[id].vue
<template>
<template v-if="data">
<h1 class="text-3xl font-semibold">
{{ data.title }}
</h1>
<img
:src="data.eyecatch?.url"
:width="data.eyecatch?.width"
:height="data.eyecatch?.height"
alt=""
class="mt-6 md:mt-10"
/>
<div
class="mt-4 flex flex-col items-start gap-2 md:flex-row md:items-center md:gap-4"
>
<div
class="rounded border-2 border-indigo-600 px-1.5 py-0.5 text-sm font-semibold text-indigo-600"
>
{{ data.category?.name }}
</div>
<div class="text-sm text-gray-700">
{{ dateFormat(data.publishedAt ?? data.createdAt) }}
</div>
</div>
<div v-html="data.content" class="prose mt-6 md:mt-10"></div>
</template>
</template>
以下のような表示になっていれば成功です。
Vercelへのデプロイ
ここまででブログの一覧画面と詳細画面を作ることができましたのでデプロイしてみましょう。
今回はホスティングサービスとしてVercelを利用します。
https://vercel.com/
まずはここまでの作業内容をGitHubに上げます。
GitHubのリポジトリを作成後、下記コマンドでプッシュしていきます。
git init
git add .
git commit -m 'first commit'
git remote add origin your-repository // 自分のリポジトリを入力
git push -u origin main
そしてVercelにログイン後「Add New」をクリック、「Project」を選択します。
その後、先ほど追加したGitHubのリポジトリを選択し、ビルド設定に進みます。
ビルド設定ではフレームワークとしてNuxt.jsを選択し、ビルドコマンドを yarn generate
に設定し環境変数のセットを行います。(.env
の内容)
Deployボタンを押して、ページを確認してみましょう!
Webhookの設定
現状ではGitHubにソースコードをPushするたびにビルド&デプロイがされますが、microCMSの記事を追加・更新してもビルドはされません。
そこで、microCMSのWebhook機能を使って、記事の追加・更新のたびにVercelでビルド&デプロイがされるように設定しましょう。
設定方法は下記の記事で紹介しているので参考にしてみてください。
https://blog.microcms.io/webhook-cloudflare-vercel/
設定後に新しく記事を公開してみて、Vercelのビルドが動き出したら成功です。
おわりに
Vue2からVue3のマイグレーションは大変ではありますが、Nuxt3へのアップグレードには多くの利点があり、特に開発体験が向上していると感じました。
みなさんにもNuxt3をぜひ試していただけたら幸いです。