Svgmin infinite loop when running inside a task - svg

I'm trying to get svgmin to work in my gulpfile. This is my current config:
var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var sass = require('gulp-sass');
var minify = require('gulp-minify');
var uglify = require('gulp-uglify');
var pump = require('pump');
var concat = require('gulp-concat');
var connect = require('gulp-connect-php');
var svgmin = require('gulp-svgmin');
// Static Server + watching scss/html files
gulp.task('serve', function() {
connect.server({}, function (){
browserSync.init({
proxy: '127.0.0.1:8000'
});
});
gulp.watch("assets/scss/*.scss", ['sass']);
gulp.watch("assets/js/*.js", ['javascripts']);
gulp.watch("assets/img/**/*.svg", ['svg']);
gulp.watch('**/*.php').on('change', function () {
browserSync.reload();
});
});
// Optimize SVG
gulp.task('svg', function() {
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'));
browserSync.reload();
});
// Compile sass into CSS & auto-inject into browsers
gulp.task('sass', function() {
return gulp.src([
"node_modules/normalize.css/normalize.css",
'node_modules/animate.css/animate.min.css',
"assets/scss/main.scss"
])
.pipe(sass().on('error', sass.logError))
.pipe(minify())
.pipe(concat('main.css'))
.pipe(gulp.dest("assets/build"))
.pipe(browserSync.stream());
});
// Compile javascripts & refresh browser
gulp.task('javascripts', function (cb) {
pump([
gulp.src([
// Javascript files we need
'assets/js/modernizr.js', // Modernizr
'node_modules/jquery/dist/jquery.min.js', // jQuery
'node_modules/gsap/src/minified/TweenMax.min.js', // GSAP Aninmations
'node_modules/scrollmagic/scrollmagic/uncompressed/ScrollMagic.js', // ScrollMagic Main
'node_modules/scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js', // GASP ScrollMagic plugin
'assets/js/main.js' // Main JS file
]),
concat('main.js'),
uglify(),
gulp.dest('assets/build'),
],
cb
);
browserSync.reload();
});
gulp.task('default', ['sass', 'svg', 'javascripts', 'serve']);
When I run gulp svg it runs correctly without any errors. But when I run gulp (and thus the serve task) the svg task ends in a infinite loop. What am I doing wrong here? I want my gulp to minify my SVG files whenever theres a new file or a change, and then update the browser with browerSync.
[15:46:09] Starting 'svg'...
[15:46:10] Finished 'svg' after 823 ms
[15:46:10] Starting 'svg'...
[15:46:11] Finished 'svg' after 609 ms
[15:46:11] Starting 'svg'...
[15:46:11] Finished 'svg' after 618 ms
[15:46:11] Starting 'svg'...
[15:46:12] Finished 'svg' after 630 ms
[15:46:12] Starting 'svg'...

Your problem originates with this watch:
gulp.watch("assets/img/**/*.svg", ['svg']);
This runs the svg task whenever an SVG file is touched. In your svg task you do the following:
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'));
This minifies all your SVG files and replaces each file with its minified version. So what happens is:
svg task is run
all SVG files are replaced with their minified version
watch is triggered, because SVG files have been touched
svg task is run
all SVG files are replaced with their minified version
watch is triggered, because SVG files have been touched
etc ...
You need to break that cycle.
One way of doing that is to just place the minified SVG files into the assets/build directory as you do with files in your other tasks:
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/build/'));
If you really want to replace the SVG files your can use the gulp-cached plugin. It prevents the SVG files from being overwritten if there are no actual content changes:
var cache = require('gulp-cached');
gulp.task('svg', function() {
return gulp.src('assets/img/**/*.svg')
.pipe(cache('svgmin'))
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'))
.pipe(browserSync.stream());
});
This has the added benefit that your svg task will run faster, since only modified files will need to be processed now.

Related

Node.js Gulp no outputfile created

I have a Gulp script to concatenate, and minimize javascript.
It seems to be working but doesn't output the combined file.
The script is (complete - including extra debug bits):
// include plug-ins
var fs = require('fs');
var gulp = require('gulp');
var count = require('gulp-count');
var debug = require('gulp-debug');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var config = {
src: 'dist/libraries/',
dest: 'dist/js/',
outputfile: 'libraries.min.js'
}
gulp.task('read', (done) => {
fs.readdir(config.src, (err, items) => {
console.log(items);
});
done();
});
//delete the output file(s)
gulp.task('clean', gulp.series('read'), (done) => {
//del is an async function and not a gulp plugin (just standard nodejs)
//It returns a promise, so make sure you return that from this task function
// so gulp knows when the delete is complete
return del([config.dest + config.outputfile]);
});
// Combine and minify all files from the app folder
// This tasks depends on the clean task which means gulp will ensure that the
// Clean task is completed before running the scripts task.
gulp.task('scripts', gulp.series('clean'), (done) => {
//Include all js files but exclude any min.js files
var files = [config.src + '*.js', '!' + config.src + '*.min.js'];
return gulp.src(files)
.pipe(debug())
.pipe(count('## files selected'))
.pipe(uglify())
.pipe(concat(config.outputfile))
.pipe(gulp.dest(config.dest));
});
//Set a default tasks
gulp.task('default', gulp.series('scripts'), (done) => {
});
Which produces the output - including file list for verification there are src files:
[07:46:25] Using gulpfile <path>\gulpfile.js
[07:46:25] Starting 'default'...
[07:46:25] Starting 'scripts'...
[07:46:25] Starting 'clean'...
[07:46:25] Starting 'read'...
[07:46:25] Finished 'read' after 996 μs
[07:46:25] Finished 'clean' after 2.73 ms
[07:46:25] Finished 'scripts' after 4.26 ms
[07:46:25] Finished 'default' after 6.9 ms
[ 'bootstrap-datetimepicker.js',
'bootstrap.min.js',
'chart.min.js',
'cycle.js',
'farbtastic.js',
'jquery-3.2.1.min.js',
'jquery-sortable-min.js',
'moment.min.js',
'ol.min.js',
'pablo.min.js',
'popper.min.js',
'proj4.js',
'promisedIndexDB.js',
'qunit-2.6.1.js',
'toastr.js' ]
If I create an empty file, at dist/js/libraries.min.js it isn't deleted as part of the gulp tasks, however if i move the call to del() outside the gulp tasks it is deleted, so that leads me to assume that its not as simple as a permissions issue, or path issues.
Any idea what I've done wrong?
PS: its on a windows box, running in an admin cmd window.
You were using the wrong signature for the task. The correct one is :
task([taskName], taskFunction)
see task signature
But your tasks look like this:
gulp.task('scripts', gulp.series('clean'), (done) => { // 3 parameters
Merely changing that to:
gulp.task('scripts', gulp.series('clean', (done) => {
...
}));
makes it work - I tested it. So now that task has only two parameters: a task name and a function. Yours had a task name plus two functions.
You would also need to change your default and clean tasks to this proper signature. Also you should call done() at the end of the task as you did with your cb().
Your new code uses task functions, which are better than named tasks for a number of reasons - but now you know what was wrong with your original code. The main body of your scripts task was never being run.
I never worked out what was wrong, but went direct to the doc's and started again (previous version was from a example)..
Works with the below (much simpler) script.
// // include plug-ins
var gulp = require('gulp');
var count = require('gulp-count');
var debug = require('gulp-debug');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var config = {
src: 'jspa-scada/dist/libraries/',
dest: 'jspa-scada/dist/js/',
outputfile: 'libraries.min.js'
}
function defaultTask(cb) {
del([config.dest + config.outputfile]);
// Include all js files but exclude any min.js files
var globs = [
config.src + '*.js',
'!' + config.src + '*.min.js'
];
return gulp.src(globs)
.pipe(debug())
.pipe(count('## files selected'))
.pipe(uglify())
.pipe(concat(config.outputfile))
.pipe(gulp.dest(config.dest));
cb();
}
exports.default = defaultTask

How to put the file compiled by gulp-compass into gulp's stream?

I am a newbie to gulp and gulp-compass. IMHO, gulp-compass doesn't work in the gulp's stream paradigm.
Normally, gulp's task should be something like:
gulp.src('path/to/src')
.pipe(doSth)
.pipe(gulp.dest('path/to/dist'));
But the following code works for gulp-compass:
gulp.src('') // <-Empty source is OK
.pipe(compass({
css: 'path/to/dist/css' // <- This is the output dir
scss: 'path/to/src/scss' // <- This is the input scss file glob
}));
// No dest is needed!
This results in my following problem.
|- dist
|- scss
|- app.scss
|- css
|- bootstrap.css
I want to use gulp-compass to compile app.scss into app.css, then bundle app.css with bootstrap.css, then minify and output as app-release.css.
I want to finish this task in ONE gulp.task.
function buildCss(inputStream) { // minify and output to dist.
return inputStream
.pipe(cssnano())
.pipe(gulp.dest('dist'));
}
gulp.task('css-build', function() {
var stream = gulp.src('scss/app.scss')
.pipe(compass({
css: 'css',
sass: 'scss'
}))
.pipe(gulp.src('css/*.css')); // <-- **HERE**
return buildCss(stream);
});
However, The compiled app.css file is not included in stream of HERE.
What is the solution?
I could fix this problem using merge-stream.
gulp.task('css', function() {
var scss = gulp.src('scss/*.scss')
.pipe(compass({
css: 'css',
sass: 'scss'
}));
var css = gulp.src('css/bootstrap.css');
var stream = merge(scss, css)
.pipe(concat('app-release.css'));
return buildCss(stream);
});

Why Gulp does not ignore the file?

My project structure:
build
public
assets
css
app.css
vendor.css
js
app.js
vendor.js
index.html
src
assets
styles
main.styl
coffee
main.coffee
index.jade
I have a task to build a library of Bower in two files : vendor.css and vendor.js:
var uglify = require('gulp-uglify');
var minifyCss = require('gulp-minify-css');
var mainBowerFiles = require('gulp-main-bower-files');
var filter = require('gulp-filter');
var concat = require('gulp-concat');
var connect = require('gulp-connect');
gulp.task('bower', ['clean'], function () {
var jsFilter = filter('**/*.js', { restore: true });
var cssFilter = filter('**/*.css', { restore: true });
return gulp.src('./bower.json')
.pipe(mainBowerFiles())
.pipe(cssFilter)
.pipe(concat('vendor.css'))
.pipe(minifyCss())
.pipe(gulp.dest(path.dist.css))
.pipe(cssFilter.restore)
.pipe(jsFilter)
.pipe(concat('vendor.js'))
.pipe(uglify())
.pipe(gulp.dest(path.dist.js))
.pipe(jsFilter.restore)
.pipe(connect.reload());
});
Here's my task on cleaning of temporary folders when you change files in the src folder:
var del = require('del');
...
gulp.task('clean', function () {
return del(['build', 'public/**', '!public/**/vendor.{js,css}']);
});
That must delete the build folder and all the contents of the public directory, except the vendor.css and vendor.js that are in the folder public/assets/css and public/assets/js.
This is done in order to not build a library of bower at each change of the file, because it takes 3-4 seconds (by the way, is this normal?), but only at the first start or change bower.json ( running separate watcher).
But somehow, the files vendor.js and vendor.css also removed. With gulp-tap I got a list of files:
List of files
What am i doing wrong?
According to https://github.com/sindresorhus/del#beware you need also exclude sub-directories, otherwise del will delete all.
So, you can use something like this:
del([.., 'public/**/*', '!public/{dir_1,dir_2}', '!test/**/vendor{.css,.js}']);

How can I make gulp-watch generate CSS file when SASS changes?

Here is my code:
gulp.task('sass', function () {
gulp.src('./public/stylesheets/*.scss')
.pipe(sass())
.pipe(gulp.dest('./public/stylesheets/'));
});
gulp.task('watch-saas', function () {
watch('./public/stylesheets/*.scss', function () {
gulp.start('sass');
});
});
Output:
[19:15:46] Using gulpfile ~/WebstormProjects/mySite/gulpFile.js
[19:15:46] Starting 'watch-saas'...
[19:15:46] Finished 'watch-saas' after 38 ms
Im afraid no CSS. Any ideas how to make this work?
I think my code looks very much like the example code here. And the 'sass' task runs fine on its own.
I'm not that experienced in Gulp, but I usually use:
gulp.task('watch-saas', function () {
return gulp.watch(['./public/stylesheets/*.scss'], ['sass']);
});
I assume that you have to return the result in your task, because it's an asynchronous task.
We should first pipe it and ask gulp to watch it in changes in our scss or file we alerted
var gulp = require('gulp')
var watch = require('gulp-watch');
gulp.task('styles', function(){
return gulp.src(''./public/stylesheets/.scss'').pipe(gulp.dest('./sass'));
});
watch('./public/stylesheets/.scss', function(){
gulp.start('styles');
});
styles is the task name which I assigned here

Gulp, livereload, jade

Need help.
I use gulp-conect and it livereload method. But if I build a few template in time, get a lot of page refresh. Is any solution, I want to build few templates with single page refresh?
So, I reproduce the problem you have and came accross this working solution.
First, lets check gulp plugins you need:
gulp-jade
gulp-livereload
optional: gulp-load-plugins
In case you need some of them go to:
http://gulpjs.com/plugins/
Search for them and install them.
Strategy: I created a gulp task called live that will check your *.jade files, and as you are working on a certain file & saving it, gulp will compile it into html and refresh the browser.
In order to accomplish that, we define a function called compileAndRefresh that will take the file returned by the watcher. It will compile that file into html and the refesh the browser (test with livereload plugin for chrome).
Notes:
I always use gulp-load-plugin to load plugins, so thats whay I use plugins.jad and plugins.livereload.
This will only compile files that are saved and while you have the task live exucting on the command line. Will not compile other files that are not in use. In order to accomplish that, you need to define a task that compiles all files, not only the ones that have been changed.
Assume .jade files in /jade and html output to /html
So, here is the gulpfile.js:
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('webserver', function() {
gulp.src('./html')
.pipe(plugins.webserver({
livereload: true
}));
gulp.watch('./jade/*.jade', function(event) {
compileAndRefresh(event.path);
});
});
function compileAndRefresh(file) {
gulp.src(file)
.pipe(plugins.jade({
}))
.pipe(gulp.dest('./html'))
}
Post edit notes:
Removed liveReload call from compileAndRefresh (webserver will do that).
Use gulp-server plugin insted of gulp-connect, as they suggest on their repository: "New plugin based on connect 3 using the gulp.src() API. Written in plain javascript. https://github.com/schickling/gulp-webserver"
Something you can do is to watch only files that changes, and then apply a function only to those files that have been changed, something like this:
gulp.task('live', function() {
gulp.watch('templates/folder', function(event) {
refresh_templates(event.path);
});
});
function refresh_templates(file) {
return
gulp.src(file)
.pipe(plugins.embedlr())
.pipe(plugins.livereload());
}
PS: this is not a working example, and I dont know if you are using embedlr, but the point, is that you can watch, and use a callback to call another function with the files that are changing, and the manipulate only those files. Also, I supposed that your goal is to refresh the templates for your browser, but you manipulate as you like, save them on dest or do whatever you want.
Key point here is to show how to manipulate file that changes: callback of watch + custom function.
var jadeTask = function(path) {
path = path || loc.jade + '/*.jade';
if (/source/.test(path)) {
path = loc.jade + '/**/*.jade';
}
return gulp.src(path)
.pipe(changed(loc.markup, {extension: '.html'}))
.pipe(jade({
locals : json_array,
pretty : true
}))
.pipe(gulp.dest(loc.markup))
.pipe(connect.reload());
}
First install required plugins
gulp
express
gulp-jade
connect-livereload
tiny-lr
connect
then write the code
var gulp = require('gulp');
var express = require('express');
var path = require('path');
var connect = require("connect");
var jade = require('gulp-jade');
var app = express();
gulp.task('express', function() {
app.use(require('connect-livereload')({port: 8002}));
app.use(express.static(path.join(__dirname, '/dist')));
app.listen(8000);
});
var tinylr;
gulp.task('livereload', function() {
tinylr = require('tiny-lr')();
tinylr.listen(8002);
});
function notifyLiveReload(event) {
var fileName = require('path').relative(__dirname, event.path);
tinylr.changed({
body: {
files: [fileName]
}
});
}
gulp.task('jade', function(){
gulp.src('src/*.jade')
.pipe(jade())
.pipe(gulp.dest('dist'))
});
gulp.task('watch', function() {
gulp.watch('dist/*.html', notifyLiveReload);
gulp.watch('src/*.jade', ['jade']);
});
gulp.task('default', ['livereload', 'express', 'watch', 'jade'], function() {
});
find the example here at GitHub

Resources