気が付けばLibSassが非推奨になりDart Sassへ移行が進んでいるので、今回はgulpでDart Sassのコンパイル環境構築をざっくり説明を入れながら作成していきます。
- Dart Sassのコンパイル環境を作成
- scssタスクの自動実行
- watchタスクにキャッシュ機能を付ける
Dart Sassのコンパイル環境を作成
ファイル構成
src/assets/scss
をコンパイルしてpublic/assets/css
に出力する構成です。
├─ public/
│ └─ assets/
│ └─ css/
│ └─ コンパイルされたcss
│
├─ src/
│ └─ assets/
│ └─ scss/
│ ├─ _variable.scss
│ ├─ layout.scss
│ └─ home.scss
│
├─ gulpfile.js
└─ package.json
パッケージの追加
gulpを実行するために必要なパッケージを入れます。
yarn add -D gulp gulp-notify gulp-plumber gulp-debug
gulp-notify
はエラー通知、gulp-plumber
はエラーが発生した場合にタスクが停止するのを防止します。gulp-debug
は処理中のファイルをログに表示できます。
次にDart Sassをコンパイルするために必要なパッケージを追加します。
yarn add -D gulp-dart-sass gulp-autoprefixer gulp-sourcemaps
gulp-dart-sass
は今回の主役です。gulp-autoprefixer
はベンダープレフィックスを追加してくれます。gulp-sourcemaps
はChrome等の検証ツールからコンパイル前のソースを調べやすくできます。
その他に圧縮したりするパッケージも入れたほうがいいですが、最低限これだけあれば十分かと思います。
scssファイルの作成
src/assets/scss
ディレクトリにlayout.scss
と@use
で読み込む設定ファイル_variable.scss
を作成します。
ついでに複数ファイルが正常にコンパイルされるか確認するためにhome.scss
を作成しておきます。
// 設定 - _variable.scss
$font_color: #262f2d;
$bg_color: #2aa47A;
// Layout - layout.scss
@use "variable" as vars;
body {
font-size: 1.6rem;
color: vars.$font_color;
background: vars.$bg_color;
}
// Home - home.scss
body {
font-size: 2rem;
}
gulpfile.jsの作成と実行
gulpfile.jsにDart Sassのコンパイルタスクを記述します。
const gulp = require('gulp');
const notify = require('gulp-notify'); // エラー通知
const plumber = require('gulp-plumber'); // エラー時のタスク停止防止
const debug = require('gulp-debug'); // ログ表示
const dartSass = require('gulp-dart-sass');
const autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス付与
const sourcemaps = require('gulp-sourcemaps'); // ソースマップ出力
const paths = {
scss: {
src: 'src/assets/scss/**/*.scss', // コンパイル対象
dest: 'public/assets/css' // 出力先
}
}
/**
* scssタスクで実行する関数
*/
function scss() {
return gulp.src(paths.scss.src)
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(sourcemaps.init())
.pipe(dartSass({
outputStyle: 'expanded'
}))
.pipe(autoprefixer({
cascade: true
}))
.pipe(sourcemaps.write('/maps'))
.pipe(gulp.dest(paths.scss.dest))
.pipe(debug({title: 'scss dest:'}));
}
exports.scss = scss; // scssタスク
exports.default = gulp.series(scss); // defaultタスク
作成したタスクが正常に動作するか確認するため、ターミナルからyarn gulp
かyarn gulp scss
、環境によってはgulp
かgulp scss
でコンパイルできるか試してみます。
# defaultタスクの実行
yarn gulp
# scssタスクの実行
yarn gulp scss
正常に動作した場合は以下のファイルが出力されます。
- public/assets/css/layout.css
- public/assets/css/home.css
- public/assets/css/maps/layout.css.map
- public/assets/css/maps/home.css.map
これでDart Sassのコンパイル環境は完成です。
scssタスクの自動実行
前述で作成したscssタスクを自動実行させるようにwatchタスクを作成します。
watchタスクはファイルを監視させて変更があった場合に指定したタスクを実行できます。
watchタスクの追加と実行
gulpfile.jsを以下のように変更します。(ハイライトされている行が変更点)
const gulp = require('gulp');
const notify = require('gulp-notify'); // エラー通知
const plumber = require('gulp-plumber'); // エラー時のタスク停止防止
const debug = require('gulp-debug'); // ログ表示
const dartSass = require('gulp-dart-sass');
const autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス付与
const sourcemaps = require('gulp-sourcemaps'); // ソースマップ出力
const paths = {
scss: {
src: 'src/assets/scss/**/*.scss', // コンパイル対象
dest: 'public/assets/css' // 出力先
}
}
/**
* scssタスクで実行する関数
*/
function scss() {
return gulp.src(paths.scss.src)
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(sourcemaps.init())
.pipe(dartSass({
outputStyle: 'expanded'
}))
.pipe(autoprefixer({
cascade: true
}))
.pipe(sourcemaps.write('/maps'))
.pipe(gulp.dest(paths.scss.dest))
.pipe(debug({title: 'scss dest:'}));
}
/**
* watchタスクで実行する関数
*/
function watch() {
return gulp.watch(paths.scss.src, gulp.series(scss))
}
exports.scss = scss; // scssタスク
exports.watch = watch; // watchタスク
exports.default = gulp.series(scss); // defaultタスク
watchタスクで実行する関数(36-41行目)とwatchタスク(44行目)を追加しました。
監視対象はscssタスクのsrcと同じsrc/assets/scss/**/*.scss
です。
ターミナルからyarn gulp watch
コマンドを実行すると監視状態になるので、layout.scss
や home.scss
を変更して保存すると自動的にコンパイルされます。
# watchタスクの実行(停止:Ctrl + C)
yarn gulp watch
これでwatchタスクは一応完成です。
次はキャッシュ機能を付けて、変更があったファイルのみコンパイルされるようにします。
watchタスクにキャッシュ機能を付ける
ここまでの流れで一応完成ですが、layout.scss
の内容を変更して保存すると、関係のないhome.scss
までコンパイルされてしまいます。
Starting 'watch'...
Starting 'scss'...
scss dest: public/assets/css/maps/home.css.map ← 変更していないファイル
scss dest: public/assets/css/home.css ← 変更していないファイル
scss dest: public/assets/css/maps/layout.css.map
scss dest: public/assets/css/layout.css
scss dest: 4 items
Finished 'scss' after 175 ms
変更を加えていないファイルまでコンパイルされてしまうと処理時間が増えてしまうため、変更したファイルだけコンパイルされるようにgulp-cached
パッケージを追加します。
gulp-cachedパッケージの追加と実装
gulp-cached
を使うとファイルをキャッシュして、変更があるファイルのみ処理されるようになります。
ターミナルから以下のコマンドを実行してパッケージを追加します。
yarn add -D gulp-cached
gulpfile.jsを以下のように変更します。
const gulp = require('gulp');
const notify = require('gulp-notify'); // エラー通知
const plumber = require('gulp-plumber'); // エラー時のタスク停止防止
const debug = require('gulp-debug'); // ログ表示
const dartSass = require('gulp-dart-sass');
const autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス付与
const sourcemaps = require('gulp-sourcemaps'); // ソースマップ出力
const cached = require('gulp-cached'); // ファイルキャッシュ
const paths = {
scss: {
src: 'src/assets/scss/**/*.scss', // コンパイル対象
dest: 'public/assets/css' // 出力先
}
}
/**
* scssタスクで実行する関数
*/
function scss() {
return gulp.src(paths.scss.src)
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(cached('scss')) // ファイルをキャッシュ
.pipe(sourcemaps.init())
.pipe(dartSass({
outputStyle: 'expanded'
}))
.pipe(autoprefixer({
cascade: true
}))
.pipe(sourcemaps.write('/maps'))
.pipe(gulp.dest(paths.scss.dest))
.pipe(debug({title: 'scss dest:'}));
}
/**
* watchタスクで実行する関数
*/
function watch() {
return gulp.watch(paths.scss.src, gulp.series(scss))
}
exports.scss = scss; // scssタスク
exports.watch = watch; // watchタスク
exports.default = gulp.series(scss); // defaultタスク
10行目に追加したgulp-cached
パッケージを読み込み、27行目にキャッシュの設定を追加しました。
ターミナルからyarn gulp watch
コマンドを実行して、layout.scss
かhome.scss
を変更すると、1回目はキャッシュがないのですべてのファイルがコンパイルされ、2回目からは変更したファイルだけコンパイルされるようになります。
処理説明をすると実際はすべてのファイルが処理されていますが、キャッシュが行われたファイルに変更がない場合は27行目で処理が中断されます。
27行目の.pipe(cached('scss'))
の前に以下を追加すると処理中のファイル名が表示されますが、コンパイル結果のログには変更があったファイルのみ表示されていることが分かります。
.pipe(require('through2').obj((file, enc, callback) => {
console.log('file:', file.path)
return callback(null, file);
}))
これでキャッシュ機能が正常に動いているのは確認できましたが、できれば1回目から変更したファイルだけコンパイルするのが理想的なので、先にキャッシュさせるように変更します。
先にキャッシュを行うように変更
gulpfile.jsを以下のように変更します。
const gulp = require('gulp');
const notify = require('gulp-notify'); // エラー通知
const plumber = require('gulp-plumber'); // エラー時のタスク停止防止
const debug = require('gulp-debug'); // ログ表示
const dartSass = require('gulp-dart-sass');
const autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス付与
const sourcemaps = require('gulp-sourcemaps'); // ソースマップ出力
const cached = require('gulp-cached'); // ファイルキャッシュ
const paths = {
scss: {
src: 'src/assets/scss/**/*.scss', // コンパイル対象
dest: 'public/assets/css' // 出力先
}
}
/**
* scssタスクで実行する関数
*/
function scss() {
return gulp.src(paths.scss.src)
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(cached('scss')) // ファイルをキャッシュ
.pipe(sourcemaps.init())
.pipe(dartSass({
outputStyle: 'expanded'
}))
.pipe(autoprefixer({
cascade: true
}))
.pipe(sourcemaps.write('/maps'))
.pipe(gulp.dest(paths.scss.dest))
.pipe(debug({title: 'scss dest:'}));
}
/**
* scssファイルをキャッシュする関数
*/
function scssCache(){
return gulp.src(paths.scss.src)
.pipe(cached('scss')) // ファイルをキャッシュさせる
.pipe(debug({title: 'scss cached:'}));
}
/**
* watchタスクで実行する関数
*/
function watch() {
return gulp.watch(paths.scss.src, gulp.series(scss))
}
exports.scss = scss; // scssタスク
exports.watch = gulp.series(scssCache, watch); // watchタスク
exports.default = gulp.series(scss); // defaultタスク
40-47行目にscssファイルのキャッシュを行うscssCache
関数と、57行目のwatchタスクでscssCache
関数を呼び出した後にwatch
関数を呼ぶように変更しました。gulp watch
を実行後にlayout.scss
を変更して保存するとlayout.scss
のみコンパイルされます。
ただしキャッシュ機能の副作用で、@use
で読み込んでいる_variable.scss
を変更して保存すると何も起こらないはずです。
これは_variable.scss
の読み込み元であるlayout.scss
に変更がないため何も処理されないというわけです。
単純な解決方法としてはlayout.scss
を変更するか、scssタスクを実行させればいいのですが何だかモヤッとします…。
この問題を解決するには、sassファイルの親子関係を管理しているsass-graph
パッケージを別の物に変更するか、パッチを作って対応する方法があるので、よかったら続きの記事を読んでみてください。
コメント