Middleman v3 -> v4 での Asset Pipeline (Sprockets) から External Pipeline への移行


Middleman の v4 では[結構いろいろ変わりました](https://middlemanapp.com/basics/upgrade-v4/) (雑な説明) 。

その中に、v4 では Sprockets が外れた、という変更があります。これが v4 の一番の目玉だと思うけど、一方でこのためにバージョンアップを躊躇してしまう、って人もおそらく多いのではないでしょうか。

ここでは、Middleman-Blog 用に作ったテンプレート (https://github.com/5t111111/middleman-blog-drops-template) を例として、Asset Pipeline (Sprockets) から External Pipeline へ移行したときのメモを残します。

ちなみに、元々大したことをやってないテンプレートだったので、移行でもそんなに大したことはやってないんんですが、同じようにシンプルなブログサイトとかなら、コピペするだけである程度今までと構成を変えずにそのまま動くんじゃないかと思います。

(※ ちなみに、一応 [middleman-sprockets](https://github.com/middleman/middleman-sprockets) という Gem が提供されていますが、少なくとも私の場合は、これを使っても過去の Middleman の Sprockets と同じ機能を使うことはできませんでした)

## External Pipeline

v4 では、Asset Pipeline の代わりとして [External Pipeline](https://middlemanapp.com/advanced/external-pipeline/) を使います。

External Pipeline というのは、Middleman に外部のアセット管理の仕組みなどを統合するもので、その対象は当然、Gulp/Grunt といったタスクランナーであったり、Browserify/webpack といった依存関係の管理ツールであったりで、要は npm のエコシステムを透過的に使いやすくするためのものと思えば大体そんな感じの機能です。

これから、具体的にやったことを書いていきます。

### webpack の導入

このテンプレートでは元々 npm でアセットをインストールしていました。それ以前は Rails Assets を使っていたこともあるのですが、Rails Assets には依存したくなかったので npm にしたという経緯です。

ただ、あくまでも v3 の時点では、npm でインストールした `node_modules` 以下のアセットを Sprockets に管理させるアプローチをとっていたので、Sprockets がないとやり方を変えるしかありません。

そこで、webpack を使うことにしました。

って、元々アセットって言っても Asset Pipeline から吐き出されるグローバルな CSS が1つあるだけだったので、「これホントに webpack 使う意味あんのかな」という感じだったのですが、まぁとりあえず webpack にまとめとけば後からきっと色々楽だろう。という安易な考えで選択してます。

### package.json の構成

まず、`package.json` の `devDependencies` を以下のようにしました。

```package.json
...

  "devDependencies": {
    "babel-core": "^6.3.26",
    "babel-loader": "^6.2.0",
    "babel-polyfill": "^6.3.14",
    "babel-preset-es2015": "^6.3.13",
    "breakpoint-sass": "^2.6.1",
    "compass-mixins": "^0.12.7",
    "css-loader": "^0.23.1",
    "file-loader": "^0.8.5",
    "node-sass": "^3.4.2",
    "resolve-url-loader": "^1.4.3",
    "sass-loader": "^3.1.2",
    "style-loader": "^0.13.0",
    "url-loader": "^0.5.7",
    "webpack": "^1.12.9"
  },

...
```

これでやりたいことは、

- スタイルは SCSS で書いて最終的に `style-loader` で読み込みたい
- SCSS の中で画像を読み込みたい
- v3 でビルトインされていた Compass を v4 でも使いたい
- Breakpoint も使ってたので使いたい
- babel はおまけ。 ES2015 の `import` を使いたかっただけ

です。

### webpack.config.js の構成

`webpack.config.js` は以下のようになりました。

```webpack.config.js
var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: {
    all: './source/javascripts/all.js'
  },

  resolve: {
    root: path.join(__dirname, 'source/javascripts'),
    modulesDirectories: [
      path.join(__dirname, "node_modules"),
      path.join(__dirname, "source/stylesheets")
    ],
    extensions: ['', '.js', '.scss']
  },

  output: {
    path: path.join(__dirname, '.tmp/dist'),
    filename: 'javascripts/[name].js'
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      },
      {
        test   : /\.scss$/,
        loaders: ['style', 'css?sourceMap', 'sass?sourceMap']
      },
      {
        test: /\.png$/,
        loader: "url-loader?mimetype=image/png"
      }
    ]
  },

  sassLoader: {
    includePaths: [path.join(__dirname, "node_modules")]
  }
};
```

これで、これまで通りに `source/stylesheets` にスタイルを書いていくことができます。

### External Pipeline の設定

最後に、`config.rb` に External Pipeline の設定を追加します。

```config.rb
...

activate :external_pipeline,
  name: :webpack,
  command: build? ? './node_modules/webpack/bin/webpack.js -p --bail' : './node_modules/webpack/bin/webpack.js --watch -d',
  source: ".tmp/dist",
  latency: 1

...
```

これで、ビルド時や、Middleman サーバーの live reload で webpack が実行されるようになります。

### .gitignore の更新

`.tmp/` に一時ファイルが作られるようになるので、`.gitignore` に追加しました。

```.gitignore
...

/.tmp/

...
```

## まとめ

Rails に親しんでいる人が、それと同じノリで頭の切り替えなしにアセット管理できる、というのは Middleman の大きな特徴だったと思ってますが、やっぱり npm 資産を気軽に使えるのは Middleman の用途としてかなり嬉しいので歓迎すべき変化だと感じます。

個人的には、とにかく `node-sass` が Ruby Sass と比べて超速いから、その導入が楽になったのが一番ありがたいですね。