Nuxt/Contentって?
Nuxtでマークダウン形式のファイルをCMS風に使用するためのモジュールです。
一部では**ヘッドレスCMSいらなくなるんじゃね?**説まで出ているので、使ってみることにしました。
インストール
Nuxtはあらかじめインストールしておいてください。
今回は公式ドキュメントにはないTypeScript での使用法を紹介したいと思います。
追記
2020/06/22 Nuxt-app v3.1.0よりNuxt Contentが標準でサポートされるようになりました😍🎉✨
Nuxt-appを使ったインストールをする際は、途中でContentを入れるか聞かれるので、そのときスペースキーで○を入れておいてください。
以下のインストール方法はあくまで後で入れるときにご利用ください。
Nuxt/contentのインストール
yarn add @nuxt/content
次にnuxt.config.js
のmodules
プロパティを以下のように追加
modules: [
'@nuxt/content'
],
nuxt-composition-api(おまけ)
これはNuxt/Contentを使用するだけなら不要です。ただ自分はComposition-apiを普段から使っていて、
もしもNuxtでComposition-apiを使うときは@vue/composition-api
よりもこちらを使う方がオススメ
(今後のアップデートでは不要になるといいですね)
yarn add nuxt-composition-api
次にnuxt.config.js
に以下を追加
buildModules: [
'nuxt-composition-api'
]
ちなみに、自動的に@vue/composition-api
が読み込まれるので、nuxt-composition-api
からrefやreactiveが読み込めます。
contentディレクトリを作る
ルートディレクトリにcontent
ディレクトリを作ります(複数形ではありません)。
このディレクトリに入れた.md
ファイルがマークダウンとして認識されます。
.md
以外にも.yaml
.csv
.json
.json5
がパースされるそうです。
今回は後学のために、content
の下にさらにarticles
ディレクトリを作っていますが、これは任意で、特にディレクトリ名は制限はないと思います。
content/
articles/
article-1.md
例えばこんな感じになると思います。
article-1.mdの中身は適当なマークダウンを書いてみましょう。
ちなみにコードブロックも書けます。PrismJS をラップしてハイライティングしているようです。
pagesで表示する
ページコンポーネントで表示してみましょう。
pages/index.vue
にて以下のように記述します。
<template>
<article>
<h1>{{ doc.title }}</h1>
<nuxt-content :document="doc" />
</article>
</template>
<script lang="ts">
import { ref, onMounted, useContext } from 'nuxt-composition-api'
export default {
setup() {
const doc = ref({})
const ctx: any = useContext()
onMounted(async () => {
doc.value = await ctx.$content('articles/article-1').fetch()
})
return { doc }
}
}
</script>
シンプルですね。ちゃんと表示されていればOKです。表示したい記事を<nuxt-content>
タグに渡しています。
CMS的な使い方ですと、_slag.vue
といもうのを作って、コンテキストからparams
経由でslag変数を取得すればブログのページっぽく書けると思います。
useContext
はNuxtのコンテキスト情報を取得するもので、通常のsetup
の引数のコンテキスト変数とは異なります。
なぜctx
がanyかというと、型情報が今の所ないようなので、anyにしておかないとESLintとかに怒られるからです。
また、なぜ新世代のasyncData
に相当する useAsync
を使わないかというと、基本このNuxt/ContentがSPA/MPAで運用されると予想されるので、useAsync
は使えないと思い、onMounted
フックで使用しています。
この辺り「こっちの方がいいのでは?」というやり方を知っていれば教えてくれると助かります。
Vueコンポーネントをマークダウンに書く
マークダウン上でVueコンポーネントを使ってみることにします。
今回はただただカウントするだけのコンポーネントを作って置いてみましょう。
~/components/TheCounter.vue
<template>
<div>
{{ count }}
<button @click="add()">ADD!</button>
</div>
</template>
<script lang="ts">
import { ref, defineComponent } from 'nuxt-composition-api'
export default defineComponent({
name: '',
setup() {
const count = ref(0)
const add = () => count.value++
return {
count,
add
}
}
})
</script>
次にマークダウン上にこのコンポーネントを書きます。
書くのですが、必ずケバブケース & セルフクロージングタグではない書き方にしてください。
具体的には以下のような形式で書いてください。
OK!
<the-counter></the-counter>
NG! ケバブケースじゃない
<TheCounter></TheCounter>
NG! セルフクロージングタグになっている
<the-counter />
最後に、<nuxt-content>
を表示するVueファイルにて、コンポーネントを登録しておきます。
<template>
<article>
<h1>{{ doc.title }}</h1>
<nuxt-content :document="doc" />
</article>
</template>
<script lang="ts">
import { ref, onMounted, useContext } from 'nuxt-composition-api'
import TheCounter from '~/components/TheCounter.vue'
export default {
name: '',
components: { TheCounter },
setup() {
const doc = ref('')
const ctx: any = useContext()
onMounted(async () => {
doc.value = await ctx.$content('articles/article').fetch()
})
return { doc }
}
}
</script>
これで表示されていればOKです。
終わりに
Vueコンポーネントをマークダウンに直接書けるというのは、なかなか画期的なのではないでしょうか?
その気になれば簡単な投票コンポーネントとか、メールフォームをどこにでも置けるという感じになると思います。
Nuxt/contentはまだ生まれたばかりで、ドキュメントもまだ少ないというのが現状です。
公式サイトで「acting as Git-based Headless CMS」(GitベースのヘッドレスCMSとして機能)とあるように、Nuxtで機能するヘッドレスCMS的な何かな使い方が可能です。
なんかヘッドレスCMSって覚えること多いなぁとか、Nuxt単体で色々やりたいなぁという方にはぜひオススメ。