I'm trying to set up a Gulp task for eslint (System: OS Windows 10). But it seems that the src is not being evaluated correctly:
gulp.task('lint-app-basic-an', function() {
gulp.src('src/main/webapp/app-basic-an/**/*.js')
.pipe(eslint({
configFile: '.eslintrc.js'
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
There are several subfolders underneath src/main/webapp/app-basic-an, e.g.
src/main/webapp/app-basic-an/components/page-header/page-header.component.js
If I create a lint error in said JS-File, it is ignored by the linter. If I specify the path 1 level more in the tasks .src-function like
gulp.src('src/main/webapp/app-basic-an/components/**/*.js')
It suddenly works, which makes no sense to me, I thought "**/" meant zero or more subdirectories?
Gulp executes its tasks in an asynchronous manner. For gulp to be able to know that some task has finished, the tasks needs to do one of the following:
return stream (e.g. the one created by gulp.src) on which gulp can listen for end event,
return q promise or
call callback function passed as task function argument
If the task does not accept arguments and does not return promise or stream, gulp considers that task synchronous (i.e. it is finished once the function call returns). Once all tasks are finished, the execution stops... hence if you have some async processing, it will never finish (or worse - it might end at a random point).
Related
Below you can see simplified view of an issue. Basically, I'm able to call task1.js using gulp.series in tasks task2,3.js, but once I add same code to call task1.js in task4.js - Task never defined: task1 error gets thrown.
There are more tasks in the tasks folder than in file structure example below.
I've got three tasks,
...
/tasks
build.js
clean.js
dev.js
gulpfile.babel.js
...
all of them required in gulpfile.babel.js using the require-dir package
import requireDir from 'require-dir';
requireDir('./tasks', {recurse: true});
This allows me to call a task from clean.js at dev.js, and it works fine.
import gulp from 'gulp';
gulp.task('dev', gulp.series('clean');
But after I add same code structure at build.js.
import gulp from 'gulp';
gulp.task('build', gulp.series('clean');
it somehow breaks gulp stream (I guess), so now on any task call I get:
$gulp dev
-AssertionError [ERR_ASSERTION]: Task never defined: clean.
$gulp -v
[11:50:11] CLI version 2.0.1
[11:50:11] Local version 4.0.0
For those migrating from gulp v3 to v4 or are using gulp.task() to define tasks in gulp v4 and get this error message: Task never defined, the problem usually lies here:
Forward references
A forward reference is when you compose tasks, using string
references, that haven't been registered yet. This was a common
practice in older versions, but this feature was removed to achieve
faster task runtime and promote the use of named functions. In newer
versions, you'll get an error, with the message "Task never defined",
if you try to use forward references. You may experience this when
trying to use exports for your task registration and composing tasks
by string. In this situation, use named functions instead of string
references.
During migration, you may need to use the forward reference registry.
This will add an extra closure to every task reference and
dramatically slow down your build. Don't rely on this fix for very
long.
From gulpjs documentation re: gulp.series and gulp.parallel documentation.
Here is what that means. There are two ways to create tasks:
1. gulp.task('someStringAsTask', function() {..})
2. function myNamedFunction () {…}
When you use version 1 (gulp.task…) you cannot refer to that task by its string name until it has been registered. So you cannot do this:
exports.sync = gulp.series('sass2css', serve, watch);
// or gulp.task('dev', gulp.series('sass2css', serve, watch); doesn't work either
gulp.task('sass2css', function() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
})
Results in
AssertionError [ERR_ASSERTION]: Task never defined: sass2css
That is a forward reference, composing a task (using gulp.series or gulp.parallel) and referring to a task by its string name (in the above case 'sass2css') before it has been registered. (calling "gulp.task(…..)" is the act of registering) Putting the gulp.task('sass2css',...) first fixes the problem.
If you use version two of defining a task:
function sass2css() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
}
you are now using a named function to register a task and do not need to use its name as a string. So this now works:
exports.sync = gulp.series(sass2css, serve, watch);
// gulp.task('dev', gulp.series(sass2css, serve, watch); this also works
followed by (or preceded by - either works):
function sass2css() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
}
The original OP used this and it worked:
import gulp from 'gulp';
gulp.task('dev', gulp.series('clean');
Noted that clean.js got imported before dev.js so that was okay.
This didn't work:
import gulp from 'gulp';
gulp.task('build', gulp.series('clean');
because the string-referenced task, 'clean' gets imported (and thus registered) after build.js where it is referenced - thus creating an illegal forward reference to a string-referenced task.
So there are two standard ways to fix this error:
Use named functions to define tasks not gulp.task('someTask',...). Then it doesn't matter the order of using those named functions when composing other tasks, i.e., when using gulp.series or gulp.parallel. And there are other advantages to using named functions, such as passing arguments, so this is the best option.
If you do use the older gulp v3 gulp.task method of creating tasks with string references, be careful to not refer to those tasks until after the task is actually created.
Also see my answer at task never defined error for fixing another problem which results in the same error message. Specifically using gulp.task('someTask', ['anotherTask'], function(){}) synatx in a gulp4 file.
The series and parallel functions of gulp 4 do not create a task definition as its README seems to suggest, but instead they both run the tasks in parameter. In order to work as intended, one need to surround the call with a closure.
So, to fix the excerpt
gulp.task('build', gulp.series('clean'));
it is necessary to add the closure:
// Older EcmaScripts:
gulp.task('build', function() { return gulp.series('clean') });
// EcmaScript 6:
gulp.task('build', () => gulp.series('clean'));
I had a similar setup where I had recursively require'd all tasks under a directory. And after updating to gulp 4 started getting error Task never defined.
I tried Pedro solution, but this caused another error:
The following tasks did not complete: default
Did you forget to signal async completion?
The solution was fairly simple for me, just import the missing tasks.
import gulp from 'gulp';
import './clean';
gulp.task('build', gulp.series('clean'));
The easiest solution might be using the official undertaker-forward-reference package:
const gulp = require("gulp");
const FwdRef = require("undertaker-forward-reference");
gulp.registry(FwdRef()); // Or gulp.registry(new FwdRef());
gulp.task("firstRegisteredTask", gulp.series("laterRegisteredTask")); // Works thanks to undertaker-forward-reference
gulp.task("laterRegisteredTask", () => {
return gulp.src("someGlob").pipe(gulp.dest("someFolder"));
});
This solution might negatively affect performance though (source):
This will add an extra closure to every task reference and dramatically slow down your build.
I'm trying to finish my gulpfile.js but I'm running into a problem with "gulp watch". When I set my watcher to run, it detects changes and run the assigned task, but only once. The next changes on the files don't trigger the tasks anymore. I don't know why, but my watcher is working just once.
I believe the watcher is not realizing the tasks it triggered are finished. Or, maybe it's something to deal with the lazy loading or run-sequence plugins I'm using...
var
gulp = require('gulp'),
plugins = require('gulp-load-plugins')({
DEBUG: true
});
plugins.runSequence = require('run-sequence');
gulp.task('watch',function(){
gulp.watch('public/**/*.+(css|js)',['buildEspecifico']);
});
gulp.task('buildEspecifico',function(callback){
return plugins.runSequence(
['deletarMainMin'],
['agruparJS','agruparCSS']
);
});
'deletarMainMin','agruparJS','agruparCSS' are other tasks defined in the same gulpfile.
Thanks in advance!
Cheers,
Fabio.
I believe the watcher is not realizing the tasks it triggered are finished.
Yes, that is exactly it. In your buildEspecifico task you accept a callback. That means gulp will not consider your buildEspecifico task to have finished unless you invoke that callback.
Since you don't invoke callback the buildEspecifico task never actually finishes once it runs. And because your buildEspecifico task is technically still running gulp doesn't start the task again when a file changes.
The solution is to pass callback to runSequence. It will invoke the callback when all of your tasks in the sequence have finished.
gulp.task('buildEspecifico',function(callback){
return plugins.runSequence(
['deletarMainMin'],
['agruparJS','agruparCSS'],
callback
);
});
Alternatively you can also just leave out the callback altogether:
gulp.task('buildEspecifico',function(){
return plugins.runSequence(
['deletarMainMin'],
['agruparJS','agruparCSS']
);
});
Obviously you have to make sure that the tasks deletarMainMin, agruparJS, agruparCSS themselves finish, so either call or leave out the callback in those tasks too.
I've specified some Gulp tasks in a gulpSequence like this:
gulp.task('default', function(done){
gulpSequence(
'private:clean',
'private:copy-app-package-file',
'private:copy-app-main-file',
'private:copy-libs',
'private:copy-app-files',
'private:copy-css-files',
'private:build-html',
'private:package-app',
done);
});
I thought that they should run one after another. The build-html tasks needs the libs, app-files and css-files, because they get included within one html file.
But if I run the default task, the build-html task is missing some files. For example the task can only inject 10 files in the html file but there are 16 files.
Is there another way to specify dependent tasks. I thought the gulpSequence will handle this.
You're on the right lines, but the npm package you are trying to use is depreciated. Might be worth considering checking out run-sequence (https://www.npmjs.com/package/run-sequence) which waits for a previous task to complete before starting.
So in your instance, this would become
gulp.task('default', function( cb ) {
$.runSequence(
'private:clean',
'private:copy-app-package-file',
'private:copy-app-main-file',
'private:copy-libs',
'private:copy-app-files',
'private:copy-css-files',
'private:build-html',
'private:package-app',
cb
)
});
You specified that all tasks should run in sequence with no parallelism at all. A new task starts as soon as a former task shows completion.
Probably you have some issues in a task before the build-html task. Do they handle the completion (done() callback) correctly? In most cases I saw there was some async action triggered and the callback was called before the async task finished. So the sequence continues before the task is really over...
I have a gulpfile, it uses run sequence and gulp.watch().
Here is an example task that uses run sequence.
gulp.task('rebuild', function (callback) {
runSequence('clean',
'lint',
['process-js', 'process-styles', 'move-fonts', 'move-static-content']);
});
When I make a change to a file, the watch task will run the task I specified exactly once. In this case, the task that should be executed is "run", which is the same as the default task except it doesn't run the dev server and watch task again. Nothing happens when I make further edits, whether in the same file or a different one.
If I pass gulp.watch a plain gulp task (without run sequence), for example the clean task, then the watch will run the clean task every time.
I'm sure I'm doing something wrong, but I don't understand what. I think something might be silently erroring and disconnecting the stream, but I can't figure out how to debug this.
You aren't passing the callback into run-sequence, therefore the task never completes. - OverZealous
So the run sequence task needs to look like this:
gulp.task('rebuild', function (callback) {
runSequence('clean',
'lint',
['process-js', 'process-styles', 'move-fonts', 'move-static-content'],
callback);
});
I am confused about gulp.src().
According to this thread I would assume that it is necessary to return gulp.src().
The examples on the gulp project always return gulp.src(). i.e. the gulp intro sample.
However many plugins do show documentation that do not return gulp.src(). i.e: gulp-less or gulp-angular-templatecache
How should I decide if my task should return gulp.src()?
You should always return gulp.src so that gulp can properly sink the stream for you. The stream may not complete otherwise, if you have a large number of files in it. Plus you get some other (minor) benefits such as that the correct task completion time will be logged by the runner.
Oftentimes I'll see people praising gulp for tasks that are reported as taking microseconds to complete, but all they did was not return the stream. The task took just as long to complete if we had returned the stream, however.
The other problem with not returning the stream is setting up dependent tasks. If you want some task to run before another task, you need to tell gulp that you're done processing. You either do this with a callback function for the task, or by returning the stream.
The only case in which I would not return the stream is if I have more than one stream in a single task; for that you can use merge-stream:
var merge = require('merge-stream');
gulp.task('task', function () {
var someOperation = gulp.src('./').pipe(gulp.dest('out'));
var someOtherOperation = gulp.src('./assets').pipe(gulp.dest('out/assets'));
return merge(someOperation, someOtherOperation);
});
So... while it is not mandatory, it is a best practice. I would suggest to pull request those plugin author's repositories to update their README files to indicate this.
If you do not return the stream, gulp will report the time it takes to build the pipe. If you return the stream, it will correctly report the time it takes to execute the task(s).