気が付けば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-debuggulp-notifyはエラー通知、gulp-plumberはエラーが発生した場合にタスクが停止するのを防止します。gulp-debugは処理中のファイルをログに表示できます。
次にDart Sassをコンパイルするために必要なパッケージを追加します。
yarn add -D gulp-dart-sass gulp-autoprefixer gulp-sourcemapsgulp-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-cachedgulpfile.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パッケージを別の物に変更するか、パッチを作って対応する方法があるので、よかったら続きの記事を読んでみてください。




コメント
※コメントは管理者が承認するまで表示されません