KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

Next.js Tutorial で使った path, fs, matter を Node.js のみで試してみた

why

gray-matter と remark の違いが分かってなかったので matter だけ動かしてみたかった

Next React ではなくてまず ES6 だけやった方がいいと言われるので Node でシンプルにやってみた

Next での matter の使用

nextjs.org

getStaticProps のためのサンプルに入っていた基礎

path と fs と matter を使って Markdown を取得していた。

lib/posts.js で

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'

3 つのライブラリを import して

const postsDirectory = path.join(process.cwd(), 'posts');

path でルートと読み取る先のディレクトリ名を合わせる。

この場合は ~/posts/ に入っているディレクトリのパスをまず取得する

const fileNames = fs.readdirSync(postsDirectory);

次に fs, file system の readdirSync read directory sync でそのディレクトリのパスから中に入っているファイル名を読み取る。これは配列になる。

nodejs.org

これが Node org の readdirSync の説明。Dir の D は大文字にならない

  const allPostsData = fileNames.map(fileName => {
    const id = fileName.replace( /\.md$/, '');
    const fullPath = path.join(postsDirectory, fileName);
    const fileContents = fs.readFileSync(fullPath, 'utf8');
    const matterResult = matter(fileContents);
    return {
      id, ...matterResult.data
    }
  })

最後に ファイル名の配列から map してファイル名一つ処理する。

ファイル名から .md を取り除いたものを id とし、

先ほど作った「読み取るディレクトリのパス」に更に map で一つ一つとってくる 「読み取るファイルのパス、ファイル名」を追加して、コンテンツを読み取れる完全なパスにする。

その完全なパスを fsreadFileSync read file sync で読み取り、 ついにファイルの中身を手に入れる。

nodejs.org

これが readFileSync の Nodejs.org の説明。

そして今度こそ最後の処理として、matter でファイルの中身を

Converts a string with front-matter, like this:

---
title: Hello
slug: home
---
<h1>Hello world!</h1>
Into an object like this:

このメタ空間の下に html テキストがある状態から

{
  content: '<h1>Hello world!</h1>',
  data: { 
    title: 'Hello', 
    slug: 'home' 
  }
}

json 形式で

  • content の html
  • data の title
  • data の slug

の形に変換する

return でこのコードでは title と slug だけを返している。


Node.js のみでやってみる

Node.js のみで matter での Markdownjson 変換を試す

import では err が出る

require を使わないといけないのを思い出した

www.npmjs.com

公式サイトを見ると、

const matter = require('gray-matter');

で import 相当をするようだ。

const mdData = `---\ntitle: Front Matter\n---\nThis is content. `
console.log(mdData)

const matteredMdData = matter(mdData)
console.log(matteredMdData)

Mark Down の データ形式を作って、そのデータと matter を通した後のデータを出力してみると

---
title: Front Matter
---
This is content. 
{
  content: 'This is content. ',
  data: { title: 'Front Matter' },
  isEmpty: false,
  excerpt: ''
}

このように、ヘッダーデータとコンテンツを分離して json にしているのがわかる。

path と fs で パスとファイル名を読み取る

const path = require('path')

const postsDir = path.join(process.cwd(), 'posts')
console.log(postsDir)

これを使うと

/Users/kaede/code/node/matter/posts

これが帰ってくる。

これで現在のディレクトリが path によって読み取られており

それに posts を追加できていることがわかる

また fs を使って そのパスから中身を読み取ってみる

const fs = require('fs')
const fileNames = fs.readdirSync(postsDir)
console.log(fileNames)

これで

[ 'text.md', 'text2.md' ]

が帰ってくる。受け取ったパスのディレクトリの中にあるファイルたちを認識できている。

fs.readFileSyinc と matter で 今の配列を読み取る

const allPostsData = fileNames.map(fileName => {
  const fullPath = path.join(postsDir, fileName)
  const fileContents = fs.readFileSync(fullPath, 'utf8')
  console.log(fileContents)
  const matterResult = matter(fileContents)
  console.log(matterResult)
})

Next.js Tutorial と同じく、 先ほど得られた fileNames を map して

fs.readFileSync にかけることとで map して一つずつとってきたファイル名で

ファイルの中身を md のまま読み取り

matter をかけることで

{
content: 'hoge'
data: { hage: 'hage', date: 'someday' },
isEmpty: false, 
}

の使いやすい json の形に持ってこれている。

実際の結果は

/Users/kaede/code/node/matter/posts
[ 'text.md', 'text2.md' ]
---
title: Hello
date: '2020-02-03'
---
content text here
2nd line
3rd line
{
  content: 'content text here\n2nd line\n3rd line',
  data: { title: 'Hello', date: '2020-02-03' },
  isEmpty: false,
  excerpt: ''
}
---
title: Hello
date: '2020-02-03'
---
text 2 main area here
{
  content: 'text 2 main area here',
  data: { title: 'Hello', date: '2020-02-03' },
  isEmpty: false,
  excerpt: ''
}

こうなった。

まとめ

Next 関係なく、Node 単体でも

path での読み取るディレクトリの指定

fs.readdirSync での中身のファイルたちの認識

認識したファイルたちの配列を map して

path での 先ほど使ったディレクトリのパスへの ファイル名の追加

fs.readFileSync での ファイルの中身の読み取り

matter での ファイルの中身の json 形式への変換

は行うことができた

次回

次回は 似たような Markdown 変換である remark.js を単体で使ってみる。