2020-06-05に更新

@nuxt/contentでブログを構築してみました

これまで nuxt と microCMS を組み合わせて JAMStack なブログを Netlify で公開していましたが、コンテンツ自体も一緒に管理できたほうが効率的かつ外部サービスに依存したくないと考え、作り直しのため markdown-it を採用つもりでした。

しかし@nuxt/content が公開されたことを知り、早速導入をしてみました。

@nuxt/content の機能について

  • ホットリロード
  • Markdown の Vue コンポーネント
  • 全文検索
  • nuxt generateで静的サイトの生成
  • MongoDB のような QueryBuilder
  • PrismJS によるマークダウンファイルのコードブロックをスタイリングする
  • 目次の生成
  • Markdown、CSV、YAML、JSON を処理する
  • hooks による拡張
  • types による Typescript のサポート (v1.0.1)

インストール時の環境

  • MacOS Catalina 10.15.4
  • yarn 1.22.4
  • NuxtJS 2.12.2 (TypeScript)
  • @nuxt/content v1.2.0

インストール

まずはパッケージをインストールします。

yarn add @nuxt/content

次に nuxt.config.ts に以下を追加します。

# nuxt.config.ts
{
  modules: [
      '@nuxt/content',
  ],
  content: {
    // デフォルト以外の設定
  }
}

TypeScript の対応

tsconfig.jsonに以下を追加します。

{
  "compilerOptions": {
    "types": ["@nuxt/types", "@nuxt/content"]
  }
}

これを追加することで Context を拡張して、後に出てくる$contentの参照が行われるようにします。

コンテンツの管理

コンテンツの管理はデフォルトでは~/content以下で行います。

それぞれのファイルはサブディレクトリでも管理することができます。

今回は~/content/articles/sample.mdとして作成してみます。

---
title: '日本語タイトルを使えます'
date: 2020-05-23
tags: [Markdown, NuxtJS]
---

# 記事タイトル

コンテンツの内容

@nuxt/contentで slug は、ファイル名の拡張子を除く部分となっています。

YAML Front Matte の機能として記事のメタデータを管理することができ、tagsのように配列で記述できます。

これらのメタデータはクエリを使って絞り込みに利用できます。

注意点としてtitletitle: 1のように文字列以外を入力すると、文字列の関数がないことでエラーが発生します。この場合はシングルクォートで括るようにすれば回避できます。

コンテンツの表示

asyncDataを使ってサーバーサイドで記事を取得します。

<template>
  <div>
    <div>{{ page.title }}</div>
    <div>{{ page.date }}</div>
    <nuxt-content :document="page" />
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { Context } from '@nuxt/types'

@Component
export default class Sample extends Vue {
  async asyncData({ $content, params, error }: Context) {
    const page = await $content('articles/sample').fetch()
    return { page }
  }
}
</script>

$content('articles/sample')とすると、content/articles/sampleを記事として取得します。

複数の記事をまとめて取得するには$content('articles')として、content/articles以下にある全ての記事を配列で取得することができます。

サーバーサイドで取得後、page変数には記事ファイルのメタデータとコンテンツが読み込まれ、
<nuxt-content :document="page">で HTML にマークアップされた状態で表示されます。

コードブロックのテーマを変更する

@nuxt/contentでコードブロックのハイライトはprismjsで行われているので、prism-themesをインストールすれば好きなテーマへ変更することができます。

yarn add prism-themes

nuxt.config.ts でテーマの変更を設定します。

# nuxt.config.ts
{
  modules: [
      '@nuxt/content',
  ],
  content: {
    markdown: {
      prism: {
        // ここに使いたいcssのテーマを設定します
        theme: 'prism-themes/themes/prism-vsc-dark-plus.css'
      }
    }
  }
}

タグの検索をする

メタデータが配列の場合は、単純な where では取得できません。

@nuxt/contentのクエリはLokiJSを使っているので、公式マニュアルを参照して$containsを使えばいいことがわかりました。

具体的には以下の方法で、特定のタグを持つ記事を取得することができます。

await $content('articles')
  .where({ tags: { $contains: 'Markdown' } })
  .fetch()

サブディレクトリの記事も取得するには

v1.3.0で実装されました。TypeScriptを使っている場合は$contentの引数に問題があるので、v1.3.1を使いましょう。

これでフラットな記事管理から解放されます。

const articles = $content('articles', { deep: true })

終わりに

開発速度が速く、どんどん機能追加がされていて、シンプルで使いやすい印象です。

実際に導入までの作業も簡単で、公式ドキュメントを見ながら行うことができました。

目的としていた記事の一元管理を短時間で構築することができました。今後ますます注目されそうな気がします。

Originally published at incrementleaf.net
ツイッターでシェア
みんなに共有、忘れないようにメモ

naoki0719

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント