Gulp: only compile changed files AND compile paren

2020-06-23 08:51发布

问题:

At work we used to use Ruby to compile SCSS. I had the Ruby compiler set up as a file watcher in PhpStorm, and when I edited a partial imported by another file, the CSS file corresponding to the ancestor file was updated without any fuss.

I want to get Gulp and Libsass to work the same way. Most solutions I've seen just compile all the SCSS files in a project when a single one changes, but our projects have way too much SCSS for that to be an acceptable solution.

gulp-cached seemed like a great solution to this problem. But when I use gulp-cached the CSS output file doesn't change when I edit partials, only their ancestor SCSS files.

I've seen a few SCSS dependency-graph solutions thrown around but I can't get them to work correctly or they simply don't do what I need. I've tried gulp-sass-graph, gulp-sass-inheritance, and gulp-sass-partials-imported.

Here's my gulp file

const gulp = require('gulp');
const glob = require('glob');
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const cached = require('gulp-cached');
const sassGraph = require('gulp-sass-graph');

const sassGlobs = [
  './sites/all/libraries/gl/**/*.scss',
  './sites/all/modules/custom/**/*.scss',
  './sites/all/themes/{bcp_bootstrap3,gl_parent,gl_shiny,gli_bootstrap3,pru_bootstrap3,pru_bootstrap3v2,ubc_bootstrap3}/**/*.scss',
];

let sassPaths = [];

for (let j = 0; j < sassGlobs.length; ++j) {
  glob(sassGlobs[j], function (er, files) {
    let path;
    for (let i = 0; i < files.length; ++i) {
      path = files[i].substring(0, files[i].lastIndexOf('/'), '');

      if (sassPaths.indexOf(path) === -1) {
        sassPaths.push(path);
      }
    }
  });
}

gulp.task('sass', function () {
  return gulp
    .src(sassGlobs, {base: "./"})
    // .pipe(sassGraph(sassPaths))
    .pipe(cached('sasscache'))
    .pipe(sourcemaps.init())
    .pipe(
      sass({outputStyle: 'compressed'})
        .on('error', sass.logError)
    )
    .pipe(sourcemaps.write())
    .pipe(gulp.dest((file) => file.base));
});

gulp.task('watch', function () {
  return gulp.watch(sassGlobs, ['sass']);
});

gulp.task('default', ['sass', 'watch']);

回答1:

what I use to solve this problem is gulp-cached + gulp-dependents + gulp-filter

the key point here is gulp-dependents, it will find all the parent files that depends on the current file.

in your case, you just need:

const cached = require('gulp-cached');
const dependents = require('gulp-dependents');
const filter = require('gulp-filter');

const f = filter(['**', '!*src/partial']); //adjust this filter to filter the file you want to compile(pass to the sourcemap init method)

gulp.task('sass', function () {
  return gulp
    .src(PATH_TO_ALL_SASS_FILES, {base: "./"})
    .pipe(cached('sasscache'))
    .pipe(dependents())// this will find all parents of current changed files
    .pipe(f) //exclude the partial files,get the files you want to compile
    .pipe(sourcemaps.init())
    .pipe(
      sass({outputStyle: 'compressed'})
        .on('error', sass.logError)
    )
    .pipe(sourcemaps.write())
    .pipe(gulp.dest((file) => file.base)); // you might need to adjust the base path here, depend on your folder structure.
});