gulp.jsで便利なタスクを作ってみよう【ESLint編】


gulp.jsで便利なタスクを作ってみよう【ESLint編】

こんにちは、店長です。

フロントエンド入門者のためのgulp.js編も第5回となりました。第3回第4回に引き続き、今回もgulp.jsで便利なタスクを作ってみましょう。今回はJavaScriptをより綺麗に書くために使いたい構文チェックツール「gulp-eslint」をご紹介します。

第3回から今回までの内容に関するファイルは、下記にまとめています。
Im0-3/gulp-tutorial – Github
5-1が前回の内容で、5-2と5-3が今回作る内容になっています。ファイルをダウンロードしたら、ターミナルでprojectフォルダに移動して

$ npm install gulp-eslint --save-dev

を実行しましょう。そうすると、制作に必要なライブラリをダウンロードできます。

 
前回までのファイルの内容は下記の通りです。

ディレクトリ構成

project
|--app
|  |--product
|  |  |--index.html
|  |  |--css
|  |  |  |--style.css
|  |--src
|  |  |--index.html
|  |  |--sass
|  |  |  |--style.scss
|--package.json
|--gulpfile.js
|--.htmlhintrc

 
gulpfile.js

var gulp = require('gulp');
var sass = require('gulp-sass');
var htmlhint = require('gulp-htmlhint');
var browserSync = require('browser-sync').create();
var notify = require('gulp-notify'); 
var plumber = require('gulp-plumber'); 

gulp.task('sass', function() {
    gulp.src('app/src/sass/*.scss')
        .pipe(plumber({
            errorHandler: notify.onError("Error: <%= error.message %>")
        }))
        .pipe(sass())
        .pipe(gulp.dest('app/product/css/'))
        .pipe(browserSync.stream());
});

gulp.task('html', function(){
    gulp.src('app/src/**/*.html')
        .pipe(htmlhint())
        .pipe(htmlhint.reporter())
        .pipe(gulp.dest('app/product/'))
        .pipe(browserSync.stream());
});

gulp.task('browser-sync', function() {
    browserSync.init({
        server: "./app/product"
    });
});

gulp.task('default', function() {
    browserSync.init({
        server: "./app/product"
    });

    gulp.watch('app/src/sass/*.scss',['sass']);
    gulp.watch('app/src/**/*.html',['html']);
});

では、さっそく見ていきましょう。

JavaScriptの構文をチェックするgulp-eslint

デバッグ編ではHTMLの構文をチェックするHTMLHintをご紹介しました。今回はJavaScriptの構文チェックで役に立つgulp-eslintを紹介します。

gulp-eslintは、ESLintをgulpで使うことができるライブラリです。

ESLintとは

eslint
http://eslint.org/

ESLintは、JavaScriptのコードの構文を検証するためのツールです。

JavaScriptの構文チェックツールは他にも、「JSHint」「JSLint」「JSCS」などもありますが、ESLintはチェック項目が豊富に用意されていて、すべてのルールを自由に付けたり外したりできるようになっています。加えて、ルールごとにアラートの強さを設定できるので、自分に合わせたルールを作りやすいのが特徴です。

今回はgulp-eslitでESLintを使用する方法と、簡単なチェック項目の追加をおこなってみたいと思います。

インストール

例によって、まずはgulp-eslintをインストールしましょう。

$ npm install gulp-eslint --save-dev

ESLintを使ってJavaScriptの構文をチェックしよう

まずはタスクを組んでみましょう。

srcディレクトリ内にjsディレクトリを作成して、その中のJavaScriptファイルをチェックするようにします。チェックしたら、product/jsディレクトリにJavaScriptファイルを追加します。

project 
|--app 
|  |--product 
|  |  |--index.html
|  |  |--css
|  |  |  |--style.css
|  |  |--js
|  |  |  |--app.js
|  |--src
|  |  |--index.html
|  |  |--sass
|  |  |  |--style.scss
|  |  |--js
|  |  |  |--app.js
|--package.json
|--gulpfile.js
|--.htmlhintrc

今回はscriptという名前の新しいタスクを用意します。

 

var gulp = require('gulp');
~ 中略 ~
var notify = require('gulp-notify');
var plumber = require('gulp-plumber');
var eslint = require('gulp-eslint'); //(*1)

~ 中略 ~

gulp.task('script', function(){
    gulp.src('app/src/js/*.js')
        .pipe(plumber({
            errorHandler: notify.onError('Error: <%= error.message %>')
        })) //(*2)
        .pipe(eslint()) //(*3)
        .pipe(eslint.format()) //(*4)
        .pipe(eslint.failAfterError()) //(*5)
        .pipe(gulp.dest('app/product/js/'));
});

gulp.task('default', function() {
    browserSync.init({
        server: "./app/product"
    });

    gulp.watch('app/src/sass/*.scss',['sass']);
    gulp.watch('app/src/**/*.html',['html']);
    gulp.watch('app/src/js/*.js',['script']); //(*5)
});
  • (*1)まずはいつものようにgulp-eslintをrequireしましょう。
  • (*2)処理の先頭で、前回使ったgulp-plumber、gulp-notifyを使って、エラー時にタスクを止めない処理と、通知を追加します。
  • (*3)その後gulp-eslintを実行して、構文のチェックをおこないます。
  • (*4)gulp-eslintのformatメソッドを使用すると、ターミナル内に結果の出力をおこなうことができます。
  • (*5)failAfterErrorメソッドをつかうとルールに引っかかった際にはエラーを出力してくれます。

まずはこれで1回実行して、コードを書いてみましょう。

 
eslint01

たとえば、関数のカッコを忘れている場合は、このようなエラーがでます。

 
では次に以下のように書いて実行してみてください。

app/src/js/app.js

var date = new Date();
var element = document.getElementById('time');

function getTime(date){
    return data.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
}

element.innerHTML = getTime(date);

5行目、returnの最初のdateをわざとdataと間違えて記述してみました。

 
eslint02

しかし、このコードではエラーは表示されないんです。ESLintは、初期の設定の場合、シンタックスエラーしかチェックをしてくれません。さらに詳細なチェックをするために、設定をカスタマイズしてみましょう。

ESLintを利用する環境にあわせよう

ESLintの設定方法はさまざまですが、今回はeslintrc.というファイルを用意して設定をおこないたいと思います。まずは、先ほどのコードを下記のように変更しましょう。

gulp.task('script', function(){
    gulp.src('app/src/js/*.js')
        .pipe(plumber({
            errorHandler: notify.onError('Error: <%= error.message %>')
        })) 
        .pipe(eslint({useEslintrc: true}))
        .pipe(eslint.format())
        .pipe(eslint.failAfterError())
        .pipe(gulp.dest('app/product/js/'));
});

useEslintrcは.eslintrcを使用するかどうかを定義するためのオプションです。

次に.eslintrcというファイルをprojectディレクトリ内に用意しましょう。このファイルはESLintの細かい設定をするためのファイルです。ここに書き込むことで、環境への対応やルールの追加、変更などができるようになります。

まずは環境にあわせた設定をしてみましょう。.eslintrc内に下記の内容を記述してください。

{
    "env": {
        "browser": true
    }
}

ここで指定した環境内にあるグローバル変数(browserで言えばwindow, documentなど)を自動で追加してくれます。他にもNode.jsや、ES6のための環境設定が存在します。

詳しくはこちらをご覧ください。
Specifying Environments – ESLint

ESLintのオススメ設定を使用してみよう

{
    "extends": "eslint:recommended"
    "env": {
        "browser": true
    }
}

先ほどのファイルに、さらに上記を追加します。

 
recommend

このように指定することで、「Rules – ESlint」に記載されているもののうち、チェックマークがついたものをチェックしてくれます。試しに、先ほどのコードをもう1回チェックしてみましょう。

 
eslint03

すると、このようにエラーが出力されました。これは未定義の変数を検知したエラーです。

 
error

アラートメッセージの内容はこちらの通り。

アラートの種類はerrorとwraning(警告)の2種類あります。errorは必ず直すべきところ、warningは注意して使用する、極力使わないようにするといった意味合いです。

設定をして更に細かく設定をしてみよう

使っていくと、ルールによってはチェックしたくないものやチェックをゆるくしたいもの、逆にチェックをもっと厳しくしたいものが出てくるかと思います。

 

var date = new Date();
var element = document.getElementById('time');

function getTime(date){
    return date.getHours(date) + ':' + date.getMinutes(date) + ':' + date.getSeconds(date);
}

element.innerHTML = getTime(date);
console.log(getTime(date));

例えば、こちらのコードを実行した場合……

 
no-console

このようなエラーが出力されます。これは、コンソールを使用した際に出力されるエラーです。しかし、コンソールは使うことがあるし、チェックをゆるくしたいなんて場合もあると思います。

 
そんなときはルールの設定を追加して、カスタマイズをしましょう!

{
    "extends": "eslint:recommended"
    "env": {
        "browser": true
    }
    "rules": {
        "no-console": 1 //コンソールを使用している
    }
}

まずは、rulesに変更や追加をしたいルール名を指定します。

 
no-console-warning

値は、0がチェックをしない、1がwarning(警告)、2がerrorとしてアラートを出すようになります。ですから、上記のようにコードを書くとコンソールを使用した際はwarning(警告)が出るようになります。

 
今度は、recommendedには設定されてないけど便利なルールを追加してみましょう。次に追加するルールは、クオートをシングルクオートで囲むか、ダブルクオートで囲むかをチェックする「quote」というルールです。

 
option

こちらのルールにはオプションがついています。

 
では実際にルールを設定してみましょう。

{
    "extends": "eslint:recommended",
    "env": {
        "browser": true
    },
    "rules": {
        "no-console": 1, //コンソールを使用している
        "quotes": [2, "single"] //シングルクオートを使用していない
    }
}

オプションが付いているルールは配列で設定値を渡します。1つ目がエラーの種類で、2つ目がルールのオプション設定です。quotesでは、ダブルクオートのみにしたい場合はdubble、シングルクオートのみにしたい場合はshigleと設定してあげます。

 

var date = new Date();
var element = document.getElementById("time");

function getTime(date){
    return date.getHours(date) + ":" + date.getMinutes(date) + ":" + date.getSeconds(date);
}

element.innerHTML = getTime(date);

では実際に、こちらのコードをチェックしてみましょう。

 
eslint04

すると、ダブルクオートを使っている部分でエラーが出ているのがわかるかと思います。

 
他にも覚えておくと便利なルールを下記にまとめてみたので、自分の環境に合わせて使用してみてください。

"rules": {
    "no-console": 1, //コンソールを使用している
    "no-alert": 1, //アラートを使用している
    "quotes": [2, "single"], //シングルクオートを使用していない
    "consistent-return": 1, //関数の戻り値に何も指定していない
    "default-case": 1, //switch文でdefaultが設定されていない
    "eqeqeq": 1, //「===, !==」ではなく「==,!=」を使用している
    "camelcase": [2, {"properties": "always"}], //キャメルケースを使用していない
    "no-unused-vars": 1 //使用していない変数がある
}

errorにするか、warningにするかは、自分の環境に合わせて調整してみてください。もちろん、まだ他にもたくさんのルールが存在します。単純な構文チェック以外にもどこにスペースを入れる入れないといった細かい指定もできます。適切に設定をして、良いルールを作っていきましょう。

ルールの内容がわからない場合やどんなルールがあるかを知りたい場合は、こちらのページをご覧ください。
Rules – ESLint

また、Web上でESLintを試してみることができるので、こちらも合わせて使ってみてください。
ESLint Demo – ESLint

errorがあるときには出力しないようにする

ルールによってチェックできるようになったので、今度はerrorが出ているときはファイルを出力しないように制御してみましょう。そのときに使用するのが、resultメソッドです。

gulp.task('script', function(){
    gulp.src('app/src/js/*.js')
        .pipe(plumber({
            errorHandler: notify.onError('Error: <%= error.message %>')
        }))
        .pipe(eslint({useEslintrc: true}))
        .pipe(eslint.format())
        .pipe(eslint.failAfterError())
        .pipe(eslint.result(function(result){
            if(result.errorCount !== 0) {
                return;
            }
            gulp.src(result.filePath)
                .pipe(gulp.dest('app/product/js/'));
        }))
        .pipe(browserSync.stream());
});

resultメソッドはチェックした結果を確認することができるメソッド。関数の引数には、結果が返ってきます。result.errorCountではerrorの数を、result.warningCountではwarningの数を、result.filePathではファイルのパスを確認できます。

もしresult.errorCountが0でない場合は処理をせず、0の場合にはファイルをproduct内に出力します。こうすることで、errorが見つかった際には出力されず、厳密にコードを保つことができます。

まとめ

ESLintはかなり高機能で、他にもカスタムのルールが使えるなどやれることが多いです。気になる方は、ぜひいろいろと調べてみてください。

これまで3回に分けてタスクの作り方をご紹介しましたが、タスクの組み方はわかってきたでしょうか? ドキュメントを読みながら使えば、そんなに怖くはありません。

次回はgulp.js連載の最終回。gulpライブラリの探し方と便利なライブラリをまとめてご紹介します! それでは。


この記事を書いた人

店長
店長 フロントエンドエンジニア 2015年入社
フロントエンドエンジニアの店長です。
LIGに入社と同時に店長(あだ名が)になりました。偉くはありません。
以前、某カフェで働いていました。

音楽とコーヒーが大好きです。よろしくお願いいたします。