orangeProse別館

orangeProse(本ブログ)の補助

いまさらながらBower入れてGruntでcss-modal

f:id:hidex7777:20140602010208j:plain

いまフロントエンドのみの案件にとりかかっているのですが、いわゆるモーダルウィンドウが必要なケースが出てきました。

なんとなーく「jQueryでいいよなー」と考えていたのですが、「そーいやCSSだけでできるのがなんかあったよなー」と思い出し、

を試してみることにしました。

bowerインストール

Bowerはnpmみたいなパッケージマネージャです。

そんでBowerはNode.jsのパッケージです。なのでNode.jsのパッケージマネージャであるnpmでインストールできます。

ややこしいですね。

Bowerの基本的なことはfrom scratch様の記事

らへんを参考にさせていただきました。

まずNode.jsのアップデートから始めるのが基本ですが、ぼくの環境はWindowsなのでアップデートするにはインストーラ使うしかないです。

Windowsじゃない方は

$ node -v
$ sudo npm cache clean -f
$ sudo npm install -g n
$ sudo n stable
$ node -v

でアップデート。

Windowsだとnコマンドが使えないです(n --helpだけ使えますw)。

この記事を書いている時点で、Windowsで利用できる最新版が0.10.28みたいです。

つぎにBowerのインストール。

(たぶんWindowsだと、Gitがインストールされていることが必須です)

>npm install -g bower
>bower -v
1.3.3

bower init

使いたいパッケージと目的が決まってるので、いきなり現行の開発環境に行きたくなりますが、テストから始めるのが良いかと思います。

さっき現行の開発環境で試しながらやってたら、とあるディレクトリがきれいさっぱり消えてなくなりました。

gitがなかったら死んでました。

>mkdir bowertest
>cd bowertest
>git init

.gitignoreファイル
node_modules/
bower_components/

>git add .
>git commit -m "init bowertest"
>bower init

めっちゃいろいろ聞かれますが、

[?] main file: index.js
[?] add commonly ignored files to ignore list?: Yes

このふたつの項目は「公開するライブラリ(Bowerにレジストする)なら」重要、とfrom scratch様の記事には書いてあった。

ここでは公開するライブラリの制作目的でなく、プロダクトの制作にのみ使うことを想定していますが、いちおう上記のように答えました。

あと、公開されないようにprivateのマークを付けるか、と聞かれるので

[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? Yes

これもYesにしました。

最後に書きだされるbower.jsonファイルが良さそうかどうか聞かれるのでこれもYesで答えます。

とりまcss-modalをインストール

>bower install css-modal --save-dev

bower.jsonのdevDependenciesにcss-modalが記述されます。

インストールしてみると、./bower_components/css-modal/以下にいろいろとファイルが置かれていますが、このうち必要なのはmodal.scssとmodal.jsだけです。

そんでもってscssファイルは/dev/scssディレクトリに、jsファイルは/dist/jsディレクトリに配置したいとします。

手作業でやるのでは自動化している意味がないので、Gruntでディレクトリ・レイアウトを指定することにします。

grunt-bower-task

bowerでパッケージをインストールすると、ディレクトリ構造ごと持ってくるので、レイアウト的に使いづらい。

レイアウトを使いやすいようにするgrunt-bower-taskをインストールします。

まだgrunt-cliがインストールされていなければ:

>npm install -g grunt-cli

まだカレントディレクトリがGruntで運用されていなければ:

>npm init
>npm install grunt --save-dev

package.jsonのdevDependenciesにgruntが記述されます。

>npm install grunt-bower-task --save-dev

終わったら、Gruntが使うpackage.jsonファイルのdevDependenciesにgrunt-bower-taskが記述されています。

Gruntfile.coffeeにbowerの挙動を記述します

module.exports = (grunt) ->
  pkg = grunt.file.readJSON 'package.json'
  #config
  grunt.initConfig
    bower:
      install:
        options:
          #ターゲットディレクトリを指定します
          targetDir: './lib'
          #byTypeでファイルの種類ごとにディレクトリを分けます
          layout: 'byType'
          #bower installタスクを実行したいか否か
          install: true
          #詳細ログを出すか
          verbose: true
          #インストール前にターゲットディレクトリを削除するか
          cleanTargetDir: true
          #必要なファイルをターゲットディレクトリにコピーした後にbower_components/を削除するか
          cleanBowerDir: false
     #plugin
     for taskName of pkg.devDependencies
          grunt.loadNpmTasks taskName if taskName.substring(0, 6) is "grunt-"

return

とりあえずこの設定でインストールを実行してみます。

>grunt bower:install

/lib/css-modal/にmodal.jsとmodal.scssがインストールされました!

cleanBowerDirをfalseにしたので、bower_components/も残っています。

bower_components/css-modal/bower.jsonをみると、"main"にmodal.scssとmodal.jsが書いてあるので、必要なファイルのみ/lib/以下にコピーされたわけです。

exportsOverride

layoutをbyTypeにしたのに、ファイルタイプごとに分けられず、/css-modal/以下に2ファイルとも配置されてしまいました。

これはタイプが定義されていないためです。

bower.jsonファイルで定義します:

  "devDependencies": {
    "css-modal": "~1.0.4"
  },
  "exportsOverride": {
    "css-modal": {
      "js": "**/*.js",
      "scss": "**/*.scss"
    }
  }
}

このように定義してgrunt bower:installを実行すると、

  • /lib/scss/css-modal/modal.scss
  • /lib/js/css-modal/modal.js

のようにタイプ分けしてくれます。

今回のケースではcss-modalしかインストールしていないので、よけいにゴチャゴチャしたように見えますが、いろんなパッケージをbowerでインストールしたときは、こっちのほうが便利なケースがあるかもしれません。

ファイルタイプでのレイアウトよりコンポーネントでのレイアウトのほうがいい、という場合は、layoutオプションを'byComponent'にします。

grunt-contrib-copy

もしかしたらgrunt-bower-taskでうまいことやれば、最終目的配置までやれるのかもしれませんが(layoutオプションに関数を定義できます)、めんどくさいので、grunt-contrib-copyを使って、決め打ちでコピーしてしまいます。

どうせファイル名がわかっているので。

>npm install grunt-contrib-copy --save-dev

package.jsonに追記されました。

Gruntfile.coffeeでコピーのタスクを記述します:

module.exports = (grunt) ->
  pkg = grunt.file.readJSON 'package.json'
  #config
  grunt.initConfig
    bower:
      install:
        options:
          targetDir: './lib'
          layout: 'byType'
          install: true
          verbose: true
          cleanTargetDir: true
          cleanBowerDir: true
    copy:
      cssModalScss:
        expand: true
        cwd: "lib/scss/css-modal/"
        src: "modal.scss"
        dest: "dev/scss/"
        flatten: true
        filter: 'isFile'
      cssModalJs:
        expand: true
        cwd: "lib/js/css-modal/"
        src: "modal.js"
        dest: "dist/js/"
        flatten: true
        filter: 'isFile'
  #plugin
  for taskName of pkg.devDependencies
    grunt.loadNpmTasks taskName if taskName.substring(0, 6) is "grunt-"
  #tasks
  grunt.registerTask "bowerinstall", [
    "bower:install"
    "copy:cssModalScss"
    "copy:cssModalJs"
  ]
return

こんどはcleanBowerDirをtrueにしてみました。

(copyの書き方も、もっとうまいことできるかと思いますがめんどくさいので1ファイルごと書いています)

これでgrunt bowerinstallを実行すると、/bower_components/ディレクトリが消え、/lib/以下に配置された各ファイルが、目的の場所にコピーされました。

css-modal

そういえば、この記事は、CSS-Modalを使うために書き始めたのでした。

完全に忘れていた。

CSS-Modalは、cssのみを使ってモーダルウィンドウを表現するライブラリです。

ただしIE8との互換性やESCキーでモーダルを消す、などの機能のためにmodal.jsも使うことになります(jsがなくても、IE8で機能することは機能するらしいです)。

使い方は簡単で

@import 'modal';

でscssファイルにインポートして、モーダルウィンドウになるパーツに対して

.my-modal-section{
  @extend %modal;
}

のように適用するだけです。

注意点は、

  • modal.scssは_modal.scssにリネームして使ったほうがいいかなー
  • _modal.scssの1行目に@charset "UTF-8";を書かないとたぶんエラーが出る
  • csslintはオフる

HTMLのマークアップはこんな感じ

<div class="work">
    <figure class="workimg">
         <a href="#modal-work01"><img src="img/dummy300.png"></a>
    </figure>
    <dl>
         <dt class="worktitle">モーダル作品1</dt>
         <dd class="workdesc">モーダル作品についての説明です。モーダル作品についての説明です。モーダル作品についての説明です。</dd>
    </dl>
    <section class="modal-work" id="modal-work01" tabindex="-1" role="dialog" aria-hidden="true">
         <div class="modal-inner">
              <div class="modal-content"><img src="img/work_01_image.jpg" alt="作品01"></div>
         </div>
         <a href="#!" class="modal-close" title="Close this modal" data-close="Close" data-dismiss="modal">×</a>
    </section>
</div><!-- /.work -->

imgにaのhrefで#modal-work01へのトリガー、モーダルウィンドウ側はhrefに#!でトップに移動しないようにする。

f:id:hidex7777:20140602010208j:plain

ちょっと気になるのは、CLOSEしたときにURLに#!がついてしまうことかなー。