Trying to get a custom watcher to work:
var gulp = require('gulp'),
shell = require('gulp-shell');
gulp.task('run-au', shell.task(['au build']));
gulp.task('build', gulp.series('run-au', () => {
return gulp.src('./wwwroot/**/*.*')
.pipe(gulp.dest('../Something.Api/wwwroot'));
}));
gulp.task('watch', () => {
gulp.watch('./src/**/*.*').on('change', gulp.series('build'));
});
Pretty straightforward, it works when I change something in src, but when it detects that change, it goes into a cyclic build cycle, where it will keep on running build
Additions
I saw that environment.js seemed to be getting updated which could have affected the watch thus creating the cyclic build, however even changing to:
gulp.task('watch', () => {
gulp.watch(['./src/**/*.*', '!./src/env*.*']).on('change', gulp.series('build'));
});
Didn't seem to change the outcome
In the docs it states:
gulp.watch(globs[, opts][, fn])
opts
Type: Object
queue (boolean, default: true). Whether or not a file change should queue the fn execution if the fn is already running. Useful for a long running fn.
So I added:
gulp.task('watch', () => {
gulp.watch(['./src/**/*.*', '!./src/env*.*'], {queue: false}, gulp.series('build'));
});
Related
Most questions and answers on this site do not contain an easy-to follow general approach to using these two libraries together.
So, being that we use the gulp-connect npm package, and we want to make use of the gulp-watch npm package, how do we set it up so that we can:
watch changes in some files
perform some operation, like building / compiling those files
live-reload the server once the building is done
First, you will define your build task. This can have pre-required tasks, can be a task of some sort, it doesn't matter.
gulp.task('build', ['your', 'tasks', 'here']);
Then, you will need to activate the connect server. It is important that you are serving the result of the compilation (in this example, the dist directory) and you're enabling livereload with the livereload: true parameter.
const connect = require('gulp-connect');
gulp.task('server', function() {
return connect.server({
root: 'dist',
livereload: true
});
});
Finally, you will setup your watch logic. Note that we're using watch and not gulp.watch. If you decide to change it, notice that their APIs are different and they have different capabilities. This example uses gulp-watch.
const watch = require('gulp-watch');
gulp.task('watch-and-reload', ['build'], function() {
watch(['src/**'], function() {
gulp.start('build');
}).pipe(connect.reload());
});
gulp.task('watch', ['build', 'watch-and-reload', 'server']);
The watch-and-reload task will depend on the build task, so that it ensures to run at least one build.
Then, it will watch for your source files, and in the callback, it will start the build task. This callback gets executed every time that a file is changed in the directory. You could pass an options object to the watch method to be more specific. Check the usage API in their repository.
Also, you will need to start the build action, for which we're using gulp.start. This is not the recommended approach, and will be deprecated eventually, but so far it works. Most questions with these issues in StackOverflow will look for an alternative workaround that changes the approach. (See related questions.)
Notice that gulp.start is called synchronously. This is what you want, since you want to allow the build task to finish before you proceed with the event stream.
And finally, you can use the event stream to reload the page. The event stream will correctly capture what files changed and will reload those.
Bringing up to speed, as per current stable gulp release
gulp.task API isn't the recommended pattern anymore. Use exports object to make public tasks
From official documentation: https://gulpjs.com/docs/en/api/task#task
To Configure watch and livereload you need following
gulp.watch
gulp-connect
watch function is available in gulp module itself
install gulp-connect using npm install --save-dev gulp-connect
To configure gulp-connect server for livereload we need to set property livereload to true
Run all tasks followed by task that calls watch function in which globs and task are given. Any changes to files that match globs trigger task passed to watch().
task passed to watch() should signal async complection else task will not be run a second time. Simple works: should call callback or return stream or promise
Once watch() is configured, append .pipe(connect.reload()) followed by pipe(dest(..)) where ever you think created files by dest are required to reload
Here is simple working gulpfile.js with connect lifereload
const {src, dest, watch, series, parallel } = require("gulp");
const htmlmin = require("gulp-htmlmin");
const gulpif = require("gulp-if");
const rename = require('gulp-rename');
const connect = require("gulp-connect");
//environment variable NODE_ENV --> set NODE_ENV=production for prouduction to minify html and perform anything related to prod
mode = process.env.NODE_ENV || 'dev';
var outDir = (mode != 'dev') ? 'dist/prod': 'dist/';
const htmlSources = ['src/*.html'];
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload());
}
function js(){
return src('src/*.js')
.pipe(uglify())
.pipe(rename({ extname: '.min.js' }))
.pipe(dest(outDir))
.pipe(connect.reload());
}
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true
})
}
function watchReload() {
let tasks = series(html, js);
watch(["src/**"], tasks);
}
exports.html = html;
exports.js = js;
exports.dev = parallel(html, js, server, watchReload);
Configure connect server with livereload property
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true //essential for live reload
})
}
Notice .pipe(connect.reload()) in the above code. It is essential that stream of required files to be piped to connect.reload() else it may not work if you call connect.reload() arbitrarily
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload()); //Keep it if you want livereload else discard
}
Since we configure public task dev following command will execute all tasks followed by connect and watchReload
gulp dev
I am attempting to re-run my gulp build when gulpfile.js changes, but I am having issues with the method all of my research has lead me to.
I have one watcher for all my less and javascript files and a configuration object that has the list of files to watch, how they are output, etc. This is a stripped-down example of what it looks like:
var $ = require('gulp-load-plugins')();
var config = {
root: rootPath,
output: {
app: 'app',
vendor: 'vendor'
}, // ...
};
gulp.task('default', ['build', 'watch']);
gulp.task('build', ['clean', 'less:app', 'less:theme', 'css:vendor', 'js:app', 'js:vendor', 'rev', 'css:copyfonts']);
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
$.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
gulp.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
// .. other build tasks ..
The above code shows how I tried the accepted answer to this:
How can Gulp be restarted upon each Gulpfile change?
However, it has a major issue. When I run watch:gulp, it runs the build just fine, and everything is great. The config.output.app variable is how the app specific css and js files are named, so my test case has been:
run gulp:watch, check that the css output is named according to config.output.app
change config.output.app, and perform step #1 again
save any random javascript file that it is watching, and see if it builds correctly
Step 3 is riddled with permission errors because of multiple watchers on the files, and this only gets worse the more I repeat steps 1 and 2. Visual Studio will even freeze.
I have not found a way to clean up the old watchers. I tried to manually kill them like this:
var appFileWatcher;
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
appFileWatcher = $.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
var gulpWatcher = $.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
if (appFileWatcher) {
appFileWatcher.unwatch();
}
gulpWatcher.unwatch();
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
This also does not work. I still get multiple watchers trying to perform the build when I perform my same test case.
How do I kill those watchers that stay around after the new gulp process is spawned?
Hi what I trying to do is to make watcher task with gulp which will run my jasmine tests. What I have done so far:
var watch = require("gulp-watch");
var jasmine = require("gulp-jasmine");
gulp.task('tests.run.change-watcher', function (cb) {
gulp.src(testsFiles)
.pipe(watch(testsFiles))
.pipe(jasmine({ verbose: true }));
});
But when I run that task and try to change any file which meets the testsFiles rules it doesn't show anything in console.
However when I run the next task:
gulp.task('tests.run', function (cb) {
gulp.src(testsFiles)
.pipe(jasmine({verbose:true}));
});
It works and shows next:
8 specs, 0 failures Finished in 0 seconds
Maybe I miss something?
Do it in two steps
1) Declare the test-unit task (like you did)
gulp.task('tests.run', function () {
return gulp.src(testsFiles)
.pipe(jasmine({verbose:true}));
});
2) Declare the watch task that will run this test-unit task when those testsFiles change
gulp.task('tests.watch', function () {
gulp.watch(testsFiles, ['tests.run']);
});
Then, you run gulp tests.watch
To run only needed specs, try something like this:
/** Watches file changes in source or spec files and executes specs automatically */
gulp.task("specs-watcher", function() {
return watch(["src/**/*.ts", "spec/**/*.ts"], { events: ["add", "change"] }, function(vinyl, event) {
if (!vinyl.isDirectory()) {
if (vinyl.basename.endsWith(".spec.ts")) {
// We are dealing with a spec file here, so call jasmine!
runJasmine(vinyl.path);
} else {
// Try to find out specs file
const specFilePath = findSpecsFile(vinyl);
if (typeof specFilePath === "string") {
runJasmine(specFilePath);
}
}
}
});
});
This watcher uses two functions, one is for deriving the spec name based on the file name. In my case, it's:
/**
* For your specs-watcher: This function is called every time a file changed which doesn't end with '.spec.ts'.
* The function's task is to return the fitting specs path of this file. For example by looking for a corresponding file in the "/spec/" folder.
* #param {vinyl} changedFile Vinyl object of changed file (see https://github.com/gulpjs/vinyl)
* #return {string|undefined} Path to the specs file to execute or undefined if your watcher shouldn't do anything.
*/
function findSpecsFile(changedFile) {
return changedFile.path.replace(__dirname, `${__dirname}/spec`).replace(".ts", ".spec.ts");
}
The other function is runJasmine, which runs jasmine with a given test file.
Just make everything fit to your setup and it should work. :-)
You can listen to file changes for both tests and source code folders with this:
"use strict";
var gulp = require('gulp');
var mocha = require('gulp-mocha');
var batch = require('gulp-batch');
gulp.watch(['tests/**', 'src/**'], batch(function (events, cb) {
return gulp.src(['tests/*.js'])
.pipe(jasmine({ verbose: true }))
.on('error', function (err) {
console.log(err.stack);
});
}));
gulp.task('default', () => {
console.log('Gulp is watching file changes...');
});
Here is my code:
gulp.task('sass', function () {
gulp.src('./public/stylesheets/*.scss')
.pipe(sass())
.pipe(gulp.dest('./public/stylesheets/'));
});
gulp.task('watch-saas', function () {
watch('./public/stylesheets/*.scss', function () {
gulp.start('sass');
});
});
Output:
[19:15:46] Using gulpfile ~/WebstormProjects/mySite/gulpFile.js
[19:15:46] Starting 'watch-saas'...
[19:15:46] Finished 'watch-saas' after 38 ms
Im afraid no CSS. Any ideas how to make this work?
I think my code looks very much like the example code here. And the 'sass' task runs fine on its own.
I'm not that experienced in Gulp, but I usually use:
gulp.task('watch-saas', function () {
return gulp.watch(['./public/stylesheets/*.scss'], ['sass']);
});
I assume that you have to return the result in your task, because it's an asynchronous task.
We should first pipe it and ask gulp to watch it in changes in our scss or file we alerted
var gulp = require('gulp')
var watch = require('gulp-watch');
gulp.task('styles', function(){
return gulp.src(''./public/stylesheets/.scss'').pipe(gulp.dest('./sass'));
});
watch('./public/stylesheets/.scss', function(){
gulp.start('styles');
});
styles is the task name which I assigned here
Basically I'd like to run grunt after my generator finishes installing dependencies, I found that you can add a callback function to the installDependencies method to run after everything has been installed like this:
this.on('end', function () {
this.installDependencies({
skipInstall: options['skip-install'],
callback: function () {
console.log('All done!');
}
});
});
However I'm not sure how to run the grunt task (as in going to the terminal and running "grunt")
After this.on('end') add this lines
// Now you can bind to the dependencies installed event
this.on('dependenciesInstalled', function() {
this.spawnCommand('grunt', ['build']);
});
check this topic for more details.
But if you're using the latest update of yeomen, you'll need to make it like this
this.on('end', function () {
if (!this.options['skip-install']) {
this.npmInstall();
this.spawnCommand('grunt', ['prepare']); // change 'prepare' with your task.
}
});