Tech

Nuxt.jsとFirebaseでサイトを作った話 -3- Markdownの変換とNuxtへの組み込み

TL;DR

Markdownを書くフォルダを作成して、それを変換、Nuxtへの組み込みについて

Markdownの変換機構

はじめに

processmd というライブラリを使用しますが、markdown-itに今後できればと思っていたりします

他にもremark 等がありますが、Reactやその静的サイトジェネレータであるgatsbyがremarkに対応していて、nuxtやvuepressはmarkdown-itの方っぽいのでmarkdown-itにしようかなという感じです

変更したら追記しますが、今回はprocessmdを使用します。

追記

変更しました!
Nuxt.jsとFirebaseでサイトを作った話 続編-1- markdown変換の見直し

フォルダツリー

コードの構造がややこしくなるので、先にフォルダツリーを紹介します。

├── note
|  ├── draft
|  |  └── nuxt-firebase-blog.md
|  ├── json
|  |  └── 2018-04-13-generate-stylelint-report-by-rule.json
|  ├── markdown
|  |  └── 2018-04-13-generate-stylelint-report-by-rule.md
|  └── summary.json

プロジェクトルートに note というフォルダを作成してそこで書いています。
一発でかけないものは draft に書き溜めていって、公開する時に日付を添えてmarkdownフォルダに入れて公開します。

mdの中にプロパティみたいなものを書けるのでmarkdownの中で公開用のステータスを保持するのも有りだと思います。

実際に変換する

フォルダーツリーを踏まえた上で変換タスクの作成です。

    "convertmd": "processmd \"note/markdown/**/*.md\" --preview 160 --stdout --outputDir note/json > note/summary.json"

jsonフォルダに一つ一つのmarkdownの変換されたjsonデータ、
summary.json に全体の概要データが出力されます。
また、 --preview のオプションで一覧表示用の短い文章抽出を行っています。

そしてこの機能がたまに上手くいっていません(空白文字が出てきたりする)

一旦はこれでスタートは切れているものの、結構多くの無駄なデータが含まれるのでいい感じに変換できる何かが欲しいかもしれませんね。
vuepressとかのコード読んでどういうことやってるか見るのもいいかもしれません。

一覧/記事ページを作る

記事ページの作成

pages/note/_date/_slug/index.vue を作成します。

template:

<div class="post" v-html="bodyHtml"></div>

scripts:

  import { sourceFileArray } from '../../../../note/summary.json';

  export default {
    data: function () {
      return {
        tag: null
      }
    },
    validate({ params }) {
      return sourceFileArray.includes(`note/markdown/${params.date}-${params.slug}.md`);
    },
    asyncData({ params }) {
      return Object.assign({}, require(`~/note/json/${params.date}-${params.slug}.json`), { params });
    },
    head() {
      const url = `${this.url}/note/${this.params.date}/${this.params.slug}/`;
    },
  };

見た目等は変換後のhtmlを見つつ調整します。

一覧ページの作成

pages/note/index.vue を作成して
一覧ページも似たような感じでsummary.jsonからデータを取得して記事の簡易情報表の示と記事に対するリンクを設定します。

この問題として記事数が数百とかになっても恐らく全データの概要のデータを取得してしまうという点です。
テキストなのでサイズ的には大したことはないとはいえども延々と膨れ上がるデータになってしまうため、
こちらも思いつきでいえば同じプロジェクトで開発しているのでsummaryのデータを読み取って一部を返すAPIを作ってもよいかもしれません。

ただそういうことばっかりやっていると nuxt generate でやっている意味がなさげ…にも思えなくもないですね。

generateタスクの編集

nuxtのgenerateはデフォルトでは _date _slug という動的な部分については nuxt generate しても生成されません。
なので手動でこれらのパスを教えて生成するようにしなければいけないのでnuxt.config.jsを編集します。

最終形はこんな感じです

  generate: {
    ...
    routes: generateDynamicRoutes,
  },

この関数の実装はこんな感じです。

const { sourceFileArray } = require('./note/summary.json')
const generateDynamicRoutes = callback => {
  const routes = sourceFileArray.map(sourceFileName => {
    return sourceFileNameToUrl(sourceFileName);
  });
  callback(null, routes);
};

sourceFileNameToUrl はこんな感じです(雑コード…)

  sourceFileNameToUrl(filepath) {
    const deleteExt = filepath.replace('.md', '')
    const fileName = deleteExt.split('/')[deleteExt.split('/').length - 1]
    const splitArray = fileName.split('-')
    return `/note/${splitArray.slice(0, 3).join('-')}/${splitArray.slice(3,).join('-')}`
  }

こうすることで動的で無視される部分を手動で登録できるので、
これによってそのURLはgenerate時にもHTMLが生成されるようになります。

おわりに

ちょっとまだ課題が多い記事詳細、記事一覧部分ですが、一旦は上記のような感じで作れると思います。

目次

このサイト作ったぞシリーズです。

share