fractalspawn fractalspawn - 2 months ago 12
Javascript Question

Why is this gulp task not being run consecutively?

I have three gulp tasks:

watch
,
build
,
test
. I'd like to have my watch running and when a file is saved, it is built and then tested (duh).

What is happening is that despite being set up to run
build
as a dependency of
test
, I need to save the file twice in order for the latest build to be the one that is tested.

I can reproduce this by starting the watch, making a change to somewhere in the client JS code (like adding a console log) and then watching the resulting output. The first save will not have any console output. Just saving the file again (no changes made) will cause the test to be re-run and the console output to display.

I have also noticed cases where the first build+test cycle will be the correct build (i.e. will have the console log statement), but after that, it takes two saves to make sure the latest code is the one being tested.

Spec files are immune to this because they are not built and instead used directly (sorta, they're transpiled first).

So, am I going crazy here? These should be run consecutively, right?

The log would suggest that's the case:

[12:05:54] Starting 'build:client:js'...
[12:05:54] Finished 'build:client:js' after 13 ms
[12:05:54] Starting 'test:client'...
19 09 2016 12:05:54.808:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
19 09 2016 12:05:54.808:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
19 09 2016 12:05:54.841:INFO [launcher]: Starting browser PhantomJS
19 09 2016 12:05:55.381:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#Zklau3qmk75NKg2HAAAB with id 61545463
LOG: 'test'
.
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 SUCCESS (0.002 secs / 0.029 secs)
[12:05:55] Finished 'test:client' after 775 ms





Build:



Basic build for AngularJS App, nothing too strange here.

gulp.task('build:client:js', () => {
gulp.src('app/sections/client/**/!(*.spec|*.e2e).js')
.pipe(sourceMaps.init())
.pipe(eslint())
.pipe(eslint.formatEach())
.pipe(babel({presets: ['es2015']}))
.pipe(ngAnnotate())
.pipe(concat('client.js'))
.pipe(uglify())
.pipe(sourceMaps.write())
.pipe(gulp.dest(paths.build))
});


Test:



This is set up so that, ideally,
build
runs and completes first.

gulp.task('test:client', ['build:client:js'], (done) => {
const src = {};
src['client'] = 'app/sections/client';

const config = getTestConfig(src);
new karmaServer(config, done).start();
});


Watch:



This should only need to run
test
because
build
is a dependency of
test
.

gulp.task('watch:client:js', () => {
gulp.watch('app/sections/client/**/*.js', ['test:client']);
});





Also, to be totally transparent, most of my
watch>build>test
gulp tasks are being generated dynamically based off a paths file. It basically returns JSON that is then used by functions to create the gulp tasks. The output below is the result of that generation, but I'm not sure that physically writing each task out like this would make any difference.

You can experiment with or see more here.

Answer

In the task 'build:client:js', you should return the stream so that gulp knows when the task actually ends.

gulp.task('build:client:js', () => {
    return gulp.src('app/sections/client/**/!(*.spec|*.e2e).js')
        .pipe(sourceMaps.init())
            .pipe(eslint())
            .pipe(eslint.formatEach())
            .pipe(babel({presets: ['es2015']}))
            .pipe(ngAnnotate())
            .pipe(concat('client.js'))
            .pipe(uglify())
        .pipe(sourceMaps.write())
        .pipe(gulp.dest(paths.build))
});
Comments