We have a fairly complex Gruntfile.js that performs numerous things to process a bunch of EPUBs. It's part of our CI process being run regularly on Jenkins. Sometimes we want to notify the person who initiated the build of things that occurred - not errors but rather warnings (the task can continue but something abnormal happened). We use Slack for communication. What's a scalable and maintainable mechanism to achieve this?

Right now we push a notification out of a then() for promise-based tasks, processing what was passed into the then(). Sometimes we have external modules we require to not bloat the Gruntfile even further. Some of the tasks are not promise-based. We want to handle all these in a standard manner.

We thought of using eventing, but then we'd have to inject a dependency into the external module. Is there a way to manage without injecting one?

processThings = require('./scripts/process-things'),

    slack: {
        options: {
            username: 'Jenkins',
        text: '{{message}}', // taken from grunt.option

grunt.registerTask('validateSVGs', function () {
    var svgFiles = glob.sync("./**/*.svg");

    Promise.all(svgFiles.map(file => {
        // perform validation here
    })).then(values => {
        // compile a message for Slack:
        let errors = values.filter(el => { return el.err !== null; });
        let message = `:rotating_light: SVG files had errors:\n${errors.join('\n')}`;

        grunt.option('message', message);

grunt.registerTask('downloadThings', function () {

    processThings.then((results) => {
        // push warnings from processThings to Slack - here or earlier, directly inside it

Options I can see right now:

  1. Inject a dependency into external modules for handling communication (either Slack or a bus of some sort).
  2. Continue handling everything in then() for promise-based tasks, and "promisify" all the non-promise-based ones.
  3. Use events, though I have no idea how to do this in NodeJS context without DOM (I guess we could use grunt.event).

I think Node.js streams could be the solution for You, providing eventful api and are very task-oriented one.

We use gulp for such things, and our system is quite complex one, managing whole product architecture/topology changes and it's deployment process. Stream-based (and gulp's) code much more concise, and .... more task-like... Each task could be stream (resolves on stream 'finish') , or any promise-like structure (you can mix if it is necessary).

Such solution will conform to your 3rd option, but it is much advanced - because streams have certain event api/convention and it is exactly flow/task based one. Their nature is functional, you can use them in object mode, and they are much more performant and easier to manage and compose than the promises or Continuation-passing code. There are bunch of stream modules/plug-ins on npm, so they will cover any possible dev-ops/ops/build/ci task or requirement.

Your Answer

