gulp-community / gulp-cached

A simple in-memory file cache for gulp
MIT License
452 stars 23 forks source link

Need an option to init the cache #17

Open thatkookooguy opened 8 years ago

thatkookooguy commented 8 years ago

Currently, when I run my gulp watch task, everything is linted on the first save. The second time around, only the file I changed gets linted.

My question: Is there a way to enable some sort of init value? I want to cache all my javascript files the first time around if the cache is empty, but NOT lint at all. after that, start my piping and only the changed file will be linted

yocontra commented 8 years ago

@Thatkookooguy You can access the cache with cache.caches[cacheName] - if this allows you to solve the problem I can look into adding an option for this, lmk 🌴

aegyed91 commented 8 years ago

@contra @Thatkookooguy I think i have a similar problem. Imagine you have multiple css tasks that work from the same source (scss-compiler, scss-linter). Because of this you want to cache the contents under the same namespace fe: cache('scss-files'). In this scenario the very first task will run and all subsequent tasks will do nothing because the first task updated the cache.

Example (with optional pre task):

gulp.task('sass-lint', () => {
  return gulp.src(paths.src)
    .pipe(gulpIf(config.isDev, cache(config.css.cacheName)))
    .pipe(sassLint())
    .pipe(sassLint.format())
    .pipe(sassLint.failOnError());
});

const preTasks = (!config.sassLint.ideSupport && config.isDev) ? ['sass-lint'] : [];

gulp.task('css', preTasks, () => {
  return gulp.src(paths.src)
    .pipe(gulpIf(config.isDev, cache(config.css.cacheName)))
    .pipe(gulpIf(config.isDev, progeny()))
    ...
});

Solution: save the previous state of the cache somewhere and only update it at the very last of same cache namespaced task? How would you do this?

cookch10 commented 8 years ago

+1

Here's a workaround that I implemented in my gulpfile.js. This example allows creating a watch task that will only lint JavaScript files that have changed:

var gulp = require('gulp');

var gulpif = require('gulp-if');

var gulpCached = require('gulp-cached');

var eslint = require('gulp-eslint');

var jscs = require('gulp-jscs');

var uglify = require('gulp-uglify');

var through2 = require('through2');

(function () {
    'use strict';

    const linting = 'linting';

    var buildConfig = {
        flags: {
            watch: false,
            build: false
        },
        src: {
            scripts: ['./app/**/*.js', './src/**/*.js']
        }
    };

    var preCacheGulpCached = function (src, cache, cacheId, cb) {
        /* Pre-build a cache for gulp-cached plugin */

        var cacheEntry = cache.caches[cacheId] = cache.caches[cacheId] || {},
            cacheFile,
            stream;

        stream = gulp.src(src).pipe(through2.obj(function (file, encoding, callback) {
            var contents = file.checksum;

            if (!contents) {
                if (file.isStream()) {
                    this.push(file);

                    callback();
                }
                if (file.isBuffer()) {
                    contents = file.contents.toString('utf8');
                }
            }

            cacheFile = cacheEntry[file.path];

            if (typeof cacheFile !== 'undefined' && cacheFile === contents) {
                callback();
            }

            cacheEntry[file.path] = contents;

            this.push(file);

            callback();
        }, cb));

        return stream;
    };

    gulp.task('eslint', function () {
        return gulp.src(buildConfig.src.scripts)
            .pipe(eslint('.eslintrc'))
            .pipe(eslint.format())
            .pipe(eslint.failAfterError());
    });

    gulp.task('jscs', function () {
        return gulp.src(buildConfig.src.scripts)
            .pipe(jscs({ configPath: '.jscsrc' }))
            .pipe(jscs.reporter())
            .pipe(jscs.reporter('fail'));
    });

    gulp.task('lint', function () {
        return gulp.src(buildConfig.src.scripts)
            .pipe(gulpif(buildConfig.flags.watch, gulpCached(linting)))
            .pipe(eslint('.eslintrc'))
            .pipe(eslint.format())
            .pipe(jscs({ configPath: '.jscsrc' }))
            .pipe(jscs.reporter())
            .pipe(gulpif(buildConfig.flags.build, jscs.reporter('failImmediately')))
            .pipe(gulpif(buildConfig.flags.build, eslint.failAfterError()));
            //.on('error', process.exit.bind(process, 1)); alternatively, this could be used in place of eslint.failAfterError.
    });

    gulp.task('watch', function () {
        buildConfig.flags.watch = true;

        preCacheGulpCached(buildConfig.src.scripts, gulpCached, linting, function () {
            console.log('gulp-cached pre-cache complete');
        });

        gulp.watch(buildConfig.src.scripts, ['lint']);
    });

})();
lewismoten commented 8 years ago

I'm running into the same problem where I need to pre-cache before the watch triggers linting.

thatkookooguy commented 8 years ago

@cookch10 tried your solution and for some reason I don't even see the console.log for the pre-cach being complete.

did something change? thanks for the script btw! it at least gave me a starting point :-)

thatkookooguy commented 8 years ago

fixed it by making the following change:

var preCacheGulpCached = function (src, cache, cacheId, cb) {
  /* Pre-build a cache for gulp-cached plugin */

  var cacheEntry = cache.caches[cacheId] = cache.caches[cacheId] || {},
    cacheFile,
    stream;

  stream = gulp.src(src).pipe(through2.obj(function (file, encoding, callback) {
    var contents = file.checksum;

    if (!contents) {
      if (file.isStream()) {
        this.push(file);

        callback();
      }
      if (file.isBuffer()) {
        contents = file.contents.toString('utf8');
      }
    }

    cacheFile = cacheEntry[file.path];

    if (typeof cacheFile !== 'undefined' && cacheFile === contents) {
      callback();
    }

    cacheEntry[file.path] = contents;

    this.push(file);

    cb();
  }));

  return stream;
};

it looks like through2 now accepts only one variable

thatkookooguy commented 8 years ago

So, since @cookch10 didn't work for me for some reason, I copied his idea and created a function to initialize the cache.

It's probably bad practice somewhere, but here we go:

var gulp = require('gulp'),
      cache = require('gulp-cached'),
      gulpif = require('gulp-if'),
      gcallback = require('gulp-callback');

var preCacheGulpCached = function (src, cacheId, cb) {
  /* Pre-build a cache for gulp-cached plugin */
  var callCallback = true; // fix callback executing more than once
  return gulp.src(src)
    .pipe(cache(cacheId))
    .pipe(gcallback(function() {
      if (callCallback && cb) {
        cb();
        callCallback = false;
      }
    }));
};

gulp.task('jscpd', function() {
  return gulp.src(FILES.LINT)
    .pipe(gulpif(buildConfig.flags.watch, cache('jscpd')))
    .pipe(jscpd({
      'min-lines': 10,
      verbose    : true
    }));
});

gulp.task('magicNumbers', function () {
  return gulp.src(FILES.JS_ALL)
    .pipe(gulpif(buildConfig.flags.watch, cache('magicNumbers')))
    .pipe(buddyjs({
      reporter: 'detailed'
    }));
});

gulp.task('watch', function() {
      buildConfig.flags.watch = true;

      preCacheGulpCached(FILES.JS_ALL, 'jscpd');
      preCacheGulpCached(FILES.JS_ALL, 'magicNumbers');
      if (argv.lint) {
        preCacheGulpCached(FILES.LINT, 'linting');
      }

      gulp.watch(argv.lint ? FILES.LINT : [], ['lint-js']);
      gulp.watch(FILES.JS_ALL, ['jscpd', 'magicNumbers']);
      gulp.watch(FILES.FRONTEND_SASS, ['styles']);
      gulp.watch(FILES.SERVER_JS).on('change', restart);
      gulp.watch(FILES.FRONTEND_ALL).on('change', function(file) {
        reloadBrowser('Frontend file changed.', file.path);
      });
    });

I use gulp-callback since I need something after the chache command. If I don't include something after the cache in preCacheGulpCached, The files aren't being cached.

I also tried to call the actual callback with gulp-callback but it printed out 3 times for each run so I removed it. UPDATE: fixed the multiple callback execution

but it works!

yocontra commented 8 years ago

How would y'all want to see this functionality added to the project? Anyone want to propose some APIs?

gosteev commented 8 years ago

the way i managed files to be precached using @Thatkookooguy function:

gulp.task('watch-pages', function(){
  return preCache(templatePagesPath, 'pages', function(){
    gulp.watch(templatePagesPath, ['pages']);
  });
})

gulp.task('watch-styles', function(){
  return preCache(stylesheetsPath, 'styles', function(){
    gulp.watch(stylesheetsPath, ['styles']);
  });
})

gulp.task('watch', ['watch-pages','watch-styles']);

notice the return statement - without it caching doesn't work