Jake
Jake is a JavaScript build tool and task runner for Node.js, designed to operate similarly to traditional build systems like GNU Make or Ruby's Rake. It is currently at version 12.9.7, with active maintenance and a consistent release cadence to support newer Node.js versions. Key differentiators include defining build tasks in plain JavaScript files (Jakefiles), supporting complex task prerequisites, namespacing for organization, and handling asynchronous task execution. Jake offers synchronous file utilities for common build operations and can be installed globally as a CLI, locally as a dev dependency, or embedded programmatically within other applications. It has a long history in the Node.js ecosystem, indicating a mature and well-tested codebase.
Common errors
-
'jake' is not recognized as an internal or external command, operable program or batch file.
cause Jake is not installed globally or its installation directory is not in the system's PATH, or a local installation is not being invoked via `npx`.fixInstall Jake globally (`npm install -g jake`) and ensure npm's global bin directory is in your system PATH, or install it locally (`npm install --save-dev jake`) and run tasks using `npx jake [taskName]`. -
SyntaxError: Cannot use import statement outside a module
cause An `import` statement was used in a `Jakefile.js` or a module loaded by it, which Node.js is treating as a CommonJS module.fixRefactor the `Jakefile.js` and any directly loaded modules to use CommonJS `require()` syntax instead of ESM `import`. Jakefiles inherently run in a CJS context. -
Task not found: my-nonexistent-task
cause The specified task name does not match any task defined in the `Jakefile.js`, or the `Jakefile.js` itself was not found or has syntax errors preventing task definition.fixVerify the task name spelling, ensure the `Jakefile.js` is in the current directory or specified with `-f`, and check the `Jakefile.js` for JavaScript syntax errors. Use `jake -T` to list available tasks. -
Error: asynchronous task function completed without calling 'complete()'
cause An asynchronous task was defined (with `{ async: true }`) but did not call `this.complete()` at the end of its execution, causing Jake to detect an incomplete task.fixEnsure all asynchronous tasks explicitly call `this.complete()` after their operations have finished to signal completion to Jake.
Warnings
- gotcha Jakefiles are executed in a CommonJS context. Attempting to use ES Modules `import` syntax directly in a `Jakefile.js` will likely result in a `SyntaxError: Cannot use import statement outside a module` or similar, as Jake does not natively support ESM for task definition files.
- breaking Jake drops support for older Node.js versions with major releases. Users should always check the `engines.node` field in `package.json` to ensure compatibility with their Node.js environment. Currently, Node.js `>=10` is required.
- gotcha When defining asynchronous tasks, the task function *must* be marked with `{ async: true }` in its options object and *must* explicitly call `this.complete()` when the asynchronous work is finished. Failure to do so will result in Jake completing the task immediately, potentially before work is done, or hanging indefinitely.
- gotcha On Windows, global installation of Jake (e.g., `npm install -g jake`) has historically led to issues where the `jake` command is not recognized or behaves unexpectedly, potentially trying to run shell scripts. While some issues may be resolved, local installation (`npm install jake`) and execution via `npx jake` is often more robust.
- gotcha When programmatically invoking tasks, `Task['my:task'].invoke()` will execute the task and its prerequisites only once, even if called multiple times within a build. If a task needs to be run multiple times, it must be 'reenabled' using `Task['my:task'].reenable()` before each subsequent invocation.
Install
-
npm install jake -
yarn add jake -
pnpm add jake
Imports
- desc, task, namespace
import { desc, task, namespace } from 'jake';const { desc, task, namespace } = require('jake'); - jake.exec
import jake from 'jake'; jake.exec(...);
const jake = require('jake'); jake.exec(['command'], { printStdout: true }, () => { console.log('Command finished.'); }); - Task['my:task'].invoke()
const jake = require('jake'); jake.Task.invoke('my:task');const { Task } = require('jake'); Task['my:task'].invoke();
Quickstart
/* Jakefile.js */
const { desc, task, namespace } = require('jake');
desc('This is the default task.');
task('default', function () {
console.log('Running the default task.');
});
namespace('build', function () {
desc('Cleans the build directory.');
task('clean', function () {
console.log('Cleaning build artifacts...');
// Example: jake.rmRf('dist'); (requires 'jake' object)
});
desc('Compiles source files.');
task('compile', ['build:clean'], function () {
console.log('Compiling source...');
// Simulate async operation
setTimeout(() => {
console.log('Compilation complete.');
this.complete(); // Important for async tasks
}, 1000);
}, { async: true });
desc('Lints JavaScript files.');
task('lint', function () {
console.log('Running linter...');
});
desc('Performs a full build, including linting.');
task('all', ['build:lint', 'build:compile'], function () {
console.log('Full build finished!');
});
});
desc('Runs all tests.');
task('test', ['build:all'], function () {
console.log('Running tests...');
});
// To run:
// npm install -g jake
// jake default
// jake build:all
// jake test