LoginSignup
1
1

More than 5 years have passed since last update.

更新時刻を保持するpngquantタスク

Posted at

pngquantに限った事ではないですが、grunt等で公開用のデータをビルドする場合、基本的にファイルの更新時刻はビルドした時点の物となります。ファイルを更新しているので当たり前ですね。

デプロイの方法によってはこれで全然問題はないのですが、レガシーな手法、例えばsshやftpなどでプッシュする場合に更新時刻をソースの物に合わせたい場合があります。もとい、あるとします。(差分で同期を取る際などに、時刻を基準とするケース)

そのようなケースに合わせるために、オリジナルの更新時刻を保持するpngquantタスクを書いてみます。

  • fs.stat/fs.statSync を使って更新時刻を取得
  • pngquantコマンドで最適化した後、touchコマンド実行で更新時刻を変更
  • 一度に多くの処理を走らせるとエラーを吐くので、決まった数ずつ順次処理していきます

尚、touchコマンド/pngquantコマンドを使用出来る環境を前提としているので、事前にpngquantコマンドをインストールしておきます。(Windowsの場合はGit CUIなどでパスを通します)

更新時刻を保持するpngquantタスク @ Gist

/**
 * Grunt task for pngquant
 * -----------------------
 */

// @example:
//
// pngquant: {
//     options: {
//         preserve_mtime: true
//     },
//     dist: {
//         src: [
//             "the/path/to/*.png",
//             "the/path/to/**/*.png"
//         ]
//     }
// }

module.exports = function(grunt){

    grunt.registerMultiTask("pngquant", "", function(){

        var my = {}, fs, cp, done;

        fs = require("fs"),
        cp = require("child_process");
        done = this.async();

        /**
         * Options:
         * - preserve_mtime:Boolean ... Preserve modified time or not
         * - pngquant:String ... Template string for pngquant command
         * - touch:String ... Tempalte string for touch command
         * - verbose:Boolean ... Verbose mode
         * - separate:Number ... Separate the process by count
         */
        my.options = this.options({
            preserve_mtime: true,
            pngquant: 'pngquant <%=file %> --iebug --ext .png --force',
            touch: 'touch -d "<%=date %>" <%=file %>',
            verbose: true,
            separate: 8
        });

        /**
         * Get file list
         */
        my.count = 0;
        my.files = (function(files){
            var list = [], res = [], i = 0;
            files.forEach(function(o){
                list = list.concat(o.src);
            });
            my.count = list.length;
            while(i<=list.length){
                res.push(list.slice(i, i+my.options.separate));
                i+=my.options.separate;
            }
            return res;
        }(this.files));
        my.length = my.files.length;

        /**
         * Get modified time of file
         * - If `preserve_mtime` is false, return null
         * @param String file
         */
        my.getMTime= function(file){
            if(! this.options.preserve_mtime){ return null; }
            var date = new Date(fs.statSync(file).mtime);
            return grunt.template.date(date, "yyyy/mm/dd HH:MM:ss");
        };

        /**
         * Optimize image file by pngquant
         * @param {String} file
         * @param {Function} callback
         */
        my.optimize = function(file, callback){
            var mtime, pngquant, touch;
            mtime = my.getMTime(file);
            pngquant = grunt.template.process(my.options.pngquant, {
                data: { file: file }
            });
            touch = mtime ? grunt.template.process(my.options.touch, {
                data: {
                    file: file,
                    date: mtime
                }
            }) : "";
            cp.exec(pngquant, function(e, out, error){
                if(e){
                    return grunt.log.error(error);
                }
                mtime && cp.exec(touch);
                callback();
            });
        };

        /**
         * Run process
         */
        my.process = function(){
            var files, count;

            if(! my.files.length){
                grunt.log.writeln("All images optimized.");
                return done();
            }

            files = my.files.pop();
            count = files.length;
            files.forEach(function(file){
                my.optimize(file, function(){
                    count -= 1;
                    ! count && my.process();
                });
            });

            if(my.options.verbose){
                var percent = 100 - parseInt(my.files.length / my.length * 100, 10);
                grunt.log.writeln(
                    grunt.template.process(
                        "<%=percent %>% of <%=total %> files",
                        {data: {percent: percent, total: my.count}}
                    )
                );
            }
        };

        my.process();

    });

};
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1