How to set gulp.dest() in same directory as pipe inputs? - gulp

I need all the found images in each of the directories to be optimized and recorded into them without setting the path to the each folder separately. I don't understand how to make that.
var gulp = require('gulp');
var imageminJpegtran = require('imagemin-jpegtran');
gulp.task('optimizeJpg', function () {
return gulp.src('./images/**/**/*.jpg')
.pipe(imageminJpegtran({ progressive: true })())
.pipe(gulp.dest('./'));
});

Here are two answers.
First: It is longer, less flexible and needs additional modules, but it works 20% faster and gives you logs for every folder.
var merge = require('merge-stream');
var folders =
[
"./pictures/news/",
"./pictures/product/original/",
"./pictures/product/big/",
"./pictures/product/middle/",
"./pictures/product/xsmall/",
...
];
gulp.task('optimizeImgs', function () {
var tasks = folders.map(function (element) {
return gulp.src(element + '*')
.pipe(sometingToDo())
.pipe(gulp.dest(element));
});
return merge(tasks);
});
Second solution: It's flexible and elegant, but slower. I prefer it.
return gulp.src('./pictures/**/*')
.pipe(somethingToDo())
.pipe(gulp.dest(function (file) {
return file.base;
}));

Here you go:
gulp.task('optimizeJpg', function () {
return gulp.src('./images/**/**/*.jpg')
.pipe(imageminJpegtran({ progressive: true })())
.pipe(gulp.dest('./images/'));
});
Gulp takes everything that's a wildcard or a globstar into its virtual file name. So all the parts you know you want to select (like ./images/) have to be in the destination directory.

You can use the base parameter:
gulp.task('uglify', function () {
return gulp.src('./dist/**/*.js', { base: "." })
.pipe(uglify())
.pipe(gulp.dest('./'));
});

Related

How to move globbed gulp.src files into a nested gulp.dest folder

QUESTION PART 1: OUTPUTTING TO A NESTED DYNAMIC FOLDER
I use Gulp.js for graphic email development. My employer is switching to a different marketing platform which requires our email templates to be in a different folder structure. I'm having trouble outputting to nested folders when gulp.src uses globbing. I'd appreciate your help!
Here is a simplified example the gulp.src folder:
build/template1/template1.html
build/template2/template2.html
build/template3/template4.html
build/template4/template4.html
Here is a simplified example the gulp.src folder:
build/template1/theme/html/template1.html
build/template2/theme/html/template2.html
build/template3/theme/html/template4.html
build/template4/theme/html/template4.html
I want to do something like a wildcard for the dynamic template folders ...
gulp.task('moveFile', function(){
return gulp.src('./build/*/*.html')
.pipe(gulp.dest('./build/*/theme/html'));
});
... But globbing only works in the gulp.src. How can I output to a dynamic folder when using a globbed gulp.src? the closest I can get is putting the /theme folder at the same level as the template folders, not inside each as desired.
Thank you for your help!
QUESTION PART 2: OUTPUTTING A *RENAMED FILE* TO A NESTED DYNAMIC FOLDER
Mark's answered my question (Thanks #Mark!), but I over-simplified my use case so I'm adding a Part 2.
In addition to nesting the file, I need to rename it. (I had this part working originally, but can't get the 2 parts to work together.) Referring to the gulp-rename documentation, I made 3 different attempts. It's so close but I'd appreciate a little more help. :-)
// ATTEMPT 1: Using gulp-rename mutating function method
gulp.task('createTwig', function(){
return gulp.src('./build/*/*.html')
.pipe(rename(
function (path) {
path.basename = "email";
path.extname = ".html.twig";
},
function (file) {
console.log(file.dirname);
file.dirname = nodePath.join(file.dirname, 'theme/html');
}
))
.pipe(gulp.dest('./build/'));
});
// ATTEMPT 2: Using gulp-rename fixed object method
gulp.task('createTwig', function(){
return gulp.src('./build/*/*.html', { base: process.cwd() })
.pipe(rename(
{
basename: "email",
extname: ".html.twig"
},
function (file) {
console.log(file.dirname);
file.dirname = nodePath.join(file.dirname, 'theme/html');
}
))
.pipe(gulp.dest('./build/'));
});
// ATTEMPT 3: Using gulp-rename mutating function method
gulp.task('createTwig', function(){
return gulp.src('./build/*/*.html')
.pipe(rename(
function (path, file) {
path.basename = "email";
path.extname = ".html.twig";
console.log(file.dirname);
file.dirname = nodePath.join(file.dirname, 'theme/html');
}
))
.pipe(gulp.dest('./build/'));
});
This works:
const rename = require("gulp-rename");
const path = require("path");
gulp.task('moveFile', function(){
return gulp.src(['build/**/*.html'])
.pipe(rename(function (file) {
console.log(file.dirname);
file.dirname = path.join(file.dirname, 'theme/html');
}))
.pipe(gulp.dest('build')) // build/template1/theme/html
});
I tried a few ways, including trying the base option and gulp-flatten and using a function in gulp.dest but this was the easiest.
Question Part #2:
gulp.task('createTwig', function(){
return gulp.src(['build/**/*.html'])
.pipe(rename(function (file) {
file.basename = "email";
file.extname = ".html.twig";
file.dirname = path.join(file.dirname, 'theme/html');
}))
.pipe(gulp.dest('build')) // build/template1/theme/html
});
path.basename/extname are just "getters", you cannot set those values.

How can I use gulp to replace a string in a particular source file using a config object?

How to achieve a replacing a string on a particular source file while the source files will be concatenated.
var gulp = require('gulp'),
rename = require('gulp-rename'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
replace = require('gulp-replace');
var config = {
cssConcatFiles: [
'one.css',
'two.css',
'three.css'
]
};
gulp.task('css-concat', function() {
return gulp.src(config.cssConcatFiles)
.pipe(replace('url\(\'', 'url\(\'../images/fancybox/'))
// I want to perform this replace to a particular file which is "two.css"
.pipe(concat('temp.css'))
.pipe(uglyfycss())
.pipe(rename('temp.min.css'))
.on('error', errorLog)
.pipe(gulp.dest('public/css/plugins/fancybox'));
});
This should work. gulp-if
const gulpIF = require('gulp-if');
gulp.task('css-concat', function() {
return gulp.src(config.cssConcatFiles)
//.pipe(replace('url\(\'', 'url\(\'../images/fancybox/'))
// I want to perform this replace to a particular file which is "two.css"
.pipe(gulpIF((file) => file.path.match('two.css') , replace('url\(\'', 'url\(\'../images/fancybox/')))
.pipe(concat('temp.css'))
.pipe(uglyfycss())
.pipe(rename('temp.min.css'))
.on('error', errorLog)
.pipe(gulp.dest('public/css/plugins/fancybox'));
});
You could use the following pipe instead of the gulp-if call:
.pipe(replace(/url\(\'/g, function(match) {
if (this.file.relative === "two.css") {
return 'url\(\'../images/fancybox/';
}
else return match;
}))
since gulp-replace will take a function as an argument and provide that function with a vinyl file reference (this.file) which you can use to test for which file is passing through the stream. You must, however, return something from the function call even when you want to do nothing - so return the original match.
I recommend using gulp-if, much cleaner in your case.

Gulp default task unable to compress after copy

At first I thought this was related to dependency of tasks so I went with run-sequence and even tried defining dependencies within tasks themselves. But I cannot get the compress task to run after copy. Or, even if it says it did finish the compress task, the compression only works if I run compress in the task runner inside visual studio by itself. What else can I try to get it to compress after copy?
/// <binding BeforeBuild='default' />
/*
This file is the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. https://go.microsoft.com/fwlink/?LinkId=518007
*/
var gulp = require("gulp");
var debug = require("gulp-debug");
var del = require("del");
var uglify = require("gulp-uglify");
var pump = require("pump");
var runSequence = require("run-sequence");
var paths = {
bower: "./bower_components/",
lib: "./Lib/"
};
var modules = {
"store-js": ["store-js/dist/store.legacy.js"],
"bootstrap-select": [
"bootstrap-select/dist/css/bootstrap-select.css",
"bootstrap-select/dist/js/bootstrap-select.js",
"bootstrap-select/dist/js/i18n/*.min.js"
]
}
gulp.task("default", function (cb) {
runSequence("clean", ["copy", "compress"], cb);
});
gulp.task("clean",
function () {
return del.sync(["Lib/**", "!Lib", "!Lib/ReadMe.md"]);
});
gulp.task("compress",
function (cb) {
pump([
gulp.src(paths.lib + "**/*.js"),
uglify(),
gulp.dest(paths.lib)
], cb);
});
gulp.task("copy",
function (cb) {
prefixPathToModules();
copyModules();
cb();
});
function prefixPathToModules() {
for (var moduleIndex in modules) {
for (var fileIndex in modules[moduleIndex]) {
modules[moduleIndex][fileIndex] = paths.bower + modules[moduleIndex][fileIndex];
}
}
}
function copyModules() {
for (var files in modules) {
gulp.src(modules[files], { base: paths.bower })
.pipe(gulp.dest(paths.lib));
}
}
You use run-sequence and your code
runSequence("clean", ["copy", "compress"], cb);
run in such order
clean
copy and compress in parallel // that's why your code compresses nothing, because you have not copied files yet
cb
Write like this and compress will be after copy
runSequence("clean", "copy", "compress", cb);
I am not familiar with runSequence. But why don't you try the following. By this way your default task depends on compress and compress depends on copy. So, 'copy' will run first and then 'compress'
gulp.task('default', ['copy','compress'], function(cb){});
gulp.task('compress',['copy'], function(cb){});
Gulp returns a steam , since you are calling it in a for loop the stream is returned during the first iteration itself.
Update your copyModule to the following and you can try either runSequence like posted by Kirill or follow my approach
function copyModules() {
var inputFileArr = [];
for (var files in modules) {
inputFileArr = inputFileArr.concat(modules[files]);
};
return gulp.src(inputFileArr, { base: paths.bower })
.pipe(gulp.dest(paths.lib));
}

Using parent directory of file-directory as destination in gulp

How can I use the parent directory of a file-directory of a wildcard source in gulp?
Source files:
|gulpfile.js (just to show where the base is)
|elements/foundations/A/js/src/mainA.js
|elements/foundations/A/js/src/subA.js
|elements/foundations/B/js/src/mainB.js
...
|elements/foundations/F/js/src/mainF.js
Desired target/result:
|elements/foundations/A/js/mainA.min.js
|elements/foundations/A/js/subA.min.js
|elements/foundations/B/js/mainB.min.js
...
|elements/foundations/F/js/mainF.min.js
I've tried different approaches, but eventually none of them worked.
This one runs without errors but doesn't generate any files.
gulp.task('scripts', function () {
return gulp.src('./elements/foundations/**/js/src/*.js', {base: './elements/foundations/**/'})
.pipe(rename({suffix: '.min'}))
// .pipe(uglify()) and others ...
.pipe(gulp.dest('./'))
;
});
This one generates files, but directly in the src directory.
gulp.task('scripts', function () {
return gulp.src('./elements/foundations/**/js/src/*.js', {base: './elements/foundations/'})
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('./elements/foundations/'))
;
});
And if I try to use the wildcard (**) in the destination, gulp ends up in an infinite loop (independently of the position of the wildcard).
gulp.task('scripts', function () {
return gulp.src('./elements/foundations/**/js/src/*.js', {base: './elements/foundations/'})
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('./elements/foundations/**/'))
;
});
I've also tried to use it without setting the base, but the results were similar.
You can pass a function to gulp-rename for more complex renaming operations. This allows you for example to use the path module of node.js to manipulate file paths:
var gulp = require('gulp');
var rename = require('gulp-rename');
var path = require('path');
gulp.task('scripts', function() {
return gulp.src('./elements/foundations/**/js/src/*.js')
.pipe(rename(function(file) {
file.dirname = path.dirname(file.dirname);
file.basename = file.basename + '.min';
return file;
}))
// .pipe(uglify()) and others ...
.pipe(gulp.dest('./elements/foundations/'))
});

How can I input and output multiple files with gulp and browserify

I'm sure there's a way to do this, but I couldn't find it. What I want is to pass multiple files into browserify and output multiple files - this is useful for a case where a site has multiple SPA's, with each having its own requires.
Say I have app1.js, app2.js, etc, with each loading in different pages and having independent require('..') statements. I'm looking for a task that does something like this:
gulp.task('browserify', function() {
return
gulp.src('src/**/*.js')
.pipe(browserify) //
.pipe(gulp.dest('dist'));
});
Any idea what's a simple way to accomplish this? thanks.
I stumbled upon this problem actually earlier this week. The problem of "creating multiple bundles". This should work:
var gulp = require('gulp'),
source = require('vinyl-source-stream'),
browserify = require('browserify'),
es = require('event-stream');
gulp.task('default', function() {
// Your main files
var files = [
'./app/main-a.js',
'./app/main-b.js'
];
// Create a stream array
var tasks = files.map(function(entry) {
return browserify({ entries: [entry] })
.bundle()
.pipe(source(entry))
.pipe(gulp.dest('./dist'));
});
return es.merge.apply(null, tasks);
});
Please do not use the gulp-browserify plugin, as it's blacklisted by now. Use browserify itself instead.
Same with Globs:
gulp.task('withglob', function() {
return glob('./app/main-**.js', function(err, files) {
var tasks = files.map(function(entry) {
return browserify({ entries: [entry] })
.bundle()
.pipe(source(entry))
.pipe(rename({
extname: '.bundle.js'
}))
.pipe(gulp.dest('./dist'));
});
return es.merge.apply(null, tasks);
})
});
Btw.: That's the reason