Skip to main content

Creating Custom Registries

Allows custom registries to be plugged into the task system, which can provide shared tasks or augmented functionality. Registries are registered using registry().

Structure

In order to be accepted by gulp, custom registries must follow a specific format.

// as a function
function TestRegistry() {}

TestRegistry.prototype.init = function (gulpInst) {}
TestRegistry.prototype.get = function (name) {}
TestRegistry.prototype.set = function (name, fn) {}
TestRegistry.prototype.tasks = function () {}

// as a class
class TestRegistry {
init(gulpInst) {}

get(name) {}

set(name, fn) {}

tasks() {}
}

If a registry instance passed to registry() doesn't have all four methods, an error will be thrown.

Registration

If we want to register our example registry from above, we will need to pass an instance of it to registry().

const { registry } = require('gulp');

// ... TestRegistry setup code

// good!
registry(new TestRegistry())

// bad!
registry(TestRegistry())
// This will trigger an error: 'Custom registries must be instantiated, but it looks like you passed a constructor'

Methods

init(gulpInst)

The init() method of a registry is called at the very end of the registry() function. The gulp instance passed as the only argument (gulpInst) can be used to pre-define tasks using gulpInst.task(taskName, fn).

Parameters

parametertypenote
gulpInstobjectInstance of gulp.

get(name)

The get() method receives a task name for the custom registry to resolve and return, or undefined if no task with that name exists.

Parameters

parametertypenote
namestringName of the task to be retrieved.

set(name, fn)

The set() method receives a task name and fn. This is called internally by task() to provide user-registered tasks to custom registries.

Parameters

parametertypenote
namestringName of the task to be set.
fnfunctionTask function to be set.

tasks()

Must return an object listing all tasks in the registry.

Use Cases

Sharing Tasks

To share common tasks with all your projects, you can expose an init method on the registry and it will receive an instance of gulp as the only argument. You can then use gulpInst.task(name, fn) to register pre-defined tasks.

For example, you might want to share a clean task:

const fs = require('fs');
const util = require('util');

const DefaultRegistry = require('undertaker-registry');
const del = require('del');

function CommonRegistry(opts){
DefaultRegistry.call(this);

opts = opts || {};

this.buildDir = opts.buildDir || './build';
}

util.inherits(CommonRegistry, DefaultRegistry);

CommonRegistry.prototype.init = function(gulpInst) {
const buildDir = this.buildDir;
const exists = fs.existsSync(buildDir);

if(exists){
throw new Error('Cannot initialize common tasks. ' + buildDir + ' directory exists.');
}

gulpInst.task('clean', function(){
return del([buildDir]);
});
}

module.exports = CommonRegistry;

Then to use it in a project:

const { registry, series, task } = require('gulp');
const CommonRegistry = require('myorg-common-tasks');

registry(new CommonRegistry({ buildDir: '/dist' }));

task('build', series('clean', function build(cb) {
// do things
cb();
}));

Sharing Functionality

By controlling how tasks are added to the registry, you can decorate them.

For example, if you wanted all tasks to share some data, you can use a custom registry to bind them to that data. Be sure to return the altered task, as per the description of registry methods above:

const { registry, series, task } = require('gulp');
const util = require('util');
const DefaultRegistry = require('undertaker-registry');

// Some task defined somewhere else
const BuildRegistry = require('./build.js');
const ServeRegistry = require('./serve.js');

function ConfigRegistry(config){
DefaultRegistry.call(this);
this.config = config;
}

util.inherits(ConfigRegistry, DefaultRegistry);

ConfigRegistry.prototype.set = function set(name, fn) {
var bound = fn.bind(this.config);
// Preserve internal properties and task metadata.
var task = Object.assign(bound, fn);
// The `DefaultRegistry` uses `this._tasks` for storage.
this._tasks[name] = task;
return task;
};

registry(new BuildRegistry());
registry(new ServeRegistry());

// `registry` will reset each task in the registry with
// `ConfigRegistry.prototype.set` which will bind them to the config object.
registry(new ConfigRegistry({
src: './src',
build: './build',
bindTo: '0.0.0.0:8888'
}));

task('default', series('clean', 'build', 'serve', function(cb) {
console.log('Server bind to ' + this.bindTo);
console.log('Serving' + this.build);
cb();
}));

Examples