I have a gulp css task that picks up a CSS file and runs several postCSS processors on it, then writes the file to a destination directory.
I have an html task that uses gulp-smoosher to pull the CSS file into the HTML file, replacing the link
tag to the CSS file.
When I run the tasks separately from the command line, everything works as expected. However, when I use gulp.watch
to automatically run the tasks when the CSS file changes, the changes aren't reflected in the final HTML file.
Is the html task somehow picking up the CSS file before the css task writes the changes? Is there a way to make sure the css task has finished before running the html task?
Update: I've done some reading and I realize Gulp runs both my css and html tasks at the same time. That explains why the CSS file isn't written yet when I start the html task. I've seen some solutions, but they either don't work or I don't understand how to use them. Here's my attempt at using the run-sequence plugin:
gulp.task('csshtml', function() {
runSequence('css', 'html');
});
gulp.task('watch', function() {
gulp.watch(paths.css, ['csshtml']);
});
... but the results were the same. I'm sure I'm doing something wrong.
gulpfile.js:
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var cssnext = require('cssnext');
var precss = require('precss');
var nesting = require('postcss-nesting');
var cssnano = require('cssnano');
var htmlmin = require('gulp-htmlmin');
var smoosher = require('gulp-smoosher');
var paths = {
css: 'src/*.css',
html: 'src/*.html'
};
gulp.task('css', function() {
var processors = [
nesting,
autoprefixer,
cssnext,
precss,
cssnano
];
return gulp.src(paths.css)
.pipe(postcss(processors))
.pipe(gulp.dest('css'));
});
gulp.task('html', function() {
return gulp.src('src/*.html')
.pipe(smoosher({ base: '.' }))
.pipe(htmlmin({
collapseWhitespace: true,
conservativeCollapse: true,
removeComments: true,
collapseInlineTagWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
removeEmptyAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
removeOptionalTags: true,
minifyCSS: true
}))
.pipe(gulp.dest('.'))
});
gulp.task('watch', function(){
gulp.watch(paths.css, ['css', 'html']);
gulp.watch(paths.html, ['html']);
});
I am going to try and answer some of your questions:
Is the html task somehow picking up the CSS file before the css task writes the changes? Is there a way to make sure the css task has finished before running the html task?
Yes there is a way to make a task finish before the next one executes. You can do this via the second parameter (which is an array/list of dependencies) in a gulp task.
This simple example is saying, before you run the
html
task, run thecss
task first. Once thats is done, then run thehtml
task.Issues with your watch task:
In your watch task you're saying when it detects a file change in the
paths.css
config value, run bothcss
andhtml
in parallel (at the same time).If you want your task to run in a particular order then you can make one depend on the other. As shown above.
You can also create a
default
task in gulp which runs both these without having to type the full task name. The example (only) shows the default task kicking offhtml
task and watch for file changes and performed the necessary task if it detects file changes.This is what I think you wanted to do, let me know if its incorrect, I'll update as necessary:
An alternate, if you don't want
html
to depend on yourcss
task and you are usingrun-sequence
from the looks of things, you could make the following changes:1. Remove the dependency
2. Add the
require
3. Setup the
run-sequence
This will run them in that order and watch for any file changes and run the appropriate task based on what you've changed. The HTML task no longer depends on the css task. The watch will behave as you'd expect.