I have a sass file with long loop (generate about 800 lines of CSS) that compiles about 25 seconds. It's too long.
How can I minimize compile time?
Thanks!
This is how I compile Sass using gulp-sass and it takes about 800ms or less. Are you sure you use the node version, not the Ruby gulp-ruby-sass? Ruby is much slower than Node.js.
The loop may be the problem, be sure you are using Each or For, never While. But I also generated big grid system with a more less 200 selectors and it also was fast. Try my task config below:
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var autoprefixer = require('gulp-autoprefixer');
var gulpif = require('gulp-if');
var minify = require('gulp-minify-css');
var argv = require('yargs').argv;
var cache = require('gulp-cached');
// Values from console flags.
var is = {
dev: argv.develop,
prod: argv.production
};
// Gulpfile config.
var config = {
sass: {
src: './src/**/*.scss',
dest: 'src/',
maps: '/'
}
};
gulp.task('sass', function () {
return gulp.src(config.sass.src)
.pipe(cache('sass'))
.pipe(gulpif(is.dev, sourcemaps.init()))
.pipe(autoprefixer())
.pipe(gulpif(is.prod, minify()))
.pipe(gulpif(is.dev, sourcemaps.write(config.sass.maps)))
.pipe(gulp.dest(config.sass.dest));
});
Related
I am a beginner to Javascript and Gulp. Am learning this based on a udemy course in which Gulp 3 is being used, and I've been looking at docs to convert the code to Gulp 4. It's been fun so far since I am learning more when I am doing the conversions myself, but am stuck on this one. Wonder if you guys can offer some advice.
Issue: When I split the gulpfile.js into separate files to organise my files better, it starts throwing errors. Code below.
styles.js
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var gulp = require('gulp'),
browserSync = require('browser-sync').create();
function cssInject(cb) {
return gulp.src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
function browserSyncReload(cb) {
browserSync.reload();
cb();
}
function watch(cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', browserSyncReload);
watch('./app/assets/styles/styles.css', gulp.series(cssInject, styles));
cb();
}
exports.browserSyncReload = browserSyncReload;
exports.watch = watch;
gulpfile.js
var stylesTasks = require('./gulp/tasks/styles.js'),
watchTasks = require('./gulp/tasks/watch.js');
exports.watch = watchTasks.watch;
exports.styles = stylesTasks.styles;
exports.browserSyncReload = watchTasks.browserSyncReload;
When I run "gulp watch", this is what I get.
error
$ gulp watch
[21:14:28] Using gulpfile ~/Projects/travel-site/gulpfile.js
[21:14:28] Starting 'watch'...
internal/async_hooks.js:195
function emitInitNative(asyncId, type, triggerAsyncId, resource) { ^
RangeError: Maximum call stack size exceeded
(Use `node --trace-uncaught ...` to show where the exception was thrown)
I found another post with almost identical code, but with a different error - which happened to be one of the errors i was getting earlier as well, and have followed the solution mentioned in that post - and that's when I get this error. Here's the link to the post.
Any help is much appreciated. Thanks for your time.
I have a full article that shows many how to regarding going from gulp3 to gulp4, I think you are going to find everything you need there
But basically, I think you need to take a look at these modules :
gulp-task-loader-recursive
gulp4-run-sequence
require-dir
Then, from a gulp.js perspective, you can end up with something like this :
// gulpfile.js
global.config = require('./gulp/config/config.json');
require('events').EventEmitter.prototype._maxListeners = 1000;
require('require-dir')('./gulp/tasks/styles');
require('require-dir')('./gulp/tasks/watch');
//... etc ...
So you would be able to then create your styles task and export it :
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
const stylesTask = task('styles', styles);
exports.stylesTask = stylesTask;
You can then validate its recognized by gulp :
gulp --tasks
If you correctly see your styles tasks, you should now be able to run your task by running :
gulp styles
Repeat those steps for the watch task.
Answering my own question feels wierd, but I found the solution after playing with it for couple of days. See below.
I needed to import styles into watch.js, and not gulpfile.js. That was my first mistake. To do this, I added the below line to watch.js
var styles = require('./styles').styles;
Then my gulpfile.js only needed two lines
gulpfile.js
var watchTask = require('./gulp/tasks/watch').watch;
exports.default = watchTask;
I also removed the variable gulp, instead created variables for src and dest. So, the rest of the code looked like below.
styles.js
var {src, dest} = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
const styles = function (cb) {
return src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var styles = require('./styles').styles;
var {src, series, watch} = require('gulp'),
browserSync = require('browser-sync').create();
const cssInject = function (cb) {
return src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
const reload = function (cb) {
browserSync.reload();
cb();
}
const watchTask = function (cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', reload);
watch('./app/assets/styles/styles.css', series(cssInject, styles));
cb();
}
exports.watch = watchTask;
Hence resolved! hope this helps someone else.
yesterday I've upgraded my Gulp to 4.0 in order to gain some speed while compiling styles for my project (they got big, right now on my Mac Pro 2016 I need to wait 19seconds)
After some digging I decided to add gulp-cached and gulp-remember to my build.
Here's my current gulpfile.js for the styles:
var gulp = require('gulp'),
sass = require('gulp-sass'),
cached = require('gulp-cached'),
sourcemaps = require('gulp-sourcemaps'),
autoprefixer = require('gulp-autoprefixer'),
remember = require('gulp-remember'),
gs = gulp.series,
concat = require('gulp-concat'),
gp = gulp.parallel;
gulp.task('compile:styles', () => {
return gulp.src([
// Grab your custom scripts
'./assets/scss/**/*.scss'
])
.pipe(sourcemaps.init()) // Start Sourcemaps
.pipe(cached('sass'))
.pipe(sass())
.pipe(autoprefixer({
browsers: ['last 2 versions']
}))
.pipe(remember('sass'))
.pipe(sourcemaps.write('.')) // Creates sourcemaps for minified styles
.pipe(gulp.dest('./assets/css/'));
});
gulp.task('watch:styles', () => {
gulp.watch('./assets/scss/**/*.scss', gs('styles'))
.on('change', function (event) {
console.log("event happened:"+JSON.stringify(event));
if (event.type === 'deleted') {
//delete from gulp-remember cache
remember.forget('sass', event.path);
//delete from gulp-cached cache
delete cache.caches['sass'][event.path];
}
});
});
gulp.task('watch', gp(
'watch:styles'
));
My issue here is that my build works well on first compilation which takes about 3 seconds, later on where ever I do a change it can see in which file I made that change, and it starting to compile, but the output file does not have the changes inside.
I think I am not getting something when it comes to gulp-cached and gulp-remeber. But at the end of the file you can see a function that are supposed to clean the caches once a change was made.
Can you please take a look at my code? Maybe you will have some advice.
Cheers!
### EDIT 26.08
I have encountered the following post while looking for a solution:
http://blog.reactandbethankful.com/posts/2015/05/01/building-with-gulp-4-part-4-incremental-builds/
I went with it accordingly with the following code (but the effect is same as in above example):
// Grab our gulp packages
var gulp = require('gulp'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps'),
autoprefixer = require('gulp-autoprefixer'),
gs = gulp.series,
gp = gulp.parallel,
cache = require('gulp-memory-cache');
gulp.task('compile:styles', () => {
return gulp.src('./assets/scss/**/*.scss', {since: cache.lastMtime('sass')})
.pipe(sourcemaps.init()) // Start Sourcemaps
.pipe(sass())
.pipe(autoprefixer({
browsers: ['last 2 versions']
}))
.pipe(cache('sass'))
.pipe(sourcemaps.write('.')) // Creates sourcemaps for minified styles
.pipe(gulp.dest('./assets/css/'));
});
gulp.task('watch:styles', () => {
gulp.watch('./assets/scss/**/*.scss', gs('compile:styles'))
.on('change', cache.update('sass'));
});
gulp.task('build', gs(
'compile:styles',
'watch:styles'
));
I have created a complete gulpfile.js here:
https://gist.github.com/MkBeeCtrl/5a6a0900dba1c5d42dc7b6da211b3e95
With js files compilation included.
// Grab our gulp packages
var gulp = require('gulp'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps'),
autoprefixer = require('gulp-autoprefixer'),
gs = gulp.series,
gp = gulp.parallel,
cached = require('gulp-cached'),
dependents = require('gulp-dependents');
gulp.task('compile:styles', () => {
return gulp.src('./assets/scss/**/*.scss')
.pipe(cached('sass'))
.pipe(dependents())
.pipe(sourcemaps.init()) // Start Sourcemaps
.pipe(sass())
.pipe(autoprefixer({browsers: ['last 2 versions']}))
.pipe(sourcemaps.write('.')) // Creates sourcemaps for minified styles
.pipe(gulp.dest('./assets/css/'));
});
gulp.task('watch:styles', () => {
gulp.watch('./assets/scss/**/*.scss', gs('compile:styles'))
.on('change', function (event) {
console.log("event happened:"+JSON.stringify(event));
if (event.type === 'deleted') {
//delete from gulp-remember cache
//emember.forget('sass', event.path);
//delete from gulp-cached cache
delete cache.caches['sass'][event.path];
}
});
});
gulp.task('build', gs(
'compile:styles',
'watch:styles'
));
The above solution works the way I want, so if you want to produce separate CSS files from multiple imported files, you can go with it. It's not blazing fast solution but I have managed to save about 1 second when recompiling (already saved about 15s, when I started this topic, a build lasted 19 secs):
1st compile: ~3.5s
2nd or late: ~2.4s
You dont need to concate or order here as the whole order thing happens when you import scss files into you main file.
Try this one. I suppose it might do what you want to achieve:
'use strict';
const gulp = require('gulp');
const path = require('path');
const cached = require('gulp-cached');
const remember = require('gulp-remember');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const sourcemaps = require('gulp-sourcemaps');
const concat = require('gulp-concat');
gulp.task('styles:compile', function() {
return gulp.src('assets/scss/**/*.scss', {since: gulp.lastrun('styles:compile')})
.pipe(sourcemaps.init())
//.pipe(cached('sass')) - a smarter but heavier alternative to since
.pipe(remember('sass'))
.pipe(concat('all.sass'))
.pipe(sass())
.pipe(autoprefixer({ browsers: ['last 2 versions'] }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('assets/css/'));
});
gulp.task('styles:watch', function() {
var watcher = gulp.watch('assets/scss/**/*.scss', gulp.series('compile:styles'));
watcher.on('unlink', function(filepath) {
remember.forget('sass', path.resolve(filepath));
//delete cached.caches.sass[path.resolve(filepath)];
});
});
gulp.task('default', gulp.series('styles:compile', 'styles:watch'));
Install path plugin to resolve paths. Use 'unlink' event if you want to detect when a file gets deleted. since just checks dates which is faster compared to cached that reads and compares content. But cached is more reliable (for example, when you deleted and then returned the file using your IDE tools since will not work since the file will be returned again with its old date). Also check paths - I might have messed them up.
There is a project, its structure:
I do run gulp watch, when changing sass-file everything works correctly , but when I change js-file - assembly going infinite.
gulpfile:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var compass = require('gulp-compass');
gulp.task('compress-js', function() {
return gulp.src([
'./www/js/jquery/**/*.js',
'./www/js/vendor/**/*.js',
'./www/js/lib/**/*.js',
'./www/js/common/app.js',
'./www/js/pages/**/*.js',
'./www/js/common/main.js',
'!./www/js/combine.js'
])
.pipe(concat('combine.js'))
.pipe(uglify())
.pipe(gulp.dest('./www/js/'));
});
gulp.task('compress-css', function() {
return gulp.src('./scss/**/*.scss')
.pipe(compass({
config_file: './scss/config.rb',
css: './www/css',
sass: './scss'
}))
.pipe(gulp.dest('./www/css/'));
});
gulp.task('watch', function() {
gulp.watch(['./scss/**/*.scss'], ['compress-css']);
gulp.watch(['./www/js/**/*.js'], ['compress-js']);
});
Tell me please, what is wrong here?
The problem seems in your gulp.watch
gulp.watch(['./www/js/**/*.js'], ['compress-js']);
When you concat the js files for the build you exclude combine.js but you take it as good for the watch so he loop
The following gulp watch task isn't getting triggered when I change any LESS file in the project. Can anyone spot what I'm doing wrong? Most the answers here say to NOT use the watch-less module, which I'm not. It's supposed to listen to changes in any LESS file in the project and when one changes, go to the app.less file to regenerate the CSS file (app.less has #includes to all the files).
var watch = require("gulp-watch");
var less = require("gulp-less");
gulp.watch(paths.source + "**/*.less", function(event){
gulp.src(paths.source + paths.assets + paths.less + "app.less")
.pipe(less().on("error", console.log))
.pipe(gulp.dest(paths.dev + paths.css));
});
Here are some issues:
require("gulp-watch"); is useless here. Actually gulp.watch is a core API of gulp.
The gulpfile.js consists of several gulp tasks.
Run gulp watch in your terminal.
For example:
var gulp = require('gulp');
var path = require('path');
var less = require('gulp-less');
var paths = {
// your paths
};
gulp.task('styles', function () {
return gulp.src(paths.source + paths.assets + paths.less + "app.less")
.pipe(less({
// paths to be used for #import directives
paths: [ path.join(__dirname, 'less', 'includes') ]
}))
.pipe(gulp.dest('./'));
});
gulp.task('watch', function() {
gulp.watch('less/**/*.less', ['styles']);
});
Im new to Gulp.. I have been able to successfully install and concatenate and minify my .js and .css files, however, there is one .css file which i want to exclude - print.css
Ive followed the instructions here: https://www.npmjs.org/package/gulp-ignore install gulp-ignore in my local directory, and modified my gulpfile.js to:
// Include gulp
var gulp = require('gulp');
// Include Our Plugins
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var minifyCSS = require('gulp-minify-css');
var imagemin = require('gulp-imagemin');
var exclude = require('gulp-ignore').exclude;
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css'],
};
// CSS Task - Non Authenticated
gulp.task('minify-css-non-auth', function() {
gulp.src(paths.stylesNonAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Non-Auth/css'))
});
// CSS Task - Authenticated
gulp.task('minify-css-auth', function() {
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
**.pipe(exclude('Auth/css/print.css'))**
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Auth/css'))
});
Within my CSS Task - Secure, i have included .pipe(exclude('Secure/css/print.css'))
When i run gulp minify-css-secure, the task completes but upon inspecting the new all.min.css, i cant see the contents of print.css within there too.
It's unclear what you are trying to achieve. If I get it right, you want to:
minify all css files (including print.css)
concat all files except print.css into all.min.css
put minified all.min.css and print.css into destination folder
To achieve that, you can use StreamQueue. (source)
var streamqueue = require('streamqueue');
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css'],
};
gulp.task('minify-css-auth', function() {
return streamqueue({ objectMode: true },
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css')),
gulp.src('Auth/css/print.css'))
.pipe(minifyCSS(opts))
)
.pipe(gulp.dest('Auth/css'))
});
If you want to just exclude some files, you don't need gulp-ignore. Gulp supports ignore globs.
Just prefix the path to exclude with bang.
Like this:
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css']