Starting point for creating a base application, with a few light plugins for running tasks and writing to the file system, and a functional CLI.
Please consider following this project's author, Jon Schlinkert, and consider starring the project to show your ❤️ and support.
- Install
- Quickstart
- CLI
- API Documentation
- .cwd
- File System API
- Task API
- Events
- Plugin API
- Options API
- Data API
- About
(TOC generated by verb using markdown-toc)
Install with npm:
$ npm install --save base-app
Below we provide a more detailed explanation of how to get started. But if you're familiar with node.js and prefer a fast-track:
Install
$ npm i -g base-app
Create an "app"
Then create a basefile.js
with the following code:
module.exports = function(app, base) {
app.task('default', function(cb) {
console.log('task >', this.name);
cb();
});
};
Run base
In the command line, run:
$ base
If everthing installed correctly, you should see task > default
in the command line.
Installing the CLI
To run base from the command line, you'll need to install base-app
globally first. You can that now with the following command:
$ npm i -g base-app
This adds the base
command to your system path, allowing it to be run from any directory or sub-directory in a project.
How the CLI works
When the base
command is run, the globally installed base-app
looks for a locally installed base module using node's require()
system.
If a locally installed base is found, the CLI loads the local installation of the base library. If a local base module is not found, the globally installed base-app
will be used.
Once the module is resolved, base applies the configuration from your basefile.js
then executes any generators or tasks you've specified for base to run.
Getter/setter that ensures the current working directory is always a fully resolved absolute filepath.
app.cwd = 'foo';
console.log(app.cwd);
//=> /User/dev/base-app/foo
Glob patterns or filepaths to source files.
Params
glob
{String|Array}: Glob patterns or file paths to source files.options
{Object}: Options or locals to merge into the context and/or pass tosrc
plugins
Example
app.src('src/*.hbs', {layout: 'default'});
Glob patterns or paths for symlinks.
Params
glob
{String|Array}
Example
app.symlink('src/**');
Specify a destination for processed files.
Params
dest
{String|Function}: File path or rename function.options
{Object}: Options and locals to pass todest
plugins
Example
app.dest('dist/');
Copy files with the given glob patterns
to the specified dest
.
Params
patterns
{String|Array}: Glob patterns of files to copy.dest
{String|Function}: Desination directory.returns
{Stream}: Stream, to continue processing if necessary.
Example
app.task('assets', function(cb) {
app.copy('assets/**', 'dist/')
.on('error', cb)
.on('finish', cb)
});
Methods for running tasks are from the base-task plugin, which uses composer. Additional documentation can be found on those libaries.
Register a task
Params
name
{String}: Task name to register (tasks are cached onapp.tasks
)dependencies
{String|Array|Function}: String, list or array of tasks.callback
{Function}: Function to be called when the task is executed. Task functions should either return a stream or call the callback to let composer know when the task is finished.
Examples
Register a task.
app.task('default', function() {
// return the stream to signal "done"
return app.src('pages/*.hbs')
.pipe(app.dest('dist'));
});
Register a task with dependencies (other tasks to run before executing the task):
app.task('site', ['styles'], function() {
return app.src('pages/*.hbs')
.pipe(app.dest('dist'));
});
app.task('default', ['site']);
Get a task
var task = app.task('site');
Run a task or array of tasks.
Example
app.build('default', function(err, results) {
if (err) {
console.error(err);
return;
}
console.log(results);
});
Compose task or list of tasks into a single function that runs the tasks in series.
Params
tasks
{String|Array|Function}: List of tasks by name, function, or array of names/functions.returns
{Function}: Composed function that may take a callback function.
Example
app.task('foo', function(cb) {
console.log('this is foo');
cb();
});
var fn = app.series('foo', function(cb) {
console.log('this is bar');
cb();
});
fn(function(err) {
if (err) return console.error(err);
console.log('finished');
});
//=> this is foo
//=> this is bar
//=> finished
Compose task or list of tasks into a single function that runs the tasks in parallel.
Params
tasks
{String|Array|Function}: List of tasks by name, function, or array of names/functions.returns
{Function}: Composed function that may take a callback function.
Example
app.task('foo', function(cb) {
setTimeout(function() {
console.log('this is foo');
cb();
}, 500);
});
var fn = app.parallel('foo', function(cb) {
console.log('this is bar');
cb();
});
fn(function(err) {
if (err) return console.error(err);
console.log('finished');
});
//=> this is bar
//=> this is foo
//=> finished
The following events are emitted by composer. See the composer docs for more details
Emitted when a build
is starting.
app.on('starting', function(app, build) {});
The event emits 2 arguments:
- the current instance of composer as the
app
and - An object with
build
runtime information:
.date
: an object with the.start
time as aDate
object..hr
: an object with the.start
time as anhrtime
array.
Emitted when a build
is finished.
app.on('finished', function(app, build) {});
The event emits 2 arguments:
app
: instance of composerbuild
: an object with build runtime information:
.date
: object with.start
and.end
properties, with staring and ending times of the build asDate
objects..hr
: object with.start
,.end
,.duration
, and.diff
properties with timing information calculated usingprocess.hrtime
Emitted when an error occurrs during a build
.
app.on('error', function(err) {});
Emitted when a task is starting.
app.on('task:starting', function(task, run) {});
Emitted when a task has finished.
app.on('task:finished', function(task, run) {});
Emitted when an error occurrs while running a task.
app.on('task:error', function(err) {});
Register a data loader for loading data onto app.cache.data
.
Params
ext
{String}: The file extension for to match to the loaderfn
{Function}: The loader function.
Example
var yaml = require('js-yaml');
app.dataLoader('yml', function(str, fp) {
return yaml.safeLoad(str);
});
app.data('foo.yml');
//=> loads and parses `foo.yml` as yaml
Define a plugin function to be called immediately upon init. The only parameter exposed to the plugin is the application instance.
Also, if a plugin returns a function, the function will be pushed
onto the fns
array, allowing the plugin to be called at a
later point, elsewhere in the application.
Params
fn
{Function}: plugin function to callreturns
{Object}: Returns the item instance for chaining.
Example
// define a plugin
function foo(app) {
// do stuff
}
// register plugins
var app = new Base()
.use(foo)
.use(bar)
.use(baz)
Run all plugins
Params
value
{Object}: Object to be modified by plugins.returns
{Object}: Returns the item instance for chaining.
Example
var config = {};
app.run(config);
Set or get an option.
Params
key
{String}: The option name.value
{any}: The value to set.returns
{any}: Returns avalue
when onlykey
is defined.
Example
app.option('a', true);
app.option('a');
//=> true
Return true if options.hasOwnProperty(key)
Params
prop
{String}returns
{Boolean}: True ifprop
exists.
Example
app.hasOption('a');
//=> false
app.option('a', 'b');
app.hasOption('a');
//=> true
Enable key
.
Params
key
{String}returns
{Object}Options
: to enable chaining
Example
app.enable('a');
Disable key
.
Params
key
{String}: The option to disable.returns
{Object}Options
: to enable chaining
Example
app.disable('a');
Check if prop
is enabled (truthy).
Params
prop
{String}returns
{Boolean}
Example
app.enabled('a');
//=> false
app.enable('a');
app.enabled('a');
//=> true
Check if prop
is disabled (falsey).
Params
prop
{String}returns
{Boolean}: Returns true ifprop
is disabled.
Example
app.disabled('a');
//=> true
app.enable('a');
app.disabled('a');
//=> false
Returns true if the value of prop
is strictly true
.
Params
prop
{String}returns
{Boolean}: Uses strict equality for comparison.
Example
app.option('a', 'b');
app.isTrue('a');
//=> false
app.option('c', true);
app.isTrue('c');
//=> true
app.option({a: {b: {c: true}}});
app.isTrue('a.b.c');
//=> true
Returns true if the value of key
is strictly false
.
Params
prop
{String}returns
{Boolean}: Uses strict equality for comparison.
Example
app.option('a', null);
app.isFalse('a');
//=> false
app.option('c', false);
app.isFalse('c');
//=> true
app.option({a: {b: {c: false}}});
app.isFalse('a.b.c');
//=> true
Return true if the value of key is either true
or false
.
Params
key
{String}returns
{Boolean}: True iftrue
orfalse
.
Example
app.option('a', 'b');
app.isBoolean('a');
//=> false
app.option('c', true);
app.isBoolean('c');
//=> true
Set option key
on app.options
with the given value
Params
key
{String}: Option key, dot-notation may be used.value
{any}
Example
app.option.set('a', 'b');
console.log(app.option.get('a'));
//=> 'b'
Get option key
from app.options
Params
key
{String}: Option key, dot-notation may be used.returns
{any}
Example
app.option({a: 'b'});
console.log(app.option.get('a'));
//=> 'b'
Returns a shallow clone of app.options
with all of the options methods, as well as a .merge
method for merging options onto the cloned object.
Params
options
{Options}: Object to merge onto the returned options object.returns
{Object}
Example
var opts = app.option.create();
opts.merge({foo: 'bar'});
Load data onto app.cache.data
Params
key
{String|Object}: Key of the value to set, or object to extend.val
{any}returns
{Object}: Returns the instance ofTemplate
for chaining
Example
console.log(app.cache.data);
//=> {};
app.data('a', 'b');
app.data({c: 'd'});
console.log(app.cache.data);
//=> {a: 'b', c: 'd'}
// set an array
app.data('e', ['f']);
// overwrite the array
app.data('e', ['g']);
// update the array
app.data('e', ['h'], true);
console.log(app.cache.data.e);
//=> ['g', 'h']
Shallow extend an object onto app.cache.data
.
Params
key
{String|Object}: Property name or object to extend ontoapp.cache.data
. Dot-notation may be used for extending nested properties.value
{Object}: The object to extend ontoapp.cache.data
returns
{Object}: returns the instance for chaining
Example
app.data({a: {b: {c: 'd'}}});
app.data.extend('a.b', {x: 'y'});
console.log(app.get('a.b'));
//=> {c: 'd', x: 'y'}
Deeply merge an object onto app.cache.data
.
Params
key
{String|Object}: Property name or object to merge ontoapp.cache.data
. Dot-notation may be used for merging nested properties.value
{Object}: The object to merge ontoapp.cache.data
returns
{Object}: returns the instance for chaining
Example
app.data({a: {b: {c: {d: {e: 'f'}}}}});
app.data.merge('a.b', {c: {d: {g: 'h'}}});
console.log(app.get('a.b'));
//=> {c: {d: {e: 'f', g: 'h'}}}
Union the given value onto a new or existing array value on app.cache.data
.
Params
key
{String}: Property name. Dot-notation may be used for nested properties.array
{Object}: The array to add or union onapp.cache.data
returns
{Object}: returns the instance for chaining
Example
app.data({a: {b: ['c', 'd']}});
app.data.union('a.b', ['e', 'f']}});
console.log(app.get('a.b'));
//=> ['c', 'd', 'e', 'f']
Set the given value onto app.cache.data
.
Params
key
{String|Object}: Property name or object to merge ontoapp.cache.data
. Dot-notation may be used for nested properties.val
{any}: The value to set onapp.cache.data
returns
{Object}: returns the instance for chaining
Example
app.data.set('a.b', ['c', 'd']}});
console.log(app.get('a'));
//=> {b: ['c', 'd']}
Get the value of key
from app.cache.data
. Dot-notation may be used for getting nested properties.
Params
key
{String}: The name of the property to get.returns
{any}: Returns the value ofkey
Example
app.data({a: {b: {c: 'd'}}});
console.log(app.get('a.b'));
//=> {c: 'd'}
Glob patterns may be passed as a string or array. All of these work:
app.data('foo.json');
app.data('*.json');
app.data(['*.json']);
// pass options to node-glob
app.data(['*.json'], {dot: true});
Namespacing allows you to load data onto a specific key, optionally using part of the file path as the key.
Example
Given that foo.json
contains {a: 'b'}
:
app.data('foo.json');
console.log(app.cache.data);
//=> {a: 'b'}
app.data('foo.json', {namespace: true});
console.log(app.cache.data);
//=> {foo: {a: 'b'}}
app.data('foo.json', {
namespace: function(fp) {
return path.basename(fp);
}
});
console.log(app.cache.data);
//=> {'foo.json': {a: 'b'}}
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.
Running Tests
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
$ npm install && npm test
Building docs
(This project's readme.md is generated by verb, please don't edit the readme directly. Any changes to the readme must be made in the .verb.md readme template.)
To generate the readme, run the following command:
$ npm install -g verbose/verb#dev verb-generate-readme && verb
You might also be interested in these projects:
- base-fs: base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file… more | homepage
- base-pipeline: base-methods plugin that adds pipeline and plugin methods for dynamically composing streaming plugin pipelines. | homepage
- base: Framework for rapidly creating high quality, server-side node.js applications, using plugins like building blocks | homepage
Jon Schlinkert
Copyright © 2018, Jon Schlinkert. Released under the MIT License.
This file was generated by verb-generate-readme, v0.6.0, on April 13, 2018.