目次
FrontNoteとは
LIGのCTOである林先生が作ったスタイルガイドジェネレータ。
Githubのアイコンかわいい。
スタイルガイドとは
簡単に説明すると、デザインの仕様書です。
エンジニアにとって馴染みの深いスタイルガイドの代表として、Bootstrapが挙げられます。
複数人での開発にはぜひ導入して置いたほうが良いと言えるもの。
(これがないとオレオレCSSが量産され、地獄を見ることも・・・)
ナレッジの共有を視覚的に図れるので開発効率の向上にもつながる。
FrontNote以外の有名なスタイルガイドジェネレータ
StyleDocco
http://jacobrask.github.io/styledocco/
トラブルが発生した環境
$ node -v v0.10.40 $ npm -v 1.4.28 $ gulp -v CLI version 1.2.1 Local version 3.9.1
gulpfile.jsのサンプル
今回は課題解決にフォーカスし、最低限のgulpfileにて検証しました。
var gulp = require("gulp"),
    watch = require('gulp-watch'),
    frontNote = require("gulp-frontnote");
var debug = require('gulp-debug');
var sassDir = "./sass/scss/";
function docs() {
  gulp.src(sassDir + '**/*.scss')
    .pipe(frontNote())
    .pipe(debug({title: "debug:"}));
}
gulp.task("docs", docs);
gulp.task('default', function() {
  gulp.watch(sassDir + '**/*.scss',["docs"]);
});
問題の概要
初回の書き出しは、全ての対象ファイルのスタイルガイドが正常に生成される。
しかし、2回目以降、gulp.watchでファイルを編集したトリガーでの生成の場合、編集した対象ファイルのみの生成となり、サイドバーのファイルリンク一覧が消えてしまう。
上記のような不具合が発生していた。
トラブル解決方法
- gulp-debug
- console.logコマンド
などで地味にトレースした結果、下記のような流れで処理が行われていた。
- gulp.wacthで対象ファイルの更新検知
- docs関数をコール
- gulp.srcのMiniMatchパターンに適合
- frontNote関数をコール
パッと見たところ、MiniMatchパターンに適合しているファイルはすべてfrontNoteをコールしていたので、gulpfile側は問題ないと考えられる。
frontNoteの内部実装をチェック
gulpfileに問題はないようで、詰まってしまったので内部実装をチェックすることに。
gulp-frontnode/index.js
- ストリームでファイル一覧を取得
- frontnoteのrenderに投げる
frontnote/lib/frontnote.js
- ファイルを1ファイルずつ全て読み込む
- スタイルガイドを生成するべきファイルをparserで抽出
- スタイルガイド生成処理
- ごにょごにょして生成完了!
おおよそ上記の流れだったのですが、課題である「ファイルリンク一覧が消える」という問題は「スタイルガイドを生成するべきファイルをparserで抽出」で起こっていました。
ファイルリンク一覧の生成方法
ファイルリンクの生成方法は「frontnote/template/index.ejs」を確認するとすぐわかりました。
<nav class="fn-sidebar">
        <a href="./index.html" class="fn-menu<%if(overview){%> fn-is-active<%}%>">Overview</a>
        <!-- 全ファイル -->
        <% files.forEach(function(file) { %> // この行が鍵
        <!-- スタイルガイドへのリンク -->
        <a href="<%- file.url %>" class="fn-menu<%if(helpers.isCurrent(current,file)){%> fn-is-active<%}%>">
            <% if (file.overview) { %>
                <%- file.overview.title %>
            <% } else { %>
                <%- file.fileName %>
            <% } %>
        </a>
        <% }) %>
    </nav>
filesという変数の中身をループ処理しているのですが、上記の「スタイルガイドを生成するべきファイルを抽出」という部分でそもそも「files」の中身が変更した1ファイルのみになっていたのです。
その処理を行っている実体ファイルは「frontnote/lib/parser/parser.js」でした。
var Parser = function(){};
Parser.prototype = {
    parse: function(file,content,useCache) {
        if (useCache) {
            var cacheData = cache.get(file);
            if (cacheData === content) {
                return null;
            }
            cache.put(file,content);
        }
        var overview = content.match(PATTERNS.overview);
        if (overview) {
            overview = this.parseComments(overview);
            if (overview) {
                overview = overview[0];
            }
        }
        var colors = content.match(PATTERNS.colors);
        if (colors) {
            colors = this.parseColors(colors);
        }
        var comments = content.match(PATTERNS.comment);
        if (comments) {
            comments = this.parseComments(comments);
        }
        if(overview || comments || colors) {
            var fileName = path.basename(file,path.extname(file));
            var relPath = path.relative(__dirname, path.dirname(file));
            if (relPath) {
                relPath = relPath.replace(/\.\.\//g,'').replace(/\.\.\\/g,'').replace(/\//g,'-').replace(/\\/g,'-') + '-';
            }
            return {
                file: file,
                fileName: fileName,
                url: relPath + fileName + '.html',
                dirs: file.split(path.sep),
                ext: path.extname(file),
                sections: comments,
                overview: overview,
                colors: colors
            };
        }
        return null;
    },
どうやらキャッシュを使う設定にしてあると、生成ファイル一覧から除外されるようです。
負荷のかからない良い対応だと思いますが、ファイルリンクが消えてしまうのは痛い。。
対応・解決方法
どうやらキャッシュが課題だということが判明したので、解決法は簡単です。
gulpfile.jsのfrontNote呼び出し部分にオプションとして
- キャッシュを無効化する
- ファイルを毎回生成する
のいずれかを設定してやれば、全てのファイルを走査するようになり、リンク一覧が正常に生成されます。
function docs() {
  gulp.src(sassDir + '**/*.scss')
    .pipe(frontNote({
      cache: false, // こっちはキャッシュの無効
      clean: true,  // こっちで毎回削除→生成
    }))
    .pipe(debug({title: "debug:"}));
}
以上で、初回出力時と同様、きれいに全てのファイルが生成されるようになりました。
最後に
今回、社内のデザイナーからお手上げ案件ということで調査・対応依頼が回ってきて対応しました。
普段、フロントエンドのプロダクトはそこまで深く触っていないものなので、若干苦戦しましたが楽しく取り組めました。
何より、このような素敵なスタイルガイドジェネレータを提供してくれている林先生には感謝です。
ぜひみなさんもスタイルガイドジェネレータを利用して、社内のコード統一・健全化に努めてはいかがでしょうか。
