Consider the following gulp file:
var gulp = require('gulp');
var eslint = require('gulp-eslint');
var debug = require('gulp-debug');
gulp.task('lint', function (done) {
gulp
.src([
'src/**/*.js',
'!src/public/javascripts/external/*'
])
.pipe(eslint())
.pipe(eslint.format())
//.pipe(debug({title: 'Linting:'}));
done();
});
If my src folder contains too many files (I am not talking about an excessive number. It's less than 20), then gulp lint will only output
Using gulpfile [my/path/to/gulpfile]
Starting 'lint'...
Finished 'lint' after 55ms
There won't be any warnings from ESLint, even though I made sure there are problems in my code of course. This problem can be reproduced by manually adding javascript files from my src folder without using wildcards. After a certain number of files (I sadly forgot to count), errors won't be displayed any more. This does depend not on which files I add, just the number.
For some reason this behavior can be 'fixed' by adding the commented line that outputs debug information, so I am assuming my mistake has something to do with me misunderstanding how the gulp works internally. ESLint also works fine when called externally. Any ideas what the problems could be or steps to narrow it down?
I was able to fix my problem although I am not 100% sure what the problem was. According to the gulp-eslint package description you are supposed to return the result of the pipes. So the correct gulpfile would look like this:
var gulp = require('gulp');
var eslint = require('gulp-eslint');
var debug = require('gulp-debug');
gulp.task('lint', function () {
return gulp // note the return here
.src([
'src/**/*.js',
'!src/public/javascripts/external/*'
])
.pipe(eslint())
.pipe(eslint.format());
// no call to 'done()' is needed
});
My guess is that the plugin runs asynchronously and I ended the task by calling done() before it was actually done. Printing the debug information either happened after the asynchronous task was done or it bought enough time to finish. Now gulp will properly receives a promise (or something like that) and waits until it is finished.
Can anyone confirm this guess?
I´m trying to build a gulp task that get all bower_components files with wiredep, then concatenates them together. Then concatenate some other JS files I have on a special folder an finally minify everything.
The problem is that I don´t know if I can specify wiredep another directory additional to the bower_components directory. If that´s not possible, is there any other solution I can use?
I´m a begginer using gulp, so any other error that you can point out in how I´m thinking my task would be highly appreciated.
var wiredep = require('wiredep')(
{
directory: 'static/bower_components', // default: '.bowerrc'.directory || bower_components
}).stream;
gulp.task('scripts',function(){
return gulp
.src('index.html') //I don´t really know what to put in the src
.pipe(wiredep())
.pipe($.inject(gulp.src("More JS files if wire dep can´t handle them")))
.pipe(minify())
.pipe(gulp.dest('static/dist/src/app.min.js'));
});
I would have a method like this (perhaps in a config file at the root of the project) to get whatever you wanted wired in with wiredep:
getWiredepDefaultOptions: function() {
var options = {
directory: bower.directory,//file path to /bower_components/
};
return options;
},
Then in your gulp task, have something like this:
gulp.task('wiredep', function() {
log('Wiring the bower dependencies into the html');
var wiredep = require('wiredep').stream;
var options = config.getWiredepDefaultOptions();
return gulp
.src('./index.html')
.pipe(wiredep(options))
.pipe(gulp.dest("wherever you want your index.html"));
});
Depending on what other things you want to wire in, you would have to add an ordering of some kind using tags within the index.html.
This seems like a very simple question, but spent the last 3 hours researching it, discovering it can be slow on every save on a new file if not using watchify.
This is my directory tree:
gulpfile.js
package.json
www/
default.htm
<script src="toBundleJsHere/file123.js"></script>
toBundletheseJs/
componentX/
file1.js
componentY/
file2.js
componentZ/
file3.js
toPutBundledJsHere/
file123.js
Requirements.
On every creation or save of a file within the folder toBundleTheseJs/ I want this file to be rebundled into toBundleJsHere/
What do I need to include in my package.json file?
And whats the minimum I need to write into my gulp file?
This should be as fast as possible so think I should be using browserify and watchify. I want to understand the minimum steps so using package manager like jspm is overkill a this point.
thanks
First you should listen to changes in the desired dir:
watch(['toBundletheseJs/**/*.js'], function () {
gulp.run('bundle-js');
});
Then the bundle-js task should bundle your files. A recommended way is gulp-concat:
var concat = require('gulp-concat');
var gulp = require('gulp');
gulp.task('bundle-js', function() {
return gulp.src('toBundletheseJs/**/*.js')
.pipe(concat('file123.js'))
.pipe(gulp.dest('./toPutBundledJsHere/'));
});
The right answer is: there is no legit need for concatenating JS files using gulp. Therefore you should never do that.
Instead, look into proper JS bundlers that will properly concatenate your files organizing them according to some established format, like commonsjs, amd, umd, etc.
Here's a list of more appropriate tools:
Webpack
Rollup
Parcel
Note that my answer is around end of 2020, so if you're reading this in a somewhat distant future keep in mind the javascript community travels fast so that new and better tools may be around.
var gulp = require('gulp');
var concat = require('gulp-concat');
gulp.task('js', function (done) {
// array of all the js paths you want to bundle.
var scriptSources = ['./node_modules/idb/lib/idb.js', 'js/**/*.js'];
gulp.src(scriptSources)
// name of the new file all your js files are to be bundled to.
.pipe(concat('all.js'))
// the destination where the new bundled file is going to be saved to.
.pipe(gulp.dest('dist/js'));
done();
});
Use this code to bundle several files into one.
gulp.task('scripts', function() {
return gulp.src(['./lib/file3.js', './lib/file1.js', './lib/file2.js']) //files separated by comma
.pipe(concat('script.js')) //resultant file name
.pipe(gulp.dest('./dist/')); //Destination where file to be exported
});
I don't understand why this simple script behaves differently depending on the del plugin setup.
When I launch gulp sass I just want to clean the public/css dir and "compile" the css from sass. So far so good:
gulp.task('clean-css', del.bind(null,['./public/css']));
gulp.task('sass', ['clean-css'], function () {
return gulp.src('./resources/sass/**/*.scss')
.pipe(plugins.sass({outputStyle: 'compressed'}))
.pipe(gulp.dest('./public/css'));
});
However if if change the clean-css task to:
gulp.task('clean-css', del(['./public/css']));
Then it only works every other time. The first it cleans and generates the css, the next one it removes the directory but doesn't generate anything.
So, what's the difference between del(['./public/css']) and del.bind(null,['./public/css'])? Why does it affect the script in that way?
UPDATE:
The times when it doesn't generate anything I am seeing this error:
events.js:141
throw er; // Unhandled 'error' event
^
Error: ENOENT: no such file or directory, open 'C:\Users\XXXX\gulp-project\public\css\style.css'
at Error (native)
tl;dr
Gulp doesn't know when del is finished if no callback is provided. with or without bind, del works every other time if your sass task is run before del and files to be deleted actually exist.
According to the gulp documentation you should also provide the callback method to del. This is how gulp knows when a task is finished:
var gulp = require('gulp');
var del = require('del');
gulp.task('clean:mobile', function (cb) {
del([
'dist/report.csv',
// here we use a globbing pattern to match everything inside the `mobile` folder
'dist/mobile/**/*',
// we don't want to clean this file though so we negate the pattern
'!dist/mobile/deploy.json'
], cb);
});
gulp.task('default', ['clean:mobile']);
I suppose that the order in which your tasks are run is different each time, since gulp doesn't know when del is finished when no callback is provided. According to the documentation:
If you want to create a series where tasks run in a particular order, you need to do two things:
give it a hint to tell it when the task is done,
and give it a hint that a task depends on completion of another.
The story:
We have a team of testers working on automating end-to-end tests using protractor for our internal AngularJS application. Here is the task they usually run for "local" testing:
grunt.registerTask('e2e:local', [
'build:prod',
'connect:test',
'protractor:local'
]);
It runs the "build" task, starts a webserver and runs the e2e tests against the local build.
The build:prod task itself is defined as:
grunt.registerTask(
'build:prod', [
'clean',
'copy:all',
'copy:assets',
'wiredep',
'ngtemplates',
'useminPrepare',
'concat',
'ngAnnotate',
'autoprefixer',
'uglify',
'cssmin',
'copy:cssfix',
'usemin',
'copy:html',
'bowercopy',
'template:setProdVersion'
]
);
Here we have a lot of subtasks (it definitely could be improved, but this is how it looks now).
The problem:
Currently, it takes about 25 seconds for the build to complete. And, every time a person is running end-to-end tests, the build task is executed.
The question:
How can I run the build:prod task only if there are changes in src directory?
Note that the requirement here is to make it transparent for the testers who run the tests. I don't want them to remember when they need to perform a build and when not.
In other words, the process should be automated. The goal is to automatically detect if build is needed or not.
Note that ideally I would like to leave the build task as is, so that if it is invoked directly via grunt build:prod it would rebuild regardless of the datestamp of the previous build.
Thoughts and tries:
there is the closely related grunt-newer package, but, since we have a rather complicated build, having a clean task at the beginning, I'm not sure how to apply it in my case
what I was also thinking about is to, inside the e2e:local task, manually check the timestamps of the files inside dist and src and, based on that, decide if build:prod is needed to be invoked. I think this is what grunt-newer is doing internally
we started to use jit-grunt that helped to improve the performance
Here's an idea if you use git:
How about using something like grunt-gitinfo and using the last commit in HEAD as a base?
The idea is:
You create a new grunt task that checks for latest commit hash
You'd save this commit hash in a file that's added to gitignore (and is NOT in the clean folder, typically can be in root of repo)
Before saving to file, it'd check the value already in it (standard node fs module can do the read/write easily)
If the hash doesn't match, run build:prod task then save new commit hash
The testers build would depend on your new task instead of build:prod directly
Another option (still using git):
You can use something like grunt-githooks and create a git hook that runs after pull and calls the git build:prod, then you can remove it from the dependencies of the grunt task that testers run.
You might have another code to check for githook and install it if required though, which can be a one-time extra step for testers, or maybe baked into the grunt task they call.
I'm surprised noone has mentioned grunt-contrib-watch yet (it's in the gruntjs.com example file and I thought it was pretty commonly known!). From github: "Run predefined tasks whenever watched file patterns are added, changed or deleted." - heres a sample grunt file that would run your tasks any time any .js files are modified in src/ or in test/, or if the Gruntfile is modified.
var filesToWatch = ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'];
grunt.initConfig({
watch: {
files: filesToWatch,
tasks: ['build:prod',
'connect:test',
'protractor:local']
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
You have your developers open a terminal and run grunt watch before they start modifying files, and every time those files are modified the tasks will automatically be run (no more going back to the terminal to run grunt build:prod every time).
It's an excellent package and I suggest you check it out. -- github -- npmjs.org
npm install grunt-contrib-watch --save-dev
Not the answer your are looking for with grunt, but this will be easy with gulp.
var fs = require('fs');
var gulpif = require('gulp-if');
var sourceChanged = fs.statSync('build/directory').mtime > fs.statSync('source/directory').mtime;
gulp.task('build:prod', function() {
if (!sourceChanged) {
return false;
}
return gulp.src('./src/*.js')
.pipe(.... build ....)
.pipe(gulp.dest('./dist/'));
});
Here's how we've done some Git HEAD sha work for our build. We use it to determine which version is currently deployed to our production environment - but I'm quite certain you could rework it to return a boolean and trigger the build if truthy.
Gruntfile.js
function getHeadSha() {
var curr, match, next = 'HEAD';
var repoDir = process.env.GIT_REPO_DIR || path.join(__dirname, '..');
try {
do {
curr = grunt.file.read(path.join(repoDir, '.git', next)).trim();
match = curr.match(/^ref: (.+)$/);
next = match && match[1];
} while (next);
} catch(ex) {
curr = 'not-found';
}
return curr;
}
grunt.initConfig({
replace: {
applicationVersion: {
src: '<%= config.dist %>/index.html',
overwrite: true,
replacements: [{
from: '{{APPLICATION_VERSION}}',
to: getHeadSha
}]
}
}
});
grunt.registerTask('build', {
'replace:applicationVersion',
/** other tasks **/
});
grunt.registerTask('e2e:local', {
'check_if_we_should_build',
/** other tasks **/
});
index.html
<html data-version="{{APPLICATION_VERSION}}">
<!-- -->
</html>
There's also the git-info package which would simplify this whole process, we're looking at switching over to that ourselves.
edit; I just noticed #meligy already pointed you in the direction of git-info. credit where credit is due.
I am not sure if its helpful or not but same things we have done it in our project using GULP framework. We have written a watcher in the gulp that continuously check for the source change and run a quick function to build the project. Its a Protractor Test case.
gulp.task('dome', function () {
gulp.src(["maintest.js"])
.pipe(notify("Change Found , Executing Scripts."))
.pipe(protractor({
configFile: "conf.js",
args: ['--baseUrl', 'http://127.0.0.1:8000']
})).on('error', function (e) {
throw e
});
})
gulp.task('default', function () {
gulp.watch('./webpages/*.js', ['dome']);
gulp.watch('maintest.js', ['dome']);
gulp.watch('conf.js', ['dome']);
});
Link to repo.
I don't have experience in protractor, but conceptually I think this could work.
What I could suggest is to set an alias in your ~/.cshrc to run the build commands only if a diff command returns true.
#./cshrc
alias build_on_diff 'diff -r branch_dir_1 branch_dir_2\
if ( $status == 1 ) then\
build:prod\
endif'
Just replace the diff command with whatever git uses, and it should work provided it returns a 1 status for differences detected. We apply a similar method at my workplace to avoid rebuilding files that haven't changed.