Creating standard and compressed css files when using Gulp efficiently - gulp

I have a gulp file that I use and it contains a process that creates a standard non-compressed .css file and a compressed .css file; I used to generate the compressed version simply by minifying the just generated non-compressed one, however this caused issues with mappings pointing to the non-compressed .css file rather than the .scss files since it never actually worked off the .scss files.
So I changed it so that both processes now use the .scss files, however this seems very inefficient as they both have to go through the same processes so they can build their respective files.
Here is the relevant part of my gulpfile.js:
var gulp = require('gulp');
var cssnano = require('gulp-cssnano');
var plumber = require('gulp-plumber');
var postcss = require('gulp-postcss');
var rename = require('gulp-rename');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var livereload = require('gulp-livereload');
var autoprefixer = require('autoprefixer');
var ap_options = {
browsers: [
'last 4 Chrome versions',
'last 4 Firefox versions',
'last 4 Edge versions',
'last 2 Safari versions',
'ie >= 10',
'> 1.49%',
'not ie <= 9'
],
};
gulp.task('postcss', function() {
return gulp.src('scss/*.scss')
.pipe(plumber()) // Deal with errors.
.pipe(sourcemaps.init()) // Wrap tasks in a sourcemap.
.pipe(sass({ // Compile Sass using LibSass.
errLogToConsole: true,
outputStyle: 'expanded' // Options: nested, expanded, compact, compressed
}))
.pipe(postcss([ // Parse with PostCSS plugins.
autoprefixer(ap_options),
]))
.pipe(sourcemaps.write('../maps')) // Create sourcemap.
.pipe(gulp.dest('./css/')) // Create style.css.
.pipe(livereload());
});
gulp.task('cssnano', ['postcss'], function() {
return gulp.src('scss/*.scss')
.pipe(plumber()) // Deal with errors.
.pipe(sourcemaps.init()) // Wrap tasks in a sourcemap.
.pipe(sass({ // Compile Sass using LibSass.
errLogToConsole: true,
outputStyle: 'compressed' // Options: nested, expanded, compact, compressed
}))
.pipe(postcss([ // Parse with PostCSS plugins.
autoprefixer(ap_options),
]))
.pipe(cssnano({ // Minify CSS
safe: true // Use safe optimizations
}))
.pipe(rename({ suffix: '.min' })) // Append our suffix to the name
.pipe(sourcemaps.write('../maps')) // Create sourcemap.
.pipe(gulp.dest('./css/')) // Create style.min.css.
.pipe(livereload());
});
Is there a more efficient way to do this where I can create correct mapping files for both the non-compressed and compressed versions?

I found that gulp-cssnano was super slow so using gulp-clean-css can at least help speed things up. You can use gulp-if and a separate variables module to toggle some settings and call the same task twice. So it only calls rename and 'cssnano' if isProduction = true and liveReload if isProduction = false so you can use it with gulp-watch. I haven't tested this but it should work!
variables.js
module.export = {
isProduction = false,
outputStyle = 'expanded'
};
gulpfile.js
var vars = require('./variables'),
runSequence = require('run-sequence')
gulpif = require('gulp-if');
gulp.task('build', () => {
runSequence('set-dev', 'css', 'set-prod', 'css');
});
gulp.task('set-dev', () => {
vars.isProduction = false;
vars.outputStyle = 'expanded';
});
gulp.task('set-prod', () => {
vars.isProduction = true;
vars.outputStyle = 'compressed';
});
gulp.task('css', function() {
return gulp.src('scss/*.scss')
.pipe(plumber()) // Deal with errors.
.pipe(sourcemaps.init()) // Wrap tasks in a sourcemap.
.pipe(sass({ // Compile Sass using LibSass.
errLogToConsole: true,
outputStyle: vars.outputStyle // Options: nested, expanded, compact, compressed
}))
.pipe(postcss([ // Parse with PostCSS plugins.
autoprefixer(ap_options),
]))
.pipe(gulpif(vars.isProduction(cssnano({ // Minify CSS
safe: true // Use safe optimizations
}))))
.pipe(gulpif(vars.isProduction(rename({ suffix: '.min' })))) // Append our suffix to the name
.pipe(sourcemaps.write('../maps')) // Create sourcemap.
.pipe(gulp.dest('./css/')) // Create style.min.css.
.pipe(gulpif(!vars.isProduction(livereload())));
});
EDIT
output the normal and compressed CSS from one task. You really just need two destinations
var gulp = require('gulp'),
$ = require('gulp-load-plugins')();
gulp.task('css', function() {
return gulp.src('scss/*.scss')
.pipe(plumber()) // Deal with errors.
.pipe($.sourcemaps.init()) // Wrap tasks in a sourcemap.
.pipe($.sass({ // Compile Sass using LibSass.
errLogToConsole: true,
outputStyle: "expanded" // Options: nested, expanded, compact, compressed
}))
.pipe($.sourcemaps.write()) // Create sourcemap.
.pipe(gulp.dest('./css/')) // Create style.min.css.
//** MIN VERSION HERE
.pipe($.sass({ // Compile Sass using LibSass.
errLogToConsole: true,
outputStyle: "compressed" // Options: nested, expanded, compact, compressed
}))
.pipe($.cleanCss({
keepSpecialComments: '*',
spaceAfterClosingBrace: true
}))
.pipe($.rename({ suffix: '.min' })) // Append our suffix to the name
.pipe(gulp.dest('./css/'));
});

Related

Modify gulpfile.js (gulp 4.0)

This is the old configuration file.
Current gulp version is 4.0
How to modify this configuration file through gulp.series(), gulp.parallel() ?
I see all the translated tutorials, don't very understanding.
How to modify this configuration file (gulp 4.0 > gulp watch, gulp.series, gulp.parallel) ?
Thanks
var gulp = require("gulp"),
sass = require("gulp-sass"),
autoPrefixer = require("gulp-autoprefixer"),
minifyCss = require("gulp-clean-css"),
rename = require("gulp-rename"),
concat = require("gulp-concat"),
uglify = require("gulp-uglify"),
plumber = require("gulp-plumber"),
util = require("gulp-util"),
browserSync = require("browser-sync").create(),
reload = browserSync.reload;
var srcs = {
"html": ["./**/*.html"],
"css": ["./assets/css/**/*.css"],
"sass": ["./assets/sass/**/*.scss"],
"js": ["./assets/js/*.js"],
};
gulp.task("default", ["browser-sync"]);
gulp.task("sass", function (done) {
return gulp.src("./assets/sass/sys.scss")
.pipe(plumber())
.pipe(sass())
.pipe(autoPrefixer({
browsers: ["> 5%", "last 2 versions", "not ie <=8"],
cascade: true,
remove: true
}))
.pipe(rename({
basename: "sys"
}))
.pipe(gulp.dest("./assets/css"))
.pipe(reload({
stream: true
}))
.pipe(minifyCss())
.pipe(rename({
suffix: ".m"
}))
.pipe(gulp.dest("./assets/css"))
.pipe(reload({
stream: true
}));
util.log(util.colors.yellow("website styles compied and minified"));
});
gulp.task("js", function (done) {
return gulp.src("./assets/js/sys.js")
.pipe(reload({
stream: true
}));
});
gulp.task("browser-sync", ["sass", "js"], function () {
browserSync.init({
server: {
baseDir: "./"
},
browser: ["google chrome"]
});
gulp.watch(srcs.html).on("change", reload);
gulp.watch(srcs.sass, ["sass"]);
gulp.watch(srcs.js, ["js"]);
});
As of Gulp 4, there is no need to register tasks through task() method.
Gulp API will still support this approach, but usage of exporting is now primary approach to register tasks. ( see: https://gulpjs.com/docs/en/getting-started/creating-tasks )
Along with this new approach, all stream methods (src, dest, series, parallel, watch) can be defined through ES6 destructuring assignment feature as:
const {src, dest, watch, series, parallel} = require('gulp');
Also, cool feature in Gulp 4 regarding series and parallel is limitless nesting, so using this approach, you can avoid duplicating tasks.
(see: https://gulpjs.com/docs/en/api/series and https://gulpjs.com/docs/en/api/parallel)
So your gulpfile.js modified according to Gulp 4 features would look like this:
const {src, dest, watch, series, parallel} = require('gulp'); //ES destructuring assignment
var sass = require("gulp-sass"),
autoPrefixer = require("gulp-autoprefixer"),
minifyCss = require("gulp-clean-css"),
rename = require("gulp-rename"),
concat = require("gulp-concat"), //you don't use this anywhere. Avoid importing objects to reduce memory buffer overload
uglify = require("gulp-uglify"),//you don't use this anywhere. Avoid importing objects to reduce memory buffer overload
plumber = require("gulp-plumber"),
util = require("gulp-util"),
browserSync = require("browser-sync").create(),
reload = browserSync.reload;
var srcs = {
html: ["./**/*.html"],
css: ["./assets/css/**/*.css"],
sass: ["./assets/sass/**/*.scss"],
js: ["./assets/js/*.js"],
};
function sass() {
return src("./assets/sass/sys.scss")
.pipe(plumber())
.pipe(sass())
.pipe(autoPrefixer({
browsers: ["> 5%", "last 2 versions", "not ie <=8"],
cascade: true,
remove: true
}))
.pipe(rename({
basename: "sys"
}))
.pipe(dest("./assets/css"))
.pipe(reload({
stream: true
}))
.pipe(minifyCss())
.pipe(rename({
suffix: ".m"
}))
.pipe(dest("./assets/css"))
.pipe(reload({
stream: true
}));
util.log(util.colors.yellow("website styles compied and minified"));
}
function js(){
return src("./assets/js/sys.js")
.pipe(reload({
stream: true
})); //not sure if you intentionally did not put dest() stream method
}
function browser_sync(cb) {
browserSync.init({
server: {
baseDir: "./"
},
browser: ["google chrome"]
});
const watcher = watch(srcs.html);
watcher.on('change', reload);
watcher.on("change", reload);
watch(srcs.sass, series(sass));
watch(srcs.js, series(js));
cb();
}
//this will first trigger sass() and js() functions parallel, then after executing these two, browser_sync will run
exports.default = series(parallel(sass, js), browser_sync);
// don't need "done" callback function since you "return" the stream
gulp.task("sass", function () {
// all your stuff unchanged here
});
// don't need "done" callback function since you "return" the stream
gulp.task("js", function () {
return gulp.src("./assets/js/sys.js")
.pipe(reload({
stream: true
}));
});
// gulp.task('taskName', only one other parameter with the function call part of gulp.series
gulp.task("browser-sync", gulp.series("sass", "js", function () {
browserSync.init({
server: {
baseDir: "./"
},
browser: ["google chrome"]
});
gulp.watch(srcs.html).on("change", reload);
// don't need gulp.series below if only calling a single task
// but if you wanted it: gulp.watch(srcs.sass, gulp.series("sass"));
// It does seem that sometimes the gulp.series is needed even though the docs
// specifically say you don't when calling only a single task
gulp.watch(srcs.sass, "sass");
gulp.watch(srcs.js, "js");
}));
// move below to the bottom, if using gulp.task cannot call a task before it has been registered,
// i.e., gulp.task("browser-sync"........
gulp.task("default", "browser-sync");
See a good migration to gulp4 article.
There are many more gulp4 benefits if you completely change your tasks to functions as mentioned in the article or the gulpJS docs, exporting etc. But what is above should get you towards working gulp4 code.

gulp-file-include and BrowserSync Doesn't Reflect the Changes to Browser

I am trying to use gulp-file-include for include some common sections like header or footer from /src/includes folder into any .html pages in a project tree along with BrowserSync to refresh changes.
When I use gulp command from command line it's compiling all files into /dist folder without problems (I hope). But after, if I change anything from /src/index.html it doesn't reflect changes to browser or write changes into /dist/index.html.
I can't figure out exactly where the problem is. You can see the project from this Git repo and here is my gulpfile.js content:
var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');
var plumber = require('gulp-plumber');
var gutil = require('gulp-util');
var concat = require('gulp-concat');
var cleanCSS = require('gulp-clean-css');
var rename = require("gulp-rename");
var sass = require('gulp-sass');
var uglify = require('gulp-uglify');
var browserSync = require('browser-sync').create();
var sourcemaps = require("gulp-sourcemaps");
var fileinclude = require("gulp-file-include");
// File Paths
var CSS_PATH = { src: "./src/sass/*.scss", dist: "./dist/css/"};
var JS_PATH = { src: "./src/js/*.js", dist: "./dist/js/"};
var HTML_PATH = { src: "./src/*.html", dist: "./dist/html/*.html"};
var INCLUDES_PATH = "./src/includes/**/*.html";
var JQUERY_PATH = "node_modules/jquery/dist/jquery.min.js";
// Error Handling
var gulp_src = gulp.src;
gulp.src = function() {
return gulp_src.apply(gulp, arguments)
.pipe(plumber(function(error) {
// Output an error message
gutil.log(gutil.colors.red('Error (' + error.plugin + '): ' + error.message));
// emit the end event, to properly end the task
this.emit('end');
})
);
};
// Styles
gulp.task('styles', function() {
return gulp.src(CSS_PATH["src"])
.pipe(sass())
.pipe(autoprefixer('last 2 versions'))
.pipe(sourcemaps.init())
.pipe(gulp.dest(CSS_PATH["dist"]))
.pipe(cleanCSS())
.pipe(sourcemaps.write())
.pipe(concat("main.css", {newLine: ""}))
.pipe(gulp.dest(CSS_PATH["dist"]))
.pipe(browserSync.reload({ stream: true }))
});
// Scripts
gulp.task('scripts', function() {
return gulp.src([JS_PATH["src"], JQUERY_PATH])
.pipe(uglify())
.pipe(concat('main.min.js'))
.pipe(gulp.dest(JS_PATH["dist"]));
});
// File Include
gulp.task('fileinclude', function() {
return gulp.src(HTML_PATH["src"])
.pipe(fileinclude({
prefix: '##',
basepath: 'src/includes'
}))
.pipe(gulp.dest('dist'));
});
// BrowserSync
gulp.task('browserSync', function() {
browserSync.init({
server: {
baseDir: 'dist/'
},
open: false,
browser: "Google Chrome",
notify: true,
notify: {
styles: {
top: 'auto',
bottom: '0',
borderRadius: '4px 0 0 0',
opacity: .9
}
},
snippetOptions: {
rule: {
match: /<\/body>/i,
fn: function (snippet, match) {
return snippet + match;
}
}
}
})
})
// Watch task
gulp.task('watch', ['fileinclude', 'browserSync'], function() {
gulp.watch(CSS_PATH["src"], ['styles']);
gulp.watch(JS_PATH["src"], ['scripts']);
gulp.watch(INCLUDES_PATH, ['fileinclude']);
gulp.watch([HTML_PATH["src"], HTML_PATH["src"]], browserSync.reload);
});
gulp.task('default', ['fileinclude', 'styles', 'scripts', 'browserSync', 'watch' ]);
I seem to have it working. I added the following to the end of the 'scripts' and 'fileinclude' tasks:
.pipe(browserSync.reload({ stream: true }))
// File Include
gulp.task('fileinclude', function() {
return gulp.src(HTML_PATH.src)
.pipe(fileinclude({
prefix: '##',
basepath: 'src/includes'
}))
.pipe(gulp.dest('dist'))
.pipe(browserSync.reload({ stream: true }))
});
// Scripts
gulp.task('scripts', function() {
// return gulp.src([JS_PATH["src"], JQUERY_PATH])
return gulp.src(JS_PATH.src)
.pipe(uglify())
.pipe(concat('main.min.js'))
.pipe(gulp.dest(JS_PATH.dist))
.pipe(browserSync.reload({ stream: true }))
});
so that the browser is reloaded after any changes to those two groups. I changed the 'watch' task to:
// Watch task
// gulp.task('watch', ['fileinclude', 'browserSync'], function() {
// 'browserSync' is already running from 'default' task so remove it from above
// 'fileinclude' is called below only where it is needed, not for changes to js/scss files
gulp.task('watch', function() {
gulp.watch(CSS_PATH.src, ['styles']);
gulp.watch(JS_PATH.src, ['scripts']);
gulp.watch(INCLUDES_PATH, ['fileinclude']);
// gulp.watch([HTML_PATH["src"], HTML_PATH["src"]], browserSync.reload);
// the above looks for changes to the source and immediately reloads,
// before any changes are made to the dist/html
// Watch for changes in the html src and run 'fileinclude'
// browserSync reload moved to end of 'fileinclude'
gulp.watch([HTML_PATH.src], ['fileinclude']);
});
Edit: to handle the subsequent question about gulp failing to watch new files, I have made some changes to my original answer. But you should really be using gulp4.0 now IMO. Gulp3.9.x relied on a library that was problematic in watching for new, deleted or renamed files.
You will need two more plugins:
var watch = require("gulp-watch");
var runSequence = require("run-sequence");
The gulp-watch plugin is better at watching for new, etc. files, but doesn't take 'tasks' as arguments but instead it takes functions as arguments so that is why I used run-sequence. [You could rewrite your tasks as regular functions - but then you might as well shift to gulp4.0].
Then use this 'watch' task:
gulp.task('watch', function () {
watch(CSS_PATH.src, function () {
runSequence('styles');
});
watch(JS_PATH.src, function () {
runSequence('scripts');
});
watch(INCLUDES_PATH, function () {
runSequence('fileinclude');
});
watch([HTML_PATH.src], function () {
runSequence('fileinclude');
});
});

Attemoting to get browsersync to work from Gulp

Have been unable to get Browsersync working in Gulp.
I have installed the standard JointsWP build (this is a wordpress/foundation mash up), but the following gulpfile doesn't kick off browsersync at all.
I am using MAMP and the site works fine.
Tried a few things but limited gulpfile knowledge.
thanks in advance.
// Grab our gulp packages
var gulp = require('gulp'),
gutil = require('gulp-util'),
sass = require('gulp-sass'),
cssnano = require('gulp-cssnano'),
autoprefixer = require('gulp-autoprefixer'),
sourcemaps = require('gulp-sourcemaps'),
jshint = require('gulp-jshint'),
stylish = require('jshint-stylish'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat'),
rename = require('gulp-rename'),
plumber = require('gulp-plumber'),
bower = require('gulp-bower'),
babel = require('gulp-babel'),
browserSync = require('browser-sync').create();
// Compile Sass, Autoprefix and minify
gulp.task('styles', function() {
return gulp.src('./assets/scss/**/*.scss')
.pipe(plumber(function(error) {
gutil.log(gutil.colors.red(error.message));
this.emit('end');
}))
.pipe(sourcemaps.init()) // Start Sourcemaps
.pipe(sass())
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.pipe(gulp.dest('./assets/css/'))
.pipe(rename({suffix: '.min'}))
.pipe(cssnano())
.pipe(sourcemaps.write('.')) // Creates sourcemaps for minified
styles
.pipe(gulp.dest('./assets/css/'))
});
// JSHint, concat, and minify JavaScript
gulp.task('site-js', function() {
return gulp.src([
// Grab your custom scripts
'./assets/js/scripts/*.js'
])
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'))
.pipe(concat('scripts.js'))
.pipe(gulp.dest('./assets/js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(sourcemaps.write('.')) // Creates sourcemap for minified JS
.pipe(gulp.dest('./assets/js'))
});
// JSHint, concat, and minify Foundation JavaScript
gulp.task('foundation-js', function() {
return gulp.src([
// Foundation core - needed if you want to use any of the
components below
'./vendor/foundation-sites/js/foundation.core.js',
'./vendor/foundation-sites/js/foundation.util.*.js',
// Pick the components you need in your project
'./vendor/foundation-sites/js/foundation.abide.js',
'./vendor/foundation-sites/js/foundation.accordion.js',
'./vendor/foundation-sites/js/foundation.accordionMenu.js',
'./vendor/foundation-sites/js/foundation.drilldown.js',
'./vendor/foundation-sites/js/foundation.dropdown.js',
'./vendor/foundation-sites/js/foundation.dropdownMenu.js',
'./vendor/foundation-sites/js/foundation.equalizer.js',
'./vendor/foundation-sites/js/foundation.interchange.js',
'./vendor/foundation-sites/js/foundation.magellan.js',
'./vendor/foundation-sites/js/foundation.offcanvas.js',
'./vendor/foundation-sites/js/foundation.orbit.js',
'./vendor/foundation-sites/js/foundation.responsiveMenu.js',
'./vendor/foundation-sites/js/foundation.responsiveToggle.js',
'./vendor/foundation-sites/js/foundation.reveal.js',
'./vendor/foundation-sites/js/foundation.slider.js',
'./vendor/foundation-sites/js/foundation.sticky.js',
'./vendor/foundation-sites/js/foundation.tabs.js',
'./vendor/foundation-sites/js/foundation.toggler.js',
'./vendor/foundation-sites/js/foundation.tooltip.js',
])
.pipe(babel({
presets: ['es2015'],
compact: true
}))
.pipe(sourcemaps.init())
.pipe(concat('foundation.js'))
.pipe(gulp.dest('./assets/js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(sourcemaps.write('.')) // Creates sourcemap for minified
Foundation JS
.pipe(gulp.dest('./assets/js'))
});
// Update Foundation with Bower and save to /vendor
gulp.task('bower', function() {
return bower({ cmd: 'update'})
.pipe(gulp.dest('vendor/'))
});
// Browser-Sync watch files and inject changes
gulp.task('browsersync', function() {
// Watch files
var files = [
'./assets/css/*.css',
'./assets/js/*.js',
'**/*.php',
'assets/images/**/*.{png,jpg,gif,svg,webp}',
];
browserSync.init(files, {
// Replace with URL of your local site
proxy: "s18.dev",
});
gulp.watch('./assets/scss/**/*.scss', ['styles']);
gulp.watch('./assets/js/scripts/*.js', ['site-js']).on('change',
browserSync.reload);
});
// Watch files for changes (without Browser-Sync)
gulp.task('watch', function() {
// Watch .scss files
gulp.watch('./assets/scss/**/*.scss', ['styles']);
// Watch site-js files
gulp.watch('./assets/js/scripts/*.js', ['site-js']);
// Watch foundation-js files
gulp.watch('./vendor/foundation-sites/js/*.js', ['foundation-js']);
});
// Run styles, site-js and foundation-js
gulp.task('default', function() {
gulp.start('styles', 'site-js', 'foundation-js');
});
It was in fact my lack of gulp knowledge....
On closer inspection of the gulpfile, there were 2 functions - one with BS and one without...
I was running 'gulp watch' with no joy, whereas simply running 'gulp browsersync' did the trick.
bonza.

Gulp Sass Compiles Only With Two Saves

I've been trying to compile changes to #imports along with those to main SCSS files, and basically have this working.
The issue with my setup: To see changes, I must save files twice (irrespective of whether they're main files or imports). Ideas on this are greatly appreciated.
The directory structure is simply:
--> SCSS
--> SCSS/partials
Here are the relevant parts of my gulpfile:
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');
var sync = require('browser-sync').create(); // create a browser sync instance.
var sassPaths = [
'bower_components/foundation-sites/scss',
'bower_components/motion-ui/src'
];
var paths = {
'assets': 'assets',
'dev': 'assets/styles/dev'
};
// DEV CSS
gulp.task('dev-styles', function() {
return gulp.src(['scss/**/*.scss', 'scss/*.scss'])
.pipe($.sass({
includePaths: sassPaths,
outputStyles: 'expanded'
})
.on('error', $.sass.logError))
.pipe(autoprefixer({
browsers: ['last 2 versions', 'ie >=9']
}))
.pipe(rename({
suffix: '.dev'
}))
.pipe(gulp.dest('paths.dev'));
});
// DEFAULT WATCH
gulp.task('default', function() {
sync.init({
injectChanges: true,
proxy: 'localhost/basic-modx'
});
gulp.watch([ 'scss/**/*.scss', 'scss/*.scss' ], ['dev-styles']);
gulp.watch([ 'scss/**/*.scss', 'scss/*.scss' ]).on('change', sync.reload);
});
Your watches are set up oddly. I suspect that the second which reloads the browser finishes before the first which actually transpiles the scss, so nothing has changed when the reload occurs. Hence you have to hit save twice.
The better way from browserSync documentation is to have the reload at the end of your 'dev-styles' task like this:
gulp.task('dev-styles', function() {
return gulp.src(['scss/**/*.scss', 'scss/*.scss'])
.pipe($.sass({
includePaths: sassPaths,
outputStyles: 'expanded'
})
.on('error', $.sass.logError))
.pipe(autoprefixer({
browsers: ['last 2 versions', 'ie >=9']
}))
.pipe(rename({
suffix: '.dev'
}))
.pipe(gulp.dest('paths.dev'));
.pipe(sync.stream());
});
and get rid of the second gulp.watch statement.

Occassional Gulpfile freakout using gulp-changed and/or gulp-newer and and upload task

I've written a nice little build script that runs some pretty standard tasks like...
Cleaning out my deploy/ directory before initially
Building, concatenation, uglifying, and copying files from their dev/ directories to associated deploy/ directories
Watching for changes
etc.
But for better context, I've included just included it below:
var gulp = require('gulp');
var changed = require('gulp-changed');
var newer = require('gulp-newer');
var sass = require('gulp-sass');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-minify-css');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var notify = require('gulp-notify');
var plumber = require('gulp-plumber');
var imagemin = require('gulp-imagemin');
var shopify = require('gulp-shopify-upload');
var watch = require('gulp-watch');
var rename = require('gulp-rename');
var filter = require('gulp-filter');
var flatten = require('gulp-flatten');
var del = require('del');
var argv = require('yargs').argv;
var runsequence = require('run-sequence');
var config = require('./config.json');
var plumberErrorHandler = {
errorHandler: notify.onError({
title: 'Gulp',
message: "Error: <%= error.message %>"
})
};
gulp.task('styles', function() {
return gulp.src(['dev/styles/updates.scss'])
.pipe(plumber(plumberErrorHandler))
.pipe(sourcemaps.init())
.pipe(sass({ errLogToConsole: true }))
.pipe(autoprefixer({ browsers: ['last 2 versions', 'ie >= 10', 'Android >= 4.3'] }))
.pipe(cssmin())
.pipe(sourcemaps.write())
.pipe(rename({ suffix: '.css', extname: '.liquid' }))
.pipe(gulp.dest('deploy/assets'));
});
gulp.task('scripts', function() {
return gulp.src(['dev/scripts/**'])
.pipe(plumber(plumberErrorHandler))
.pipe(sourcemaps.init())
.pipe(concat('main.js'))
.pipe(uglify())
.pipe(sourcemaps.write())
.pipe(rename({ suffix: '.js', extname: '.liquid' }))
.pipe(gulp.dest('deploy/assets'));
});
gulp.task('vendor', function() {
var styles = filter(['styles/**/*.scss']);
var scripts = filter(['scripts/**/*.js']);
return gulp.src(['dev/vendor/**'])
.pipe(plumber(plumberErrorHandler))
.pipe(styles)
.pipe(sass({ errLogToConsole: true }))
.pipe(cssmin())
.pipe(styles.restore())
.pipe(scripts)
.pipe(concat('vendor.js'))
.pipe(uglify())
.pipe(scripts.restore())
.pipe(flatten())
.pipe(gulp.dest('deploy/assets'));
});
gulp.task('copy', function() {
return gulp.src(['dev/liquid/**'], {base: 'dev/liquid'})
.pipe(plumber(plumberErrorHandler))
.pipe(newer('deploy/'))
.pipe(gulp.dest('deploy/'));
});
gulp.task('clean', function(cb) {
del(['deploy/**/*'], cb);
});
gulp.task('imagemin', function() {
return gulp.src(['dev/liquid/assets/*'])
.pipe(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true }))
.pipe(gulp.dest('dev/liquid/assets/'));
});
gulp.task('build', ['clean'], function(cb) {
runsequence(['copy', 'styles', 'scripts', 'vendor'], cb);
});
gulp.task('watch', ['build'], function() {
gulp.watch(['dev/styles/**/*.scss'], ['styles']);
gulp.watch(['dev/scripts/**/*.js'], ['scripts']);
gulp.watch(['dev/vendor/**/*.{js,scss}'], ['vendor']);
gulp.watch(['dev/liquid/**'], ['copy']);
});
gulp.task('upload', ['watch'], function() {
if (!argv.env) {
return false;
} else if (argv.env && config.shopify.hasOwnProperty(argv.env)) {
env = config.shopify[argv.env];
} else {
env = config.shopify.dev;
}
return watch('deploy/{assets|layout|config|snippets|templates|locales}/**')
.pipe(shopify(env.apiKey, env.password, env.url, env.themeId, env.options));
});
gulp.task('default', ['clean', 'build', 'watch', 'upload']);
The problem I've been running into is directly related to the upload task and copy task.
When running gulp --env [environment-name] (e.g. gulp --env staging) or just gulp --env, some of the time when I save a file living in one of the subdirectories of dev/liquid/, the copy task runs as expected, and the singular saved and copied file is then uploaded via. the upload task. However, occasionally I'll save a file and the copy task runs as usual, but then the watch upload freaks out and tries uploading every file inside of deploy/ (which causes an api call limit error, which naturally gives me problems).
I originally had used gulp-changed inside of my copy task, but then noticed that it only will do 1:1 mappings and not directories (not sure how correct I am on this). So I switched to gulp-newer, and things worked for a while, but then things started freaking out again.
I can't figure out what's causing this, I have my suspicions but I can't figure out how to act on them. Any advice, observations, suggestions for improvements, good places for a romantic dinner, reliable pet-sitter, etc. would be greatly appreciated.
tytytytyty!!!
_t
Edit: I've been having a hard time reproducing the freakout (i.e. all files trying to upload at once), and at times running the same gulp --env staging causes a freak out, and other times firing up the same task on the same set of files does nothing. Maybe it could possibly have something to do with gulp-newer and gulp-changed's use of date modified as its comparison??
Double Edit: Maybe it's a race condition cause it works sometimes, and sometimes not? I remember seeing something on the node-glob or minimatch github pages about race conditions....