Nuxt.jsを使いつつ、ブログのような静的なページを作るのに適したNuxt Content
。
そのNuxt ContentをNuxt.jsのプロジェクトに導入する方法を記載します
検証した環境
1 | yarn | 1.22.4 |
2 | nuxt | 2.14.12 |
3 | @nuxt/content | 1.13.1 |
前提
create nuxt-app
を実行した際は以下のようにしました。
TypeScript
を選びつつ、その他は必要最低限にしました。
create-nuxt-app v3.5.2
✨ Generating Nuxt.js project in add-nuxt-content-sample
? Project name: add-nuxt-content-sample
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Linting tools: Prettier
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: Git
$ yarn run dev
を実行した時は以下のようになります
Nuxt Contentのパッケージを追加
Nuxt Contentのパッケージを追加します
yarnの場合
$ yarn add @nuxt/content
npmの場合
$ npm install @nuxt/content
パッケージが導入出来ている事を確認。
プロジェクトフォルダでnpm ls
を使って@nuxt/content@<バージョン番号>
が表示されればOK!
$ npm ls --depth=0 | grep nuxt
2:├── @nuxt/content@1.13.1 //この行が表示される
3:├── @nuxt/types@2.14.12
・・・
configファイルの編集
Nuxt Contentを使う事をnuxt.config.js
に記載
export default {
modules: ['@nuxt/content'],
}
TypeScriptの場合
TypeScriptの場合、tsconfig.json
に追記を行う必要があります。
公式に書いてある通り、 @nuxt/types
もしくは@nuxt/vue-app
の後ろに書く必要があります。
{
"compilerOptions": {
・・・
},
"types": [
"@types/node",
"@nuxt/types",
"@nuxt/content" //@nuxt/typesの後に追記
]
}
「なぜ?」というのが公式に書いてあってパッと見「??」てなるんですけど
nuxt の動作方法のため、コンテキストの $content プロパティは TypeScriptのdeclaration merging機能 を通して、nuxt Context インターフェースにマージする必要があります。型に @nuxt/content を追加すると、パッケージから型をインポートし、TypeScript が Context インターフェースに追加されたものを認識するようになります。
要は $context
を@nuxt/types
のContext
インタフェースに追加して使えるようにするよ、という事を言っています。
<script lang="ts">
import { Context } from '@nuxt/types'
export default {
async asyncData({ $content, params }: Context) {
const articles = await $content('articles').fetch()
・・・
実際に記事を取得する部分では上記のように書きます。
@nuxt/types
の後ろに@nuxt/content
を書かないと{ $content, params }: Context
の部分で
Property '$content' does not exist on type 'Context'.
と怒られます。
サンプル用の記事を追加
記事を書くためのフォルダを作成します。
Nuxt Contentではデフォルトでプロジェクト直下の「content」フォルダ配下に記事のファイルを作成するルールになっています
content/
articles/
sample-01.md
sample-02.md
articles
というフォルダ名は何でも問題なく、例えばblogs
やnews
といったフォルダ名もつけられます。
マークダウンが正しく表示出来るか試したいので「sample-01.md」は以下のようにしました。
---
title: sample-01のタイトル
description: Learn how to use @nuxt/content.
---
# h1 Heading
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with '+', '-', or '*'
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as '1.'
Start numbering with offset:
57. foo
1. bar
マークダウンの頭の部分
---
title: Introduction
description: Learn how to use @nuxt/content.
---
は 「Front Matter」(フロントマター) と言って、静的ジェネレーターでよく使われているイメージのもので、 Front Matter | Jekyll • シンプルで、ブログのような、静的サイト
カテゴリやタグなんかを設定する事も出来ます。
Nuxt Contentの場合、.md
内でVueのコンポーネントが使えるため、公式のようなこんな便利な使い方も!
何これすごいんですけど!!
記事一覧と記事詳細ページを作る
フォルダ階層は以下のように
pages/
articles/
_slug.vue //記事詳細
index.vue //記事一覧(トップページ
「articles/」というフォルダ名はURLになります。
↑の場合https://hogehoge.com/articles/sample-01
というURLにアクセスすると
「sample-01.md」の内容が表示されます。
「pages/blogs/_slug.vue」とすればhttps://hogehoge.com/blogs/sample-01
に。
とっても簡素ですがまずコード
記事一覧
<template>
<ul>
<li v-for="article in articles" :key="article.slug">
<nuxt-link :to="`/articles/${article.slug}`">
{{ article.title }}
</nuxt-link>
<p>{{ article.updatedAt }}</p>
</li>
</ul>
</template>
<script lang="ts">
import { Context } from '@nuxt/types'
export default {
async asyncData({ $content, params }: Context) {
const articles = await $content('articles').fetch()
return { articles }
}
}
</script>
記事詳細
<template>
<main>
<h1>{{ article.title }}</h1>
<nuxt-content :document="article" />
</main>
</template>
<script lang="ts">
import { Context } from '@nuxt/types'
export default {
async asyncData({ $content, params }: Context) {
const article = await $content('articles', params.slug).fetch()
return { article }
}
}
</script>
無事表示が出来ました!
コードについて
以下のコードで全ての記事が取得出来ます
async asyncData({ $content, params }: Context) {
// 記事を全て取得する
const articles = await $content('articles').fetch()
// 記事をdataに設定する
return { articles }
}
$content('articles').fetch()
は $content('<content/<フォルダ名>')
になります。
例えば以下の場合は $content('blogs').fetch()
になります
content/
blogs/
sample-01.md
sample-02.md
return { articles }
はNuxtのasyncData()
の書き方のため詳細は省きますが、
最終的にVueのdata
に格納しています。
記事詳細の取得は以下
async asyncData({ $content, params }: Context) {
const article = await $content('articles', params.slug).fetch()
return { article }
}
$content
は第2引数文字列を渡す事で以下のように変換されます
$content('articles', 'sample-01')
→/articles/sample-01
この事については Nuxt Content の公式ドキュメントに書かれています。
引数を複数与えることもできます。
$content('article', params.slug)
は/articles/${params.slug}
に変換されます。
params.slug
はNuxtの書き方になるので詳細は省きますが、ファイル名を_slug.vue
としているからです。
例えばファイル名を_file.vue
とした場合、params.file
になります。
NuxtのプロジェクトにNuxt Contentを追加するサンプルコードGitHubに上げてあります