Metalsmithはやりたいことをプラグインで導入していくスタイルなので、若干のとっつきにくさはあるかもしれません。ただ、だいたいの仕組みとよく使うプラグインを把握してしまえばあとは自由にサイトを作ることができるようになってくるので、Node製でそういったものを求めているのであればMetalsmithが最良の選択になりそう。自分が使っているプラグインの可能性もあるけれども、ビルドは他のジェネレータと比較して、それほど早いといった感じはないなので記事数が膨大の場合には微妙なのかもしれない。
自分のサイトも今のところMetalsmithで作成しています。
インストール
まずはMetalsmithをインストール。
CLIを使う場合にはグローバルにインストールするのが普通なんだろうけど、CLIは使わないので普通にインストールしていきます。
npm init
npm install metalsmith --save
これだけではほとんど何もすることができません。必要なプラグインを自分でインストールしていきましょう。
プラグイン
よく使うプラグインをリストアップしておきます。
- metalsmith-branch: 指定されたパターンで分岐処理
- metalsmith-collections: ファイルのコレクションを生成
- metalsmith-permalinks: 出力ファイルのディレクトリを
\*.html
から*/index.html
に変更 - metalsmith-copy: ファイルのコピー、もしくは移動。リネームも可能
- metalsmith-layouts: テンプレートの処理
- metalsmith-tags: カテゴリ、タグページの出力
- metalsmith-markdown: Markdownの変換
- metalsmith-asciidoc: AsciiDocの変換
- metalsmith-filemetadata: 指定されたパターンにマッチするファイルにメタデータを追加
- metalsmith-except: メタデータの除外
- metalsmith-paths: メタデータに自身のパス情報を追加
- metalsmith-replace: メタデータの置き換え
- metalsmith-define: 使用するモジュールを一括で指定
- metalsmith-draft: draftをbuildから除外
- metalsmith-autotoc: ToC生成
- metalsmith-highlight: コードのハイライト
ブログ程度のものであれば必要なプラグインはだいたい揃っているので、プラグインを自作しないといけないようなことにはならないとおもう。
metalsmith-collections
ブログをつくる目的であればかなりの重要なプラグインなんだけど、いきなりMetalsmithを理解しないまま使おうとすると、何をするためにつかうプラグインなのかがわかりにくいとおもう。
metalsmith
.use(asciidoc())
.use(collections({
posts: {
pattern: '_posts/**.html',
sortBy: 'date',
reverse: true
}
}))
.use(templates())
こうするとテンプレート側でcollections.posts
を指定したとき、pattern
にマッチしたファイルのデータを呼び出すことができます。
ol
each item in collections.posts
li: a(href=item.path)= item.title
これは_posts/**.html
のファイルをメタデータのdate
で日付の新しい順にソートしたもので、一般的なブログのArchivesのページを想像するとわかりやすい。
next
とprev
にはソート順で前後にあるファイルのデータが含まれていて、よくあるブログの前後ナビゲーションはこのプラグインでつくることができます。
metalsmith-collectionsがあればmetalsmith-feedやmetalsmith-sitemapのようなプラグインを使わなくてもRSSのようなフィードやsitemap.xmlをつくることはそれほど難しいことではありません。
うっかりやりそうなミスとしてはcollectionを作るタイミングがはやすぎて、必要なmetadataをもっていない状態のcollectionをつくってしまうこと。
metalsmith
.use(asciidoc())
.use(collections({
posts: {
pattern: '_posts/*.html',
sortBy: 'date',
reverse: true
}
}))
.use(branch('_posts/*.html')
.use(fileMetadata([
{
pattern: '_posts/*.html',
metadata: {
template: 'posts/blog.jade',
autotoc: true
}
}
]))
)
.use(templates())
サンプルだから処理そのものはちょっと不自然になっているけれども、このサンプルのようにfileMetadata
でmetadataを追加するタイミングがcollectionを作成した後になっていると、このcollectionにはfileMetadata
で追加されたmetadataは含まれていないことになります。
metalsmith-layouts, metalsmith-filemetadata
Wordpressからの移行で、JekyllやOctopressのような静的ジェネレータを一切使ったことがない場合にはちょっとわかりにくいのかもしれません。
---
title: テスト投稿
date: 2015-06-12
tags: test
layout: post.jade
---
[[test]]
== テスト
これはテスト投稿です。
このAsciiDocの上部にある---
で囲まれている部分がYAML front-matterになります。テンプレートを使う場合にはここのメタデータにtemplateを追加して、テンプレートに使うファイルを指定するだけです。
ただブログの記事のようにそのフォルダ内すべてでかならず共通になるメタデータをすべてのファイルに記述するのは面倒なので、metalsmith-collectionsを使わないときにはmetalsmith-filemetadataをつかうのがおすすめ。
metalsmith
.use(asciidoc())
.use(fileMetadata([
{
pattern: '_posts/*.html',
metadata: {
layout: 'post.jade'
}
}
]))
これで_posts
直下にあるすべてのHTMLファイルのメタデータにtemplate: post.jade
が追加されます。
metalsmith-highlight
コードのハイライトにはすでにmetalsmith-metallicやmetalsmith-code-highlightがあったのですが、自分はAsciiDocを使っていたのでMarkdown限定のmetalsmith-metallicは使えず、metalsmith-code-highlightはコードの推論がいらなかったことと、classの言語のプレフィックスがlang-
である必要があったためmetalsmith-highlightというプラグインを作りました。
metalsmith-code-highlightはハイライトにhiglight.jsを使っていますが、metalsmith-highlightはPrismを使っています。
metalsmith
.use(highlight())
オプションの設定項目はありません。それとPrismでは言語の指定で短縮表記を使えないようだったので、いくつかの言語にエイリアスをつくってあります。
gulpからMetalsmithでサイトを生成する
Metalsmithで使うJavaScriptやCSSはgulpでビルドしたいので、Metalsmithのビルドでもgulpから実行したくなります。
gulpからMetalsmith、もしくはその逆を扱うためにgulpsmithというプラグインがあるのですが、デフォルトではYAML front matterを読み込めないため使うには面倒な記述が必要になるのでgulpからコマンドを実行することにしました。
var gulp = require('gulp');
var exec = require('child_process').exec;
gulp.task('build:metalsmith', function() {
exec('node metalsmith/build.js', function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
});
GitHub Pagesで公開する
作成したサイトをGitHub Pagesで公開します。masterブランチにコードと変換前のデータ、gh-pagesブランチに公開データをプッシュします。gh-pagesブランチを事前に作成する必要はありません。
git add . -A
git commit -m "message"
git push -u origin master
git subtree push --prefix public origin gh-pages
このとき最終的にビルドしたサイトをpublic
フォルダとすると、そのpublic
フォルダのビルド結果をmasterブランチに含めなければいけません。また毎回ローカルで出力結果をビルドする必要があるので少し面倒な方法です。
werckerでビルドしてgh-pagesにプッシュする
サイトのビルドからgh-pagesブランチへのプッシュするまでの流れはwerckerで自動化すると便利です。
まずプロジェクトのルートにwercker.yml
を作成します。
box: nodesource/trusty
build:
steps:
- npm-install
- script:
name: build
code: npm run build
deploy:
steps:
- lukevivier/gh-pages:
token: $GITHUB_TOKEN
domain: 4uing.net
basedir: public
検索でかかる情報の中には古い情報もあって、古い情報のwercker.yml
を使うとおそらく動きません。自分はまずboxの指定から間違えていてかなりハマりました。
werckerでの設定はとくに難しいところはありません。
Createからリポジトリを選択して指示通りにアプリケーションを作成、Deploy targetsのDeploy target nameにgh-pages
、
Auto deployにmaster
を指定します。Deploy pipelineにwercker.yml
で使用するGITHUB_TOKEN
を作成して終了です。
その他の静的サイトジェネレータ
Node.js製の静的サイトジェネレータにはMetalsmith以外にもいくつかあるので、Metalsmithの前に使ったことのあるジェネレータの簡単な紹介をしておきます。
Hexo
Node.js製のジェネレータの中ではGitHubのStar数が最上位なので、Node.js製という条件内であれば今のところ一番人気といっていいんじゃないかとおもう。
初期状態のCSSプリプロセッサがstylusになっていたり、デフォルトテーマのEJSがまるでWordpressのテンプレートをみているような記述になってるので、これだけでHexoが嫌いになりそうになったんだけども、このへんはすべて差し替え可能なので問題になることはありません。
<% if (theme.sidebar === 'bottom'){ %>
<%- partial('_partial/sidebar') %>
<% } %>
こういう記述はJadeに置き換えることができるので、以下のように記述することができます。
if theme.sidebar === 'bottom'
!= partial('_partial/sidebar')
ドキュメントがわかりやすいので、テーマの作成で困ることはないとおもう。コードのシンタックスハイライトにはhighlight.jsが使われているんだけども、Jekyllからの移植用のためなのかクラス名はPygmentsに準じたものになっていたりと、Jekyllからのテーマの移植もしやすいようになっているのかもしれません。
ヘルパーも結構便利でToCみたいなものから、記述が面倒になりがちなリンクや日付関連のものだったり色々と揃ってるのでテンプレートを自作するときにはまず一通り確認するとよさそう。
HubPress
静的サイトジェネレータでも、さまざまな環境から手軽にアップデートができるのがHubPress。記事の作成や更新はもちろんブログの作成からすべてをGitHubのページ上で行うことができます。
記事をMarkdownではなくAsciiDocで書くというのがわりと新鮮。AsciiDocの存在自体、HubPressで知ったんだけれども技術系のブログ記事であればAsciiDocのほうが書きやすいはず。ただこのAsciiDocが合わなかった場合、Markdownに変更するといったようなテンプレートエンジンの変更もできないので選択肢から除外されることになります。
ただそれよりも現状の移行における大きな問題は生成したHTMLファイルの出力先のフォルダを指定できないことで、これはつまり過去の記事はこれまでのURLとは異なるものにならざるをえないことを意味しています。ブログの移行ですべての記事のURLが変わることを許容することは難しいので、メインのブログからの移行はまだ現実的ではなさそう。