From 93564bd7b71b953e442babff7cc22d7f91e3c392 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Mon, 24 Aug 2020 00:13:45 +0000 Subject: [PATCH] Docs: Add advanced section for creation of custom registries (#2479) Co-authored-by: Blaine Bublitz --- docs/advanced/creating-custom-registries.md | 199 ++++++++++++++++++++ docs/api/registry.md | 2 +- 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 docs/advanced/creating-custom-registries.md diff --git a/docs/advanced/creating-custom-registries.md b/docs/advanced/creating-custom-registries.md new file mode 100644 index 000000000..8125b6a19 --- /dev/null +++ b/docs/advanced/creating-custom-registries.md @@ -0,0 +1,199 @@ + + +# 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()`](registry). + +## Structure + +In order to be accepted by gulp, custom registries must follow a specific format. + +```js +// 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()`. + +```js +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 + +| parameter | type | note | +|:---------:|:----:|------| +| gulpInst | object | Instance 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 + +| parameter | type | note | +|:---------:|:----:|------| +| name | string | Name 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 + +| parameter | type | note | +|:---------:|:----:|------| +| name | string | Name of the task to be set. | +| fn | function | Task 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 the 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: + +```js +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: + +```js +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: + +```js +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) { + // The `DefaultRegistry` uses `this._tasks` for storage. + var task = this._tasks[name] = fn.bind(this.config); + 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 + +* [`undertaker-registry`](https://github.com/gulpjs/undertaker-registry): The Gulp 4 default registry. +* [`undertaker-common-tasks`](https://github.com/gulpjs/undertaker-common-tasks): Proof-of-concept custom registry that pre-defines tasks. +* [` undertaker-task-metadata`](https://github.com/gulpjs/undertaker-task-metadata): Proof-of-concept custom registry that attaches metadata to each task. diff --git a/docs/api/registry.md b/docs/api/registry.md index 415f2cd94..c25198a3d 100644 --- a/docs/api/registry.md +++ b/docs/api/registry.md @@ -60,4 +60,4 @@ When a registry without an `init` method is passed as `registryInstance`, throws When a registry without a `tasks` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `tasks` function". -[creating-custom-registries]: ../documentation-missing.md +[creating-custom-registries]: ../advanced/creating-custom-registries.md