これまで nuxt と microCMS を組み合わせて JAMStack なブログを Netlify で公開していましたが、コンテンツ自体も一緒に管理できたほうが効率的かつ外部サービスに依存したくないと考え、作り直しのため markdown-it を採用つもりでした。
しかし@nuxt/content が公開されたことを知り、早速導入をしてみました。
nuxt generate
で静的サイトの生成まずはパッケージをインストールします。
yarn add @nuxt/content
次に nuxt.config.ts に以下を追加します。
# nuxt.config.ts
{
modules: [
'@nuxt/content',
],
content: {
// デフォルト以外の設定
}
}
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
のように配列で記述できます。
これらのメタデータはクエリを使って絞り込みに利用できます。
注意点としてtitle
をtitle: 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 })
開発速度が速く、どんどん機能追加がされていて、シンプルで使いやすい印象です。
実際に導入までの作業も簡単で、公式ドキュメントを見ながら行うことができました。
目的としていた記事の一元管理を短時間で構築することができました。今後ますます注目されそうな気がします。