Nuxt.js に MarkDown を読み込む
create: 2019-11-29
Blog Nuxt化 Nuxt.js Markdown

ブログをHexoからNuxt.jsに移行するに当たり、過去記事のMarkdownファイルは捨てたくありません。
.vueへのコンバートも面倒です。

なので、引き続き記事はMarkdownで書きつつ、Nuxt.jsで Vue テンプレートにロードする方式にします。
Nuxt のジェネレート時にMarkdownファイルを取り込む方式です。

frontmatter 対応で記事に属性をもたせたい

frontmatterとは、md ファイルの先頭に yaml 形式で記事に属性を持たせる方法です。

---
title: Nuxt.js に MarkDown を読み込む
tags: [Blog Nuxt化, Nuxt.js, Markdown]
date: 2019-11-28
parent: nuxt-blog-index
---

ブログを`Hexo`から`Nuxt.js`に移行するに当たり、過去記事の`Markdown`ファイルは捨てたくありません。
`.vue`へのコンバートも面倒です。...

↑ md ファイルの頭に --- で囲まれた部分が記事属性になります。
この記事にはtitletagsdateparentの属性が設定されています。

これをvueに読み込ませたい!

nuxt.config.js で md ファイルのロードに対応する

.mdファイルのローダーを設定して、JavaScriptで扱いやすくします。
frontmatterを扱えるローダーがnpmパッケージに公開されていたので、ありがたく利用させていただきます。
frontmatter-markdown-loader

ライブラリのインストール

yarn add -D frontmatter-markdown-loader

nuxt.config.js に登録する

.mdファイルのローダーとしてfrontmatter-markdown-loaderを登録します。
これで.mdファイルをimportするとJavaScriptオブジェクトになります。
ソースコードのハイライト表示もしたいので、highlight.jsとも連携しています。

import hljs from 'highlight.js'
export default {
  build: {
    extend(config, _ctx) {
      config.module.rules.push({
        test: /\.md$/,
        loader: 'frontmatter-markdown-loader',
        options: {
          markdownIt: {
            html: true,
            linkify: true,
            breaks: true,

            // ソースハイライトするためにhighlight.jsと連携
            highlight(str, lang) {
              if (lang && hljs.getLanguage(lang)) {
                try {
                  return hljs.highlight(lang, str).value
                } catch (e) {
                  console.error(e)
                }
              }

              return '' // use external default escaping
            }
          }
        }
      })
    }
  }
}

md ファイルをロードしてみる

test.mdを作成して読み込ませてみる。

md ファイルの作成

---
title: テストタイトル
tags: [tag1, tag2, tag3]
date: 2019-11-28
---

# 本文タイトル

本文のテスト1
本文のテスト2

md ファイルのロード

import md from './test.md'
console.log(JSON.stringify(md))

ログにこんなのが出る。

{"attributes":{"title":"テストタイトル","tags":["tag1","tag2","tag3"],"date":"2019-11-28T00:00:00.000Z"},"html":"<h1>本文タイトル</h1>\n<p>本文のテスト1<br>\n本文のテスト2</p>\n"}

おお、できてる!

見やすく整形したのがこちら。

{
  "attributes": {
    "title": "テストタイトル",
    "tags": ["tag1", "tag2", "tag3"],
    "date": "2019-11-28T00:00:00.000Z"
  },
  "html": "<h1>本文タイトル</h1>\n<p>本文のテスト1<br>\n本文のテスト2</p>\n"
}

vue ファイルに流し込む

結果の JSON を見るに、

  • attributes属性にfrontmatterで記述された属性
  • html属性にHTML形式に変換された本文

が登録されているようです。

HTML形式になっているので、このまま流し込めばいいですね。

<template lang="pug">
.posts-contents
  .title.is-1 {{md.attributes.title}}
  .markdown-body(v-html="md.html")
</template>
<script>
  import md from './test.md'
  export default {
    data() {
      return {
        md
      }
    }
  }
</script>

ウルトラ上手にできましたー!!
これを応用すればタグや日付表示などにも使えそうです!

frontmatter の記述について補足

hexoのときにできていたfrontmatter記法が、frontmatter-markdown-loaderでは読めないパターンが有りました。

hexoのときに書いていた記法、いわゆるハッシュの中に配列を書く書き方です。

tags:
  - tag1
  - tag2
  - tag3

これがfrontmatter-markdown-loaderでは読めなかったので、下記のように対応しました。

tags: [tag1, tag2, tag3]

ここだけほぼ全ファイルに修正が入りましたが、重要な本文はノーメンテで持っていけたので良かったです!