to pagetop
:)
spec5zigen Creator's Lab.

プログラマーの後藤です。
先日弊社で @__kageyama__ 先生をお招きしてgrunt勉強会を行いました。
そのまとめもかねてコーディングの開発環境の話を少ししてみたいと思います。

弊社はもともと少数精鋭のちっさい制作会社なので、
個人プレーが多く制作業務の連携が苦手だなーと感じてました。
また、最近品質管理の打ち合わせに出席し、
品質向上や進行管理のことについて考えることが多くなっていました。

そんななかでも制作の大半のスタッフが担当するコーディングの分野で
制作行程がまちまちで、作業を引き継いだり共同で作業する際に
連携がうまく行かないなと思うことが多々あります。
そこで最近巷で話題のgruntというモノがあることを知り興味を持ちました。
gruntがどんなものかは、さすがにもうgoogle先生に聞けばすぐ答えが出てくると思うので今回は割愛します。

まだ検討中の段階ですが、
今のところ自分個人がgruntをどのように運用するかをざっくりまとめてみました。

Gruntfile.jsはかんな感じ

module.exports = function(grunt){
    grunt.initConfig({
        // bowerでjqueryやnormalize.cssを取得
        bower: {
            install: {
                options: {
                    install: true,
                    cleanTargetDir: false,
                    cleanBowerDir: false
                }
            }
        },
        // 取得したライブラリ等を適切な場所にコピー
        copy: {
            setup: {
                files: [{
                    expand: true,
                    cwd: 'components/jquery/',
                    src: 'jquery.min.js',
                    dest: '_product/html/common/js/lib/',
                    filter: 'isFile'
                },
                {
                    expand: true,
                    cwd: 'components/normalize-css/',
                    src: 'normalize.css',
                    dest: '_product/html/common/css/',
                    filter: 'isFile'
                }]
            },
            release: {
                files: [{
                    expand: true,
                    cwd: '_product/html/',
                    src: ['*.html'],
                    dest: '_release/html/' // makes all src relative to cwd
                }]
            }
        },
        // jadeの設定
        jade: {
            compile: {
                options: {
                    pretty: true,
                    data: {
                        debug: false
                    }
                },
                files: {
                    "_product/html/index.html": "_dev/jade/index.jade"
                }
            }
        },
        // stylusの設定
        stylus: {
            compile: {
                options: {
                    'include css': true,
                    compress: false,
                    urlfunc: 'embedurl',
                    paths: ['common/css']
                },
                files: {
                  '_product/html/common/css/main.css': '_dev/stylus/*.styl'
                }
            }
        },
        // 画像圧縮の設定
        imagemin : {
            dist : {
                files : [
                    {
                        expand : true,
                        cwd    : '_release/html/common/img/',
                        src    : ['*.{png,jpg}'],
                        dest   : '_release/html/common/img/'
                    }
                ]
            }
        },
        // coffeeの設定
        coffee: {
            options: {
              bare: true
            },
            files: {
                expand:true,
                cwd: '_dev/coffee/',
                src: ['**/*.coffee'],
                dest: '_product/html/common/js/',
                ext: '.js'
            }
        },
        // jsの圧縮設定
        uglify: {
            options: {
                mangle: true // true にすると難読化がかかる。false だと関数や変数の名前はそのまま
            },
            dist: {
                files: {
                    '_release/html/common/js/lib.min.js': ['_product/html/common/js/*.js','!**/main.js'],
                    '_release/html/common/js/main.min.js': ['_product/html/common/js/main.js']
                }
            }
        },
        // cssの圧縮設定
        mincss: {
            compress: {
                files: {
                    "_release/html/css/main.min.css": ["_product/html/css/main.css"]
                }
            }
        },
        // 監視タスクの設定
        watch : {
            js : {
                files : [
                    '_dev/coffee/*.coffee'
                ],
                tasks : ['coffee']
            },
            css : {
                files : [
                    '_dev/stylus/*.styl'
                ],
                tasks : ['stylus']
            },
            jade : {
                files : [
                    '_dev/jade/*.jade'
                ],
                tasks : ['jade']
            }
        }
    });

    // ここに扱うモジュールを書く
    var pkg = grunt.file.readJSON('package.json'); //loadNpmTasksをpackage.jsonから動的に読み込む
    // loadNpmTasksを変更
    var taskName;
    for(taskName in pkg.devDependencies) {
        if(taskName.substring(0, 6) == 'grunt-') {
          grunt.loadNpmTasks(taskName);
        }
    }
    //フォルダ構成初期構築
    grunt.registerTask('setup','setup directory',function(){
        grunt.task.run('bower:install');
        grunt.task.run('copy:setup');
        grunt.file.defaultEncoding = 'utf8';
        grunt.file.mkdir('_release');
        grunt.file.mkdir('_release/html');
        grunt.file.mkdir('_release/html/common');
        grunt.file.mkdir('_release/html/common/css');
        grunt.file.mkdir('_release/html/common/js');
        grunt.file.mkdir('_release/html/common/js/lib');
        grunt.file.mkdir('_release/html/common/img');

        grunt.file.mkdir('_product');
        grunt.file.mkdir('_product/html');
        grunt.file.mkdir('_product/html/common');
        grunt.file.mkdir('_product/html/common/css');
        grunt.file.mkdir('_product/html/common/js');
        grunt.file.mkdir('_product/html/common/js/lib');
        grunt.file.mkdir('_product/html/common/img');

        grunt.file.mkdir('_dev');
        grunt.file.mkdir('_dev/jade');
        grunt.file.mkdir('_dev/stylus');
        grunt.file.mkdir('_dev/coffee');
    });

    grunt.registerTask('default', ['coffee','jade','stylus']);
    grunt.registerTask('release', ['uglify','mincss','copy:release']);
};

ちなみにインストールされているのはこんな感じ

  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-coffee": "~0.7.0",
    "grunt-contrib-watch": "~0.4.4",
    "grunt-contrib-mincss": "~0.3.2",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-uglify": "~0.2.2",
    "grunt-bower-task": "~0.2.3",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-jade": "~0.6.0",
    "grunt-contrib-stylus": "~0.5.0",
    "grunt-contrib-imagemin": "~0.1.4",
    "nib": "~0.9.1"
  }

これをテンプレートとし、まず新規にプロジェクトを立ち上げる際に
gruntで「setup」のタスクを実行します。
すると、”grunt.task.run(‘taskname’);”で「bower」と「copy」のタスクが実行され
jqueryとnormalize.cssの取得し、次に
“grunt.file.mkdir(‘path’);”で基本のフォルダ構造を自動で生成するところまでやってくれます。

あとは「watch」タスクを走らせて、javascriptは’CoffeeScript’で、HTMLは’jade’で
cssは’stylus’で記述してがしがしコンパイルさせていきます。
プリコンパイラさまさまですねー。
‘coffee’,’jade’,’stylus’あたりの話はまたの機会にしたいと思います。

ソースは_devフォルダ配下に、書き出したものは_productフォルダ配下に、
最後にサイトにアップするようのファイルを_releaseへ必要最低限のファイルが書き出されるような想定をしています。

まだ実際の案件で運用したことはないので、これからどんどんブラッシュアップして行こうと思います。

それにしてもgruntさん使いなせるようになるとホントに便利そう!
是非皆さんも使ってみていろんな手法を編み出して共有してほしいです。
Gruntfileを共有できるこんなサイトもありますよ!
http://mygrunt.kageya.ma/

それではまたー!