最近 VuePress で個人ブログの運用をはじめました。
ですが、VuePress 単体では記事の Markdown を自動で生成できないことに悩んでいたので、{{ mustache }} を使った簡易的な記事生成スクリプトを作りました。
イメージ的には hexo
の new コマンド のような感じです。
登場人物
new-post.js
と templates/*.mustache
を新規に追加します。
$ tree vuepress
.
├── new-post.js <------------------------- スクリプト本体
├── package.json
├── docs <-------------------------------- VuePress のプロジェクトフォルダ
│ ├── .vuepress
│ │ └── config.yml
│ └── _posts
│ └── 2019-12-31-newpost.md <------- 生成される markdown
└── templates <--------------------------- テンプレート フォルタ
├── base.mustache
└── header.mustache
スクリプトの実装
まずは、スクリプトです。mustache
を使うのでパッケージを入れておきます。
$ yarn add --dev mustache
スクリプト本体は git で管理 してますがここにも記載しておきます。そんな大したことはしてません。
機能:
- 引数で次の 3 つを指定
- ベースとなるテンプレート
- 記事のタイトル
- (optional) markdown のファイル名
- ベースとなるテンプレートに「タイトル」と「日付」を埋め込んで出力
- 出力するファイルは
2019-12-13-lower-case-title.md
のような名前
new-post.js
'use strict';
const fs = require("fs");
const path = require('path');
const mustache = require('mustache');
function formatedateDate(date, includesDatetime) {
const dateStr = [
date.getFullYear(),
("0" + (date.getMonth() + 1)).slice(-2),
("0" + date.getDate()).slice(-2)
].join("-");
const datetimeStr = [
("0" + date.getHours()).slice(-2),
("0" + date.getMinutes()).slice(-2),
("0" + date.getSeconds()).slice(-2),
].join(":");
return includesDatetime ? dateStr + " " + datetimeStr : dateStr;
}
function sanitizeTitle(title) {
return title.replace(/[ ?!@;'\\.]/g, '-').toLowerCase().replace(/^[ -]+|[ -]+$/g, "");
}
/** Parameters */
const postDir = path.join("docs", "_posts");
const templateEngine = {
name: "Mustache",
dir: "templates",
extension: ".mustache",
};
/** Parse arguments */
const usage = "Usage: node new-post.js <template-name> <title> [<title-for-filename>]";
const args = process.argv.slice(2, process.argv.length);
if (args.length != 2 && args.length != 3) {
console.error("Invalid arguments")
console.error(usage);
process.exit(1);
}
const templatePath = path.join(templateEngine.dir, args[0] + templateEngine.extension);
const title = args[1];
const filetitle = args[2] ? sanitizeTitle(args[2]) : sanitizeTitle(title);
const postFilename = formatedateDate(new Date(), false) + "-" + filetitle + ".md";
const postPath = path.join(postDir, postFilename);
/** Main */
fs.readFile(templatePath, 'utf8', function (err, templateData) {
if (err) throw err;
// render the template with mustache.
const renderedData = mustache.render(templateData, {
title: title,
date: formatedateDate(new Date(), true),
overview: title + "についての記事です。",
});
// write a markdown file out.
fs.writeFile(postPath, renderedData, {
flag: 'wx'
}, function (err) {
if (err) {
throw err;
}
console.log("Created a new post at: " + postPath)
});
});
テンプレートの実装
templates/<template-name>.mustache
にテンプレートを置いていきます。
base.mustache
---
title: "{{ title }}"
date: {{ date }}
category: その他
tags:
- タグ
---
{{ overview }}
<!-- more -->
# {{ title }}
[[toc]]
## はじめに
new-post.js
内の以下の部分が、テンプレートに値を代入して markdown をレンダリングする処理に相当します。
// render the template with mustache.
const renderedData = mustache.render(templateData, {
title: title,
date: formatedateDate(new Date(), true),
overview: title + "についての記事です。",
});
使い方
$ node new-post.js <template-name> <title> [<title-for-filename>]
# e.g.
$ node new-post.js base "はじめての Node.js" getting-started-with-nodejs