LoginSignup
8
13

More than 3 years have passed since last update.

NuxtでGitベースのヘッドレスCMS機能を実現するNuxt/Contentの紹介

Last updated at Posted at 2020-05-22

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.jsmodulesプロパティを以下のように追加

  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単体で色々やりたいなぁという方にはぜひオススメ。

リンク

公式サイト

8
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
13