Hugoの新しい記事作成時にファイル名を自動生成する


あらすじ

Hugoで新しい記事を作成するときにパス(記事のファイル名)を考えるのが面倒だったので、ファイル名を自動生成することにした。

Hugoでの記事作成方法

Hugoでは次のコマンドで記事を作成できる(参考:hugo new | Hugo)。

hugo new [path] [flags]

使用例:

hugo new posts/my-first-post.md

コンテンツのディレクトリを変更していない場合はcontent/posts/my-first-post.mdにファイルが作成される。

パスを元に記事のテンプレート(archetypes/*)を選択して新しい記事を生成する(参考:Archetypes | Hugo)が、結果としてはファイルを作っているだけなのでコマンドを叩かずに手で作成してもよい?🤔(日付の入力は面倒だが)

ちなみに、既に存在するパスでコマンドを叩くと「既にファイルが存在するため」新しいファイルを作成できない(自動生成するときにファイルの存在チェックを行わなくても良さそう)。

実装の方針

どのタイミングでどうやってパスを自動生成しコマンドを叩くのか考えたところ、氷砂糖のスキルだと「Node.jsでパスを生成してそのままコマンドを叩く」方法が簡単そうだった。

パスのフォーマット

生成するパスのフォーマットは、NotionのCopy linkから取得できるURLを参考に「16進数っぽい32文字の文字列」にした。

生成するURLのイメージ:

http://localhost:1313/efa373e28f78af98644500de87092dbd

実装

パスの生成

パスの生成には、検索で見つけたNano Idを使用する。

初期化とパッケージの追加:

yarn init -y
yarn add --dev nanoid

nenoidを使用すると、URLフレンドリーな21文字のIDを生成できる。

const { nanoid } = require('nanoid')
const id = nanoid()
console.log(id)
// 生成例: V2dAP3vwixvuA-iY2P9UO

生成する文字数を変えたい場合は第1引数で指定できる。

const { nanoid } = require('nanoid')
const id = nanoid(8)
console.log(id)
// 生成例: NUS_PAQc

今回は「16進数っぽい32文字の文字列」を生成したいので、customAlphabetで使用文字と文字数を指定して対応する。

const { customAlphabet } = require('nanoid')
const nanoid = customAlphabet('0123456789abcdef', 32)
const id = nanoid()
console.log(id)
// 生成例: efa373e28f78af98644500de87092dbd

コマンドの実行

Node.jsでは次のようにして同期的にコマンドを実行できる。

const { execSync } = require('child_process')
const command = 'echo 1'
const stdout = execSync(command, { encoding: 'utf8' })
console.log(stdout)

execSyncを実行するときにencodingを指定しないと返り値がBufferになる。

console.logを使用するとstdoutの行末の改行とconsole.log自体の改行で1行開いてしまうため、回避するにはstdouttrimしたり、process.stdout.writeを使用するといいかもしれない🤔

// stdoutをtrim
console.log(stdout.trim())
// process.stdout.writeを使用
process.stdout.write(stdout)

先ほどのパス生成と組み合わせるとこのような感じになる🤔

const { execSync } = require('child_process')
const { customAlphabet } = require('nanoid')
const nanoid = customAlphabet('0123456789abcdef', 32)

const id = nanoid()
const command = `hugo new ${id}.md`
const stdout = execSync(command, { encoding: 'utf8' })

process.stdout.write(stdout)

スクリプトの使用準備

新しい記事を作成するスクリプトをscripts/new.jsに実装する。

実装後、package.jsonnode scripts/new.jsを実行するコマンドを追加する。

{
  "scripts": {
    "new": "node scripts/new.js"
  }
}

このコマンドを追加した場合、yarn newで記事を作れるようになる。

参考