21 Sep 2014

grunt-bower-task の exportsOverride で type 名のディレクトリを作らないようにする

結論としては以下の 2 つの方法があり、おそらく前者のほうが良さそう。

  • layout オプションに type を無視してディレクトリを作るようなコールバックを渡す
  • exportsOverride のキー名を空文字にする

背景

Bower は基本的に対象のパッケージを git pull してくるだけで、ファイルをいい感じに配置しれくれたりいらないファイル (そのパッケージのテストやビルドスクリプトなど) を省いたりといった機能は提供していない。そのあたりの面倒はサードパーティのライブラリで見たほうがよさそうで、例えば grunt プラグインの grunt-bower-task はいろいろとファイル配置に関する機能を提供している。なかでも exportsOverride というディレクティブで細かくファイル配置を指定できる。bower が 一応公式に推奨している main ディレクティブ は単にインストール対象となりうるファイルの一覧 (パターン) を記載するだけだが、exportsOverride はより細かい指定ができて実用的だ。

exportsOverride には type という概念がある。インストール対象のパッケージに含まれるファイルそれぞれに js, css, img といった型がわりあてられ、(layoutbyType の場合は) たとえば jquery/js/jquery.js といったように 型名/パッケージ名/ファイル といった配置になる。

ここで、(1 種類の type のファイルしか提供しないパッケージや既存のプロジェクトを bower 移行する場合などにありそうだが、) わざわざ型別にディレクトリを切らず、パッケージ名ディレクトリの直下にファイルを配置したい。こちらの qiita の投稿 によると exportsOverride のオブジェクトのキー名 (本来 type を入れるべきところ) を空文字列にするといいらしい。

確かにこれで意図した動作になるし、コードを読んだ限りでも うまく動きそう。ただしこの方法はドキュメントに記載がないし、設定ファイルをみても挙動が読めないのでトリッキーな印象がある。別の方法として layout オプションに任意のコールバックが渡せる ので、こんな感じでそちらで頑張ったほうがまだましな気がする。

var path = require('path');

grunt.initConfig({
  bower: {
    install: {
      options: {
        layout: function(type, component, source) {
          // type を無視する
          return path.join(component);
        }
      }
    }
  }
});

ちなみに JavaScript のオブジェクトのキーは文字列であればいいので、空文字列でももちろんいい。たいていのブラウザでも問題なく動作するようだ。

またこれも余談だけど、exportsOverridebower.json 側に書かせるのはなぜなんだろう。あくまで grunt-bower-task が提供している機能なので、Gruntfile.js に書いたほうがよさそうなんだけれど。