Javascript API

Roots v3 has been built from the ground up to have a strong js API, which is significantly different from all previous versions of roots. Let's walk through it here.

Creating a new Roots instance

There are two ways you can create a new instance of the Roots class - first using the traditional constructor, which expects a path that contains a roots project, and second with the Roots.new class method. Let's take a look at both here.

First, let's look at the more traditional constructor:

var Roots = require('roots'),
    path = require('path');

var project = new Roots(path.join(__dirname, 'example-project'));

As you can can see here, roots is initialized with a path pointing to the project root. You can also pass a second optional parameter specifying options for the project, which are documented here. Note that the path passed to the constructor must already exist, or roots will throw an error.

Now let's check out the Roots.new alternate constructor. This method will create a roots project from a template at a given path, then return an instance. However, since it involves quite a bit of I/O, it is also asynchrnonous. The Roots.new method itself returns a promise, which, if fulfilled, will return an initialized roots instance. Since it's a lengthy process, the promise also returns progress events along the way. Below is an example of how it could be used:

var Roots = require('roots'),
    path = require('path');

Roots.new({
  // directory can not yet exist
  path: path.join(__dirname, 'example-project'),
  // optional - defaults to 'roots-base'
  template: 'roots-base',
  // optional - data to pass to template
  overrides: { description: 'foobar' }
}).progress(function(message){
  // ex: 'progress: dependencies installing'
  console.log('progress: ' + message);
}).done(function(project){
  console.log(project); // new roots project instance
}, function(err){
  console.error("oh no! " + err);
});

Note that the path you pass to this constructor should not exist, a folder will be created there. If a folder already exists at that path, it will be filled with the files from the template, which probably is not what you want.

Compiling a Project

To compile a roots project once, you can use the compile method, which is fairly straightforward and returns a promise for the compiled project if you need it. Below is a quick example of loading in a roots project and compiling it:

var Roots = require('roots');
var project = new Roots('/path/to/project');

project
  .on('error') // compile error
  .on('done'); // compile is finished

project.compile();

Here we use the event emitter interface to listen for events and determine what's going on. As mentioned above, the compile method itself also returns a promise for the finished compilation process. So if you aren't concerned with the events and rather just know if it's finished or if there was an error, you could run code like this:

var Roots = require('roots');
var project = new Roots('/path/to/project');

project.compile().then(successFn, errorFn);

This will work fine, and fit nicely into any existant promise chain. The promise compile returns is A+ compliant and generated by the latest version of when.js.

Watching a Project

You can also watch through the public API, but beware -- while watching, there is currently no way to stop the process other than exiting it manually. It returns your instance like compile and you can listen for the same events:

var Roots = require('roots');
var project = new Roots('/path/to/project');

project
  .on('error')
  .on('done');

project.watch();

If you need to cancel the watcher at any time, the actual watch method returns a chokidar watcher instance, which you can call .close() on to stop the watcher. For example:

var Roots = require('roots');
var project = new Roots('/path/to/project');

project
  .on('error')
  .on('done')

var watcher = project.watch();
setTimeout(watcher.close, 1000);

This code would, for some reason, start a watcher but stop it after 1 second. You get the idea.