1

I'm using gulp to compile some .less files and inject the changes in the browser with live-reload.

This is the task I originally created:

var gulp = require('gulp');
var less = require('gulp-less');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
var livereload = require('gulp-livereload');
var path = require('path');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer-core');
var mqpacker = require('css-mqpacker');
var csswring = require('csswring');

gulp.task('less', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    mqpacker,
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/'],
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(livereload());
});
gulp.task('watch', function() {
  gulp.watch('./**/*.less', ['less']);  // Watch all the .less files, then run the less task
});

gulp.task('default', ['watch']); // Default will run the 'entry' watch task

I created an other gulp task to perform the same tasks but using browser-sync instead of live-reload for cross testing:

var gulp = require('gulp');
var less = require('gulp-less');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
var path = require('path');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer-core');
var csswring = require('csswring');
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;

gulp.task('less', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(reload({stream: true}))
  // .pipe(livereload());
});
gulp.task('serve', ['less'], function() {

    browserSync.init({
        proxy: "http://my-site.dev/"
    });

    gulp.watch("./css/*.less", ['less']);
});

I then tried to compile both files to be able to run either task depending on if i'm doing local development or if testing. I've created a "less" task to compile the css, a "lrl" live reload watch task and a "bs" browser-sync watch task. I created the "less" task to remove the duplication but now when i change the css the browser reload everything instead of just injecting the css.

var gulp = require('gulp');
var less = require('gulp-less');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
var path = require('path');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer-core');
var csswring = require('csswring');
var livereload = require('gulp-livereload');
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;

gulp.task('less', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
});

gulp.task('lrl',['less'], function(){
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(livereload());
});


gulp.task('watch',['lrl'], function() {
  livereload.listen();
  gulp.watch('./**/*.less', ['lrl']);  // Watch all the .less files, then run the less task
});


// browser-sync setup
gulp.task('bs',['less'], function(){
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(reload({stream: true}))
});

gulp.task('serve', function() {
    browserSync.init({
        proxy: "http://my-site.dev/"
    });
    gulp.watch("./css/*.less", ['bs']);
    gulp.watch("./js/script.js").on('change', reload);
    gulp.watch("./templates/*.php").on('change', reload);
});

// run default task with live reload for local development
gulp.task('default', ['watch']); // Default will run the 'entry' watch task

I'm a bit confused with the way to call tasks within tasks. Is there a way to make sure that the css are injected, it's much faster to work on design this way.

Thanks a lot

=================== BIG EDIT ============================

I've been messing about with run-sequence but I still have the same problem. In some way the task is working. With the default task i get live-reload on my local server only. With gulp serve I get a server where i can debug my layout across browsers and devices. The problem is that i don't get css injection anymore. it looks like gulp keeps re-running all of the tasks and refresh the browser to reconnect it.

so I made a working version with duplicated code to make what i'm trying to achieve clearer

var gulp         = require('gulp'),
    less         = require('gulp-less'),
    watch        = require('gulp-watch'),
    plumber      = require('gulp-plumber'),
    path         = require('path'),
    postcss      = require('gulp-postcss'),
    autoprefixer = require('autoprefixer-core'),
    mqpacker     = require('css-mqpacker'),
    csswring     = require('csswring'),
    livereload   = require('gulp-livereload'),
    browserSync  = require('browser-sync').create(),
    reload       = browserSync.reload;


gulp.task('less-lrl', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    mqpacker,
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/'],
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(livereload());
});
gulp.task('watch', function() {
  livereload.listen();
  gulp.watch('./**/*.less', ['less-lrl']);  // Watch all the .less files, then run the less task
});


gulp.task('less-bs', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    mqpacker,
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(reload({stream: true}))
});
gulp.task('serve', ['less-bs'], function() {

  browserSync.init({
    proxy: "http://myserver.dev"
  });

  gulp.watch("./css/*.less", ['less-bs']);
});

gulp.task('default', ['watch']); // Default will run the 'entry' watch task

When I do this it works smoothly. But I wanted to avoid the code duplication from the "less-lrl" and "less-bs" tasks. The only thing that differ is .pipe(livereload()); and .pipe(reload({stream: true}))

There's some stoopid going on in my brain, i don't haz understand :)

Pavlo
  • 43,301
  • 14
  • 77
  • 113
Yannick Schall
  • 32,601
  • 6
  • 29
  • 42
  • Read - http://www.sitepoint.com/build-css-preprocessor-postcss/ – vsync Apr 29 '15 at 17:34
  • My gulpfile is a mess because i'm trying stuff to understand :). I don't want to Use postcss as a replacement for less yet (doing this for work and we all use less ). I've been recommended postcss to handle autoprefixer. Since then i discovered some nice plugin that i like to use so i stick to it. Thanks for the link. – Yannick Schall Apr 29 '15 at 23:28
  • have you tried what I wrote in my answer? – vsync Apr 30 '15 at 08:33
  • Yes i did but to no avail. – Yannick Schall Apr 30 '15 at 09:09
  • Actually, i'm trying again. I had to change back `gulp.src('./**/*.less)` to `gulp.src('./css/style.less)`. otherwise it compiles all individual less files to css in their own folders. The css injection works fine with live-reload. But when I try the browser-sync task i have the same problem. – Yannick Schall Apr 30 '15 at 09:29
  • ok I have another approach, wait. I don't know how it's in LESS, but in SCSS you only compile files which aren't prefixed with `_`, but if you have just one file which includes all others in it, your setup is fine. – vsync Apr 30 '15 at 10:22
  • I don't see that you are calling the `serve` task. do you need it? – vsync Apr 30 '15 at 10:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/76630/discussion-between-yannick-schall-and-vsync). – Yannick Schall Apr 30 '15 at 10:39

4 Answers4

2

If I understood your question correctly, the runSequence would solve your problem. Take a look here: https://www.npmjs.com/package/run-sequence

You just need to add

var runSequence = require('run-sequence');

And create a task that runs your desired ones. For example:

gulp.task('build', function(callback) {
  return runSequence(
    'less',
    ['lrl'],
    callback
  );
});

then

gulp.task('watch',['build'], function() {
  livereload.listen();
  gulp.watch('./**/*.less', ['build']);  // Watch all the .less files, then run the less task
});
Felipe Skinner
  • 16,246
  • 2
  • 25
  • 30
1

note - please do not use both less and postcss together, since postcss was invented to replace and enhance what less does. Google it..

Please make sure LESS files path is correct!

Try it like this:

var gulp         = require('gulp'),
    less         = require('gulp-less'),
    watch        = require('gulp-watch'),
    plumber      = require('gulp-plumber'),
    path         = require('path'),
    postcss      = require('gulp-postcss'),
    autoprefixer = require('autoprefixer-core'),
    csswring     = require('csswring'),
    livereload   = require('gulp-livereload'),
    browserSync  = require('browser-sync').create(),
    reload       = browserSync.reload;


gulp.task('less', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];

  gulp.src('./**/*.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(livereload());
});


gulp.task('watch', function() {
  livereload.listen();
  gulp.watch('./**/*.less', ['less']);  // Watch all the .less files, then run the less task
});


// browser-sync setup
gulp.task('bs',['less'], function(){
  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(reload({stream: true}))
});

gulp.task('serve', function() {
    browserSync.init({
        proxy: "http://my-site.dev/"
    });
    gulp.watch("./css/*.less", ['bs']);
    gulp.watch("./js/script.js").on('change', reload);
    gulp.watch("./templates/*.php").on('change', reload);
});

// run default task with live reload for local development
gulp.task('default', ['less', 'watch']); // Default will run the 'entry' watch task
vsync
  • 118,978
  • 58
  • 307
  • 400
0

I tried both suggested answers above but to no avail. I can't manage to create a "less" subtask to be shared with the "live-relaod" and "browser-sync" tasks (It does re-run all tasks all the time and i loose the benefits of css injection).

The best I managed to do is to run them together like this:

var gulp         = require('gulp'),
    less         = require('gulp-less'),
    watch        = require('gulp-watch'),
    plumber      = require('gulp-plumber'),
    path         = require('path'),
    postcss      = require('gulp-postcss'),
    autoprefixer = require('autoprefixer-core'),
    csswring     = require('csswring'),
    livereload   = require('gulp-livereload'),
    browserSync  = require('browser-sync').create(),
    reload       = browserSync.reload;


gulp.task('less', function() {
  var processors = [
    autoprefixer({browsers: ["last 2 version", "> 1%", "ie 9", "ie 8", "ie 7", "ios 6"]}),
    csswring({
      preserveHacks: true,
      removeAllComments: true
    })
  ];

  gulp.src('./css/style.less')  // only compile the entry file
  .pipe(plumber())
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(postcss(processors))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./css/'))
  .pipe(livereload());
});


gulp.task('watch', function() {
  livereload.listen();
  gulp.watch('./**/*.less', ['less']);  // Watch all the .less files, then run the less task
});

gulp.task('serve', function() {
    browserSync.init({
      //files: "**/*.css", 
     files: ['**/*.js', '**/*.php','**/*.css'], // is this better than gulp watch?
      proxy: "http://leadgen.dev/node/1272"
    });
    //gulp.watch("./js/script.js").on('change', reload);
    //gulp.watch("./templates/*.php").on('change', reload);
});

// run default task with live reload for local development
gulp.task('default', ['less', 'watch', 'serve']); // Default will run the 'entry' watch task

So now I have both tasks running together. I would still prefer to be able to switch between one or the other though.

Yannick Schall
  • 32,601
  • 6
  • 29
  • 42
0

I've got same issue with stylus. You can try two dest, it may help

 gulp.src('./css/style.less')  // only compile the entry file
  .pipe(less({
    paths: ['./css/']
  } ))
  .pipe(gulp.dest('./css/'))
  .pipe(postcss(processors))
  .pipe(gulp.dest('./css/'))
  .pipe(livereload());
});
Katya Pavlenko
  • 3,303
  • 3
  • 16
  • 28