2

I'd like to construct a gulp task that will conditionally manually invoke some other tasks before running itself. After seeing that gulp.run('task') has been deprecated, I ended up with this basic structure:

const build = {
    server: () => {
        return gulp.src(files.server)
            ...
            .pipe(gulp.dest(files.outDir))
    },

    web: () => {
        return gulp.src(files.web)
            ...
            .pipe(gulp.dest(files.outDir))
    }
}

gulp.task('serve', () => {
    // run the server and if necessary, force it to stop first
    const start = () => expressServer.start('./dist/main.js')

    // don't try to run if build hasn't been run first
    try {
        fs.statSync('./dist/main.js') // throws an exception if the file doesn't exist
        start()
    } catch (err) {
        // ----- TODO in parallel; build server and web
        // afterwards; run server iff there were no errors

        if (failed)
            console.error(err)
        else
            start()
    }
})

It looks like invoking build.server() or build.web() does actually run the gulp tasks, but the function returns straight away - I guess that means the body of these functions is running asynchronously?

Could anyone help me to understand:

  • What does the gulp.src(...). ... .gulp.dest(...) chain actually return? Is gulp, as I suspect, running these operations asynchronously?
  • Assuming asynchronous operation; how can I wait for these to be completed?
  • If not asynchronous, how can I execute them?
Micheal Hill
  • 1,619
  • 2
  • 17
  • 38
  • 1
    For synchronous operation, see also here ➝ http://stackoverflow.com/a/26390567/444255. Make 'third' a distinct task, and depend it on 'second' and 'first'. Also make 'second' depend on 'first'. This should guarantee waiting for each other's completion. – Frank N Feb 06 '16 at 12:38
  • @FrankN A good suggestion, but I could not think of a good way to fit it into OP's context (as OP wants to kick off the task conditionally within the code). If you have an idea how I'd be interested in seeing an answer from you, chance for me to learn something as well :-) – Jeroen Feb 06 '16 at 13:01
  • 1
    @FrankN Thanks for that. I was trying to avoid synchronous tasks for a bit, since I was copying the entire node_modules directory into my dist folder (which understandably took ages - but I've fixed that). I'm still (slowly) getting my head around Gulp, and I ended up with a very convoluted approach to something that didn't really need it! – Micheal Hill Feb 09 '16 at 08:39

1 Answers1

1

I find the DefinitelyTyped (Typescript) files often help figuring out what's going on. As far as I can tell:

  • The gulp.src function will give a NodeJS.ReadWriteStream;
  • The node.d.ts file is somewhat harder to understand, but basically all ...Streams have a pipe method which takes in a stream and returns one of the samem/similar (?) type.

So bascially, you return the result of gulp.src (the piping bit doesn't change the type of return value), which is a node stream.

This basically means you can run the server and web tasks and use finish callbacks of the streams those tasks return to take action only when they've completed successfully.

As a footnote, though I'm unfamliar with the precise workings, I think merge-stream may be of help too, if you need to wait for multiple streams to be completed.


Here's a basic example (based off your code, minus the try..catch bit):

var gulp = require("gulp");
var mergeStream = require("merge-stream");

const build = {
  server: () => {
    process.stdout.write("MYMESSAGE: Server...\n");
    return gulp.src("src/nonexistent/server.js").pipe(gulp.dest("./build/server"));
  },
  web: () => {
    process.stdout.write("MYMESSAGE: Web...\n");
    return gulp.src("src/web.js").pipe(gulp.dest("./build/server"));
  }
}

gulp.task("serve", () => {
  const start = () => process.stdout.write("MYMESSAGE: Starting!\n");

  try {
    throw new Error("Simulated error!");
  } catch(err) {
    // In parallel build server and web, afterwards run
    // server iff there were no erros.
    mergeStream(build.server(), build.web())
      .on("error", () => console.error(err))
      .on("finish", () => start());    
  }
});
Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • 1
    That's brilliant. I'm actually using some typescript elsewhere in my project and I didn't even think about using the .d.ts for this issue. – Micheal Hill Feb 09 '16 at 08:33