Visual Studio 2013 で Bower を使う【利用編】

クロスワープの大鷲です。

前回は、Bower を使うために必要なツールをセットアップしたところで終わってしまいました。
今回は、実際に Bower を利用してみます。

プロジェクトを作る

Visual Studio 2013 を立ち上げて、Web アプリケーション プロジェクトを作りましょう。
ソリューション エクスプローラーから「NuGet パッケージの復元の有効化」をしておきます。
f:id:cw_owashi:20150303162905p:plain

続いて、コマンド プロンプトでプロジェクトのあるディレクトリを開き、以下のように入力します。

bower init

いくつか質問されますが、回答内容はさほど重要ではありません。すべて既定値で Enter キーを押していくだけでも構いません。
一通り終わると、ディレクトリに bower.json というファイルが作られます。
このファイルは重要なのでソース管理に追加しておきましょう。

jQuery のインストール

Web アプリケーション プロジェクトを作成すると、既に NuGet 経由で jQuery がインストールされていますが、それは一旦置いておいて、Bower 経由で jQuery を入れてみます。
コマンド プロンプトで

bower install jquery --save

と実行してください。最後の --save を忘れないように。

完了すると、プロジェクト ディレクトリ内に bower_components というディレクトリができます。中には jQuery が入っているはずです。
また、bower.json に dependencies セクションが作られ、jQuery が登録されています。

{
  "name": "VSBower",
  "version": "1.0.0",
  "authors": [
    "owashi <owashi@crosswarp.com>"
  ],
  "license": "MS-PL",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "~2.1.3"
  },
  "private": true
}

bower install の時につけた --save オプションは、この dependencies に登録するという意味です。

再インストールしてみる

このプロジェクトは jQuery を使うという情報が bower.json に記録されましたので、今後はいちいち bower install する必要はありません。
試しに bower_components ディレクトリを削除した上で、

bower install

と叩いてみましょう。
Bower は bower.json を読み取って、自動的に jQuery を再インストールしてくれます。
NuGet で言う「NuGet パッケージの復元の有効化」と同じことです。

このため、bower.json がソースコード管理にコミットされていれば、bower_components ディレクトリをコミットする必要はありません。
リポジトリからコードを取得したら、まず

bower install

すればいいわけです(ビルド サーバーでの自動ビルドの際は、まずこのコマンドを実行するように設定しておきます)。

繰り返しますが、最初のインストールの時に --save を付けていないとこうはいきませんので、忘れないように注意してください(実際、よく忘れるんです)。

Bootstrap もインストールしてみる

bower install bootstrap --save

と叩けばインストール完了です。

なお、他にどんなパッケージがあるのかは、Bower の公式サイトで検索できます。

Bower 版の jQuery と Bootstrap を使う

インストールができたら、VS のプロジェクトに追加しましょう。
まずは NuGet 版と同じようなファイルを追加しておきます。こんな感じでしょうか。
f:id:cw_owashi:20150303171954p:plain
画像には写っていませんが、bower.json も追加しておいてください。

続いて、App_Start フォルダーの下にある BundleConfig.cs も、bower_components を参照するように書き換えましょう。

namespace VSBower
{
  using System;
  using System.Web;
  using System.Web.Optimization;

  public class BundleConfig
  {
    // バンドルの詳細については、http://go.microsoft.com/fwlink/?LinkId=301862  を参照してください
    public static void RegisterBundles(BundleCollection bundles)
    {
      /*
      bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/Scripts/jquery-{version}.js"));
      */

      bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/bower_components/jquery/dist/jquery.js"));

      bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
        "~/Scripts/jquery.validate*"));

      // 開発と学習には、Modernizr の開発バージョンを使用します。次に、実稼働の準備が
      // できたら、http://modernizr.com にあるビルド ツールを使用して、必要なテストのみを選択します。
      bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
        "~/Scripts/modernizr-*"));

      /*
      bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
        "~/Scripts/bootstrap.js",
        "~/Scripts/respond.js"));

      bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/Content/bootstrap.css",
        "~/Content/site.css"));
      */

      bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
        "~/bower_components/bootstrap/dist/js/bootstrap.js",
        "~/Scripts/respond.js"));

      bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/bower_components/bootstrap/dist/css/bootstrap.min.css",
        "~/Content/site.css"));
    }
  }
}

普通は古いコードをコメントで残したりはしませんが、ここではわかりやすく新旧比較するために敢えてこうしています。

ここまでできたら、NuGet から Bootstrap はアンインストールしてしまって構いません(jQuery はまだ消せません)。

その他のライブラリも Bower に移行してみる

Web アプリケーション プロジェクトを作ると、最初から NuGet でインストールされているフロントエンド ライブラリには、以下のようなものがあります。

  • Bootstrap
  • jQuery
  • jQuery Validation
  • jQuery Unobtrusive Validation
  • Modernizr
  • Respond JS

Modernizr 以外は Bower でも公開されていますので、Bower に移行することができます。
まとめてやってしまいましょう(jQuery Validation は jQuery Unobtrusive Validation の依存性として自動的にインストールされます)。

bower install jquery-validation-unobtrusive respond-minmax --save

注目すべきは、jQuery Unobtrusive Validation は Microsoft 製のパッケージであり、それが Bower に登録されているということです。
ここからも、Microsoft が Bower にコミットしていく姿勢が見られます。

さて、追加したファイルをプロジェクトに含めて、BundleConfig.cs も書き換えましょう。
f:id:cw_owashi:20150303181242p:plain

namespace VSBower
{
  using System;
  using System.Web;
  using System.Web.Optimization;

  public class BundleConfig
  {
    // バンドルの詳細については、http://go.microsoft.com/fwlink/?LinkId=301862  を参照してください
    public static void RegisterBundles(BundleCollection bundles)
    {
      bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/bower_components/jquery/dist/jquery.js"));

/*
      bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
        "~/Scripts/jquery.validate*"));
*/

      bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
        "~/bower_components/jquery-validation/dist/jquery.validate.js",
        "~/bower_components/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"));

      // 開発と学習には、Modernizr の開発バージョンを使用します。次に、実稼働の準備が
      // できたら、http://modernizr.com にあるビルド ツールを使用して、必要なテストのみを選択します。
      bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
        "~/Scripts/modernizr-*"));

/*
      bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
        "~/bower_components/bootstrap/dist/js/bootstrap.js",
        "~/Scripts/respond.js"));
*/

      bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
        "~/bower_components/bootstrap/dist/js/bootstrap.js",
        "~/bower_components/respond-minmax/dest/respond.min.js"));

      bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/bower_components/bootstrap/dist/css/bootstrap.css",
        "~/Content/site.css"));
    }
  }
}

ここまで終わったら、NuGet からは削除してしまいましょう。
Modernizr は消さないように気を付けてくださいね。

jQuery の分裂

最近のちょっとした事件として、jQuery Plugin Registrynpm に移行したという件が挙げられます。
前回、npm のことを

サーバーサイド用なのでどちらかと言えばバックエンド パッケージ マネージャーです(でした)。

と書いたのは、この件が、npm がフロントエンド ライブラリに進出しようとしているように見えたからです。
しかし、jQuery 自体は Bower でインストールすることを推奨しているようです。
今後どうなるのでしょうか。

それはともかく、今回は Bower を使って進めていきます。

実はバグっているコード

NuGet から Bower に移行するに伴って書き換えた BundleConfig.cs ですが、実はわかりづらいバグが潜んでいます。
デバッグモードで実行すると動いてしまうのですが、リリースモードで、Web.config を

<system.web>
  <compilation debug="false" targetFramework="4.5"/>
</system.web>

のようにしたり、あるいは、デバッグモードでも JavaScript や CSS の最適化を有効にするために、

BundleTable.EnableOptimizations = true;

などという設定を入れると、Bootstrap の GlyphiconjQuery UI を使っている場合に、画像が出なくなります。

これは、Bundle に伴って CSS の URL が

~/bower_components/bootstrap/dist/css/bootstrap.css

から

~/bundles/bootstrap

に変わっても、Glyphicon の画像(フォント)ファイルは CSS ファイルからの相対パスで読み込もうとするので、

~/fonts/glyphicons-halflings-regular.eot

という実在しないパスを読み込もうとして失敗するためです。
f:id:cw_owashi:20150303195945p:plain
最適化を有効にしなければ CSS の URL が変わらないため発生せず、また、発生したとしても動作に致命的な影響を及ぼさない小さな画像のため、非常にわかりづらい問題です。

この問題を回避するためには、Bundle のパスを変更するとか、CssRewriteUrlTransform クラスを使うといった方法がありますが、今回は思い切って Bundle を使うのをやめて gulp を使って対応したいと思います。

というところで、gulp については次回。

最後までお読み頂き、ありがとうございました。