kubik v0.9.3
Kubik
⚠️ Warning: Kubik is currently in pre-1.0.0 release. Expect potential changes and experimental features that may not be fully stable yet.
Kubik is a simple task runner for node.js with first-class TypeScript support.
Kubik tasks are defined by TypeScript / Node.js scripts, with dependencies to other tasks. Kubik supports running tasks with different parallelization modes and has a built-in watch mode.
- Quick Start
- Getting Started
- Tasks vs Services
- Typescript Support
- Watch Mode
- Parallelization
- Environment Files
- Shebang
- API
- Debugging
Quick Start
Any build.(m)js
script can be converted to a task by importing Task
and running Task.init
in the
very beginning of the script:
import { Task } from 'kubik';
Task.init(import.meta);
/* ... build script ... */
The Task.init
method accepts configuration (dependencies & watch mode configuration), see
API section.
Use the following commands to run tasks:
- Build:
npx kubik ./build.mjs
- Watch mode:
npx kubik -w ./build.mjs
- Debug (run without Kubik):
node build.mjs
ortsx build.mjs
- Run sequential build:
npx kubik -j 1 ./build.mjs
A real-life example is available here.
Task dependencies
Kubik allows defining dependencies between tasks using deps
option in the Task.init
method:
// build-main.mjs
import { Task } from 'kubik';
Task.init(import.meta, {
deps: ['./other-task.mjs'], // these are relative to script folder
});
// ... run some tasks
To run tasks with their dependencies to completion, run:
npx kubik ./build-main.mjs
Multiple roots
In a complicated projects, it might be necessary to build a project from multiple entry points. In this case, you can pass multiple entry points to Kubik:
npx kubik ./build-main.mjs ./build-other.mjs
In this case, if both build-main.mjs
and build-other.mjs
depend on shared.mjs
task, then
the task will be executed only once.
Running services
By default, task is considered successful if its process completes with 0 exit code, and unsuccessful if it fails with non-zero code.
However, certain tasks require a running process; for example, launching development server.
In this case, you can use Task.done()
to notify Kubik that the task completed and it's dependants
can start executing:
import { Task } from 'kubik';
Task.init(import.meta);
// ...launch HTTP server...
// Report the task as complete.
Task.done();
TypeScript support
Kubik supports running tasks defined in a .ts
/ .mts
files using tsx. To use typescript, simply install tsx
along side with kubik,
and use .ts
/.tsx
extension to write your scripts:
Install
tsx
:npm i --save-dev tsx
Write your scripts in a
.ts
or.mts
files:// hello.ts import { Task } from 'kubik'; Task.init(import.meta); const foo: String = 'Hello, typescript!'; console.log(foo);
Run your tasks as usual:
npx kubik ./hello.ts
Watch Mode
Kubik supports watch mode where it listens for changes on the file system and reruns tasks and their dependencies.
To run watch mode, use -w
or --watch
flag:
npx kubik -w ./build.mjs
In watch mode, Kubik launches a terminal app that shows progress, duration and logs from all the tasks:
There are a few shortcuts available to navigate inside the watch mode app:
- To cycle focus through panels, use
Tab
andShift-Tab
- To scroll logs of the focused pane, use arrows,
j
,k
,Ctrl-U
,Ctrl-D
,gg
andShift-G
. - You can also use mouse to scroll logs
By default, Kubik watches for changes in files commonly involved in build tasks, such as:
package.json
package-lock.json
tsconfig.json
However, you can customize files and directories to watch and to ignore during Task initialization:
import { Task } from 'kubik';
Task.init(import.meta, {
deps: ['./build-third-party.mjs'],
watch: ['./src'], // these are relative to script folder
ignore: ['./src/generated'], // these are relative to script folder too
});
NOTE: Be careful with watch mode: if the build procedure changes some of the watched files, then Kubik will re-run the build one time, causing "infinite" builds. You'll observe this with tasks never completing. Use
ignore
option to mitigate this behavior.
Parallelization
Kubik supports -j, --jobs <number>
flag to customize number of parallel jobs. By default, Kubik allows an unlimited number of parallel jobs.
Environment Files
Kubik supports -e, --env-file <env file>
flag to load environment variables from a file.
npx kubik -e .env ./build.mjs
This will load all the environment variables from .env
file, and pass them to all scripts.
Shebang
You can use kubik shebang in scripts, like this:
#!/usr/bin/env npx kubik
import { Task } from 'kubik';
Task.init(import.meta, {
watch: ['./src'],
ignore: ['./src/generated'],
});
API
The Task.init
function prepares the build environment, offering utilities like $
for shell commands (powered by execa), __dirname
, and __filename
based on the current script's context.
The whole API boils down to the following:
#!/usr/bin/env npx kubik
import { Task } from 'kubik';
import fs from 'fs';
const {
$, // execa shell runner, that uses __dirname as CWD
__dirname, // **this** script directory absolute path
__filename, // **this** script file absolute path
} = Task.init(import.meta, {
name: 'my library',
watch: ['./src'], // all the paths are resolved relative to this script
ignore: ['./src/generated'], // relative to this script
deps: ['../third-party/build.mjs'], // relative to this script
});
console.log(Task.isWatchMode()); // wether the script is being run under watch mode.
// Use $ to run commands, e.g. typescript.
// Note that $ uses __dirname as CWD.
await $`tsc --pretty -p .`;
// If node.js process does not exit (i.e. it runs a server),
// then we can notify Kubik explicitly that the task is done.
Task.done();
Debugging
You can run build scripts as regular node.js scripts; in this case, these are executed directly by node.js, with no Kubik in the way.
node ./build-main.mjs
5 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 years ago
8 years ago
8 years ago