Gulp: How to set up multiple sources and destinations in one task? - gulp

I'm using gulp-imagemin to minify images in my images folder. The output of the task should be streamed into dist/images directory. However, the source images folder has a subfolder images/headers whose compressed contents should be streamed to dist/images/headers. So this is the source folder structure:
-images
-headers
whose contents should be streamed to:
-dist
-images (contents of `images`)
-headers (contents of `images/headers`)
Currently my task definition looks like this:
gulp.task('compress', function () {
return gulp.src('images/*')
.pipe(imagemin({
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
}))
.pipe(gulp.dest('dist/images'));
});
My question is how I can tell Gulp to stream images/headers into dist/images/headers without writing a separate task for it.
I know that I can pass array of sources, but then ho can I tell Gulp where to output processed contents of each destination so that each source has a different destination?

You should use a recursive glob. Now you're only watching for changes directly in the images folder. Instead of using gulp.src('images/*') you should use gulp.src('images/')**.
Your new task will look like:
gulp.task('compress', function () {
return gulp.src('images/**')
.pipe(imagemin({
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
}))
.pipe(gulp.dest('dist/images'));
});
This will process every image located in the images folder and below to the dist/images folder.

Related

Input 2 files in gulp.src() and output them in different paths

I have html files located on different paths in src folder. I can read them at once with gulp.src(['path/to/file1','path/to/file2']) and output them such as gulp.dest('dist/') and it works fine. But what if I want to output the input files in different paths in the same gulp task?
project structure
src
- index.html
- pages
- about.html
// how I want to output
dist
- index.html
- pages
- about.html
My gulpfile.js for html task looks like
const filePath = {
input: 'src/',
output: 'dist/',
markup: {
index: 'src/index.html',
pages: 'src/pages/**/*.html',
outputIndex: 'dist/',
outputPages: 'dist/pages/'
}
}
function markup(done) {
src([filePath.markup.index, filePath.markup.pages])
// including src/layouts markup into index and pages markup files
.pipe(fileInclude({
prefix: '##',
basepath: '#file'
}))
// change references to files for build
.pipe(useref({noAssets: true}))
// minify on production
.pipe(mode.production(htmlmin(
{ collapseWhitespace: true, removeComments: true }
)))
.pipe(dest(filePath.output));
return done();
}
So far I have tried
.pipe(dest(filePath.markup.outputIndex));
.pipe(dest(filePath.markup.outputPages));
but it outputs both files in root dist as well as pages folder.
And with gulp-if
.pipe(gulpIf(filePath.markup.pages), dest(filePath.markup.outputPages))
.pipe(dest(filePath.markup.outputIndex));
but this also doesn't seem to work also this throws an error Error: gulp-if: child action is required.
I can do this by creating different tasks for index and pages but is there a way I can do it in a single gulp task?

Gulp imagemin - optimize only one image

This code is working perfectly, it will optimize all images in folder and that is ok if I need to call the task manually using gulp images.
But usually I just do gulp watch and for that all images previously added don't need to be reoptimised.
So, how can gulp optimize only the image that was just added to folder, and not all of them?
gulp.task('images', function() {
gulp.src('images/src/*.{png,jpg,gif}')
.pipe(plumber(plumberErrorHandler))
.pipe(imagemin({
optimizationLevel: 7,
progressive: true
}))
.pipe(gulp.dest('images'))
.pipe(notify("Images optimized."));
});
gulp.task('watch', function() {
gulp.watch('images/src/*.{png,jpg,gif}', ['images']);
});
gulp-changed should serve this purpose.
Basically it compares the files' last-modified property if the source is newer than the destination he passes it down the stream, otherwise it's removed from it.

gulp-html-minify .pipe destination to original folder structure

Hello people of the North, I am trying to minify my HTML using gulp because https://developers.google.com/speed/pagespeed/insights is telling me my site is too slow.
My original html files are in the structure of
/app/blog/page1.html
/app/contact/contactus.html
/app/xxx/xxx.html
With my current code the gulp output puts all of the html files into the _build folder, but this wont work for me since, on page load it will look for the html in the respective folder. Should I / can I put the minified html in its original folder so it is referenced automatically as normal?
gulp.task('minify-html', function () {
return gulp.src(configHTML.src)
.pipe(angularify())
.pipe(minifyHTML())
.pipe(gulp.dest('_build/'));
});
It's possible, you should try changing your code for:
gulp.src(configHTML.src, { base: "." })
.pipe(htmlmin({ collapseWhitespace: true, minifyCSS: true, minifyJS: true }))
.pipe(gulp.dest("."))
this will minify those files itself

In Gulp, how do I only run a task on one file if any of multiple files are newer?

I'm probably trying to make gulp do something that's not idiomatic, but here goes.
I want my build task to only run if the source files are newer than the output file.
In gulp, it seems standard practice to create a build task that always runs, and then set up a watch task to only run that build task when certain files change. That's okay, but it means that you always build on the first run.
So, is it possible to do what I want? Here's what I've got so far (newer is gulp-newer):
gulp.task('build_lib', function() {
return gulp.src(["app/**/*.ts"])
.pipe(newer("out/outputLib.js")) //are any of these files newer than the output?
** NEED SOMETHING HERE **
how do I say, "If I got _any_ files from the step before, replace all of them with a single hardcoded file "app/scripts/LibSource.ts" "?
.pipe(typescript({
declaration: true,
sourcemap: true,
emitError: false,
safe: true,
target: "ES5",
out: "outputLib.js"
}))
.pipe(gulp.dest('out/'))
});
I tried using gulpif, but it doesn't seem to work if there are no files going into it to begin with.
.pipe(gulpif(are_there_any_files_at_all,
gulp.src(["app/scripts/LibSource.ts"])))
However, my condition function isn't even called because there are no files on which to call it. gulpif calls the truthy stream in this case, so LibSource gets added to my stream, which isn't what I want.
Maybe doing all of this in a single stream really isn't the right call, since the only reason I'm passing those files through the "gulp-newer" filter is to see if any of them is newer. I'm then discarding them and replacing them with another file. My question still stands though.
You can write your own through/transform stream to handle the condition like so:
// Additional core libs needed below
var path = require('path');
var fs = require('fs');
// Additional npm libs
var newer = require('gulp-newer');
var through = require('through');
var File = require('vinyl');
gulp.task('build_lib', function() {
return gulp.src(["app/**/*.ts"])
.pipe(newer("out/outputLib.js"))
.pipe(through(function(file) {
// If any files get through newer, just return the one entry
var libsrcpath = path.resolve('app', 'scripts', 'LibSource.ts');
// Pass libsrc through the stream
this.queue(new File({
base: path.dirname(libsrcpath),
path: libsrcpath,
contents: new Buffer(fs.readFileSync(libsrcpath))
}));
// Then end this stream by passing null to queue
// this will ignore any other additional files
this.queue(null);
}))
.pipe(typescript({
declaration: true,
sourcemap: true,
emitError: true,
safe: true,
target: "ES5",
out: "outputLib.js"
}))
.pipe(gulp.dest('out/'));
});
I know like, this question was posted over 4 years ago, however; I am sure this problem crosses the path of everyone, and although I think I understand the question that is being asked, I feel that there is an easier way to perform this task, off which, I posted a similar question recently on stackoverflow at New to GULP - Is it necessary to copy all files from src directory to dist directory for a project?
It uses gulp-changed, and for me, it worked like a charm, so for others who may look at this post for similar reasons, have a look at my post and see if it is what you are looking for.
Kind Regards
You don't need to build first. You can on your 'first run' only run the watch task from which you run all the other ones.
example:
// Create your 'watch' task
gulp.task( 'watch', function() {
gulp.watch( 'scripts/*.js', [ 'lint', 'test', 'scripts' ] );
gulp.watch( 'styles/sass/*.scss', [ 'sass_dev' ] );
} );
// On your first run you will only call the watch task
gulp.task( 'default', [ 'watch' ] );
This will avoid running any task on startup. I hope this will help you out.
May I suggest gulp-newy in which you can manipulate the path and filename in your own function. Then, just use the function as the callback to the newy(). This gives you complete control of the files you would like to compare.
This will allow 1:1 or many to 1 compares.
newy(function(projectDir, srcFile, absSrcFile) {
// do whatever you want to here.
// construct your absolute path, change filename suffix, etc.
// then return /foo/bar/filename.suffix as the file to compare against
}

Why don't newly added files trigger my gulp-watch task?

I have a gulp task which uses gulp-imagemin to compress images. When I add new files to this directory I'd like for this task to compress them as well. I read that gulp.watch doesn't trigger on new files and that I should try gulp-watch so I used it like so;
gulp.task('images', function() {
watch({glob: './source/images/*'}, function (files) {
return files
.pipe(plumber())
.pipe(imagemin({
progressive: true,
interlaced: true
}))
.pipe(gulp.dest('./www'));
});
});
This works the same as gulp.watch on the first run, but when I add a new image to the directory nothing happens. If I overwrite an existing file however, it DOES run the task again, so it does behave differently.
The documentation on gulp-watch called this "Batch Mode" and said I could also run the task on a per-file basis, so I tried this way too;
gulp.task('images', function() {
gulp.src('./source/images/*')
.pipe(watch())
.pipe(plumber())
.pipe(imagemin({
progressive: true,
interlaced: true
}))
.pipe(gulp.dest('./www'));
});
But nothing changed. Why isn't adding files to my image directory triggering the task?
Adding an extra argument {cwd:'./'} in gulp.watch worked for me:
gulp.watch('src/js/**/*.js',{cwd:'./'},['scripts']);
2 things to get this working:
1 Avoid ./ in the file/folder patterns
2 Ensure ./ in the value for cwd
Good Luck.
Ref:- https://stackoverflow.com/a/34346524/4742733
Most likely such kind of questions are redirected to gaze package and its internal processes, that runs complicated watching procedures on your OS. In this case you should pass images/**/* to glob option, so gaze will watch all (including new) files in images directory:
var gulp = require('gulp');
var watch = require('gulp-watch');
var imagemin = require('gulp-imagemin');
gulp.task('default', function() {
watch({glob: 'images/**/*'}, function (files) {
files.pipe(imagemin({
progressive: true,
interlaced: true
}))
.pipe(gulp.dest('./www'));
});
});
But this fill not fix case, when you have empty images directory. If you want to watch them, pass ['images', 'images/**/*'] to glob, and it will watch directory, that initially empty.
P.s. also you dont need gulp-plumber in this case, because watch will rerun function, that uses imagemin every time, even when imagemin pops an error.