npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

redun

v0.2.1

Published

A Gulp task generator to help keep your task definitions DRY.

Readme

Redun

Redun is a a Gulp task generator to help keep your task definitions DRY. It makes it easier to create multiple tasks (called a task family), that perform similar functions, using cascading configurations, while encouraging definition of one file/module per task family.

Installation

Install via NPM:

npm install --save-dev redun

Requiring Redun

To require redun in CommonJS you must access the default exported property, which is also exported as redun:

var redun = require('redun').redun;
var redun = require('redun').default;

If you're writing in ES6 syntax, in addition to the above, you can import using either of these two approaches:

import {redun} from 'redun';
import redun from 'redun';

Basic Usage

/******** gulpfile.js ********/

var gulp = require('gulp');
var redun = require('redun').redun;

redun.add('tasks/**/*.js');
redun.bootstrap();

gulp.task('default', ['hello']);
/******** tasks/hello.js ********/

// export a function
module.exports = function(callback) {
  console.log('Hello Redun');
  callback();
};

Creates a hello gulp task, which runs the exported function.

Tasks with a configuration object

Configuration for tasks can be specified by exporting an object instead of a function, and specifying a formula property for the configuration, and an actions property which specifies the task function itself. The configuration object is generated from the formula and available as this.config within the context of the executing function.

/******** tasks/hello.js ********/

// export an array
module.exports = {
  formula: {
    name: 'Merott'
  },

  action: function(callback) {
    console.log('Hello ' + this.config.name);
    callback();
  }
}

Task Families

Prefixing a config property name with : indicates a subtask/child task. This task will inherit config properties of the parent task but can override them.

/******** tasks/hello.js ********/

module.exports = {
  formula: {
    ':merott': {
      name: 'Merott'
    },

    ':james': {
      name: 'James'
    }
  },

  action: function(callback) {
    console.log('Hello ' + this.config.name);
    callback();
  }
};

Creates 6 tasks:

  • hello - runs both hello:merott and hello:james tasks, using gulp task dependencies.
  • hello.
  • hello:merott
  • hello:merott.
  • hello:james
  • hello:james.

Redun calls these a Task Family.

See Tasks without external dependencies to understand what the dot-suffixed versions of the tasks are about.

Note that when a task has at least one child task, it becomes an alias task and does not execute itself, but instead triggers its children tasks to run. It's equivalent to defining a Gulp task like this:

gulp.task('say-hi', ['say-hi:hello', 'say-hi:hola']);

It is possible to explicitly set which children tasks to run when calling an alias task, by defining the #default property:

/******** tasks/hello.js ********/

module.exports = {
  formula: {
    '#default': 'merott', // string, or array of string(s), e.g. ['merott']

    ':merott': {
      name: 'Merott'
    },

    ':james': {
      name: 'James'
    }
  },

  action: function(callback) {...}
};

With the above configuration, running gulp hello will only run gulp hello:merott, not both.

Tasks with dependencies

Meta configurations for tasks can be specified using special properties that are prefixed with the # symbol. One such special property is #deps which specifies gulp dependencies of that task.

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean']
  },

  action: function jsBuildFunction() {
    // return js-build stream
  }
}

Tasks without external dependencies

Every Gulp task created by Redun also comes with a sibling task, that excludes any external task dependencies. For example, when you define a js-build task that depends on some clean task, Redun will also create a js-build. task, that will not depend on clean. This allows the js-build process to be run on its own, without triggering a clean.

To achieve this using pure Gulp, you'd do something like:

/******** gulpfile.js ********/

gulp.task('js-build', ['clean'], jsBuildFunction);
gulp.task('js-build.', [], jsBuildFunction);

function jsBuildFunction() {
  // return js-build stream
}

With Redun, you only have to know that the following export creates a js-build. task as well as js-build.

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean']
  },

  action: function jsBuildFunction() {
    // return js-build stream
  }
}

Let's say js-build was actually defined like this:

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean'],

    ':es5': {
      transpile: false
    },

    ':es6': {
      transpile: true
    }
  },

  action: function jsBuildFunction() {
    // return js-build stream, transpiled if es6
  }
}

The above would create a js-build task that depends on jsbuild:es5, jsbuild:es6, and clean.

Additionally, it creates a jsbuild. task, which depends on jsbuild:es5. and jsbuild:es6., but not on clean.

Optional dependencies

You can make some dependencies optional by prefixing them with a ? symbol:

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['?clean']
  },

  action: function jsBuildFunction() {
    // return js-build stream
  }
}

The clean task will be an optional dependency of the js-build task, and ignored if the task clean does not exist.

Preventing inherited properties

By default all task configuration properties (except meta configurations), are inherited by child tasks in a task family. To prevent a configuration from being inherited, you can prefix the property name with the - symbol. The prefix is automatically removed by Redun during task generation.

module.exports = {
  formula: {
    '-someConfig': 'someValue'
  },

  action: function taskFunction() {}
}

Inheriting meta configurations

By default meta configurations, marked with the # prefix, do not cascade and are not inherited by child tasks. If you want a meta property to cascade to children tasks, you can prefix it with +, so for example to to apply a cascading #deps configuration, you would set it as +#deps.

Merging configurations instead of overriding

Normally a configuration property that is redefined in a child task overrides the configuration that is inherited from the parent. You can tell Redun to merge an object/array with the one from the parent by prefixing the property name using the ^ symbol.

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean'],

    ':es5': {
      transpile: false
    },

    ':es6': {
      transpile: true,
      options: {
        comments: true
      },

      ':with-sourcemap': {
        '^options': {
          sourcemaps: true
        } // becomes { comments: true, sourcemaps: true }
      }
    }
  },

  action: function jsBuildFunction() {
    // return js-build stream, transpiled if es6
  }
}

Overriding task names

By default Redun will create Gulp tasks matching the names of the files that it matches. You can override the given name by passing a second argument to redun#add, which has original task names as keys, and replacement task names as values.

redun.add('tasks/**/*.js', {hello: 'hola'});

Alternatively, you can pass a function, which will be called for every task matched, passing the original name and expecting the new name returned:

redun.add('tasks/**/*.js', function(name) {
  return name.replace(/\.task$/, '');
});

Alias tasks

You can define an alias task by providing a single task name or multiple task names in place of the configuration of that task:

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean'],

    // js-build:es2015 aliases 'js-build:es6'
    ':es2015': 'js-build:es6',

    // 'js-build:z' aliases 'js-build:x' and 'js-build:y' in parallel
    'z': ['x', 'y'],

    ':es6': {
      transpile: true
    }
  },

  action: function jsBuildFunction() { /* ... */ }
}

It is recommended to use the originQualifier setting when defining task aliases to ensure that the alias will still work even if the task names are overriden:

/******** tasks/js-build.js ********/

module.exports = {
  formula: {
    '#deps': ['clean'],

    ':es2015': 'jsModule/js-build:es6', // jsModule is the originQualifier

    ':es6': {
      transpile: true
    }
  },

  action: function jsBuildFunction() {
    // return js-build stream, transpiled if es6
  }
}

API

redun.add(glob[, overrideNames, originQualifier])

Add recipes to be loaded when redun bootstraps.

glob

Type: String | String[]

A single glob, or an array of globs, that will be expanded to find modules containing task recipes to add. Non-absolute paths will be resolved relative to the current working directory.

overrideNames (optional)

Type: Object | Function

An object map of task names to override, e.g. { webpack: bundle } will change the name of the webpack task to bundle.

Or, a function that will get called for each recipe matched by the glob. Read more under Overriding task names.

originQualifier (optional)

Type: String

Qualify task names using a {originQualifier}/ prefix, e.g. If myPrefix is set as the qualifier, task webpack will also be registered as myPrefix/webpack (aliased). Please note tasks that were given new names through the overrideNames parameter retain their original names in their qualified version. i.e. given myQualifier as the qualifier, renaming webpack to bundle will lead to registering myQualifier/webpack as an alias of bundle.

redun.add('tasks/**/*.js', {hello: 'hola'}, 'origin');

The above registers the hola task, and an alias of it as origin/hello.

To do

Although Redun is usable, it still requires a lot of polishing. Here is a quick to-do list:

  • Unit tests
  • Logging, with multiple levels
  • Auto-add recipes from node_modules
  • Check for recursive dependencies - fatal
  • And more... see // todo(mm): comments