Gear.js is an easy to use, simple to extend, and powerful build system. Chain tasks together to build projects with ease.
new Queue()
.read('foo.js')
.inspect()
.jshint()
.jsminify()
.write('foo.min.js')
.inspect()
.run();
Features
- Basic building blocks that can be combined to perform complex builds.
- Tasks are simply defined and keep system internals to a minimum.
- Asynchronous execution.
- Extensible task loading via NPM, file, or directory.
- Advanced flow control for complex task execution.
- Runs in Node.js and the browser.
Installation
Node.js Install
To get the most out of Gear.js, install gear-lib which contains tasks for linting, minifying, and deploying JS/CSS assets.
$ npm install gear gear-lib
Usage
var gear = require('gear');
new gear.Queue({registry: 'gear-lib'}).log('test!').run();
// Or creating a registry object with module parameter explicitly
new gear.Queue({registry: new gear.Registry({module: 'gear-lib'})}).log('test!').run();
Browser Install
<script type="text/javascript" src="https://github.com/yahoo/gear/raw/master/build/gear.js"></script>
<script type="text/javascript" src="https://github.com/yahoo/gear-lib/raw/master/build/gear-lib.js"></script>
Usage (localStorage is used as a simple filesystem for read/write tasks)
require(['gear', 'gear-lib'], function(gear, lib) {
new gear.Queue({registry: new gear.Registry({tasks: lib})}).log('test!').run();
});
Source
Examples
Execute Tasks On Multiple Items
new Queue()
.read(['foo.js', {name: 'bar.js'}, 'baz.js'])
.log('read files')
.inspect()
.write(['foo2.js', 'bar2.js']) // Not writing 'baz.js'
.run();
Parallel Task Execution
new Queue()
.read('foo.js')
.log('Parallel Tasks')
.tasks({
read: {task: ['read', ['bar.js', 'baz.js']]},
combine: {requires: 'read', task: 'concat'}, // Runs after read completes
minify: {requires: 'combine', task: 'jsminify'},
print: {requires: 'minify', task: 'inspect'},
parallel: {task: ['log', "Hello Gear.js world!"]}, // Run parallel to read
join: {requires: ['parallel', 'print']} // Joined data is passed to next task in queue
})
.inspect()
.run();
Documentation
Queue
Registry
Tasks
Library Tasks
Custom Tasks
CLI
Queue()
Queue(options)
Queue constructor.
Arguments
- options - (Object) Options for queue.
- options.logger - (Object) Logger instance, usually console.
- options.registry - (Registry) Registry loaded with available tasks.
new Queue()
.log('New queue')
.run();
Queue.task(name)
Queue.task(name, options)
Helper method to run the specified task. Preferred task execution style is to call the task directly i.e. inspect() instead of task('inspect').
Arguments
- name - (String) Name of task in registry.
- options - Task specific options.
new Queue()
.task('log', 'New queue')
.run();
Queue.run()
Queue.run(callback)
Runs the queue.
Arguments
- callback - (Function(err, results)) Called on queue completion.
new Queue()
.log('test')
.run();
Registry()
Registry(options)
Creates a new Registry instance. Registries contain available tasks.
Arguments
- options - See Registry.load.
new Registry();
Registry.load(options)
Load tasks from NPM module, directory, or file.
Arguments
- options.module - Module to load tasks from.
- options.dirname - Directory to load tasks from.
- options.filename - File to load tasks from.
- options.tasks - Object to load tasks from. Format: {name0: fn0, ..., nameN: fnN}
new Registry().load({dirname: 'foo'});
var registry = new Registry({tasks: {
counter: function(options, blob, done) {
console.log(options + ' for ' + blob.name + ': ' + blob.result.length);
done(null, blob);
}
}});
new gear.Queue({registry: registry})
.read(['foo.js', 'bar.js'])
.counter('CHAR COUNT')
.run();
read(name)
read(options)
Appends file contents onto queue.
Arguments
- options.name - (String) Filename to read.
- options.encoding - (String) bin (binary) or utf8 (default).
new Queue()
.read('foo.js')
.read(['foo.js', 'bar.js'])
.read([{name: 'foo.js'}, {name: 'bar.js'}, {name: 'baz.js'}])
.run(function(err, results) {
console.log(('' + results[0]).length + ' characters');
});
write(name)
write(options)
Write the blob to disk.
Arguments
- options.name - (String) File to write, will replace {checksum} with hash of blob content.
- options.encoding - (String) bin (binary) or utf8 (default).
new Queue()
.read('foo.js')
.write('foo2.js')
.write({name: 'foo3.js'})
.inspect()
.run();
concat()
concat(callback)
Concatenates blobs.
Arguments
- callback - (Function) N/A.
new Queue()
.read(['foo.js', 'bar.js'])
.concat()
.inspect()
.run();
inspect()
Inspects blobs.
new Queue()
.read(['foo.js', 'bar.js'])
.inspect()
.run();
log(message)
Log a message.
Arguments
- message - (String) Message to log.
new Queue()
.log('Hi')
.run();
replace(options)
Replace strings using RegExp.
Arguments
- options.regex - RegExp object or string.
- options.flags - RegExp flags if using string.
- options.replace - Replacement string.
new Queue()
.read('foo.js')
.inspect()
.replace({regex: /Y.log\(.+?\);?/mg, replace: ''})
.replace({regex: "console.log\\(.+?\\);?", replace: '', flags: 'mg'}) // Using string
.inspect()
.run();
tasks(workflow)
Arguments
- workflow - (Object) Task workflow described below.
// label - Task instance name.
// label.task - Task name and optionally options.
// label.requires - List of labels that must be executed before this task runs.
new Queue()
.read('foo.js')
.tasks({
dev: {task: ['write', 'output.js']},
prodmin: {task: 'jsminify'},
prod: {requires: 'prodmin', task: ['write', 'output.min.js']},
join: {requires: ['dev', 'prod']}
})
.run(function() {
console.log('output.js - ' + localStorage['output.js'].length);
console.log('output.min.js - ' + localStorage['output.min.js'].length);
});
Library Tasks
gear-lib contains tasks such as:
- jshint
- jsminify
- csslint
- cssminify
- s3
- handlebars
Node.js
$ npm install gear-lib
Browser
<script type="text/javascript" src="https://github.com/yahoo/gear-lib/raw/master/build/gear-lib.js"></script>
Custom Tasks
Writing a task is especially easy compared to other Node.js build systems. Tasks operate on simple immutable blobs. The task returns a transformed blob via its callback.
Arguments
- options - Options for the task.
- blob - Immutable blob.
- done(err, result) - Callback executed when task is complete.
// example.js
// Example task creates new blob containing `string`
exports.example = function(string, blob, done) {
done(null, new blob.constructor(string)); // blob.constructor() is equivalent to Blob()
};
Running Example Task
new Queue({registry: new Registry({filename: 'example.js'})})
.example('EXAMPLE')
.run();
Inline Custom Task
var tasks = {
example: function(string, blob, done) {
done(null, new blob.constructor(string));
};
};
new Queue({registry: new Registry({tasks: tasks})})
.example('EXAMPLE')
.run();
Working With Blobs
Blobs are loosely based on the W3C Blob.
- Immutable data object.
- Contains a property bag as well as a private non-enumerable result property.
- Blobs can be merged with other blobs. When merging, properties in the property bag are merged, while result is concatenated.
- result property can be Buffer or String.
var b1 = new Blob('Hello');
console.log(b1);
var b2 = new Blob([b1, ' world!']);
console.log(b2);
var b3 = new Blob(b2, {name: 'TEST'});
console.log(b3.result + ' - ' + b3.name);
CLI
It's possible to execute a tasks workflow from the command line.
Create a file named Gearfile in your project directory. You can include executable Javascript which evaluates to a valid workflow.
// Gearfile
{
js: {task: ['read', ['foo.js', 'bar.js', 'baz.js']]},
js_concat: {requires: 'js', task: 'concat'},
js_min: {requires: 'js_concat', task: 'jsminify'}
js_write: {requires: 'js_min', task: ['write', 'foobarbaz.min.js']}
css: {task: ['read', 'xyz.css']},
css_min: {requires: 'css', task: 'cssminify'},
css_write: {requires: 'css_min', task: ['write', 'xyz.min.css']}
join: {requires: ['js_write', 'css_write']}
}
Then run the gear command:
$ gear
If you have any require paths you will need to use an absolute path like so:
// Sample Gearfile
(function() {
var path = require('path'),
handlebars = require(path.join(process.cwd(), 'node_modules/handlebars')),
template = handlebars.compile('<h1>{{msg}}<h1>');
return {
log: {task: ['log', template({msg: 'Hello, world!'})]},
join: {requires: 'log'}
};
})();
By not returning a workflow you can run a queue in the normal way. The gear object is automatically included in the context.
(function() {
new gear.Queue()
.log('Hello, Gearfile!')
.run();
})();
Who's Using Gear.js
Mojito Shaker by Yahoo.
Special Thanks
Gear.js takes inspiration from a few sources: