Gulp js running twice for the watch statement - gulp

I see the console log statement that js task run twice once I change any of the javascript files. I wonder why it run two times for each change?
var gulp = require('gulp');
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
gulp.task('default', function() {
gulp.watch("public/js/**/*.*", ["js"]);
});
gulp.task("js", function(){
var js = [
"public/js/**/*.js",
"!public/js/api/**/*.js"
];
gulp.src(js)
.pipe(concat("app.min.js"))
.pipe(uglify())
.pipe(gulp.dest("public/js"));
});
Console
[13:02:27] Starting 'js'...
[13:02:27] Finished 'js' after 1.6 ms
[13:02:27] Starting 'js'...
[13:02:27] Finished 'js' after 5.1 ms

The problem is that you are watching the same directory which is used as the destination directory in the task you run when the change is detected. Currently, your build flow looks like this:
Imagine you're modifying a file public/js/script.js.
The watch task detects the change and starts your custom js task. As the result, the public/js/app.min.js file is created.
Since the app.min.js is inside the watched directory, the watch task detects another change, hence the js task is executed once more. You actually should run into a loop, but Gulp seems to be smart enough do detect such a cycle.
The best solution for this issue is to separate source files from the output. In your task pipe, set the destination folder to something outside the source directory, for example:
.pipe(gulp.dest("dist/js"));
After that, your project should has the following structure:
public
js
script.js
dist
js
app.min.js
grunfile.js
...
Where the public directory is used to keep the source files that are watched and the dist directory holds the output of the build. If I were you, I would reconsider renaming the public directory to something more descriptive like src, but that is up to you :)

Related

Configure the gulp bundling destination folder outside the project folder

We have bundling our application using gulp process(using aurelia-bundler). As of now the bundle process destination folder resides inside the project folder named "dist". We need to place the destination folder outside the project folder
gulp.task('bundle', function (callback) {
runSequence('unbundle',
'bundle-config',
'copy-app-files',
'compress',
function () {
});
});
In theory, you just have to change the exportSrvRoot variable of the build/paths.js file. For instance:
//var exportSrvRoot = 'export/';
var exportSrvRoot = '../'; //this is outside of the project folder.
Now, the gulp export command will export the files to the folder above the project folder. The solution is the same for build output (gulp build/bundle), but you'd have to change the outputRoot variable instead of exportSrvRoot.
However, there is a problem in this approach. Since your export folder is outside of the project folder, if you run gulp export, you will get an error saying that gulp.del cannot delete a folder that is outside of the project folder. This could be solved by passing additional parameters to gulp.del, but the task uses vinyl-paths to call gulp.del, preventing you to send any additional parameters for it =/.
One of the ways to solve the above problem is deleting the line 36 of the export-release.js:
// use after prepare-release
gulp.task('export', function(callback) {
return runSequence(
'bundle',
//'clean-export', <---- this line
'export-copy',
callback
);
});
In this way, gulp export won't try to delete the folder, preventing the error. But now, you must delete the export folder manually before each time you run gulp export.
Another way to solve this is rewriting the clean-export task in order to remove its dependency from vinyl-paths.
Hope this helps!

How to use gulp-newer?

I'm new to gulp and I tried to follow the documentation in https://www.npmjs.com/package/gulp-newer to understand how it works. However its not working as expected for the below task. I think I'm missing something obvious.
Here's the folder structure,
temp
file1.js
file2.js
new
file1.js
file3.js
change
<empty initially>
I want to compare temp folder with new folder and if there are any new files in new folder(which was not present in temp earlier) then move those files to change folder. This is just me trying to understand how gulp-newer works. Am I doing it right?
gulp.task('newer', function() {
return gulp.src('temp/*.js')
.pipe(newer('new/*.js'))
.pipe(gulp.dest('change'))
});
However when I run this task it just copy all the files in temp folder to change folder. So after task run change folder has file1.js and file2.js. I'm expecting just file3.js to be present in change(since that's a new file). Correct me if my understanding with the approach is incorrect.
From gulp-newer:
Using newer with many:1 source:dest mappings Plugins like gulp-concat
take many source files and generate a single destination file. In this
case, the newer stream will pass through all source files if any one
of them is newer than the destination file. The newer plugin is
configured with the destination file path.
and the sample code:
var gulp = require('gulp');
var newer = require('gulp-newer');
var concat = require('gulp-concat');
// Concatenate all if any are newer
gulp.task('concat', function() {
// Add the newer pipe to pass through all sources if any are newer
return gulp.src('lib/*.js')
.pipe(newer('dist/all.js'))
.pipe(concat('all.js'))
.pipe(gulp.dest('dist'));
});
it seems that you need to pass in all the files already concatenated to newer. In your case:
gulp.task('newer', function() {
return gulp.src('temp/*.js')
.pipe(newer('new/*.js'))
.pipe(concat('*.js'))
.pipe(gulp.dest('change'))
});
Also, since newer checks the files modified date make sure that the files are actually newer. I know it's obvious, but I'm usually stuck on "obvious" stuff.
May I also 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
}

Overwrite file in gulp stream

I have following directory structure:
common
-services
--service1.js
--service2.js
-app
--gulpfile.js
--src
---services
----service1.js
----service3.js
I want to made gulp task that will take all files from common directory, take files from app directory and replace all files with same filenames in original stream. After that I will concat it and write to other directory.
I tried this:
var gulp = require('gulp'),
merge = require('gulp-merge'),
concat = require('gulp-concat');
gulp.task('templates', function () {
return merge(
gulp.src(['../common/**/*.js']),
gulp.src(['src/**/*.js'])
)
.pipe(concat('app.js'))
.pipe(gulp.dest('build/js'));
});
I expected to got content of common/services/service2.js, app/src/services/service1.js, app/src/services/service3.js in dest/app.js.
But instead I've got content of all files.
I tried to change cwd or base of gulp.src, but it has no effect.
I know that I can write this stream to tmp directory, and after that get files from it, but it seems not really like gulp-style solution. So how can I overwrite files with same file names in streams?
Ok, i can't find any existing solution for that, so I write my own gulp plugin: gulp-unique-files.

Having trouble gulping, what is wrong with my gulpfile that copies and renames files?

My default task is to execute the "step2" task, which depends on step1. Step1 copies over a bunch of files, step2 is supposed to rename a single file, "file1.txt". My default task says to just do "step2". I am using gulp-rename.
gulp.task('step1', function() {
var files = [
'./folder1/**/*.*',
'./file1.txt'
];
return gulp.src(files, {base: "."})
.pipe(gulp.dest("./build"));
});
gulp.task('step2', ['step1'], function() {
gulp.src('./build/file1.txt')
.pipe(rename("./renamed-file1.txt"))
.pipe(gulp.dest("./build"));
});
The problem is I don't see a renamed file at all, and instead I see both the copy of the file I copied over and the renamed file. How do I fix this?
Also, why is it that for "./renamed-file1.txt", I have to specify it that way to ensure it gets in the build directory as opposed to ./build/renamed-file1.txt?
The gulp-rename plugin renames the files in the stream not the ones in the file system: I guess you should split your step1 in to 2 gulp flows renaming your file while copying it.

Gulp + source maps (multiple output files)

I just started playing with gulp, and it's very fast and easy to use but it seems to have a critical flaw: what do you do when a task needs to output more than one type of file?
For example, gulp-less says it doesn't even support the sourceMapFilename option. I don't want my source map embedded in my CSS file. Am I hooped? Should I just go back to using Grunt, or is there a way to deal with this?
This task will take multiple files, do stuff to them, and output them along with source maps.
It will include the source code within the maps files by default, so you don't have to distribute the source code files too. This can be turned off by setting the includeContent option to false. See the gulp-sourcemaps NPM page for more source map options.
gulpfile.js:
var gulp = require("gulp");
var plugins = require("gulp-load-plugins")();
gulp.task("test-multiple", function() {
return gulp.src("src/*.scss")
.pipe(plugins.sourcemaps.init())
.pipe(plugins.sass())
.pipe(plugins.autoprefixer())
.pipe(plugins.sourcemaps.write("./"))
.pipe(gulp.dest("result"));
});
package.json
"gulp": "~3.8.6",
"gulp-load-plugins": "~0.5.3",
"gulp-sass": "~0.7.2",
"gulp-autoprefixer": "~0.0.8",
"gulp-sourcemaps": "~1.1.0"
The src directory:
first.scss
second.scss
The result directory after running the test-multiple task:
first.css
first.css.map // includes first.scss
second.css
second.css.map // includes second.scss
Gulp supports multiple output files fine. Please read the docs.
Example:
gulp.task('scripts', function () {
return gulp.src('app/*js')
.pipe(uglify())
.pipe(gulp.dest('dist'));
});
This will read in a bunch of JS files, minify them and output them to the dist folder.
As for the gulp-less issue. You could comment on the relevant ticket.
In the docs it shows you how to have multiple output files:
gulp.src('./client/templates/*.jade')
.pipe(jade())
.pipe(gulp.dest('./build/templates'))
.pipe(minify())`
.pipe(gulp.dest('./build/minified_templates'));