BLOG

ブログ

2022/08/22 プログラミング技術系

Nuxt.jsでブログを作る

この記事を書いた人 T.U

こんにちは、T.Uです。
Nuxt Contentを使って、ブログを作る機会がありましたので、今回はNuxt Contentについてまとめたいと思います。

Nuxt Contentとは

公式サイトには下記のように説明されています。

nuxt/contentモジュールを使ってNuxtJSアプリケーションを強化します。content/ディレクトリに書き込むことで、MongoDBのようなAPIを使ってMarkdown、JSON、YAML、CSVファイルを取得します。これはGitベースのヘッドレスCMSとして動作します。

https://content.nuxtjs.org/ja/v1/getting-started/introduction

content/ フォルダにあるマークダウンファイルやJSONファイルなどからブログを作ることができるNuxt.jsのモジュールです。
全文検索や目次の自動生成、Prism.jsを使うことでコードブロックのシンタックスハイライトをすることも可能です。

プロジェクトの作成

Nuxt.jsのインストール手順に沿って、プロジェクトを作成します。

yarn create nuxt-app nuxt-blog

CSSのフレームワークとしてはTailwind CSS、モジュールにContentを使用するのでプロジェクト作成時に選択します。
その他、Package managerやLinting toolsはお好みで。

作成したプロジェクトルートに移動し、開発サーバーを起動します。

cd nuxt-blog
yarn dev

http://localhost:3000/ にアクセスし、「Welcome to your Nuxt Application」の表示ができていればプロジェクト作成は完了です。

追加モジュールをインストールする

Nuxt.jsにはaxiosやPWA、Google Fontsなどを簡単に導入できるモジュールが準備されています。
今回はDay.jsとGoogle Fontsのモジュールを導入します。

Google Fontsモジュールを追加

ターミナルを開きプロジェクトルートで下記のコマンドを実行し @nuxtjs/google-fonts モジュールをインストールします。

yarn add --dev @nuxtjs/google-fonts

nuxt.config.jsのbuildModulesに下記を追記し、ウェブフォントが読み込まれるように設定します。
今回は私が大好きな、QuicksandとM Plus 1pを使用します。

buildModules: [
    ['@nuxtjs/google-fonts', {
        families: {
            Quicksand: [300],
            'M PLUS 1p': [300]
        }
    }]
],

Day.jsモジュールを追加

Google Fontsモジュールの導入と同様に下記のコマンドを実行し、@nuxtjs/dayjs をインストールします。

yarn add @nuxtjs/dayjs

nuxt.config.jsのmodulesに下記を追記します。

modules: [
    '@nuxtjs/dayjs'
],

以上の設定で、Day.jsを使用することができます

// <template>タグの中で使用する
{{ $dayjs().format('YYYY-MM-DD') }}
// <script>タグ内で使用する
this.$dayjs().format('YYYY-MM-DD')

コンポーネントを作成する

この記事では、トップページと記事ページのみを作成しますが、タグ記事一覧とトップページのレイアウトはほぼ共通で使用できるので、ヘッダー・フッター・記事一覧のコンポーネントを作成します。

ヘッダーとフッターを作成する

components 配下に AppHeader.vueAppFooter.vue を作成し、以下の内容でコーディングします。

<template>
  <header>
    <NuxtLink to="/" class="text-xl font-quicksand tracking-wide text-gray-800">
      Nuxt.js Blog
    </NuxtLink>
    <div class="w-full my-10 text-center select-none text-gray-500" style="letter-spacing: 20px">°°°</div>
  </header>
</template>
<template>
  <footer class="flex flex-col text-sm text-gray-800 font-quicksand">
    <div class="w-full my-10 text-center select-none text-gray-500" style="letter-spacing: 20px">°°°</div>
    <ul class="flex flex-col mb-3 justify-center space-y-2 sm:space-y-0 sm:space-x-5 sm:flex-row">
      <li>
        <NuxtLink to="/about" class="transition-colors duration-300 rounded px-2 py-1 hover:bg-gray-400">About</NuxtLink>
      </li>
      <li>
        <NuxtLink to="/profile" class="transition-colors duration-300 rounded px-2 py-1 hover:bg-gray-400">Profile</NuxtLink>
      </li>
    </ul>
    <p class="text-center mt-3">
      © 2022 Nuxt.js Blog
    </p>
  </footer>
</template>

記事一覧を作成する

記事一覧コンポーネントは記事データを受け取るため、props で 配列を受け取れるようにしておきます。

<template>
  <div>
    <div v-for="(article, index) of articles" :key="article.slug"
         class="flex flex-col py-10 border-b-2 text-gray-800"
         :class="(index + 1) === articles.length ? 'border-none' : ''">
      <div class="text-xs mb-2">
        <p>{{ $dayjs(article.updatedAt).format('YYYY-MM-DD') }}</p>
      </div>
      <NuxtLink :to="{ name: 'article-slug', params: { slug: article.slug }}" class="inline-block">
        <p class="text-2xl font-light leading-none">{{ article.title }}</p>
      </NuxtLink>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    // 記事一覧を受け取る
    articles: {
      type: Array,
      required: true
    }
  }
}
</script>

レイアウトファイルを作成する

layouts 配下に default.vue を作成し、先程作成した、AppHeader.vueAppFooter.vue を記載します。

<template>
  <div class="py-16 mx-auto max-w-2xl">
    <!-- components/AppHeader.vue -->
    <app-header />
    <!-- パスに一致するpagesファイルが呼ばれる -->
    <Nuxt />
    <!-- components/AppFooter.vue -->
    <app-footer />
  </div>
</template>

各ページを作成する

pages 配下に index.vuearticle/_slug.vue ファイルを作成します。

記事一覧ページを実装する

index.vue に以下の内容コーディングして、記事一覧を実装します。

<template>
  <main>
    <article-list :articles="articles" />
  </main>
</template>

<script>
export default {
  name: 'IndexPage',
  async asyncData({ $content }) {
    const articles = await $content()
      // sortByを指定し、updatedAt(更新日)の降順にソート
      .sortBy('updatedAt', 'desc')
      // limitを指定し、10件のみ取得
      .limit(10)
      .fetch()

    return {
      articles
    }
  }
}
</script>

<style>
*,
.font-mplus1p {
  font-family: 'M PLUS 1p', sans-serif;
}
.font-quicksand {
  font-family: 'Quicksand', sans-serif;
}
</style>

記事データの取得について

Nuxt Contentは、以下のようなメソッドチェーンをする形で、 content ディレクトリに存在する記事データを取得します。

const articles = await $content()
  .sortBy('updatedAt', 'desc')
  .limit(10)
  .fetch()

index.vue には登場しませんが、where() でフィルタリングを行ったり、search() で全文検索を行うことができます。
その他のメソッドは、ドキュメントの Fetching content にまとめられています。

// フィルタリング
await $content().where({ title: 'Blog' }).fetch()
// 全文検索
await this.$content('articles').search('welcome').fetch()

記事ページを実装する

次に、article/_slug.vue に以下の内容コーディングして、記事ページを実装します。

<template>
  <main>
    <h1 class="text-3xl text-center">{{ article.title }}</h1>
    <nuxt-content :document="article"/>
  </main>
</template>

<script>
export default {
  async asyncData({ $content, params }) {
    const article = await $content(params.slug).fetch()

    return {
      article
    }
  }
}
</script>

記事データ取得について

article/_slug.vue というファイル作成すると http://localhost/article/hello-world にアクセスした場合に、「hello-world」 の部分 params.slug で取得することができるようになります。

取得した params.slug を、 $content() に渡すことで、パスパラメータで指定された記事データを取得します。

const article = await $content(params.slug).fetch()

詳しくは、ドキュメントの Dynamic Pages をご参照ください。

動作確認

ここまでコーディングができたら、記事ファイルを作成し動作を確認します。
本記事では .md ファイルを作成していますが、.md ファイル以外にも .yaml.yml.csv.json.json5.xml ファイルを読み込むことができます。

content 配下に hello-world.md を作成し、以下の内容を追記します。

---
title: Hello World
description: Nuxt Content Blog Page!
---

# H1タグ

## H2タグ

### H3タグ

こんにちは!pタグ

* リスト1
* リスト2
* リスト3

[リンクテキスト](https://www.google.com/)

ビルドが終わり、 http://localhost:3000 にアクセスすると、記事一覧と記事ページを表示することができるようになります。

記事ページの見た目を整える

今の状態では記事部分には何もCSSがあたっておらずかなり微妙な見た目になっています。
Nuxt Contentは、.nuxt-content クラス以下のh1タグやpタグにCSSを指定することで見た目を調整することが可能です。

pages/article/_slug.vue を開き、CSSを追記します

<style>
.nuxt-content * {
  margin-top: 15px;
  margin-bottom: 15px;
}
.nuxt-content h1 {
  background-color: #000000A0;
  color: #fff;
  padding: 10px 20px;
}
.nuxt-content h2 {
  border-left: 5px solid #000000A0;
  padding-left: 5px;
}
.nuxt-content h3 {
  border-bottom: 2px solid #000000A0;
}
.nuxt-content ul {
  list-style: disc;
}
.nuxt-content a {
  color: blue;
}
</style>

http://localhost:3000/article/hello-world にアクセスすると画像のように記事部分にCSSをあたっていることを確認できます。

まとめ

今回は、Nuxt Contentでブログの作り方を紹介しました。

本記事では紹介しませんでしたが、yarn generate すれば静的サイトとしてファイルを生成することができ、S3とCloudFrontを利用し、ウェブサイトとして公開することも可能です。

また、目次前の記事・次の記事なども実装することができます。



株式会社ウイングドアは福岡のシステム開発会社です。
現在、私達と一緒に"楽しく仕事が出来る仲間"として、新卒・中途採用を絶賛募集しています!
ウイングドアの仲間達となら楽しく仕事できるかも?と興味をもった方、
お気軽にお問い合わせ下さい!

アーカイブ