UNPKG

tochibuild

Version:

An extremely fast JavaScript/Typescript and CSS bundler with minimal configuration.

406 lines (325 loc) 17.2 kB
# tochibuild `tochibuild` is a safer, smarter, tsup-powered bundler designed to reduce mistakes and enhance configurability — whether you build single packages, monorepos, or libraries. Powered by [tsup](https://github.com/egoist/tsup) and [esbuild](https://github.com/evanw/esbuild). ## Table of Contents - [tochibuild](#tochibuild) - [Table of Contents](#table-of-contents) - [Features](#features) - [Installation](#installation) - [Usage](#usage) - [Configuration](#configuration) - [Config Helpers](#config-helpers) - [`defineConfig(options, config?)`](#defineconfigoptions-config) - [`defineConfigWithIndexEntries(options, config?)`](#defineconfigwithindexentriesoptions-config) - [`defineConfigWithCommonEntries(options, config?)`](#defineconfigwithcommonentriesoptions-config) - [BuildUtils](#buildutils) - [Entrypoint patterns](#entrypoint-patterns) - [Utility Methods](#utility-methods) - [Build Lifecycles](#build-lifecycles) - [CLI Commands](#cli-commands) - [`tochibuild`](#tochibuild-1) - [Tip](#tip) - [`tochibuild config`](#tochibuild-config) - [`tochibuild pack`](#tochibuild-pack) - [`tochibuild merge`](#tochibuild-merge) - [Type Safety \& Defaults](#type-safety--defaults) - [Troubleshooting](#troubleshooting) - [`Error: Cannot find module 'typescript'`](#error-cannot-find-module-typescript) - [Docs \& Reference](#docs--reference) - [Credits](#credits) ## Features - [x] Safer `clean` defaults to protect your project - [x] Build lifecycle support (pre/post hooks, publish, deprecate) - [x] Smarter `defineConfig` helpers for common entry patterns - [x] Custom config support (`.ts`, `.js`, `.json`, `package.json`) - [x] Utilities for merging configs, creating tarballs, and manipulating package.json - [x] CLI with useful commands like `config`, `merge` and `pack` - [x] Powered by `tsup`, extended by `tochibuild` ## Installation ```bash npm i -D tochibuild ``` ## Usage ```bash tochibuild [options] ``` - If no options are passed, `tochibuild` looks for a config file or `tochibuild` key in `package.json`. - Use `--config <file>` to specify a config file, or `--no-config` to skip config files entirely. ## Configuration You can optionally configure `tochibuild` via: - `tochibuild.config.ts` - `tochibuild.config.js` - `tochibuild.config.json` - `tochibuild` property in `package.json` ```ts // tochibuild.config.ts import { defineConfig } from 'tochibuild'; export default defineConfig({ entry: ['src/index.ts'], clean: false, splitting: true, }); ``` or with hooks ```ts // tochibuild.config.ts import { defineConfig } from 'tochibuild'; import packageJson from './package.json'; export default defineConfig({ entry: ['src/index.ts'], clean: false, splitting: true, { lifecycle: { packageManager: 'bun', hooks: { publish: { command: 'publish', args: ['--access', 'public', '--no-private'], }, deprecate: { packageManager: 'npm', args: [ `${packageJson.name}@"<${packageJson.version}"`, `"Deprecated: Please upgrade to version ${packageJson.version} or higher."`, ], }, custom: [ { position: 'before.build', cli: { name: 'node', args: ['scripts/prebuild.js'] } }, { name: 'copy-types', position: 'after.build', action: async utils => { await utils.mergeFiles( ['dist/index.d.mts', 'types/*.d.ts'], 'dist/index.d.mts' ); }, }, ], }, // use `packageJson` to manipulate the package.json // that will be included in the published package packageJson: data => ({ ...data, main: 'dist/index.mjs', types: 'dist/index.d.mts', exports: { '.': { types: './dist/index.d.mts', require: './dist/index.mjs', import: './dist/index.mjs', }, }, }), }, } }); ``` > `clean`, `splitting`, and `entry` are required to avoid accidental destructive behavior. ## Config Helpers ### `defineConfig(options, config?)` Main entrypoint for config with fully customizable options. ### `defineConfigWithIndexEntries(options, config?)` Uses `BuildUtils.defaultEntriesIndex` as `entry`. ### `defineConfigWithCommonEntries(options, config?)` Uses `BuildUtils.defaultEntriesCommon` as `entry`. Each helper includes default values like: ```ts { tsconfig: "tsconfig.json", dts: true, format: ["esm"], minify: true, } ``` ## BuildUtils Utility class that powers `tochibuild`. ```ts import { BuildUtils } from 'tochibuild'; ``` ### Entrypoint patterns - `BuildUtils.entriesIndex` → `['**/index.{js,ts}']` - `BuildUtils.entriesCommon` → `['**/*.{js,ts}']` - `BuildUtils.ignoredEntries` → `['!*.d.ts', '!build/**', '!dist/**', '!node_modules/**', ...]` - `BuildUtils.defaultEntriesIndex` → Combined index + ignored - `BuildUtils.defaultEntriesCommon` → Combined common + ignored ### Utility Methods - `generateConfig()` – Creates config file programmatically - `ensureEntries()` – Ensures required entries are included - `getPackageJson()` – Loads `package.json` file + data - `getPackageJsonDeps()` – Retrieves dependencies from a package.json - `mergeFiles()` – Merge multiple files into a single output - `createTarball()` – Build a publish-ready tarball from a package ## Build Lifecycles You can run hooks before and after certain events. The order of the hooks are: 1. `before.build` 2. `after.build` 3. `before.publish` 4. `publish` 5. `after.publish` 6. `before.deprecate` 7. `deprecate` 8. `after.deprecate` Define lifecycle scripts for `publish`, `deprecate`, or custom commands/actions. ```ts lifecycle: { packageManager: 'npm', hooks: { publish: { args: ['--no-private'] }, custom: [ { position: 'before.build', cli: { name: 'node', args: ['scripts/prebuild.js'] } }, { name: 'copy-types', position: 'after.build', action: async utils => { await utils.mergeFiles( ['dist/index.d.mts', 'types/*.d.ts'], 'dist/index.d.mts' ); }, }, ] } } ``` ## CLI Commands ### `tochibuild` Basic build command: ```bash # uses configuration from tochibuild.config or package.json tochibuild ``` ```bash # uses configuration from tochibuild.config or package.json # but overrides format, target and splitting tochibuild --format esm --target node --splitting ``` ```bash # uses a custom configuration path tochibuild --config custom/path/to/config.ts ``` ```bash # uses a custom configuration path # appends entries tochibuild --config custom/path/to/config.ts --entry somefile.ts --entry anotherfile.ts ``` Refer to `tsup` for more info: https://tsup.egoist.dev/#usage | Option | Description | Default | |-------------------------------|----------------------------------------------------------------------------------------------|------------------| | `[...files]` | Files to bundle | - | | `--entry <file>` | Use a key-value pair as entry files | - | | `-d, --out-dir <dir>` | Output directory | - | | `--format <...format>` | Bundle format: `esm`, `cjs`, `iife` | - | | `--minify [terser]` | Minify bundle | `false` | | `--minify-whitespace` | Minify whitespace only | `false` | | `--minify-identifiers` | Minify identifiers only | `false` | | `--minify-syntax` | Minify syntax only | `false` | | `--keep-names` | Preserve function/class names in minified code | `false` | | `--target <...target>` | Bundle target: `esnext`, `es2022`, etc. | `esnext` | | `--legacy-output` | Output formats to separate folders instead of using different extensions | `false` | | `--dts [entry]` | Generate declaration file (`.d.ts`) | `false` | | `--dts-resolve` | Resolve external types for `.d.ts` files | `false` | | `--dts-only` | Emit only `.d.ts` files | `false` | | `--experimental-dts [entry]` | Experimental `.d.ts` generation | - | | `--sourcemap [inline]` | Generate sourcemap or inline sourcemap | `false` | | `--watch [...path]` | Enable watch mode (defaults to `.` if path omitted) | `false` | | `--ignore-watch <...path>` | Ignore paths in watch mode | - | | `--onSuccess <command>` | Run a command after a successful build | - | | `--env.* <value>` | Define compile-time environment variables | - | | `--inject <file>` | Replace a global with an import from another file | - | | `--define.* <value>` | Define compile-time constants | - | | `--external <name>` | Mark packages or deps as external | - | | `--global-name <name>` | Global var name for IIFE builds | - | | `--jsxFactory <name>` | Name of JSX factory function | `React.createElement` | | `--jsxFragment <name>` | Name of JSX fragment function | `React.Fragment` | | `--replaceNodeEnv` | Replace `process.env.NODE_ENV` | `false` | | `--no-splitting` | Disable code splitting | `false` | | `--clean` | Clean output directory before build | `false` | | `--silent` | Suppress logs except errors and onSuccess output | `false` | | `--pure <...expr>` | Mark expressions as pure for tree-shaking | - | | `--metafile` | Emit esbuild metafile (`.json`) | `false` | | `--platform <platform>` | Target platform: `node`, `browser`, `neutral` | `node` | | `--loader <ext=loader>` | Custom loader for specific file extensions | - | | `--tsconfig <filename>` | Use a specific `tsconfig.json` | `tsconfig.json` | | `--config <filename>` | Use a custom `tochibuild.config` file | - | | `--no-config` | Disable config file loading | `false` | | `--shims` | Enable CJS and ESM shims | `true` | | `--inject-style` | Inject CSS via style tag in the document head | `false` | | `--treeshake [strategy]` | Treeshaking: `recommended`, `smallest`, `safest` | `recommended` | | `--publicDir [dir]` | Copy contents of a public directory to output | `public` | | `--killSignal <signal>` | Signal to kill child process: `SIGTERM`, `SIGKILL` | `SIGTERM` | | `--cjsInterop` | Enable CommonJS interop | `true` | --- #### Tip For most options like `--env.*`, `--define.*`, etc., you can repeat the flag or use dot notation: ```bash tochibuild --env.API_URL=https://api.com --define.DEBUG=true ``` ### `tochibuild config` Generate a template config file. ```bash tochibuild config --ext .ts -f custom.config --dir ./configs --overwrite ``` | Flag | Description | Default | | ------------------- | ----------------------------------------------------------- | ------------------------- | | `--ext` | File extension to use (`.ts`, `.js`, `.cjs`, `.json`) | `.ts` | | `--filename`, `-f` | Name of the config file (excluding extension) | `tochibuild.config` | | `--outDir` | Output directories (absolute or relative, multiple allowed) | Current working directory | | `--overwrite`, `-o` | Overwrite file if it already exists | `false` | --- ### `tochibuild pack` Generate a `.tgz` tarball for publishing. ```bash tochibuild pack --dir . --pkg ./package.json --out ./dist ``` | Flag | Description | Default | | ------------- | ------------------------------------------------------------- | ------------------------- | | `--dir` | Path to the original package directory (relative or absolute) | Current working directory | | `--pkg`, `-p` | Path to `package.json` (relative or absolute) | `package.json` | | `--out`, `-o` | Output tarball path (relative or absolute) | `tochibuild.package.tgz` | --- ### `tochibuild merge` Merge the contents of all files into a single file. ```bash tochibuild merge <outFile> <...files> tochibuild merge dist/merged.d.ts types/a.d.ts types/b.d.ts types/c.d.ts ``` | Argument | Description | | ------------ | --------------------------------------------------------------------- | | `<outFile>` | Output file path (relative or absolute) | | `<...files>` | One or more file paths to merge into the output file (glob supported) | ## Type Safety & Defaults All config helpers enforce required properties (`entry`, `clean`, `splitting`) and provide smart defaults to prevent accidents. > `tochibuild` exists to keep you from `rm -rf ./`-ing your soul again. ## Troubleshooting ### `Error: Cannot find module 'typescript'` Happens when using `npx`. Use a local install instead: ```bash npm i -D tochibuild typescript ``` More: [tsup troubleshooting](https://tsup.egoist.dev/#troubleshooting) ## Docs & Reference - Full API: see the type definitions in `index.d.mts` - tsup options: https://www.jsdocs.io/package/tsup#Options ## Credits Built on top of: - [tsup](https://github.com/egoist/tsup) - [esbuild](https://github.com/evanw/esbuild) - [npm-packlist](https://github.com/npm/npm-packlist) - [@npmcli/arborist](https://github.com/npm/arborist)