themekit: Watch doesn't trigger while processing scss with Gulp

Describe the bug I am using Gulp to compile several .scss files into my main theme.scss.css file (which is in the assets directory). This works fine, but Theme Watch doesn’t recognise when the theme.scss.css file has been updated when recompiled. However, if I manually update the theme.scss.css file in my IDE it will recognise the change and push up to the remote server.

Working with other normal section, asset and snippet files works fine - theme watch detects the change and pushes them up.

To Reproduce Steps to reproduce the behavior:

  1. Install Gulp and create the following Gulpfile.js:
const gulp = require('gulp');
const sass = require('gulp-sass');
const rename = require("gulp-rename");

gulp.task('sass', function(){
  return gulp.src('scss/main.scss')
	.pipe(sass())
	.pipe(gulp.dest('css'))
});

gulp.task('rename', function(){
return gulp.src("css/main.css")
  .pipe(rename("theme.scss.css"))
  .pipe(gulp.dest("assets"));
});

gulp.task('do-sass', gulp.series('sass', 'rename'))`
  1. Run theme watch
  2. Compile scss with the gulp do-sass command
  3. theme watch may push up the first set of changes to theme.scss.css, but not any subsequent changes

Expected behavior A clear and concise description of what you expected to happen.

Environment (please complete the following information):

  • OS [e.g. iOS]: MacOS 10
  • Themekit version [e.g. v0.7.5]: 1.0.0
  • Editor [e.g. atom, sublime]: Sublime

Additional context Add any other context about the problem here.

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 26 (8 by maintainers)

Most upvoted comments

Currently, this is a feature of gulp 4 due to a limitation of node’s fs.Stat object. If you need mtime to change - you need to modify the mtime on the files in your pipeline.

So it seems like will not be fixed in Gulp, we will have to find ways of handling it downstream and it sounds like they even suggest something like my gulp-touch solution. I will see if there is something I can do within themekit to handle this better without effecting other tools

Edit: It seems like even in the other issues linked in the gulp issue, other developers have solved this in a similar way.

gulp-touch (and similar gulp-touch-xxx) npm packages are 2 years out of date and don’t appear to be working for gulp 4, FYI. I was able to achieve results using through2 which will accept a Writeable stream and allow me to change the atime/mtime.

const { task, watch, src, dest, series } = require('gulp');
const sass = require('gulp-sass');
const autoprefix = require('gulp-autoprefixer');
const t2 = require('through2'); // Get through2 as t2

sass.compiler = require('node-sass');

function scss(cb) {
  src('./src/scss/**/*.scss')
    .pipe(sass({outputStyle: 'expanded'}))
    .on('error', sass.logError)
    .pipe(autoprefix({
      browsers: ['> 2%', 'ie >= 10'],
      grid: true
    }))
    .pipe(t2.obj((chunk, enc, cb) => { // Execute through2
      let date = new Date();
      chunk.stat.atime = date;
      chunk.stat.mtime = date;
      cb(null, chunk);
    }))
    .pipe(dest('./assets/'))

    cb();
}

function watcher(cb) {
  watch('./src/scss/**/*.scss', series(scss))
  cb()
}

module.default = task('default', series([scss, watcher]));

This is working like a charm for me.

@rickydazla and @trev-dev I’m glad you found my little pipe function useful!

I’ve updated it to be better and more reusable:

import through2 from 'through2';
const touch = () => through2.obj( function( file, enc, cb ) {
  if ( file.stat ) {
    file.stat.atime = file.stat.mtime = file.stat.ctime = new Date();
  }
  cb( null, file );
});

So you can use .pipe( touch() ) like so

function sassDev() {
  return gulp.src( sassFiles )
    .pipe( sourcemaps.init() )
    .pipe( sass() )
    .pipe( postcss() )
    .pipe( sourcemaps.write() )
    .pipe( touch() )
    .pipe( gulp.dest( sassDest ) );
}

Okay so I have noticed that when I change main.scss (the file that is outputted directly as assets/main.css) the timestamp changes but when I change my variables the timestamp does not change on the file. You can explore this yourself by running date -r main.css on your own file.

The newest implementation uses polling based on checksums and timestamps and no longer uses inotify for linux and kqueue for OSX. (library for reference) This means that if your tool, gulp in this instance does not change the mod time on a file themekit won’t pick it up. I will look into a way we can make this better through the library. I believe what it does currently is first check the time and then check the checksum but maybe we can make it do both.

For now as a workaround I found a gulp lib called gulp-touch that would touch the file for every modification and made this change to my gulpfile.js

const { task, watch, src, dest, series } = require('gulp');
const sass = require('gulp-sass');
const autoprefix = require('gulp-autoprefixer');
const touch = require('gulp-touch'); //added this

sass.compiler = require('node-sass');

function scss(cb) {
  src('./src/scss/**/*.scss')
    .pipe(sass({outputStyle: 'expanded'}))
    .on('error', sass.logError)
    .pipe(autoprefix({
      browsers: ['> 2%', 'ie >= 10'],
      grid: true
    }))
    .pipe(dest('./assets/'))
    .pipe(touch()); //added this

    cb();
}

function watcher(cb) {
  watch('./src/scss/**/*.scss', series(scss))
  cb()
}

module.default = task('default', series([scss, watcher]));

I hope this speeds up your development again and I will hopefully have a more official fix for you in the future.

I just ran across this… As @tanema notes above, it seems to because the timestamp does not change. There are a few options, like gulp-touch (or gulp-touch-fd better, for use with Gulp 4). I liked this one from stackoverflow:

.pipe(through2.obj(function(file,enc,cb){ // change mod date, for qs watch
  let date = new Date();
  file.stat.atime = date;
  file.stat.mtime = date;
  cb(null,file);
}))

Currently, this is a feature of gulp 4 due to a limitation of node’s fs.Stat object. If you need mtime to change - you need to modify the mtime on the files in your pipeline.

So it seems like will not be fixed in Gulp, we will have to find ways of handling it downstream and it sounds like they even suggest something like my gulp-touch solution. I will see if there is something I can do within themekit to handle this better without effecting other tools Edit: It seems like even in the other issues linked in the gulp issue, other developers have solved this in a similar way.

gulp-touch (and similar gulp-touch-xxx) npm packages are 2 years out of date and don’t appear to be working for gulp 4, FYI. I was able to achieve results using through2 which will accept a Writeable stream and allow me to change the atime/mtime.

const { task, watch, src, dest, series } = require('gulp');
const sass = require('gulp-sass');
const autoprefix = require('gulp-autoprefixer');
const t2 = require('through2'); // Get through2 as t2

sass.compiler = require('node-sass');

function scss(cb) {
  src('./src/scss/**/*.scss')
    .pipe(sass({outputStyle: 'expanded'}))
    .on('error', sass.logError)
    .pipe(autoprefix({
      browsers: ['> 2%', 'ie >= 10'],
      grid: true
    }))
    .pipe(t2.obj((chunk, enc, cb) => { // Execute through2
      let date = new Date();
      chunk.stat.atime = date;
      chunk.stat.mtime = date;
      cb(null, chunk);
    }))
    .pipe(dest('./assets/'))

    cb();
}

function watcher(cb) {
  watch('./src/scss/**/*.scss', series(scss))
  cb()
}

module.default = task('default', series([scss, watcher]));

This is working like a charm for me.

Brilliant! Thanks so much! Works!

Currently, this is a feature of gulp 4 due to a limitation of node’s fs.Stat object. If you need mtime to change - you need to modify the mtime on the files in your pipeline.

So it seems like will not be fixed in Gulp, we will have to find ways of handling it downstream and it sounds like they even suggest something like my gulp-touch solution. I will see if there is something I can do within themekit to handle this better without effecting other tools

Edit: It seems like even in the other issues linked in the gulp issue, other developers have solved this in a similar way.

@trev-dev echo "$(uname) $(uname -m)" I will be able to support other Arch users in the future.

I beg your pardon @tanema - here’s the output for this: Linux x86_64