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
7 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
8 years ago
9 years ago
9 years ago