https://github.com/hackwaly/task
A lightweight turborepo like task runner
https://github.com/hackwaly/task
Last synced: 5 months ago
JSON representation
A lightweight turborepo like task runner
- Host: GitHub
- URL: https://github.com/hackwaly/task
- Owner: hackwaly
- Created: 2025-10-20T13:41:24.000Z (8 months ago)
- Default Branch: master
- Last Pushed: 2025-10-20T15:33:30.000Z (8 months ago)
- Last Synced: 2025-10-20T15:35:27.677Z (8 months ago)
- Language: TypeScript
- Size: 12.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# @hackwaly/task
A lightweight, TypeScript-native task runner inspired by Turborepo. Define your build pipeline with code, not configuration files.
## Features
- 🚀 **TypeScript-first**: Define tasks in TypeScript with full type safety
- 📦 **Dependency management**: Automatic task dependency resolution and execution
- 👀 **Watch mode**: File watching with intelligent task re-execution
- ⚡ **Parallel execution**: Run independent tasks concurrently
- 🎯 **Persistent tasks**: Support for long-running processes (servers, watchers)
- 🔄 **Interruptible tasks**: Graceful handling of task interruption
- 📁 **Input/Output tracking**: File-based change detection for efficient rebuilds
## Installation
```bash
npm install @hackwaly/task
# or
pnpm add @hackwaly/task
# or
yarn add @hackwaly/task
```
## Quick Start
1. Create a `taskfile.js` in your project root:
```javascript
import { configInit } from "@hackwaly/task";
const { defineTask } = configInit(import.meta);
export const build = defineTask({
name: "build",
command: "tsc --build",
inputs: ["src/**/*.ts", "tsconfig.json"],
outputs: ["dist/**/*.js"],
});
export const test = defineTask({
name: "test",
command: "vitest run",
dependsOn: [build],
});
export const dev = defineTask({
name: "dev",
command: "tsc --watch",
persistent: true,
});
export default build;
```
2. Run tasks:
```bash
# Run a single task
npx task run build
# Run multiple tasks
npx task run build test
# Run with watch mode
npx task run build --watch
# List available tasks
npx task list
```
## Task Configuration
Tasks are defined using the `defineTask` function with the following options:
```typescript
interface TaskConfig {
name: string; // Task name (required)
description?: string; // Task description for help text
command?: string | string[] | { program: string; args?: string[] };
env?: Record; // Environment variables
cwd?: string; // Working directory (defaults to taskfile location)
inputs?: string[]; // Input file patterns (for change detection)
outputs?: string[]; // Output file patterns
persistent?: boolean; // Whether task runs continuously (like servers)
interruptible?: boolean; // Whether task can be interrupted safely
dependsOn?: TaskDef[]; // Task dependencies
}
```
### Command Formats
Commands can be specified in multiple formats:
```javascript
// String (parsed with shell-like parsing)
command: "tsc --build --verbose"
// Array
command: ["tsc", "--build", "--verbose"]
// Object
command: {
program: "tsc",
args: ["--build", "--verbose"]
}
```
### Dependencies
Tasks can depend on other tasks. Dependencies are resolved automatically:
```javascript
export const generateTypes = defineTask({
name: "generate-types",
command: "generate-types src/schema.json",
outputs: ["src/types.ts"],
});
export const build = defineTask({
name: "build",
command: "tsc --build",
inputs: ["src/**/*.ts"],
dependsOn: [generateTypes], // Runs generateTypes first
});
```
### Persistent Tasks
For long-running processes like development servers:
```javascript
export const server = defineTask({
name: "server",
command: "node server.js",
persistent: true, // Runs continuously
interruptible: true, // Can be stopped gracefully
});
```
## Watch Mode
Watch mode automatically re-runs tasks when their input files change:
```bash
npx task run build --watch
```
Features:
- Monitors all input patterns defined in tasks
- Ignores `node_modules` by default
- Propagates changes through the dependency graph
- Only reruns tasks that are affected by changes
## Commands
### `run `
Run one or more tasks:
```bash
# Single task
npx task run build
# Multiple tasks
npx task run lint test build
# With watch mode
npx task run build --watch
```
### `list` / `ls`
List all available tasks:
```bash
npx task list
```
Shows task names and descriptions in a formatted table.
## Examples
### Basic Build Pipeline
```javascript
import { configInit } from "@hackwaly/task";
const { defineTask } = configInit(import.meta);
export const lint = defineTask({
name: "lint",
description: "Lint TypeScript files",
command: "eslint src/**/*.ts",
inputs: ["src/**/*.ts", ".eslintrc.json"],
});
export const typecheck = defineTask({
name: "typecheck",
description: "Type check TypeScript files",
command: "tsc --noEmit",
inputs: ["src/**/*.ts", "tsconfig.json"],
});
export const build = defineTask({
name: "build",
description: "Build the project",
command: "tsc --build",
inputs: ["src/**/*.ts", "tsconfig.json"],
outputs: ["dist/**/*.js"],
dependsOn: [lint, typecheck],
});
export const test = defineTask({
name: "test",
description: "Run tests",
command: "vitest run",
dependsOn: [build],
});
```
### Development Workflow
```javascript
export const generateSchema = defineTask({
name: "generate-schema",
command: "generate-schema api.yaml",
inputs: ["api.yaml"],
outputs: ["src/generated/schema.ts"],
});
export const dev = defineTask({
name: "dev",
description: "Start development server",
command: "vite dev",
persistent: true,
interruptible: true,
dependsOn: [generateSchema],
});
export const buildWatch = defineTask({
name: "build:watch",
description: "Build in watch mode",
command: "tsc --watch",
persistent: true,
dependsOn: [generateSchema],
});
```
## Advanced Usage
### Monorepo Support
Each package can have its own `taskfile.js`:
```javascript
// packages/ui/taskfile.js
import { configInit } from "@hackwaly/task";
const { defineTask } = configInit(import.meta);
export const build = defineTask({
name: "build:ui",
command: "rollup -c",
inputs: ["src/**/*", "rollup.config.js"],
outputs: ["dist/**/*"],
});
// packages/app/taskfile.js
import { build as buildUI } from "../ui/taskfile.js";
export const build = defineTask({
name: "build:app",
command: "vite build",
dependsOn: [buildUI], // Cross-package dependency
});
```
### Custom Task Logic
For complex tasks, you can provide custom logic:
```javascript
export const customTask = defineTask({
name: "custom",
async run(ctx) {
// Custom async logic
console.log("Running custom task...");
// Check if aborted
if (ctx.abort.aborted) {
return;
}
// Your custom logic here
},
inputs: ["src/**/*"],
});
```
## License
MIT