nuxt/contentといういい感じにブログを作成できるモジュールがあったので使ってみる。
このブログもnuxt/content
を利用しています。
2021-04-24: 新しくブログ(Rustに入門してみた)を作ったのでその時の最新バージョンに更新しました。
Table of Content
- nuxt/content
- 環境
- Nuxt.jsのインストール
- ページを追加する
- コンテンツの取得とクエリ
- シンタックスハイライト
- Google Analytics
- Google Adsense
- テストしてみる
- マークダウンの書式を拡張する
- サイトマップを作成する
nuxt/content
nuxt/contentはNuxtjsアプリケーションを拡張するモジュールです。
GitベースのヘッドレスCMSとして機能します。
content/
ディレクトリに書き込んだMarkdown、JSON、YAML、XML、CSVファイルといったファイルをMongoDBのAPIような機能で扱えるようになります。
特徴
- 開発中の高速ホットリロード
- Markdownの中でのVueコンポーネント
- 全文検索
nuxt generate
で静的サイト生成をサポートする- (MongoDBのような)強力なQueryBuilderAPI
- PrismJSを使用してマークダウンファイルのコードブロックを強調表示する構文。
- 目次の生成
- マークダウン、CSV、YAML、JSON(5)、XMLを処理します
- カスタムパーサーでの拡張(Latexや引用符など)
/content
に書いたマークダウンがそのままコンテンツになります。
ホットリロードも対応しているため、ローカルでマークダウンを書きながらすぐに内容とスタイルを確認できます。
また、マークダウンの中に書いた変数でフィルタリングしたりページの構成に使えるようになります。
---
id: 264
title: nuxt/contentでブログを作る
created_at: 2020-12-12
updated_at: 2020-12-17
isDraft: false
tags: Nuxtjs,Vuejs,TypeScript,JavaScript
top_image: /icons/nuxt.svg
icon: /icons/nuxt.svg
---
## 本文
咳をしても一人
DBを使っていないのにかなり自由度が高い。
Create a Blog with Nuxt Contentを参考に作ってみます。
環境
- Node.js vv14.16.1
- npm 6.14.12
- yarn 1.22.5
構築後
- Nuxt: ^2.14.6
- @nuxt/content: ^1.11.1
Nuxt.jsのインストール
公式のインストールをみてプロジェクトを作るところから進める。
アプリを作成したいパスでyarn create nuxt-app <project-name>
を実行する。
yarn
で進めます。npm
とnpx
は公式をみておくれ。
> yarn create nuxt-app myblog
。。。
create-nuxt-app v3.4.0
✨ Generating Nuxt.js project in myblog
# プロジェクト名
? Project name: myblog
# ここでTypeScriptを選べる
? Programming language:
JavaScript
> TypeScript
# パッケージマネージャ
? Package manager: (Use arrow keys)
> Yarn
Npm
# UIフレームワーク
? UI framework:
None
Ant Design Vue
Bootstrap Vue
Buefy
> Bulma
Chakra UI
Element
Framevuerk
iView
Tachyons
Tailwind CSS
Vuesax
Vuetify.js
# ここで@nuxt/contentをインストール出来る
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Axios
( ) Progressive Web App (PWA)
(*) Content
# リントツール
? Linting tools:
(*) ESLint
>(*) Prettier
( ) Lint staged files
( ) StyleLint
( ) Commitlint
# テストツール
? Testing framework:
None
> Jest
AVA
WebdriverIO
# レンダリングモード
? Rendering mode: (Use arrow keys)
> Universal (SSR / SSG)
Single Page App
# デプロイターゲット
? Deployment target:
Server (Node.js hosting)
> Static (Static/JAMStack hosting)
? Development tools:
>(*) jsconfig.json (Recommended for VS Code if you're not using typescript)
( ) Semantic Pull Requests
( ) Dependabot (For auto-updating dependencies, GitHub only)
# CIツール
? Continuous integration:
None
> GitHub Actions (GitHub only)
? What is your GitHub username? (suzuroku)
? Version control system: (Use arrow keys)
> Git
None
select
で選択する。
キーが効かないときはないときは日本語入力になってます。
プロジェクト作成時にTypeScriptの導入もしておくと楽です。
レンダリングモードとデプロイターゲットはnuxt.config.js
のtargetで後から変更できます。
作成したディレクトリに移動して、アプリを立ち上げます。
$ cd myblog
$ yarn dev
## 静的サイトを作成する
# dist/ に静的サイトのページが作る
$ yarn run generate
# dist/ のページを確認する
$ yarn run start
ページを追加する
/posts/{記事}
となるようにページを追加します。
また、/posts/
は一覧になるようにする。
├─content # マークダウンを置くところ。
| ├─ about.md
│ └─posts
│ ├─post1.md
│ └─post2.md
├─pages # そのパスの処理
| ├─_slug.vue
│ └─posts
│ ├─index.vue # /posts/ で一覧を表示する
│ └─_slug.vue # /posts/{_slug} パスを引数にとる
記事のマークダウン
---
title: nuxt/contentでブログを作る
created_at: 2020-12-12
tags: Nuxtjs,Vuejs,TypeScript,JavaScript
top_image: /icons/nuxt.svg
icon: /icons/nuxt.svg
---
## 本文
咳をしても一人
記事を表示するVueページ
CSSフレームワークのbulmaを利用しています。
<template>
<article class="article content section-article">
// 記事のヘッダー部分の例
<section class="header">
<h1>{{ post.title }}</h1>
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="post.top_image" />
</figure>
</div>
<div class="media-content">
<div class="tags">
<i class="mdi mdi-tag" />&nbsp;
<span v-for="tag in post.tags.split(',')" :key="tag">
<a :href="'/tags/' + tag" class="tag">{{ tag }}</a>
</span>
</div>
</div>
<div class="media-right">
<i class="mdi mdi-update" />&nbsp;
<time v-html="post.updated_at.split('T')[0]"></time>
</div>
</div>
</section>
// 記事の本文
<NuxtContent :document="post" />
</article>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
async asyncData({ $content, params }) {
// URIから変数を取得 /posts/{_slug}
const slug = params.slug
return {
// content/posts/{_slug}.mdのマークダウンを取得
post: await $content('posts/' + slug).fetch()
}
},
})
</script>
TypeScriptのこの形になるまでかなり試行錯誤した。
コンテンツの取得とクエリ
Contentはグローバルに content `を使えばどこからでもアクセスできる。
例
// クエリのイメージ
list = {
[{ title: 'article1', tags: 'Nuxtjs,ブログ'}],
[{ title: 'article2', tags: 'Python'}],
[{ title: 'article3', tags: '数式,KaTeX'}],
};
$content(list)
.sortBy(title, asc)
.limit(2)
// titleで昇順に2件取得する
$content(list)
.only('tags')
.where({ 'tags': { $contains: [ 'Nuxtjs' ] } })
// tagsに絞ってtagsの文字列に'Nuxtjs'を含むオブジェクトをフィルタリングする。
$contentのWhere句は内部的にtechfort/LokiJSを利用している。 クエリの詳細とたくさんの例が載っているので、ぜひ参照してください。
シンタックスハイライト
Google Analytics
yarn add --dev @nuxtjs/google-analytics
googleAnalytics: {
id: process.env.GOOGLE_ANALYTICS_ID
},
GOOGLE_ANALYTICS_ID
は環境変数。
Google Adsense
$ yarn add @nuxtjs/google-adsense
modules: [
['@nuxtjs/google-adsense', {
id: process.env.GOOGLE_ADSENSE_ID
}]
]
GOOGLE_ADSENSE_ID
は環境変数。
<template>
<div>
<adsbygoogle
:ad-slot="'xxxxxxxx'"
:ad-style="{ display: 'block' }"
:ad-format="'auto'"
/>
</div>
</template>
手動広告は、このようにしてページ内の広告を表示したい場所に書くことができる。
ad-slot
は広告キーで、アドセンスで広告ユニットを作ると発行される。
テストしてみる
プロジェクト作成で追加したJestでユニットテストをします。
import { mount } from '@vue/test-utils'
import Logo from '@/components/Logo.vue'
describe('Logo', () => {
test('is a Vue instance', () => {
const wrapper = mount(Logo)
expect(wrapper.vm).toBeTruthy()
})
})
$ yarn test
yarn run v1.22.5
$ jest
PASS test/Logo.spec.js
Logo
√ is a Vue instance (15 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 0 | 100 | 100 | 0 |
index.vue | 0 | 100 | 100 | 0 | 29
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.69 s
Ran all test suites.
Done in 5.96s.
マークダウンの書式を拡張する
nuxt/contentに絵文字と数式のプラグインを追加するって記事に書きました。