つかびーの技術日記

情報系修士卒のWeb系技術日記です。現在のフォーカス分野はアドテクです。

grunt-bower-installとgrunt-useminが出力するファイルパスを調整

   

現在あるWebアプリを作っているのですが、そこではyeoman-angular-fullstackを使っています。これはgrunt-bower-installgrunt-useminを使うのですが、Angularのhtml5modeで少し悩んだのでメモしておきます。

前提知識

  • Yeoman
    Grunt, Bower, HTML, CSSなどのテンプレートを作成してくれるツール。Gruntの設定ファイル作成が面倒だとかいうケースに使える。
  • yeoman-angular-fullstack
    AngularJSやExpressなどのMEAN環境を作ってくれるYeomanのジェネレータ。
  • grunt-bower-install
    Bowerによってインストールした依存関係のあるパッケージへのリンクをHTMLに自動で挿入してくれるツール。HTMLファイルの特定部分にscript src=””を自動で挿入してくれる。
  • grunt-usemin
    MinifyなどでJSファイルやCSSファイルが結合されたり、リネームされたりするけど、その新しい名前に合わせてHTMLファイルを変更してくれるツール。HTML内のscript src=””などの部分を書き換えてくれる。

経緯

現在とあるWebアプリをAngularJSで作っているわけですが、Angularにはhtml5modeというものが存在します。Angularはデフォルトではhttp://localhost/#/menu/settingsというように#以下をパスとして解析して動作するようになっています。html5modeをonにするとhttp://localhost/menu/settingsというように自然なパスでアクセスできるようになります。

このModeは色々落とし穴があるのですが、今回はそのうちの1つの#の方式と比べてカレントディレクトリが変わる、という問題について扱います。例えば#の方式だと常にカレントは/、つまりルートですが、html5modeだと/だったり/menuだったり色々変わります。

AngularはSinglePageApplicationを作るものですので、index.htmlと複数のpartial(index.htmlの一部分)を使って開発することが多いと思います。

上記の状況でindex.htmlにscript src=”bower_components/jquery.js”などと相対パスで書いていると/でアクセスしたときは問題ないけど、/menu/settingsへアクセスしたときに問題が発生します。

(※作り方にもよりますが、Angularでhtml5modeだと/menu/settingsへアクセスしても/index.htmlを読み込みます。このときコンテキストは/menu/なので相対だと問題になります。)

今回はこれを解決した話です。

解決

まずはgrunt-bower-installの問題を解決します。grunt-bower-installを実行するとindex.htmlなどに自動的にscriptタグが挿入されます。

例えばこれが

こうなります。

このままだとsrc指定が相対パスになっているので/menu/などにアクセスすると正しく動きません。

これはStackOverflowですぐに見つかりました。

Can I change what path gets rendered when using bower in an yeoman angular app?

なんかこの質問者もhtml5modeみたいですし、ドンピシャですね。

回答者に従ってgrunt-bower-installのversion 0.8.0を入れます。ここで1.4.0などの最新版を入れたのですが、失敗しました。素直に0.8.0を入れます。

–save-devはpackage.jsonのdevDependenciesも書き換えるという意味です。@はバージョン指定です。

次にGruntの設定を以下のような感じで書き換えます。

replaceがキモで、{{filePath}}の前に/を入れることで絶対指定にしています。

この状態でbower-installするとscript src=”/bower_components…というように絶対指定になるので大丈夫です。

初めはgrunt-bower-installの1.4.0を入れてみたのですが、1.0.0以降ではなぜか../bower_componentsのようにパスが変わってしまうため諦めました。なんで../になるんだろう・・・誰か知ってたら教えてください。

次にgrunt-useminの問題を解決します。

yeoman-angular-fullstackはデフォルトで色々なGruntタスクを作成してくれますが、その中の一つにbuildがあります。grunt buildとするとdistフォルダにminifyなどをした本番環境用のリソースを作ってくれます。ここで複数のjsファイルは1つに結合されて、リネームされたりminifyされたり色々します。

例えばindex.htmlでこうだったものが

こうなります。

かなり良い仕事してくれていますが、相対パスに戻っております・・・。

これは簡単に直すことができます。

以下の部分を

このようにして、scriptsの前に/を入れればOKです。

実際にやってみると以下のようになります。

ツールの使い方が悪かったという単純な原因ですが、ここまで来る間にAngularのInjectionエラーだとか謎のSyntaxエラーだとか開発モード実行(grunt serve)だと上手く行くのに本番モード実行(grunt serve:dist)だとコケるとか様々な試練が待っていました・・・。

次からもっと早く解決したいです。

 - ツール , , ,