Gulp4でHTML / SASS / JavaScriptのLintを自動化

## 概要
生まれ変わったタスクランナーGulp4を使って、webサイト(≠ webアプリ)制作用のBoilerplateを作成し、HTML / SASS / JavaScriptの構文チェック（Lint）を自動化するタスクを作ってみました。
下記のようなsrcとdistに別れたフォルダ構成でのwebサイト制作において、`dist`側ではなく`src`ファイル側のインデントや文法エラーを自動的に修正して行きます。

```text:terminal:terminal
.
├── README.md
├── dist
│   ├── css
│   │   └── style.css
│   ├── img
│   │   ├── sample.jpg
│   ├── index.html
│   ├── js
│   │   ├── lib.min.js
├── gulpfile.js
├── package.json
├── scss-lint.yml
└── src
    ├── html
    │   ├── index.html
    ├── img
    │   ├── sample.jpg
    ├── js
    │   ├── app
    │   │　　　　└──  some_function.js
    │   └── core
    │      └── jquery-3.3.1.js
    │ 
    │       
    └── sass
        ├── foundation
        │   ├── _config.scss
        │   ├── _mixin.scss
        │   └── _reset.scss
        ├── layout
        │   ├── _common.scss
        │   ├── _footer.scss
        │   ├── _header.scss
        │   └── _sidebar.scss
        ├── object
        │   ├── component
        │   │   ├── _breadcrumb.scss
        │   │   ├── _button.scss
        │   │   ├── _form.scss
        │   │   └── _nav.scss
        │   ├── project
        │   └── utility
        │       ├── _clearfix.scss
        │       └── _utility.scss
        └── style.scss
```
### 期待するメリット
- 手作業構文テストからの脱却
- 構文エラー減少によるコード品質の高位安定化
- ケアレスミスに気づきやすくなる
- 古い（obsoleteな）記法のコードが減らせる
- CSSプロパティ順を統一することでgzip圧縮時のパフォーマンスが上がる
- どのエディタを使って作業してもインデントや改行など些細なスタイルの違いが現れることがなくなる
 - [宗教戦争](https://youtu.be/SsoOG6ZeyUI)の回避 => 世界平和の到来:angel:
 - Gitで差分が取りやすくなる
 - 複数人が参加するチーム仕事がやりやすくなる
- .cssなどコンパイル済みファイルではなく、.scssファイル形式などのソースファイルで納品できるようになる

## 使用するパッケージ
### [HTMLHint](http://htmlhint.com/)
HTMLのvalidator / linterは色々ありましたが、ダウンロード数が多くまたメンテナンスが継続されていたこのパッケージを採用。

### [gulp-scss-lint](https://www.npmjs.com/package/gulp-scss-lint)
Sassのvalidator / linter。scss-lintはruby gemであり別途インストールが必要。
※gemはアンダースコアの（scss_lint）なので注意。
※rubyやxcodeのバージョン違い、MacOSをSierraからHigh Sierraにアプデした場合などにエラーが出ることがあります。そのときは下記を参照してください。
[Ruby Sass is Deprecated](http://sass.logdown.com/posts/7081811)だったりすることもあり、sassのLintツールはnode-sassベースの[gulp-sass-lint](https://www.npmjs.com/package/gulp-sass-lint)など他のパッケージも検討中です。

#### `$ gem install scss_lint`でエラーが出るとき
- `$ gem install scss_lint`でインストール失敗するときはまず`$ sudo gem install -n /usr/local/bin scss_lint`を試してみてください。
- それでもダメなときは以下が参考になります。
  - [Homebrewのインストールとrbenvのインストールまで Mac編](https://qiita.com/is-lab/items/e0443b79da117ed48294)
  - [rbenvでバージョンがうまく切り替わらなかった時にやったこと
](https://qiita.com/akatsuki174/items/c0384b9903b4b5cbbdaf)
  - [macOS High SierraにアップグレードしたあとGitコマンドでエラーが出た Command Line Toolsを新しくする](https://e-yota.com/idle_talk/mac-os-high-sierra_git_xcrun_error/)


### [gulp-eslint](https://www.npmjs.com/package/gulp-eslint)
おなじみ[ESLint](https://eslint.org/)のgulp版。
さあ、関連パッケージを一気にインストールしましょう。
これらのパッケージは全て開発にしか使わないので`--save-dev`オプションをつけてしまっていいと思います。
Gulp3=>Gulp4はBreaking Changeで今までのコードが動かなくなる可能性が高いので今Gulp3を使っている方は要注意。後で紹介している[Gulp4への移行方法](#gulp4関連)をご覧ください。

```terminal:terminal
gem install scss_lint
※上記コマンドでエラーが出る場合はこっち＝＞ sudo gem install -n /usr/local/bin scss_lint
npm i gulp@next --save-dev
npm i gulp-sass --save-dev
npm i gulp-htmlhint --save-dev
npm i gulp-scss-lint --save-dev
npm i sass-lint-auto-fix --save-dev
npm i gulp-eslint　--save-dev
npm i gulp-reporter --save-dev
```

## gulpfile.js
以下はLint関連箇所の抜粋です。
gulp4では`gulp.series`でタスクの直列処理、`gulp.parallel`で並列処理ができるようになっているのがいい感じです。
コードの見通しが良くなるので、慣れればこっちの方が使いやすそうです。

```js:gulpfile.js
const eslint = require("gulp-eslint");
const gulp = require("gulp");
const htmlhint = require("gulp-htmlhint");
const scsslint = require("gulp-scss-lint");
const paths = {
    root: "./src",
    html: {
        src: "./src/html/**/*.html",
        dest: "./dist/"
    },
    styles: {
        src: "./src/sass/**/*.scss",
        dest: "./dist/css"
    },
    scripts: {
        src: "./src/js/**/*.js",
        jsx: "./src/js/**/*.jsx",
        dest: "./dist/js"
    }
};

//===Lint Tasks===
//HTML Lint
function htmlLint() {
    return gulp
        .src(paths.html.src)
        .pipe(htmlhint())
	    .pipe(htmlhint.reporter())
}
//SASS Lint
function sassLint() {
    return gulp.src(paths.styles.src).pipe(
        scsslint({
            config: "scss-lint.yml"
        })
    );
}
//ESLint
function esLint() {
    return gulp
        .src([paths.scripts.src, paths.scripts.jsx, "!./src/js/core/**/*.js"])
        .pipe(eslint({
            fix: true
        }))
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
}

gulp.task("eslint", esLint);
gulp.task("html-lint", htmlLint);
gulp.task("sass-lint", sassLint);
gulp.task("lint", gulp.series(sassLint, esLint, htmlLint));

```
## package.json
関係ある箇所の抜粋です。

```json:package.json
{
  "name": "gulp-boilerplate",
  "version": "1.0.0",
  "main": "gulpfile.js",
  "dependencies": {},
  "author": "me",
  "license": "ISC",
  "description": "frontend develop gulp modules",
  "repository": {
    "type": "git",
    "url": ""
  },
  "devDependencies": {
    "eslint-plugin-react": "^7.10.0",
    "gulp": "^4.0.0",
    "gulp-eslint": "^4.0.2",
    "gulp-htmlhint": "^2.1.1",
    "gulp-reporter": "^2.8.3",
    "gulp-sass": "^4.0.1",
    "gulp-scss-lint": "^0.6.1",
    "sass-lint-auto-fix": "^0.11.0"
  },
  "scripts": {
    "sass-lint": "sass-lint -v",
    "sass-lint:fix": "sass-lint-auto-fix -c scss-lint.yml",
    "lint": "sass-lint-auto-fix -c scss-lint.yml & gulp lint"
  }
}
```
## 実行
`$ npm run lint -s` でHTML, SASS, JavaScriptをまとめてLintします。
HTMLHint, scss-lint, ESLint共に豊富なオプションが用意されているので適宜自分にあった設定を追加していきましょう。
### 実行時のnpmエラー
`$ npm run lint`を実行すると以下のようなエラーが出ます。

```terminal:terminal
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! yourproject@1.0.0 test: `gulp lint`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the yourproject@1.0.0 lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
```
これはテストに通っていないからエラーが出てるというある種正常な状態なので、 `$ npm run lint -s` と `--silent`オプションをつけてこのエラー表示を消してやります。

### sass-lint-auto-fix
scss-lintに[sass-lint-auto-fix](https://www.npmjs.com/package/sass-lint-auto-fix)を組み合わせることで、`$ npm run sass-lint:fix`でsrcフォルダ内の.scssファイルがルールに基づき自動修正されます。

# 参考文献
下記を参考にさせていただきました。ありがとうございます。

### gulp4関連
- [gulp API docs at v4.0.0](https://github.com/gulpjs/gulp/blob/v4.0.0/docs/API.md)
- [gulp4.0にしました。 - cidermitaina](http://cidermitaina.hatenablog.com/entry/2017/11/27/014525)
- [Webデザイナーの仕事を楽にする! gulpではじめるWeb制作ワークフロー入門 公式サポートサイト](https://nayucolony.github.io/gulp-support/)
- [gulp v4.0.0がプレリリース！ 移行方法と変更点まとめ
](https://satoyan419.com/gulp-v4/)

### 自動Lintとツール関連
- [JavaScript、HTML、CSSを簡単にLintできる開発環境を作った](https://qiita.com/muraken720/items/468b9f420ab4c900e241)
- [HTMLHint](http://htmlhint.com/)
- [【gulp】「gulp-htmlhint」でHTMLの文法をチェックする方法をメモメモ](http://bashalog.c-brains.jp/15/10/08-121056.php)
- [gulp gulp-eslint の設定](https://qiita.com/choro/items/83507a3c46092a1470ca)
- [SassのファイルをSCSS-Lint+Gulpで自動的にテスト](https://firegoby.jp/archives/6595)
- [sass-lintのエラールールを日本語で分かるようにした](https://qiita.com/nezurika/items/4cc858ee9ebd6154dd44)

# 所感
Gulp4は3よりコードの見通しがよくなってて好き。
またsass-lint-auto-fixはコマンド一発でインデントやCSSプロパティの順番など気にせず雑に書いたコードが綺麗に自動整形されるのが気持ちいいです。
また今後はテンプレートエンジンや[Prettier](https://prettier.io/)やWebpackと組み合わせた構成にして行ければ。

この運用を始めたばかりなので、導入の結果どうなったかについてはまだ書くことができません。半年後くらいに続報を追記できればと思います。:bow_tone1: