grunt-useminでファイルの重複処理が気になる年頃

@nqounetです。

yeomanは便利で良いのですが、JavaScriptがよくわかってないので、ちょっとしたところで躓いてしまいます。

yeoman

yeomanというシステムの中でも、yo webappはひな形としてかなり優秀だと思います。

bootstrap、sass、modernizrをオプションで選択できますし、どれを選んでも(または選ばなくても)それなりのタスク(便利なコマンド集と言っても良い)があって便利です。

gruntで公開用のファイルを作成するbuildのタスクがありますが、その中に、ファイルの結合(concat)と最小化(uglifyjs, cssmin)があります。

yo webappで作成したプロジェクトには、これらの設定をHTMLファイルから生成してくれる、grunt-useminというプラグインが入っています。

HTMLファイルにHTMLのコメントとして設定を書くことができるので、Gruntfile.jsがわからなくても良しなに処理してくれます。

ただ、ファイルが1つ(index.html)だけの場合は全く問題ないのですが、HTMLファイル数を増やすと同じファイルを何度も最小化しようとしてしまうんです。

出来上がりは一緒なのですが、作っては捨て、作っては捨て、というのを見るのはちょっと耐えられません。

2回位ならまだ良いですが、10回にもなるとさすがにちょっと考えます。

buildする度に、余計な作業を10倍しているわけです。

その部分をうまくやれば10倍の高速化が期待できるのに…と思います。

こういう部分を見ると、思想が大雑把というか雑な感じに見えてきます。

節約する部分の違い

node.jsが今どきだな、と思うのは、メモリとかストレージの容量に関しては気にしていない、というところです。

グローバルへのインストールがオプション、というのも、それぞれのプロジェクト単位でライブラリを持っていたほうが、他のプロジェクトの影響を受けなくてすむので安全だからです。

昔からよくある不具合として、ライブラリをアップデートしたら今まで動いていたものが動かなくなる、というようなものです。

PerlでもCartonでパッケージを管理できるようになりましたが、それは最近の話です。

perlbrewやplenvなどで、ユーザー領域にPerlをコンパイルしてインストールするようになったのも、まあ最近の話です。

メモリやストレージが潤沢にあるからこそ、他のプロジェクトの影響を受けないような環境作りにシフトすることができるようになってきたわけですよ。

しかし、その潤沢に使える感覚が、プログラムにも影響を与えているんじゃないかなと思います。

同じファイルを何度も最小化するのは無駄という感覚が欠如しているんじゃないかと思うのです。

重複を省くのは難しいですか?

重複を処理する処理はそんなに難しいものではないはずです。

配列を扱うライブラリには大体uniqという感じのライブラリがあると思います。

ウェブサイトの作りを考えてみれば、同じファイルは1回だけ処理すれば良い、というのはすぐに思いつきそうです。

もし仮に同じファイル名で違うファイルを生成してしまうというのなら、それは設定ミスでしょう。

そう考えれば、出力先が同じ場合は処理を飛ばす、というのはすぐ思いつくと思うのですが、どうしてまだないのでしょうね?

公式のドキュメントによると、optionのflowという項目にpostということで後処理が書けるようです。

試行錯誤の結果、cssはうまくいきましたが、jsの方は私には無理でした。

抜粋するとこんな感じです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
useminPrepare: {
    options: {
        dest: '<%= config.dist %>',
        flow: {
            steps: {
                js: ['concat', 'uglifyjs'],
                css: ['concat', 'cssmin']
            },
            post: {
                css: [{
                    name: 'concat',
                    createConfig: function(context, block){
                        var generated = context.options.generated;
                        var obj = {};
                        var uniq = generated.files.filter(function(x){
                            var flag = obj[x.dest];
                            obj[x.dest] = true;
                            return !flag;
                        });
                        generated.files = uniq;
                    }
                },{
                    name: 'cssmin',
                    createConfig: function(context, block){
                        var generated = context.options.generated;
                        var obj = {};
                        var uniq = generated.files.filter(function(x){
                            var flag = obj[x.dest];
                            obj[x.dest] = true;
                            return !flag;
                        });
                        generated.files = uniq;
                    }
                }]
            }
        }
    },
    html: '<%= config.app %>/*.html'
},

なんだかムムムって感じです。

ここまで書かないと無理なものなんですかね…。

普通に考えると、concatを絞り込むだけで良さそうなのですが、concatの結果は無関係のようです。

これらは別々に書く必要がありました。

なんというか、node.jsの奥底にある思想が私にはまだ理解できてないようです。

今更ですが良いことを思いつきました

これだけ苦労した後ですが。

ここまで考えるくらいなら、grunt-useminに渡すためのHTMLファイルを用意したほうが簡単のような気がします。

…実際に試してみたところ、うまくいきました。

あまりの簡単さに拍子抜けしてしまいました。

こんな手があったなんて…。

Gruntfile.jsを一部修正します。元々はindex.htmlになっている部分です。

1
html: '<%= config.app %>/usemin.html'

そして、usemin.htmlというファイルを用意し、各htmlファイルから該当部分をコピペしたあと重複部分を削除しておくだけです。

grunt serve:distで確認したところ、うまく動いているので、おそらくは問題ないだろうと思います。

あとで、個人サイトの方も変更しておこうと思います。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。