静的サイトをMetalsmithでビルドし、Github Pagesにwerckerでデプロイする

Metalsmithはやりたいことをプラグインで導入していくスタイルなので、若干のとっつきにくさはあるかもしれません。ただ、だいたいの仕組みとよく使うプラグインを把握してしまえばあとは自由にサイトを作ることができるようになってくるので、Node製でそういったものを求めているのであればMetalsmithが最良の選択になりそう。自分が使っているプラグインの可能性もあるけれども、ビルドは他のジェネレータと比較して、それほど早いといった感じはないなので記事数が膨大の場合には微妙なのかもしれない。

* [hbsnow/4uing.net](https://github.com/hbsnow/4uing.net)

自分のサイトも今のところMetalsmithで作成しています。

## インストール

まずはMetalsmithをインストール。

CLIを使う場合にはグローバルにインストールするのが普通なんだろうけど、CLIは使わないので普通にインストールしていきます。

```ps1
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を理解しないまま使おうとすると、何をするためにつかうプラグインなのかがわかりにくいとおもう。

```js
metalsmith
  .use(asciidoc())
  .use(collections({
    posts: {
      pattern: '_posts/**.html',
      sortBy: 'date',
      reverse: true
    }
  }))
  .use(templates())
```

こうするとテンプレート側で`collections.posts`を指定したとき、`pattern`にマッチしたファイルのデータを呼び出すことができます。

```jade
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をつくってしまうこと。

```js
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のような静的ジェネレータを一切使ったことがない場合にはちょっとわかりにくいのかもしれません。

```adoc
---
title: テスト投稿
date: 2015-06-12
tags: test
layout: post.jade
---

[[test]]
== テスト
これはテスト投稿です。
```

このAsciiDocの上部にある`---`で囲まれている部分がYAML front-matterになります。テンプレートを使う場合にはここのメタデータにtemplateを追加して、テンプレートに使うファイルを指定するだけです。

ただブログの記事のようにそのフォルダ内すべてでかならず共通になるメタデータをすべてのファイルに記述するのは面倒なので、metalsmith-collectionsを使わないときにはmetalsmith-filemetadataをつかうのがおすすめ。

```js
metalsmith
  .use(asciidoc())
  .use(fileMetadata([
    {
      pattern: '_posts/*.html',
      metadata: {
        layout: 'post.jade'
      }
    }
  ]))
```

これで`_posts`直下にあるすべてのHTMLファイルのメタデータに`template: post.jade`が追加されます。

### metalsmith-highlight

コードのハイライトにはすでに[metalsmith-metallic](https://github.com/weswigham/metalsmith-metallic)や[metalsmith-code-highlight](https://www.npmjs.com/package/metalsmith-code-highlight)があったのですが、自分はAsciiDocを使っていたのでMarkdown限定のmetalsmith-metallicは使えず、metalsmith-code-highlightはコードの推論がいらなかったことと、classの言語のプレフィックスが`lang-`である必要があったため[metalsmith-highlight](https://www.npmjs.com/package/metalsmith-highlight)というプラグインを作りました。

metalsmith-code-highlightはハイライトに[higlight.js](https://highlightjs.org/)を使っていますが、metalsmith-highlightは[Prism](https://prismjs.com/)を使っています。

```js
metalsmith
  .use(highlight())
```

オプションの設定項目はありません。それとPrismでは言語の指定で短縮表記を使えないようだったので、いくつかの言語にエイリアスをつくってあります。

## gulpからMetalsmithでサイトを生成する

Metalsmithで使うJavaScriptやCSSはgulpでビルドしたいので、Metalsmithのビルドでもgulpから実行したくなります。

gulpからMetalsmith、もしくはその逆を扱うためにgulpsmithというプラグインがあるのですが、デフォルトではYAML front matterを読み込めないため使うには面倒な記述が必要になるのでgulpからコマンドを実行することにしました。

```js
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ブランチを事前に作成する必要はありません。

```ps1
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](http://wercker.com/)で自動化すると便利です。

まずプロジェクトのルートに`wercker.yml`を作成します。

```yaml
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が嫌いになりそうになったんだけども、このへんはすべて差し替え可能なので問題になることはありません。

```ejs
<% if (theme.sidebar === 'bottom'){ %>
  <%- partial('_partial/sidebar') %>
<% } %>
```

こういう記述はJadeに置き換えることができるので、以下のように記述することができます。

```jade
if theme.sidebar === 'bottom'
  != partial('_partial/sidebar')
```

ドキュメントがわかりやすいので、テーマの作成で困ることはないとおもう。コードのシンタックスハイライトには[highlight.js](https://highlightjs.org/)が使われているんだけども、Jekyllからの移植用のためなのかクラス名はPygmentsに準じたものになっていたりと、Jekyllからのテーマの移植もしやすいようになっているのかもしれません。

ヘルパーも結構便利でToCみたいなものから、記述が面倒になりがちなリンクや日付関連のものだったり色々と揃ってるのでテンプレートを自作するときにはまず一通り確認するとよさそう。

### HubPress

静的サイトジェネレータでも、さまざまな環境から手軽にアップデートができるのが[HubPress](https://github.com/HubPress/hubpress.io)。記事の作成や更新はもちろんブログの作成からすべてをGitHubのページ上で行うことができます。

記事をMarkdownではなくAsciiDocで書くというのがわりと新鮮。AsciiDocの存在自体、HubPressで知ったんだけれども技術系のブログ記事であればAsciiDocのほうが書きやすいはず。ただこのAsciiDocが合わなかった場合、Markdownに変更するといったようなテンプレートエンジンの変更もできないので選択肢から除外されることになります。

ただそれよりも現状の移行における大きな問題は生成したHTMLファイルの出力先のフォルダを指定できないことで、これはつまり過去の記事はこれまでのURLとは異なるものにならざるをえないことを意味しています。ブログの移行ですべての記事のURLが変わることを許容することは難しいので、メインのブログからの移行はまだ現実的ではなさそう。