gulp-sourcemaps with gulp-minify-css crashes - gulp

I'm compiling bootstrap-sass with the gulp task:
gulp.task('build-bootstrap-sass', function () {
return gulp.src('styles/styles.sass')
.pipe(sourcemaps.init())
.pipe(sass({includePaths: ['node_modules/bootstrap-sass/assets/stylesheets/']}).on('error', sass.logError))
.pipe(rename({basename:'bootstrap'}))
.pipe(autoprefixer())
.pipe(minifyCss())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist/' ));
});
But this gives me the following error:
[09:32:38] Using gulpfile d:\Code\Templates\App\gulpfile.js
[09:32:38] Starting 'build-bootstrap-sass'...
d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\text\escape-store.js:49
var index = this.restoreMatcher.exec(placeholder)[1];
^
TypeError: Cannot read property '1' of null
at EscapeStore.restore (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\text\escape-store.js:49:52)
at UrlsProcessor.restore (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\text\urls-processor.js:61:35)
at Object.restore (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\clean.js:195:28)
at store (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\source-maps.js:12:21)
at value (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\helpers.js:102:5)
at property (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\helpers.js:91:5)
at body (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\helpers.js:77:5)
at all (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\helpers.js:140:9)
at stringify (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\stringifier\source-maps.js:74:3)
at SelectorsOptimizer.process (d:\Code\Templates\App\node_modules\gulp-minify-css\node_modules\clean-css\lib\selectors\optimizer.js:20:10)
The issue seems to be when I use sourcemaps; If I remove it, the task passes. But I'm on the "latest" version for all my gulp dependencies; and the gulp-minify-css changelog indicates it got support for sourcemaps < 1.1.6.
The build also passes when I use sourcemaps without minify.

gulp-sourcemaps does not support gulp-minify-css.
You can find all supported plugins here: https://github.com/floridoo/gulp-sourcemaps/wiki/Plugins-with-gulp-sourcemaps-support
You could consider using gulp-cssnano for minifying css files.

Related

gulp stops server on error even with jshint included in gulpfile.js

I don't know why the server still stops whenever there's an error in my js files even though I have jshint in my gulpfile. I installed jshint and included it in my project because it reports errors in js files, but it's still failing. How can I fix this?
gulp.task('scripts', () => {
return gulp.src('assets/js/src/*.js')
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish', {beep: true}))
.pipe(concat('main.js'))
.pipe(gulp.dest('assets/js/build/'))
.pipe(uglify())
.pipe(gulp.dest('assets/js/'))
.pipe(browserSync.stream({stream: true}));
});
gulp-jshint does what you says it does: it reports errors in JavaScript files. Nothing more, nothing less. It doesn't prevent defective JavaScript files from reaching later pipe stages like uglify() (which throws up and thus stops your server if there's any error in a JavaScript file).
If you want to prevent defective JavaScript files from wrecking your server, you need to put all the jshint stuff into it's own task and make sure that task fails when any JavaScript file has an error:
gulp.task('jshint', () => {
return gulp.src('assets/js/src/*.js')
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish', {beep: true}))
.pipe(jshint.reporter('fail'))
});
Then you need to make your scripts task depend on that jshint task:
gulp.task('scripts', ['jshint'], () => {
return gulp.src('assets/js/src/*.js')
.pipe(concat('main.js'))
.pipe(gulp.dest('assets/js/build/'))
.pipe(uglify())
.pipe(gulp.dest('assets/js/'))
.pipe(browserSync.stream({stream: true}));
});
Now your scripts task will only run when the jshint task was successful. If any JavaScript file was defective jshint will output the error to the console while your server continues to run using the last good version of your JavaScript.
The simplest fix would be to use gulp-plumber to handle the error a little more gracefully:
var plumber = require("gulp-plumber");
gulp.task('scripts', () => {
return gulp.src('assets/js/src/*.js')
.pipe(plumber())
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish', {beep: true}))
.pipe(concat('main.js'))
.pipe(gulp.dest('assets/js/build/'))
.pipe(uglify())
.pipe(gulp.dest('assets/js/'))
.pipe(browserSync.stream({stream: true}));
});
Personally, I don't like that solution because it will prevent your minified file from being updated. Here's what I would recommend:
var jshintSuccess = function (file) {
return file.jshint.success;
}
gulp.task('scripts', () => {
return gulp.src('assets/js/src/*.js')
.pipe(sourcemaps.init())
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish', {
beep: true
}))
.pipe(gulpif(jshintSuccess, uglify()))
.pipe(concat('main.js'))
.pipe(sourcemaps.write('maps'))
.pipe(gulp.dest('assets/js/'))
.pipe(browserSync.stream({
stream: true
}));
});
First, notice that I'm not writing to multiple destinations. Instead, I'm using sourcemaps so that you don't need unminified code. Second, I'm using gulp-if to conditionally pipe your code through uglify based on the results of jshint. Code with errors will bypass uglify so that it still makes it into to your destination file.
Now, you can inspect and debug it with the developer tools.
Note: I recommend this for local development only. I wouldn't connect this to a continuous integration pipeline because you'll only want good code to make it into production. Either set up a different task for that or add another gulp-if condition to prevent broken code from building based on environment variables.

Gulp watch less and error?

I am using gulp for creating some css from less and have watch function. Everything working ok when there is no errors in less files, watch is calling less function and compile css. But when i have errors in less files, watch just breaks say where is error stop. When i fix error in less file, watch does not work anymore. I have to start it again, is it possible to see if there is error and just continue watching for compiling, here is my gulp.js
// Less to CSS task
var parentPath = './content/css/';
var sourceLess = parentPath;
var targetCss = parentPath;
gulp.task('less', function () {
return gulp.src([sourceLess + 'styles.less'])
.pipe(less({ compress: true }).on('error', gutil.log))
.pipe(autoprefixer('last 10 versions', 'ie 9'))
.pipe(minifyCSS({ keepBreaks: false }))
.pipe(gulp.dest(targetCss))
.pipe(notify('Less Compiled, Prefixed and Minified'));
});
gulp.task('watch', function () {
gulp.watch([sourceLess + 'styles.less'], ['less']); // Watch all the .less files, then run the less task
});
In gulp-less plugin documentation says that it doesn't have a built-in way to fail the task and keep the watcher active. But it says that you can't do it with stream-combiner2.
You can see the example here taked from the official gulp github repo.

Trying to integrate gulp SASS with gulp Autoprefixer-postcss, failing miserably

So, Autoprefixer has been bugging me to use the updated postcss version so I am trying to update my Gulp file.
The problem is all the examples do not integrate Sass as the first step; I use gulp-ruby-sass.
If I run my sass task on my sass directory (there are 2 scss files I need to process in there), this works and outputs 2 css files in the dest directory:
gulp.task('sass', function() {
return sass('./app/assets/sass')
.on('error', function(err) {
console.error('Error!', err.message);
})
.pipe(gulp.dest('./app/assets/css'))
.pipe(reload({
stream: true
}));
});
But my question is how to integrate the next part, to pass the CSS through autoprefixer and generate sourcemaps? If I run this next in a sequence, this blows up with object is not a function errors:
gulp.task('autoprefixer', function() {
return gulp.src('./app/assets/css/')
.pipe(sourcemaps.init())
.pipe(postcss([autoprefixer({
browsers: ['last 2 versions']
})]))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./app/assets/css'));
});
I was trying to run them as a sequence, but would rather integrate them:
gulp.task('styles', function() {
runSequence('sass', 'autoprefixer');
});
I just cannot put together the pipe that gets ruby-sass, autoprefixer, and sourcemaps to all work together.
UPDATE:
OK, even if I decide to keep the task separated (as suggested below by #patrick-kostjens), when I run the Autoprefixer task I get this error:
[08:56:38] Starting 'autoprefixer'...
events.js:72
throw er; // Unhandled 'error' event
^
TypeError: Cannot call method 'toString' of null
at new Input (/Users/stevelombardi/github/designsystem/node_modules/gulp-postcss/node_modules/postcss/lib/input.js:29:24)
at Object.parse [as default] (/Users/stevelombardi/github/designsystem/node_modules/gulp-postcss/node_modules/postcss/lib/parse.js:17:17)
at new LazyResult (/Users/stevelombardi/github/designsystem/node_modules/gulp-postcss/node_modules/postcss/lib/lazy-result.js:54:42)
at Processor.process (/Users/stevelombardi/github/designsystem/node_modules/gulp-postcss/node_modules/postcss/lib/processor.js:30:16)
at Transform.stream._transform (/Users/stevelombardi/github/designsystem/node_modules/gulp-postcss/index.js:44:8)
at Transform._read (_stream_transform.js:179:10)
at Transform._write (_stream_transform.js:167:12)
at doWrite (_stream_writable.js:223:10)
at writeOrBuffer (_stream_writable.js:213:5)
at Transform.Writable.write (_stream_writable.js:180:11)
at write (/Users/stevelombardi/github/designsystem/node_modules/gulp-sourcemaps/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:623:24)
at flow (/Users/stevelombardi/github/designsystem/node_modules/gulp-sourcemaps/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:632:7)
at DestroyableTransform.pipeOnReadable (/Users/stevelombardi/github/designsystem/node_modules/gulp-sourcemaps/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:664:5)
at DestroyableTransform.EventEmitter.emit (events.js:92:17)
at emitReadable_ (/Users/stevelombardi/github/designsystem/node_modules/gulp-sourcemaps/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:448:10)
at emitReadable (/Users/stevelombardi/github/designsystem/node_modules/gulp-sourcemaps/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:444:5)
And I tried autoprefixer = autoprefixer-core as suggested.
Personally, I would make the sass task a dependency of autoprefixer by declaring the autoprefixer task as follows:
gulp.task('autoprefixer', ['sass'], function() {
// Your current autoprefixer code here.
});
You can then simply run the autoprefixer task.
If you really want to integrate them into one task (even though the tasks do two separate things) you can try something like this:
gulp.task('autoprefixer', function() {
return es.concat(
gulp.src('./app/assets/css/')
.pipe(sourcemaps.init())
.pipe(postcss([autoprefixer({
browsers: ['last 2 versions']
})]))
.pipe(sourcemaps.write('.'))
,
sass('./app/assets/sass')
.on('error', function(err) {
console.error('Error!', err.message);
}))
.pipe(gulp.dest('./app/assets/css'));
});
Do not forget to define es as require('event-stream').
How are you including the autoprefixer requirement? This doesn't work for me:
var autoprefixer = require('gulp-autoprefixer');
This does work:
var autoprefixer = require('autoprefixer-core');
Try importing autoprefixer instead. I couldn't get gulp-autoprefixer working either and autoprefixer-core is now deprecated.
npm install autoprefixer --save-dev

Gulp not watching correctly

I'm new to using gulp and I think I have it setup correctly, but it does not seem to be doing what it should be doing.
My gulpfile.js has
gulp.task('compass', function() {
return gulp.src('sites/default/themes/lsl_theme/sass/**/*.scss')
.pipe(compass({
config_file: 'sites/default/themes/lsl_theme/config.rb',
css: 'css',
sass: 'scss'
}))
.pipe(gulp.dest('./sites/default/themes/lsl_theme/css'))
.pipe(notify({
message: 'Compass task complete.'
}))
.pipe(livereload());
});
with
gulp.task('scripts', function() {
return gulp.src([
'sites/default/themes/lsl_theme/js/**/*.js'
])
.pipe(plumber())
.pipe(concat('lsl.js'))
.pipe(gulp.dest('sites/default/themes/lsl_theme/js'))
// .pipe(stripDebug())
.pipe(uglify('lsl.js'))
.pipe(rename('lsl.min.js'))
.pipe(gulp.dest('sites/default/themes/lsl_theme/js'))
.pipe(sourcemaps.write())
.pipe(notify({
message: 'Scripts task complete.'
}))
.pipe(filesize())
.pipe(livereload());
});
and the watch function
gulp.task('watch', function() {
livereload.listen();
gulp.watch('./sites/default/themes/lsl_theme/js/**/*.js', ['scripts']);
gulp.watch('./sites/default/themes/lsl_theme/sass/**/*.scss', ['compass']);
});
when I run gulp, the result is
[16:14:36] Starting 'compass'...
[16:14:36] Starting 'scripts'...
[16:14:36] Starting 'watch'...
[16:14:37] Finished 'watch' after 89 ms
and no changes are registered.
for file structure, my gulpfile.js is in the root directory and the sass, css, and js are all in root/sites/default/themes/lsl_theme with the sass folder containing the folder 'components' full of partials.
My assumption is that you are on windows? Correct me if I'm wrong.
There is this problem that gulp-notify tends to break the gulp.watch functions. Try commenting out
// .pipe(notify({
// message: 'Scripts task complete.'
// }))
and see if the problem still exists.
If that does fix the issue, a solution from this thread may be helpful.
You can use the gulp-if
plugin in combination with
the os node module
to determine if you are on Windows, then exclude gulp-notify, like
so:
var _if = require('gulp-if');
//...
// From https://stackoverflow.com/questions/8683895/variable-to-detect-operating-system-in-node-scripts
var isWindows = /^win/.test(require('os').platform());
//...
// use like so:
.pipe(_if(!isWindows, notify('Coffeescript compile successful')))
It turns out that a large part of my issue was just simply being a rookie with Gulp. When I removed 'scripts' from my gulp watch it started working.
I then made the connection that it was watching the same directory that it was placing the new concatenated and minified js files in so it was putting the new file, checking that file, and looping over and over causing memory issues as well as not allowing 'compass' to run.
After creating a 'dest' folder to hold the new js everything started working just peachy.

Best way to concat and uglify js in gulp

I am trying to do automation to concat and uglify js in gulp.
Here is my gulpfile.js:
gulp.task('compressjs', function() {
gulp.src(['public/app/**/*.js','!public/app/**/*.min.js'])
.pipe(sourcemaps.init())
.pipe(wrap('(function(){"use strict"; <%= contents %>\n})();'))
.pipe(uglify())
.pipe(concat('all.js'))
.pipe(rename({
extname: '.min.js'
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('public/app'));
})
Do you think it is needed to wrap every file with (function(){"use strict"; <%= contents %>\n})(); to avoid conflict when every file is being join together? Do you think my gulp task is good, or it can even better for performing it's task?
Wrapping every file in a closure really isn't necessary for most code. There are some bad libs out there that leak vars, but I'd suggest you deal with them on a case by case basis and, if possible, issue Pull Requests to fix the problem or just stop using them. Usually, they can't be fixed as simply as wrapping them in a function.
The task you have above won't properly pass all files to the uglify task - you will need to concatenate first. You also don't need to rename as you can specify the full name in concatenate.
Below is a well tested Gulp setup for doing exactly what you've asked:
gulp.task('javascript:vendor', function(callback) {
return gulp.src([
'./node_modules/jquery/dist/jquery.js',
'./node_modules/underscore/underscore.js',
'./node_modules/backbone/backbone.js'
])
.pipe(sourcemaps.init())
// getBundleName creates a cache busting name
.pipe(concat(getBundleName('vendor')))
.pipe(uglify())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./public/app'))
.on('error', handleErrors);
});