Get Gulp watch to perform function only on changed file - javascript

I am new to Gulp and have the following Gulpfile
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
gulp.task('compress', function () {
return gulp.src('js/*.js') // read all of the files that are in js with a .js extension
.pipe(uglify()) // run uglify (for minification)
.pipe(gulp.dest('dist/js')); // write to the dist/js file
});
// default gulp task
gulp.task('default', function () {
// watch for JS changes
gulp.watch('js/*.js', function () {
gulp.run('compress');
});
});
I would like to configure this to rename, minify and save only my changed file to the dist folder. What is the best way to do this?

This is how:
// Watch for file updates
gulp.task('watch', function () {
livereload.listen();
// Javascript change + prints log in console
gulp.watch('js/*.js').on('change', function(file) {
livereload.changed(file.path);
gutil.log(gutil.colors.yellow('JS changed' + ' (' + file.path + ')'));
});
// SASS/CSS change + prints log in console
// On SASS change, call and run task 'sass'
gulp.watch('sass/*.scss', ['sass']).on('change', function(file) {
livereload.changed(file.path);
gutil.log(gutil.colors.yellow('CSS changed' + ' (' + file.path + ')'));
});
});
Also great to use gulp-livereload with it, you need to install the Chrome plugin for it to work btw.

See incremental builds on the Gulp docs.
You can filter out unchanged files between runs of a task using the gulp.src function's since option and gulp.lastRun

Related

Gulp watch only detects the first change

I am working on gulp and implementing watch functionality. But the gulp watch detects the changes only for the first time.
I want to write the code so that it detects the changes in CSS and JS files and performs minification and concatenation on the development environment.
I am using the following code:
var gulp = require('gulp');
var concat = require('gulp-concat');
var clean_css = require('gulp-clean-css');
var uglify = require('gulp-uglify');
gulp.task('style', function(){
gulp.src(['assets/css/style.css', 'assets/css/custom.css'])
.pipe(concat('build.min.css'))
.pipe(clean_css())
.pipe(gulp.dest('assets/build'));
});
gulp.task('script', function(){
gulp.src(['assets/js/jquery.js', 'assets/js/custom.js'])
.pipe(concat('build.min.js'))
.pipe(uglify())
.pipe(gulp.dest('assets/build'));
});
gulp.task('watch', function(){
gulp.watch('assets/css/*.css', gulp.series('style') );
gulp.watch('assets/js/*.js', gulp.series('script'));
});
This is probably because gulp does not know the task has finished the first time so it will not re-start the task again when you modify a file next. This can be solved just by adding return statements to your tasks:
gulp.task('style', function(){
return gulp.src(['assets/css/style.css', 'assets/css/custom.css'])
.pipe(concat('build.min.css'))
.pipe(clean_css())
.pipe(gulp.dest('assets/build'));
});
gulp.task('script', function(){
return gulp.src(['assets/js/jquery.js', 'assets/js/custom.js'])
.pipe(concat('build.min.js'))
.pipe(uglify())
.pipe(gulp.dest('assets/build'));
});

minify css/js into their individual files

I have this default gulp file from a Visual Studio template:
/// <binding BeforeBuild='clean, minPreBuild' />
"use strict";
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify");
var webroot = "./wwwroot/";
var paths = {
js: webroot + "js/**/*.js",
minJs: webroot + "js/**/*.min.js",
css: webroot + "css/**/*.css",
minCss: webroot + "css/**/*.min.css",
concatJsDest: webroot + "js/_site.min.js",
concatCssDest: webroot + "css/_site.min.css"
};
gulp.task("clean:js", function (cb) {
rimraf(paths.concatJsDest, cb);
});
gulp.task("clean:css", function (cb) {
rimraf(paths.concatCssDest, cb);
});
gulp.task("clean", ["clean:js", "clean:css"]);
gulp.task("min:js", function () {
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
gulp.task("min:css", function () {
return gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});
gulp.task("min", ["min:js", "min:css"]);
gulp.task("minPreBuild", ["min:js", "min:css"]);
The problem I'm having is one of my js files in the directory has a dependency on knockout, but I'm only using knockout on one of the pages on the site. I don't want to include knockout on my shared view, and the default bundling all files into a single file causes a JS error "ko is undefined" as one of the JS files is dependent on KO.
Is there a way that I can minify files individually, without concatting it into the main "site.min.css"?
First you need to exclude the Knockout file from your min:js task. Prepending a path with ! tells gulp to ignore that file:
gulp.task("min:js", function () {
return gulp.src([
paths.js,
"!" + paths.minJs,
"!js/path/to/knockout.js" // don't include knockout in _site.min.js
], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
Then you need to create a new task min:knockout that does nothing but minify your Knockout file. You'll probably want the minified file to end with a .min.js extension so you'll have to install the gulp-rename plugin as well.
var rename = require('gulp-rename');
gulp.task("min:knockout", function () {
return gulp.src("js/path/to/knockout.js", { base: "." })
.pipe(rename("js/_knockout.min.js"))
.pipe(uglify())
.pipe(gulp.dest("."));
});
Finally you need to make sure your new min:knockout task is executed when running the min and minPreBuild tasks:
gulp.task("min", ["min:js", "min:knockout", "min:css"]);
gulp.task("minPreBuild", ["min:js", "min:knockout", "min:css"]);

Detect what file change with gulp

I have this gulpfile:
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify');
gulp.task('minifyJS', function() {
return gulp.src(['src/*.js'])
.pipe(uglify())
.pipe(gulp.dest('min'));
});
gulp.task('watch', function() {
gulp.watch(['src/*.js'], ['minifyJS']);
});
I want to know what file trigger the watcher and his absolute path.
For example: if my project is placed in /myCode and I change the file src/main.js, I want to see /myCode/src/main.js inside minifyJS task. Is there a way to do it?
Thank you for your time.
You can do it by using gulp-ng-annotate and gulp-changed:
var gulp = require('gulp');
var changed = require('gulp-changed');
var rename = require('gulp-rename');
var ngAnnotate = require('gulp-ng-annotate'); // just as an example
var SRC = 'src/*.js';
var DEST = 'src/';
//Function to get the path from the file name
function createPath(file) {
var stringArray = file.split('/');
var path = '';
var name = stringArray[1].split('.');
stringArray = name[0].split(/(?=[A-Z])/);
if (stringArray.length>1) {stringArray.pop()};
return {folder: stringArray[0], name: name[0]}
}
gulp.task('default', function () {
return gulp.src(SRC)
.pipe(changed(DEST))
// ngAnnotate will only get the files that
// changed since the last time it was run
.pipe(ngAnnotate())
.pipe(rename(function (path) {
var createdPath = createPath(path);
path.dirname = createdPath.folder;
path.basename: createdPath.name,
path.prefix: "",
path.suffix: "",
path.extname: ".min.js"
}))
.pipe(gulp.dest(DEST));
});
Result:
Use gulp-changed npm package.
$ npm install --save-dev gulp-changed
Try the below in gulp file, (I haven't tried)
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
changed = require('gulp-changed');
gulp.task('minifyJS', function() {
return gulp.src(['src/*.js'])
.pipe(changed('min'))
.pipe(uglify())
.pipe(gulp.dest('min'));
});
gulp.task('watch', function() {
gulp.watch(['src/*.js'], ['minifyJS']);
});
see the documentation of this package https://www.npmjs.com/package/gulp-changed
Based on your comment to Julien's answer this should be fairly close to what you want, or at least get you going in the right direction:
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
cache = require('gulp-cached'),
rename = require('gulp-rename'),
path = require('path');
function fileName(file) {
return file.dirname + path.sep + file.basename + file.extname;
}
gulp.task('minifyJS', function() {
return gulp.src(['src/*.js'])
.pipe(cache('minifyJS'))
.pipe(rename(function(file) {
var nameOfChangedFile = fileName(file);
if (nameOfChangedFile == './main.js') {
file.basename = 'main.min'
}
if (nameOfChangedFile == './userView.js') {
file.basename = 'user/userView.min'
}
console.log(nameOfChangedFile + ' -> ' + fileName(file));
}))
.pipe(uglify())
.pipe(gulp.dest('min'));
});
gulp.task('watch', function() {
gulp.watch(['src/*.js'], ['minifyJS']);
});
This uses gulp-cached to keep an in-memory cache of all the files in your src/ folder that have passed through the stream. Only files that have changed since the last invocation of minifyJS are passed down to the gulp-rename plugin.
The gulp-rename plugin itself is then used to alter the destination path of the changed files.
Note: the cache is empty on first run, since no files have passed through the gulp-cached plugin yet. This means that the first time you change a file all files in src/ will be written to the destination folder. On subsequent changes only the changed files will be written.

Gulp task apply uglify if file in pipe is javascript

I want to check if the file in the pipe is .js or not (it could be .map, .html, ...). And if so, uglifying it before copying it in the correct path.
ʕ •́؈•̀) I've try something like this (which not working):
gulpfile.js
gulp.src(current + '/**/*', {base: current})
.pipe($.tap(function (file) {
if (path.extname(file.path) === '.js') {
return gulp.src(file.path)
.pipe($.uglify());
}
}))
.pipe(gulp.dest(destination + '/' + name));
But for now, the uglify seems to do nothing...
Is anyone have a clue on how to do this ? (╥﹏╥)
If you're open to using plugins there is one called gulp-filter that does what you're asking for. https://www.npmjs.com/package/gulp-filter
It would probably look something like this
var gulp = require('gulp');
var gulpFilter = require('gulp-filter');
gulp.task('default', function () {
// create filter instance inside task function
var jsfilter = gulpFilter('**/*.js', {restore: true});
return gulp.src(current + '/**/*', {base: current})
// filter a subset of the files
.pipe(jsFilter)
// run them through a plugin
.pipe($.uglify())
// bring back the previously filtered out files (optional)
.pipe(jsFilter.restore)
.pipe(gulp.dest(destination + '/' + name));
});
try using gulp-filter
something like
var filter = require('gulp-filter');
var jsFilter = filter('**/*.js');
gulp.src('*/*')
.pipe(jsFilter)
.pipe(uglify)

Creating a Gulp task but not working, why?

according to the Gulp Docs, and according to what I see, I have everything fine.
Before, lets say a week ago, I was doing ctrl + s on Sublime Text and my view(browser) reload automatically. Now, after some merges with master branch, those tasks are not working anymore, nothing is reloading and I have to go to my console and do Gulp every time I want to see changes and I hate that. I am going to paste my gulpfile.js here so maybe you have an answer for me
var gulp = require('gulp'),
watch = require('gulp-watch'),
gutil = require('gulp-util'),
bower = require('bower'),
concat = require('gulp-concat'),
sass = require('gulp-sass'),
autoprefixer = require('gulp-autoprefixer'),
minifyCss = require('gulp-minify-css'),
rename = require('gulp-rename'),
sh = require('shelljs'),
jshint = require('gulp-jshint'),
jscs = require('gulp-jscs'),
shell = require('gulp-shell'),
uglify = require('gulp-uglify'),
ngAnnotate = require('gulp-ng-annotate');
var paths = {
sass: ['./scss/**/*.scss']
};
// Dev task
gulp.task('dev', ['sass', 'lint', 'compress-lib', 'compress-js', 'run-ionic'], function() { });
// Build task
gulp.task('default', ['dev']);
//Ionic Serve Task
gulp.task('run-ionic',shell.task([
'ionic serve'
]));
gulp.task('compress-lib', function() {
gulp.src([
'./www/lib/ionic/js/ionic.bundle.min.js',
'./www/lib/localforage/dist/localforage.min.js',
'./www/lib/lodash/lodash.min.js',
'./www/lib/moment/moment.js',
'./www/lib/validator-js/validator.min.js',
'./www/lib/localforage-wrapper/localforage-wrapper.js',
'./www/lib/ua-parser-js/dist/ua-parser.min.js'
])
.pipe(concat('lib.min.js'))
.pipe(gulp.dest('./www/js'))
});
gulp.task('compress-js', function() {
gulp.src([
'./www/js/app.js',
'./www/js/controllers.js',
'./www/js/common/footerController.js',
'./www/js/common/sportsFilter.js',
'./www/js/common/searchBarDirective.js',
'./www/js/auth/controller.js',
'./www/js/auth/service.js',
'./www/js/auth/interceptor.js',
'./www/js/auth/logoutController.js',
'./www/js/sports/controller.js',
'./www/js/sports/service.js',
'./www/js/leagues/service.js',
'./www/js/lines/controller.js',
'./www/js/lines/service.js',
'./www/js/betSlip/controller.js',
'./www/js/betSlip/service.js',
'./www/js/deviceDetector/service.js'
])
.pipe(ngAnnotate())
.pipe(concat('code.min.js'))
.pipe(gulp.dest('./www/js'))
});
// JSHint task
gulp.task('lint', function() {
gulp.src(['www/js/*.js', 'www/js/**/*.js', '!www/js/lib.min.js', '!www/js/code.min.js'])
.pipe(jscs())
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
gulp.task('sass', function(done) {
gulp.src('./scss/ionic.app.scss')
.pipe(sass({onError: function(e) { console.log(e); } }))
.pipe(autoprefixer('last 2 versions', 'Chrome', 'ios_saf','Android'))
.pipe(gulp.dest('./www/css/'))
.pipe(minifyCss({
keepSpecialComments: 0
}))
.pipe(rename({ extname: '.min.css' }))
.pipe(gulp.dest('./www/css/'))
.on('end', done);
});
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']);
});
gulp.task('install', ['git-check'], function() {
return bower.commands.install()
.on('log', function(data) {
gutil.log('bower', gutil.colors.cyan(data.id), data.message);
});
});
gulp.task('git-check', function(done) {
if (!sh.which('git')) {
console.log(
' ' + gutil.colors.red('Git is not installed.'),
'\n Git, the version control system, is required to download Ionic.',
'\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.',
'\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.'
);
process.exit(1);
}
done();
});
all I need is the reloading part back, every time I save -- ctrl + s something in my IDE, I want to see the changes in the browser automatically, I am wasting a lot of my time by going to the console and typing gulp everty time I want to see changes.
you should check when the gulpfile changed in git, then diff the two versions to see what changed.
$ git log gulpfile.js
$ git diff <commit id> gulpfile.js
In regards to the browser not refreshing, it's likely an issue with LiveReload. Check your watchPatterns config in the ionic.project file.
https://github.com/driftyco/ionic-cli#testing-in-a-browser
As for gulp not running after you change a file:
It sounds like someone may have moved some files around. Confirm that this path still points to the files you want to watch:
sass: ['./scss/**/*.scss']. If it's not, update it and run gulp watch.
Keep in mind that gulp.watch() can't detect new files, so it will need to be restarted every time a new watchable file is created.

Categories