gulp-sassで自動でSass/SCSSからcssファイルを生成する - 人生リアルタイムアタック の続き。完全上位互換のつもり。
前回は gulp-sass の導入だけだったので、この記事では gulp / Sass (SCSS) 周り全般について述べたい。
構成
以下のディレクトリ構成を例にする。
./test
├── css
│ └── // cssファイルの生成先
└── assets
│ └── sass
│ └── **/*.scss
└── index.html
Node.jsは LTSのv4.4.5 がインストール済みで、$ npm
コマンドが利用可能になっている前提。
package.jsonをつくる
最初に、Node.jsのパッケージ管理ファイルであるpackage.jsonを生成する。 package.jsonはコマンドで生成できる。
$ npm init -y
Wrote to /Users/<user_name>/git/test/package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
scripts に gulp default コマンドを追加する
package.jsonのscripts部分に "start": "gulp default",
を追加する。詳細は後述。
"scripts": {
"start": "gulp default",
"test": "echo \"Error: no test specified\" && exit 1"
},
package.jsonはこうなればOK.
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"dependencies": {},
"devDependencies": {},
"scripts": {
"start": "gulp default",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
インストール
それではgulpとgulp-sassをインストールする。
-g
オプションを付けずにプロジェクト配下にインストールすることで、複数人で開発する場合でもバージョンを揃えて利用するようにする。
先程package.jsonに "start": "gulp default",
を追加したのは、$ npm start
コマンドでプロジェクト配下にインストールしたgulpからdefaultタスクを実行する為の設定。
なお、開発環境用のツールなので--save-dev
を必ず書こう。
$ npm install gulp gulp-sass --save-dev
インストール完了後、package.jsonを開いてみよう。
...
"devDependencies": {
"gulp": "^3.9.1",
"gulp-sass": "^2.3.2"
},
...
devDependencies
に、gulpとgulp-sassが追加されていればOK.
package.jsonとは
package.jsonとは、Node.jsのパッケージ管理ファイル。
bundleのように今後は $ npm install
するだけで同じバージョンのパッケージをインストールすることが可能になる。
ただし、 --save-dev
を付け忘れると、devDependenciesに追加されないので忘れずに付けよう。
gulpfile.jsの作成
インストールが完了したので、今度はgulp-sassを利用する為のタスクをgulpfile.jsに記述していく。
まずは最も簡単な例として、*.scssに変更があれば自動で*.cssを生成する例。
'use strict';
var SCSS_SRC = './assets/sass/**/*.scss';
var CSS_DEST = './css/';
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('sass-compile', function(){
return gulp.src(SCSS_SRC)
.pipe(sass.sync().on('error', sass.logError))
.pipe(gulp.dest(CSS_DEST));
});
gulp.task('scss:watch', function(){
var watcher = gulp.watch(SCSS_SRC, ['sass-compile']);
watcher.on('change', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
});
gulp.task('default', ['scss:watch']);
sassとscssという単語が混在しているのはちょっと諦め気味...
なお、最近はgulp-plumberは不要。
試してみる。
ここまでで、既に自動でSCSSからcssファイルを生成できるので試してみる。
$ npm start
を叩いて、ファイルを保存するだけで既に自動でcssファイルが生成可能になる。
$ npm start
> test@1.0.0 start /Users/<user_name>/git/test
> gulp default
[11:57:40] Using gulpfile ~/git/test/gulpfile.js
[11:57:40] Starting 'scss:watch'...
[11:57:40] Finished 'scss:watch' after 12 ms
[11:57:40] Starting 'default'...
[11:57:40] Finished 'default' after 9.47 μs
この状態で、assets/sass/hoge/fuge.scss にこんなSCSSを書いてみる。
* {
font-size: 10rem;
p {
color: #ccc;
}
}
File /Users/<user_name>/git/test/assets/sass/hoge/fuge.scss was changed, running tasks...
[12:01:58] Starting 'sass-compile'...
[12:01:58] Finished 'sass-compile' after 35 ms
こんな感じのログがでて、./css/hoge/fuge.cssが生成されれば完了。終了するにはctrl + c
。
だが、SCSS環境構築はまだ終わりではない。
Lintツールを併用する
Sass/SCSSを書くにあたり、Lintツールを導入しなければCSS同様すぐ煩雑なコードになってしまう。
Lintツール無しで作ったSCSSはCSSの大差無く万人がみても分かりづらい。最初からLintを入れてどのように書けばいいのか学びながら書いた方がよい。
gulpがあれば自動でチェックできるので、このタイミングでLintツールを導入しよう。
Ruby製の scss-lint はドキュメントが充実しており、オプションも豊富で、一時的な除外もできて使い勝手がよい。airbnbがgithubに公開している有名なスタイルルールもこのscss-lint用だ。
ということで、scss-lintと、gulp上でscss-lintを実行する為の gulp-scss-lint の2つを導入する。
インストール
$ gem install scss_lint
$ npm install gulp-scss-lint --save-dev
gulpfile.jsにgulp-scss-lint設定を追加
先程つくったgulpfile.jsを以下のように3箇所書き換える。
var SCSS_SRC = './app/assets/stylesheets/**/*.scss';
var CSS_DEST = './css/';
var gulp = require('gulp');
var sass = require('gulp-sass');
var scsslint = require('gulp-scss-lint');
gulp.task('sass', function(){
...(略)
});
gulp.task('scss-lint', function(){
return gulp.src(SCSS_SRC)
.pipe(scsslint());
});
gulp.task('scss:watch', function(){
var watcher = gulp.watch(SCSS_SRC, ['scss-lint', 'sass-compile']);
watcher.on('change', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
});
gulp.task('default', ['scss:watch']);
scss:watchタスク内の配列にscss-lintタスクを追加したことで、sass-compile後にscss-lintを実行するようになった。
scss-lintタスクの書き方については幾つかあるが、上記のようにlintタスク単体で記述しておけばコンパイルせずにlintだけ単体実行することも可能になるので、独立したタスクにして配列で渡すとよい。
ちなみに.scss-lint.ymlを指定する場合にはこう書く。
gulp.task('scss-lint', function(){
return gulp.src(SCSS_SRC)
.pipe(scsslint({'config': '.scss-lint.yml'}));
});
Sass/SCSS書き換え時にブラウザ自動リロードしたい
Browsersync - Time-saving synchronised browser testing を利用する。
インストール
$ npm install browser-sync --save-dev
gulpfile.jsの書き換え
var HTML_SRC = './template/**/*.html';
var CSS_SRC = './css/**/*.css';
var bs = require('browser-sync').create();
...(略)
gulp.task('bs', function(){
var bsOptions = {};
bsOptions.files = [HTML_SRC, CSS_SRC];
bsOptions.server = './';
bs.init(bsOptions);
});
gulp.task('default', ['bs', 'sass-watch']);
試してみる
$ npm start
> test@1.0.0 start /Users/<user_name>/git/test
> gulp default
[16:08:24] Using gulpfile ~/git/test/gulpfile.js
[16:08:24] Starting 'bs'...
[16:08:24] Finished 'bs' after 16 ms
[16:08:24] Starting 'scss:watch'...
[16:08:24] Finished 'scss:watch' after 14 ms
[16:08:24] Starting 'default'...
[16:08:24] Finished 'default' after 13 μs
[BS] Access URLs:
----------------------------------------
Local: http://localhost:3000
External: http://xxx.xxx.xxx.xxx:3000
----------------------------------------
UI: http://localhost:3001
UI External: http://xxx.xxx.xxx.xxx:3001
----------------------------------------
[BS] Serving files from: ./
[BS] Watching files...
ブラウザで http://localhost:3000 index.html が開き、htmlやcssに変更があれば自動で再読み込みされるようになる。
Railsなどで開発している場合には、serverプロパティをコメントアウトした上で、コメントアウトしている bsOptions.proxy などの設定を有効化すれば利用可能。
オマケ1. gulp default以外もscriptsに登録する
gulpfile.jsにgulp defalutを追加した要領で、他のタスクも追加できる。
"scripts": {
"start": "gulp default",
"scss-lint": "gulp scss-lint",
"test": "echo \"Error: no test specified\" && exit 1"
}
上記のように記述すると、$ npm run-script scss-lint
で scss-lintタスクが実行可能。
start
, test
など、一部のコマンド以外は run-script を含めたコマンドになる、$ npm run
で確認しよう。
$ npm run
Lifecycle scripts included in test-project:
start
gulp default
available via `npm run-script`:
scss-lint
gulp scss-lint
オマケ2. gulpのタスクを都度package.jsonに書くのはダルい
"scripts": {
"start": "gulp default",
"gulp": "gulp",
"test": "echo \"Error: no test specified\" && exit 1"
}
とすると、$ npm run-script gulp <task_name>
で実行できる。
しかし開発環境として配布する場合には、メンバー間の余計なコストが掛からないようscriptsに幾つか纏めておいておいた方が良さ気。
オマケ3. ここでは語らないもの
- .scss-lint.ymlのつくり方
- 各エディタでのscss-lint実行方法
- お好みのエディタ名 + scss-lintでググろう
- Browsersyncの設定
- gulpfile.jsのscriptsの仕様
- 本番, デプロイ環境でのSCSSコンパイル環境
- Railsなどならそちらでアセットパイプラインの中で纏めてくれる。ベストプラクティス模索中。
- アプリケーションサーバ側でSCSSコンパイルしてくれるなら、gulpすら要らずBrowsersyncだけで事足りたりすることも。
〆
ということで、大体こんな感じのpackage.jsonとgulpfile.jsを現在は利用している。
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "gulp default",
"gulp": "gulp",
"scss-lint": "gulp scss-lint",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"browser-sync": "^2.13.0",
"gulp": "^3.9.1",
"gulp-sass": "^2.3.2",
"gulp-scss-lint": "^0.4.0"
}
}
gulpfile.js
'use strict';
var HTML_SRC = './template/**/*.html';
var CSS_SRC = './css/**/*.css';
var SCSS_SRC = './assets/sass/**/*.scss';
var CSS_DEST = './css/';
var gulp = require('gulp');
var sass = require('gulp-sass');
var scss_lint = require('gulp-scss-lint');
var bs = require('browser-sync').create();
gulp.task('bs', function(){
var bsOptions = {};
bsOptions.files = [HTML_SRC, CSS_SRC];
bsOptions.server = './';
bs.init(bsOptions);
});
gulp.task('sass-compile', function(){
return gulp.src(SCSS_SRC)
.pipe(sass.sync().on('error', sass.logError))
.pipe(gulp.dest(CSS_DEST));
});
gulp.task('scss-lint', function(){
return gulp.src(SCSS_SRC)
.pipe(scss_lint());
});
gulp.task('scss:watch', function(){
var watcher = gulp.watch(SCSS_SRC, ['scss-lint', 'sass-compile']);
watcher.on('change', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
});
gulp.task('default', ['bs', 'scss:watch']);
もうちょっと何かあったら追記する。