Orchestrate your build with TypeScript - execute it with native tools!
@ninjutsu-build/core is a TypeScript library for creating
ninja files. Combined with a set of plugins for
commonly used JavaScript tools, @ninjutsu-build can be used to orchestrate
your JavaScript and TypeScript builds.
Ninjutsu Build is built using itself. You can see the
configure.mjs script used to generate the
build.ninja file.
Some of the selling points of @ninjutsu-build are:
Though core library @ninjutsu-build/core (npm)
has everything you need to create ninja files, there are a set of plugins that have already solved
some of the more common requirements:
biome (npm @ninjutsu-build/biome)
for linting and formatting using `biomejsbun (npm @ninjutsu-build/bun)
for transpiling TypeScript to JavaScript using bunesbuild (npm @ninjutsu-build/esbuild)
for transpiling and bundling TypeScript/JavaScript using esbuildnode (npm @ninjutsu-build/node)
for running node (and node's test runner) while tracking all JavaScript dependenciestsc (npm @ninjutsu-build/tsc)
for compiling TypeScript to JavaScript using tsc while tracking all TypeScript dependenciesThis project requires NodeJS (version 18 or later) and npm.
Most likely you require @ninjutsu-build/core as a devDependency, which can be
achieved by running the following npm command:
$ npm install @ninjutsu-build/core --save-dev
// configure.ts
import { NinjaBuilder, needs } from "@ninjutsu-build/core";
import { makeTSCRule } from "@ninjutsu-build/tsc";
import { makeNodeTestRule } from "@ninjutsu-build/node";
import { writeFileSync } from "fs";
// Create a `NinjaBuilder`
const ninja = new NinjaBuilder({
ninja_required_version: "1.11",
builddir: ".builddir",
});
// Create our rules, some from existing plugins, some from `NinjaBuilder.rule`
ninja.comment("Rules");
const tsc = makeTSCRule(ninja);
const test = makeNodeTestRule(ninja);
const concat = ninja.rule("concat", {
command: "concat $in > $out",
description: "Concatting '$in' to $out",
in: needs<readonly string[]>(),
out: needs<string>(),
})
ninja.comment("Build Edges");
// Compile 3 TypeScript files to JavaScript + their declaration files
const [index, indexTypes, test1, test1Types, test2, test2Types] = tsc({
in: ["src/index.ts", "src/index1.test.ts", "src/index2.test.ts"],
compilerOptions: {
outDir: "dist",
declaration: true,
target: "ES2021",
lib: ["ES2021"],
module: "NodeNext",
moduleResolution: "NodeNext",
strict: true,
noImplicitAny: true,
},
});
// Run our 2 tests using node's test runner
const results = [test1, test2].map((test) => test({
in: test,
out: `$builddir/${test}.results.txt`,
}));
// Concatenate the results to one file (not really needed here
// but acts as demonstration of how it would be used)
concat({
in: results,
out: "$builddir/all-tests.results.txt",
});
// Write the ninja file to disk
writeFileSync("build.ninja", ninja.output);
Run this script with npx tsx configure.ts (or ts-node etc.) and then run ninja!
After changing any of the mentioned TypeScript files mentioned in the script, just run
ninja to rebuild only those outputs that are needed.
node (>=18)ninja (>=1.11)npm ci --prefix configurenpm run configure (or for a slightly faster option in node >=22 node --run configure)ninjaIf new files are added then you must run npm run configure/node --run configure again
to regenerate a file build.ninja that includes these new files.