brec
v0.0.8
Published
A task runner for the Bun ecosystem.
Maintainers
Readme
brec
A task runner for the Bun ecosystem. (Bun RECipes)
Define recipes in TypeScript. Run them from the command line. Dependencies are resolved as a directed acyclic graph (DAG) and run with maximum concurrency.
Install
bun add -d brecQuick start
Create a brec.ts or brec.js in your project root:
import { recipe, $ } from "brec";
export const clean = recipe("Remove build artifacts", () => $`rm -rf ./build`);
export const build = recipe(
() => $`bun build ./src/index.ts --outdir ./build --target bun`,
[clean],
);List available recipes:
$ brec
clean Remove build artifacts
buildRun a recipe:
$ brec build
▶ clean
▶ buildAPI
recipe()
Creates a recipe. Call it with a description and a run function. Optionally pass recipe dependencies as a third argument.
recipe(description: string, run: Task, deps?: Recipe[]): Recipe
recipe(run: Task, deps?: Recipe[]): Recipe- description: optional text that appears when you list recipes
- run: the function to execute (
Taskis a type alias for() => void | Promise<any>) - deps: optional other recipes that must run first
Dependencies run before the recipe. Independent dependencies run concurrently.
Example:
export const lint = recipe("Lint the codebase", () => { ... });
export const test = recipe("Run tests", () => { ... });
// both "lint" and "test" run (in parallel) before "ci"
export const ci = recipe("CI pipeline", async () => { ... }, [lint, test]);
// shorthand (description is optional)
export const build = recipe(() => $`bun build`, [clean]);$
A re-export of Bun's built-in shell tagged template literal. Use it to run shell commands inside recipes.
export const dev = recipe("Start dev server", () => $`bun run dev`);Recipes
Brec discovers recipes from the exports of your brec.ts or brec.js file.
Named exports
Each named export that is a Recipe becomes available as a recipe. The export name is the recipe name.
export const lint = recipe("Lint the codebase", () => { ... });
export const test = recipe("Run tests", () => { ... });$ brec
lint Lint the codebase
test Run testsDefault export
Export a Recipes as the default export to create recipes dynamically.
import { recipe, type Recipes } from "brec";
const services = ["api", "web", "worker"];
export default Object.fromEntries(
services.map((s) => [
`deploy-${s}`,
recipe(`Deploy the ${s} service`, async () => { ... }),
]),
) satisfies Recipes;$ brec
deploy-api Deploy the api service
deploy-web Deploy the web service
deploy-worker Deploy the worker serviceYou can use both named exports and a default export in the same file.
Dependencies
Pass recipe variables directly as dependencies. This gives you type safety and ensures referenced recipes exist.
const clean = recipe(() => $`rm -rf dist`);
const compile = recipe(() => $`bun build src/index.ts --outdir dist`);
export const bundle = recipe(async () => { ... }, [clean, compile]);If there's a cycle in the dependency graph, brec reports an error.
License
brec is licensed under the MIT License. See LICENSE for details.
