# build-ts

[![Test](https://github.com/WillBooster/build-ts/actions/workflows/test.yml/badge.svg)](https://github.com/WillBooster/build-ts/actions/workflows/test.yml)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![wbfy](https://img.shields.io/badge/wbfy-18.7.7-1e90ff.svg)](https://github.com/WillBooster/shared/tree/main/packages/wbfy)

[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)

An opinionated, low-config build tool for Node.js applications and libraries written in TypeScript, powered by [Rolldown](https://rolldown.rs/).

## Highlights

- **No build-ts-specific config** — point it at a package and it bundles `src/index.{ts,tsx,cts,mts}` into `dist/` with sensible defaults (minification, sourcemaps, and tree-shaking enabled).
- **Fast by design** — bundling is handled by Rolldown, declaration files are generated by `tsgo` ([TypeScript native preview](https://github.com/microsoft/typescript-go)), and console removal uses [Oxc](https://oxc.rs/) parsing. Babel is used only for decorator transforms.
- **Multiple targets** — Node.js apps, GCP/Firebase Functions, and Node.js / browser / React libraries.
- **Dual-format libraries** — emits CommonJS and ES modules side by side; the format matching `package.json`'s `type` uses `.js`, the other uses `.cjs` / `.mjs`.
- **TypeScript runner** — executes TypeScript files directly via [tsx](https://tsx.is/) (or Bun when running on Bun).

## Requirements

- Node.js >= 24

## Usage

`build-ts` works without installation via `npx build-ts` (or `bunx build-ts`), or can be added as a dev dependency:

```sh
npm install --save-dev build-ts
```

### Build a Node.js application

Bundles the app into a single directory, `dist/`:

```sh
npx build-ts app [package]
```

### Build GCP/Firebase Functions

Bundles the functions and generates an optimized `package.json` for deployment in `dist/` (removing `scripts` and `devDependencies`):

```sh
npx build-ts functions [package]
```

To generate only the optimized `package.json` without bundling:

```sh
npx build-ts functions --only-package-json
```

### Build a Node.js / browser / React library

Bundles the library into `dist/` with `.d.ts` declaration files, preserving the module structure of `src/`:

```sh
npx build-ts lib [package]
```

React libraries are detected automatically when `src/` contains `.tsx` files.

Declaration file generation requires a `tsconfig.json` in the package directory (or an ancestor directory).

### Run a TypeScript file

Runs a TypeScript file directly, passing along any arguments after `--`:

```sh
npx build-ts run src/main.ts -- --foo bar
```

## Options

### Common build options (`app`, `functions`, and `lib`)

| Option                           | Alias | Default  | Description                                                                                                                              |
| -------------------------------- | ----- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `--input`                        | `-i`  | (auto)   | Source files (or glob patterns like `src/**/*.ts`) to build. The first file is the main entry. Defaults to `src/index.{ts,tsx,cts,mts}`. |
| `--out-dir`                      | `-o`  | `dist`   | Output directory, resolved from the current directory (e.g., `../../dist/shared`). Removed before building.                              |
| `--module-type`                  | `-m`  | (varies) | Output module format: `esm`, `cjs`, `either` (follow `package.json`'s `type`), or `both` (`lib` only).                                   |
| `--minify` / `--no-minify`       |       | `true`   | Enable/disable minification.                                                                                                             |
| `--sourcemap` / `--no-sourcemap` |       | `true`   | Enable/disable sourcemaps.                                                                                                               |
| `--watch`                        | `-w`  | `false`  | Rebuild on file changes.                                                                                                                 |
| `--external`                     |       |          | Additional dependencies to keep external (not bundled).                                                                                  |
| `--inline`                       |       |          | Names of environment variables to inline into the bundle.                                                                                |
| `--auto-inline`                  |       | `false`  | Inline all environment variables defined in `.env` files.                                                                                |
| `--silent`                       | `-s`  | `false`  | Suppress non-error output.                                                                                                               |

An `--input` value containing glob syntax (`*`, `?`, `[...]`, or `{a,b}`) is expanded with matches sorted alphabetically; any other value is treated as a file path. Two caveats: in watch mode, patterns are expanded only once at startup, so files created later are not picked up until a restart; and for the `functions` target, the main entry (`index`) is the first match, so prefer listing the main entry explicitly (entry-name conflicts fail the build).

### `functions`-specific options

| Option                | Alias | Default | Description                                             |
| --------------------- | ----- | ------- | ------------------------------------------------------- |
| `--only-package-json` |       | `false` | Generate only the optimized `package.json` for `dist/`. |

### `lib`-specific options

| Option               | Alias | Default | Description                                                        |
| -------------------- | ----- | ------- | ------------------------------------------------------------------ |
| `--declaration-only` |       | `false` | Emit only declaration (`.d.ts`) files without bundling JavaScript. |

When `--input` is given explicitly, declaration files are generated only for the entry files and the files they (transitively) import, matching the bundled JavaScript. Without `--input`, declarations cover all files under `src/`. Ambient declaration files (`src/**/*.d.{ts,mts,cts}`) always participate in type checking, so files they import may also emit declarations.

Declaration generation compiles with `rootDir: src`, so every file (transitively) imported by the entries must live under the package's `src/`; entries importing sibling-package sources fail with `TS6059`.

Run `npx build-ts <command> --help` for the full list of options, including environment-variable handling shared with other WillBooster tools.

## Console Removal

`build-ts app`, `build-ts functions`, and `build-ts lib` remove global `console` calls during production builds. The build command sets `NODE_ENV=production` when `NODE_ENV` is not already set.

- When `NODE_ENV` is `production`, `console.log`, `console.debug`, and other non-excluded global console methods are removed; `console.error`, `console.info`, and `console.warn` are preserved.
- When `NODE_ENV` is `test`, `console.log` and other non-excluded methods are removed; `console.debug`, `console.error`, `console.info`, and `console.warn` are preserved.
- When `NODE_ENV` is any other value, console removal is disabled.
- Local bindings named `console` (function parameters, imports, `let`/`const`/`var` declarations, and class/function declarations) are always preserved. A binding whose name comes from the declaring construct itself (`namespace console`, `enum console`, `import console = ...`) or one declared in a `case` clause is not detected.

Console removal is controlled solely by `NODE_ENV`; there is no `--drop-console` option.

## Examples

The [`test/fixtures`](test/fixtures) directory contains ready-to-build sample projects:

```sh
npx build-ts app test/fixtures/app-node
npx build-ts functions test/fixtures/functions
npx build-ts lib test/fixtures/lib
npx build-ts lib test/fixtures/lib-react
```

## Development

```sh
bun install          # install dependencies
bun run test         # run tests
bun verify           # type check and lint
bun verify-full      # type check, lint, and all tests
```

## License

Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE) for details.
