--- url: /docs/guide/workspaces.md --- # Bunup Workspaces Effortlessly manage multiple packages in monorepos with Bunup's workspace support. Define and build multiple packages with a single configuration file and command. ## Configuration Structure ### Creating a Workspace Configuration Use the `defineWorkspace` function to define your monorepo structure: ```typescript [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace([ // Package configurations go here ]); ``` ### Package Configuration Each package in your workspace requires: | Property | Type | Description | |----------|------|-------------| | `name` | `string` | Unique identifier for the package | | `root` | `string` | Relative path to the package directory | | `config` | `BunupConfig \| BunupConfig[]` | Build configuration(s) for this package | ## Basic Usage Here's a simple workspace with two packages: ```typescript [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace([ { name: "core", root: "packages/core", config: { entry: ["src/index.ts"], format: ["esm", "cjs"], }, }, { name: "utils", root: "packages/utils", config: { entry: ["src/index.ts"], format: ["esm"], }, }, ]); ``` ## Using Shared Options You can simplify configuration by using shared options: ```typescript [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace( [ { name: "core", root: "packages/core", config: { format: ["esm", "cjs"], // Overrides shared format }, }, { name: "utils", root: "packages/utils", // config is optional when using only shared options }, ], { // Shared configuration applied to all packages entry: ["src/index.ts"], format: ["esm"], minify: true, target: "node", } ); ``` When a package has multiple configurations, shared options will apply to all of them: ```typescript [bunup.config.ts] export default defineWorkspace( [ { name: "web-package", root: "packages/web", config: [ { name: "browser-esm", format: ["esm"], target: "browser", }, { name: "node-cjs", format: ["cjs"], target: "node", }, ], }, ], { // These shared options apply to both browser-esm and node-cjs configs entry: ["src/index.ts"], minify: true, } ); ``` ## Multiple Build Configurations You can define multiple build configurations for a single package by using an array: ```typescript [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace([ { name: "web-package", root: "packages/web", config: [ { name: "browser-esm", entry: ["src/index.ts"], format: ["esm"], target: "browser", }, { name: "node-cjs", entry: ["src/index.ts"], format: ["cjs"], target: "node", }, ], }, ]); ``` ::: tip Use the `name` property within each config to easily identify different builds in logs. ::: ## Path Resolution All paths in workspace configurations are resolved relative to each **package's root directory**: ``` myproject/ ├── packages/ │ ├── core/ <- package root │ │ ├── src/ <- entry points relative to this package │ │ └── dist/ <- output goes here │ └── utils/ <- another package root ├── bunup.config.ts └── package.json ``` For example, with this configuration: ```typescript { name: 'core', root: 'packages/core', config: { entry: ['src/index.ts'], // resolves to packages/core/src/index.ts outDir: 'dist', // outputs to packages/core/dist/ }, } ``` ::: tip Plugin Path Resolution When using plugins that accept path options (like the [`copy`](/docs/plugins/copy) plugin), those paths are also resolved relative to the package's root directory. For example, `copy(['assets'])` will copy from `packages/core/assets` when used in the `core` package configuration. ::: ## Build Packages To build all packages in your workspace: ```sh bunup ``` ### Watch Mode To automatically rebuild packages when files change: ```sh bunup --watch ``` This single command watches and rebuilds all packages in your workspace. ### Building Specific Packages To build only specific packages, use the `--filter` option with the package names (the `name` property defined in your workspace configuration): ```sh bunup --filter core,utils # or watch specific packages bunup --filter core,utils --watch ``` ::: info Bunup do incremental builds in workspaces, meaning it will only rebuild packages that have changed. ::: --- --- url: /docs/guide/cli-options.md --- # CLI Options Bunup supports various command-line options: ```sh bunup [...entries] [options] ``` | Option | Alias | Description | Default | | ---------------------------------- | ----------- | -------------------------------------------------------------------------------------------------- | ---------------- | | `--entry ` | | Entry file path or glob pattern (use '!' prefix to exclude files) | `[]` | | `--out-dir ` | `-o` | Output directory | `dist` | | `--format ` | `-f` | Output formats (comma-separated: esm,cjs,iife) | `cjs` | | `--minify` | `-m` | Enable all minification options | `false` | | `--minify-whitespace` | `-mw` | Minify whitespace | `false` | | `--minify-identifiers` | `-mi` | Minify identifiers | `false` | | `--minify-syntax` | `-ms` | Minify syntax | `false` | | `--watch` | `-w` | Watch mode | `false` | | `--dts` | `-d` | Generate TypeScript declarations | `false` | | `--external ` | `-e` | External dependencies (comma-separated) | `[]` | | `--no-external ` | `-ne` | Force include dependencies (comma-separated) | - | | `--target ` | `-t` | Target environment (node, browser, bun) | `node` | | `--clean` | `-c` | Clean output directory before build | `true` | | `--splitting` | `-s` | Enable code splitting | Format dependent | | `--sourcemap ` | `-sm` | Sourcemap generation (none,linked,external,inline) | `none` | | `--banner ` | `-bn` | Text to add at the beginning of output files | - | | `--footer ` | `-ft` | Text to add at the end of output files | - | | `--public-path ` | `-pp` | Prefix to be appended to import paths in bundled code | - | | `--name ` | `-n` | Name for this build configuration | - | | `--resolve-dts ` | `-rd` | Resolve external types for declaration files (can be boolean flag or comma-separated package list) | `false` | | `--preferred-tsconfig-path ` | `-tsconfig` | Path to preferred tsconfig file used for typescript declaration files generation | - | | `--bytecode` | `-bc` | Generate bytecode for JavaScript/TypeScript entrypoints to improve startup times | `false` | | `--silent` | | Disable logging during the build process | `false` | | `--env ` | | Control environment variable handling (inline, disable or PREFIX\_\*) | - | | `--config ` | | Specify a custom path to the configuration file | - | | `--onSuccess ` | | Command to execute after a successful build | - | | `--filter ` | | Build only specific packages in a workspace (comma-separated) | - | | `--version` | `-v` | Display version information | - | | `--help` | `-h` | Display help information | - | --- --- url: /docs/plugins/copy.md --- # Copy This plugin copies files and directories to the output directory after each build. It supports glob patterns for flexible file selection. If no destination is specified, files are copied to the build output directory. ## Usage ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { copy } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [copy(['README.md', 'assets/**/*'])], }); ``` **Basic copying:** ```ts copy(['README.md', 'assets/**/*']) ``` **Copy and rename a file:** ```ts copy(['README.md'], 'dist/documentation.md') ``` **Copy to a specific directory:** ```ts copy(['assets/**/*'], 'dist/static') ``` --- --- url: /docs/plugins/exports.md --- # Exports This plugin automatically generates and updates the `exports` field in your package.json file after each build. Bunup handles mapping all entry points to their corresponding output files, including ESM/CJS formats and type declarations. The exports field stays perfectly in sync with your build configuration always - no manual updates needed when you make any change to config. ## Usage ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { exports } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [exports()], }); ``` When using the exports plugin, your package.json will be automatically updated with the correct exports field each time you build. For example: ```json [package.json] { "name": "my-package", "version": "1.0.0", "type": "module", "files": [ // [!code ++] "dist" // [!code ++] ], // [!code ++] "module": "./dist/index.js", // [!code ++] "main": "./dist/index.cjs", // [!code ++] "types": "./dist/index.d.ts", // [!code ++] "exports": { // [!code ++] ".": { // [!code ++] "import": { // [!code ++] "types": "./dist/index.d.ts", // [!code ++] "default": "./dist/index.js" // [!code ++] }, // [!code ++] "require": { // [!code ++] "types": "./dist/index.d.cts", // [!code ++] "default": "./dist/index.cjs" // [!code ++] } // [!code ++] } // [!code ++] } // [!code ++] } ``` ## Options ### `customExports` The `customExports` option allows you to specify additional export fields that will be preserved alongside the automatically generated exports. This is useful when you need custom export conditions or paths that aren't automatically generated by the build process. ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { exports } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [ exports({ customExports: (ctx) => ({ './package.json': './package.json', }) }) ], }); ``` ### `exclude` The `exclude` option allows you to prevent specific entry points from being included in the exports field. You can provide either an array of glob patterns or exact entry point names, or a function that returns such an array. ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { exports } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts', 'src/cli.ts', 'src/plugins.ts'], plugins: [ exports({ exclude: ['src/cli.ts'] }) ], }); ``` You can also use glob patterns: ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { exports } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts', 'src/cli/*.ts', 'src/plugins.ts'], plugins: [ exports({ exclude: ['src/cli/*'] }) ], }); ``` For more dynamic control, you can use a function: ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { exports } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts', 'src/cli.ts', 'src/plugins.ts'], plugins: [ exports({ exclude: (ctx) => { // Access build context information const { options, output, meta } = ctx; return ['src/cli.ts']; } }) ], }); ``` --- --- url: /docs/plugins/inject-styles.md --- # Inject Styles The `injectStyles` plugin transforms CSS files and automatically injects them into the document head at runtime. This is particularly useful when building component libraries where you want styles to be automatically applied when components are used. ## Installation The `injectStyles` plugin uses LightningCSS under the hood. You'll need to install it as a dev dependency: ```bash bun add --dev lightningcss ``` ## Usage ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { injectStyles } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [injectStyles()], }); ``` With this configuration, any imported CSS files will be transformed and injected into the document head when your JavaScript code runs. ## Options The plugin leverages Lightning CSS for transformations and passes the options directly to LightningCSS. Available options include: * `minify`: Controls whether the CSS should be minified (enabled by default if minify option is enabled in build config) * `targets`: Specifies browser targets for CSS feature compatibility For a complete list of transformation options, refer to the [Lightning CSS documentation](https://lightningcss.dev/docs.html). --- --- url: /docs/guide/options.md --- # Options Bunup provides a rich set of options to customize your build. See the table of contents on the right side to quickly navigate to the option you are looking for. ## Entry Points Bunup supports multiple ways to define entry points. Entry points are the source files that Bunup will use as starting points for bundling. ### Single Entry Point The simplest way to define an entry point is to provide a single file path: ::: code-group ```sh [CLI] bunup src/index.ts ``` ```ts [bunup.config.ts] export default defineConfig({ entry: 'src/index.ts', }); ``` ::: This will generate an output file named after the input file (e.g., `dist/index.js`). ### Multiple Entry Points You can specify multiple entry points in several ways: ::: code-group ```sh [CLI - method 1] bunup src/index.ts src/cli.ts ``` ```sh [CLI - method 2] bunup --entry src/index.ts --entry src/cli.ts ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts', 'src/cli.ts'], }); ``` ::: This will generate output files named after each input file (e.g., `dist/index.js` and `dist/cli.js`). ### Using Glob Patterns You can use glob patterns to include multiple files that match a pattern: ::: code-group ```sh [CLI] bunup 'src/**/*.ts' '!src/**/*.test.ts' ``` ```ts [bunup.config.ts] export default defineConfig({ entry: [ 'src/**/*.ts', '!src/**/*.test.ts', '!src/internal/**/*.ts' ], }); ``` ::: Glob pattern features: * Use patterns like `**/*.ts` to match files recursively * Prefix patterns with `!` to exclude files that match the pattern * Patterns are resolved relative to the project root ## Output Formats Bunup supports three output formats: * **esm**: ECMAScript modules (default) * **cjs**: CommonJS modules * **iife**: Immediately Invoked Function Expression (for browser) You can specify one or more formats: ### Using the CLI ::: code-group ```sh [CLI - single format] bunup src/index.ts --format esm ``` ```sh [CLI - multiple formats] bunup src/index.ts --format esm,cjs,iife ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], // Single format format: ['esm'], // Or multiple formats // format: ['esm', 'cjs', 'iife'], }); ``` ::: ### Output File Extensions The file extensions are determined automatically based on the format and your package.json `type` field: **When package.json has `"type": "module"`:** | Format | JavaScript Extension | TypeScript Declaration Extension | | ------ | -------------------- | -------------------------------- | | esm | `.js` | `.d.ts` | | cjs | `.cjs` | `.d.cts` | | iife | `.global.js` | `.global.d.ts` | **When package.json has `"type": "commonjs"` or is unspecified:** | Format | JavaScript Extension | TypeScript Declaration Extension | | ------ | -------------------- | -------------------------------- | | esm | `.mjs` | `.d.mts` | | cjs | `.js` | `.d.ts` | | iife | `.global.js` | `.global.d.ts` | ## Named Configurations You can give your build configurations names for better logging: ::: code-group ```sh [CLI] bunup src/index.ts --name my-library ``` ```ts [bunup.config.ts] export default defineConfig({ name: 'my-library', entry: ['src/index.ts'], }); ``` ::: This is especially useful when you have multiple configurations: ```typescript export default defineConfig([ { name: 'node-build', entry: ['src/index.ts'], format: ['cjs'], target: 'node', // ... other options }, { name: 'browser-build', entry: ['src/index.ts'], format: ['esm', 'iife'], // ... other options }, ]); ``` ## Customizing Dependency Bundling By default, Bunup treats all packages listed in your `package.json` under `dependencies` and `peerDependencies` as **external**. This means: * `dependencies` will be installed automatically when your package is installed. * `peerDependencies` are expected to be installed by the end user. These external packages are **not included** in your final bundle. However, any modules listed in `devDependencies` or others **will be bundled**. ### External Dependencies You can explicitly mark any package as external, even if it's not listed in `dependencies` or `peerDependencies`. #### Using the CLI ::: code-group ```sh [CLI - single package] bunup src/index.ts --external lodash ``` ```sh [CLI - multiple packages] bunup src/index.ts --external lodash,react,react-dom ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], external: ['lodash', 'react', '@some/package'], }); ``` ::: ### Forcing External Packages to Be Bundled Sometimes, you may want to include specific modules in your bundle, even if they're marked as external (e.g., part of `dependencies` or `peerDependencies`). #### Using the CLI ::: code-group ```sh [CLI] # Mark lodash as external, but include lodash/merge in the bundle bunup src/index.ts --external lodash --no-external lodash/merge ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], external: ['lodash'], noExternal: ['lodash/merge'], // This will be bundled }); ``` ::: ::: info Both `external` and `noExternal` support exact strings and regular expressions. ::: ## Tree Shaking Bunup tree-shakes your code by default. No configuration is needed. ## Code Splitting Code splitting allows Bunup to split your code into multiple chunks for better performance and caching. ### Default Behavior * Code splitting is **enabled by default** for ESM format * Code splitting is **disabled by default** for CJS and IIFE formats ### Configuring Code Splitting You can explicitly enable or disable code splitting: #### Using the CLI ::: code-group ```sh [CLI] # Enable code splitting bunup src/index.ts --splitting # Disable code splitting bunup src/index.ts --splitting=false ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], format: ['esm'], // Enable for all formats splitting: true, // Or disable for all formats // splitting: false, }); ``` ::: ## Minification Bunup provides several minification options to reduce the size of your output files. ### Basic Minification To enable all minification options: ::: code-group ```sh [CLI] bunup src/index.ts --minify ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], minify: true, }); ``` ::: ### Granular Minification Control You can configure individual minification options: #### Using the CLI ::: code-group ```sh [CLI - single option] # Minify whitespace only bunup src/index.ts --minify-whitespace ``` ```sh [CLI - multiple options] # Minify whitespace and syntax, but not identifiers bunup src/index.ts --minify-whitespace --minify-syntax ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], // Configure individual options minifyWhitespace: true, minifyIdentifiers: false, minifySyntax: true, }); ``` ::: The `minify` option is a shorthand that enables all three specific options. If you set individual options, they take precedence over the `minify` setting. ## Bytecode Bunup can generate bytecode for your JavaScript/TypeScript entrypoints, which can significantly improve startup times for large applications. ::: code-group ```sh [CLI] bunup src/index.ts --bytecode --target bun ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], bytecode: true, target: 'bun', // Bytecode compilation requires "bun" target }); ``` ::: For more information, see the [Bun documentation on bytecode](https://bun.sh/docs/bundler#bytecode) and [Bun's blog post on bytecode compilation](https://bun.sh/blog/bun-v1.1.30#compile-to-bytecode-for-2x-faster-startup-time). ## Source Maps Bunup can generate source maps for your bundled code: ::: code-group ```sh [CLI - linked] bunup src/index.ts --sourcemap linked ``` ```sh [CLI - inline] # Use --sourcemap for inline source maps bunup src/index.ts --sourcemap ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], sourcemap: 'linked' // Can also use boolean // sourcemap: true // equivalent to 'inline' }); ``` ::: Available sourcemap values: * `none` * `linked` * `external` * `inline` * `true` (equivalent to 'inline') For detailed explanations of these values, see the [Bun documentation on source maps](https://bun.sh/docs/bundler#sourcemap). ## Define Global Constants Bunup allows you to define global constants that will be replaced at build time. This is useful for feature flags, version numbers, or any other build-time constants. ```typescript export default defineConfig({ entry: ['src/index.ts'], define: { PACKAGE_VERSION: '"1.0.0"', DEBUG: 'false', }, }); ``` The `define` option takes an object where: * Keys are the identifiers to replace * Values are the strings to replace them with For more information on how define works, see the [Bun documentation on define](https://bun.sh/docs/bundler#define). ## Banner and Footer You can add custom text to the beginning and end of your bundle files: ::: code-group ```sh [CLI] bunup src/index.ts --banner 'use client' --footer '// built with love in SF' ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], // Add text to the beginning of bundle files banner: '"use client";', // Add text to the end of bundle files footer: '// built with love in SF', }); ``` ::: The `banner` option adds text to the beginning of the bundle, useful for directives like "use client" for React or license information. The `footer` option adds text to the end of the bundle, which can be used for license information or other closing comments. For more information, see the Bun documentation on [banner](https://bun.sh/docs/bundler#banner) and [footer](https://bun.sh/docs/bundler#footer). ## Drop Function Calls You can remove specific function calls from your bundle: ```typescript export default defineConfig({ entry: ['src/index.ts'], drop: ['console', 'debugger', 'anyIdentifier.or.propertyAccess'], }); ``` The `drop` option removes function calls specified in the array. For example, `drop: ["console"]` will remove all calls to `console.log`. Arguments to calls will also be removed, regardless of if those arguments may have side effects. Dropping `debugger` will remove all `debugger` statements. For more information, see the [Bun documentation on drop](https://bun.sh/docs/bundler#drop). ## Custom Loaders You can configure how different file types are loaded: ```typescript export default defineConfig({ entry: ['src/index.ts'], loader: { '.png': 'dataurl', '.txt': 'file', }, }); ``` The `loader` option takes a map of file extensions to built-in loader names, allowing you to customize how different file types are processed during bundling. For more information, see the [Bun documentation on loaders](https://bun.sh/docs/bundler#loader). ## Public Path You can specify a prefix to be added to specific import paths in your bundled code: ::: code-group ```sh [CLI] bunup src/index.ts --public-path https://cdn.example.com/ ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], publicPath: 'https://cdn.example.com/', }); ``` ::: The `publicPath` option only affects certain types of imports in the final bundle: * Asset imports (like images or SVG files) * External modules * Chunk files when code splitting is enabled By default, these imports are relative. Setting `publicPath` will prefix these specific file paths with the specified value, which is useful for serving assets from a CDN. For example: ```js [Input] import logo from './logo.svg'; console.log(logo); ``` ```js [Output without publicPath] var logo = './logo-a7305bdef.svg'; console.log(logo); ``` ```js [Output with publicPath] var logo = 'https://cdn.example.com/logo-a7305bdef.svg'; console.log(logo); ``` For more information, see the [Bun documentation on publicPath](https://bun.sh/docs/bundler#publicpath). ## Environment Variables Bunup provides flexible options for handling environment variables in your bundled code: ::: code-group ```sh [CLI] # Inline all environment variables available at build time FOO=bar API_KEY=secret bunup src/index.ts --env inline # Disable all environment variable inlining bunup src/index.ts --env disable # Only inline environment variables with a specific prefix (e.g., PUBLIC_) PUBLIC_URL=https://example.com bunup src/index.ts --env PUBLIC_* ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], // Inline all available environment variables at build time env: 'inline', // Or disable inlining entirely (keep process.env.FOO in the output) // env: "disable", // Or inline only variables that start with a specific prefix // env: "PUBLIC_*", // Or explicitly provide specific environment variables // These will replace both process.env.FOO and import.meta.env.FOO // env: { // API_URL: "https://api.example.com", // DEBUG: "false", // }, }); ``` ::: ### How it Works The `env` option controls how `process.env.*` and `import.meta.env.*` expressions are replaced at build time: | Value | Behavior | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `"inline"` | Replaces all `process.env.VAR` references in your code with the actual values of those environment variables at the time of the build. | | `"disable"` | Disables environment variable replacement. Keeps `process.env.VAR` as-is in output. | | `"PREFIX_*"` | Only inlines environment variables matching the given prefix (e.g. `PUBLIC_*`). | | `{ key: value }` | Replaces both `process.env.KEY` and `import.meta.env.KEY` with the provided values, regardless of the environment. | For more information, see the [Bun documentation on environment variables](https://bun.sh/docs/bundler#env). ## Target Environments Bunup allows you to specify the target environment for your bundle: ::: code-group ```sh [CLI] bunup src/index.ts --target browser ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], target: 'browser', }); ``` ::: Available targets: * `node` (default): Optimized for Node.js * `browser`: Optimized for browsers * `bun`: For generating bundles that are intended to be run by the Bun runtime. If a file contains a Bun shebang (`#!/usr/bin/env bun`), the `bun` target will be used automatically for that file. When targeting `bun`, bundles are marked with a special `// @bun` pragma that tells the Bun runtime not to re-transpile the file before execution. While bundling isn't always necessary for server-side code, it can improve startup times and runtime performance. ## Output Directory You can specify where Bunup should output the bundled files: ::: code-group ```sh [CLI] bunup src/index.ts --out-dir build ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], outDir: 'build', }); ``` ::: The default output directory is `dist`. ## Cleaning the Output Directory By default, Bunup cleans the output directory before each build. You can disable this behavior: ::: code-group ```sh [CLI] bunup src/index.ts --clean=false ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], clean: false, }); ``` ::: ## Post-build Operations The `onSuccess` option runs after the build process successfully completes. It supports three different formats: ### Function Callback Execute custom JavaScript code after a successful build: ```typescript export default defineConfig({ entry: ['src/index.ts'], onSuccess: (options) => { console.log('Build completed!'); const server = startDevServer(); // Optional: return a cleanup function for watch mode return () => server.close(); }, }); ``` ### Simple Command Execute a shell command as a string: ::: code-group ```sh [CLI] bunup src/index.ts --onSuccess "bun run ./scripts/server.ts" ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], onSuccess: 'bun run ./scripts/server.ts', }); ``` ::: ### Advanced Command Options For more control over command execution: ```typescript export default defineConfig({ entry: ['src/index.ts'], onSuccess: { cmd: 'bun run ./scripts/server.ts', options: { cwd: './app', env: { ...process.env, FOO: 'bar' }, timeout: 30000, // 30 seconds killSignal: 'SIGKILL', }, }, }); ``` Available command options: * **cwd**: Working directory for the command * **env**: Environment variables (defaults to `process.env`) * **timeout**: Maximum execution time in milliseconds * **killSignal**: Signal used to terminate the process (defaults to `'SIGTERM'`) ::: info In watch mode, `onSuccess` runs after each successful rebuild. ::: --- --- url: /docs/advanced/plugin-development.md --- # Plugin Development Guide Bunup provides a flexible plugin system that allows you to extend its functionality to meet your specific needs. This guide will walk you through the process of creating your own plugins for Bunup. ## Plugin Types Bunup supports two types of plugins: 1. **Bun Plugins** - Native Bun plugins that are passed directly to the underlying `Bun.build` configuration 2. **Bunup Plugins** - Custom plugins specifically designed for Bunup with lifecycle hooks ## Creating a Bun Plugin Bun plugins work with Bun's native bundler and are passed directly to the `Bun.build` configuration. These plugins can be used to modify how modules are resolved, transformed, and loaded. ```ts import type { BunPlugin } from "bun"; // Create a simple Bun plugin const myBunPlugin = (): BunPlugin => { return { name: "my-bun-plugin", setup(build) { // Plugin implementation build.onLoad({ filter: /\.txt$/ }, async (args) => { const text = await Bun.file(args.path).text(); return { contents: `export default ${JSON.stringify(text)}`, loader: "js", }; }); }, }; }; export default myBunPlugin; ``` To use this plugin in Bunup: ```ts import { defineConfig } from "bunup"; import myBunPlugin from "./my-bun-plugin"; export default defineConfig({ entry: ["src/index.ts"], format: ["esm", "cjs"], plugins: [ { type: "bun", name: "my-bun-plugin", // Optional plugin: myBunPlugin() } ] }); ``` For more information about creating Bun plugins, see the [Bun plugin documentation](https://bun.sh/docs/bundler/plugins). ## Creating a Bunup Plugin Bunup plugins provide additional hooks into the build process beyond what Bun's native plugin system offers. These plugins can be used to extend Bunup's functionality with custom build steps, reporting, and more. ```ts import type { Plugin } from "bunup"; // Create a simple Bunup plugin export function myBunupPlugin(): Plugin { return { type: "bunup", name: "my-bunup-plugin", hooks: { // Run before the build starts onBuildStart: async (options) => { console.log("Starting build with options:", options); }, // Run after the build is completed onBuildDone: async ({ options, output }) => { console.log("Build completed with files:", output.files.length); // Do something with the build output } } }; } ``` To use this plugin in Bunup: ```ts import { defineConfig } from "bunup"; import { myBunupPlugin } from "./my-bunup-plugin"; export default defineConfig({ entry: ["src/index.ts"], format: ["esm", "cjs"], plugins: [ myBunupPlugin() ] }); ``` ## Available Hooks Bunup plugins support the following hooks: ### `onBuildStart` Called before a build starts, allowing you to perform setup or preprocessing tasks. ```ts onBuildStart: (options: BuildOptions) => Promise | void ``` * `options`: The build options configured for this build ### `onBuildDone` Called after a build is successfully completed, providing access to the build output. ```ts onBuildDone: (ctx: BuildContext) => Promise | void ``` Where `BuildContext` contains: * `options`: The build options used * `output`: Information about the generated files * `meta`: Meta data about the build like the package.json that was used ## Publishing Plugins If you've created a useful plugin for Bunup, consider publishing it as an npm package for others to use. Use a naming convention like `bunup-plugin-*` to make it easily discoverable. --- --- url: /docs/advanced/programmatic-usage.md --- # Programmatic Usage Bunup can be used programmatically in your scripts. This is useful when you need custom build workflows or want to integrate bunup into your own tools. ::: info The build function must be run in the Bun runtime. ::: ## Basic Usage ```typescript import { build } from 'bunup'; await build({ entry: ['src/index.ts'], }); ``` ## Options The build function accepts the same options as `defineConfig`. See the [Options Guide](/docs/guide/options) for detailed documentation of all available options. For TypeScript users, the `BuildOptions` type is available: ```typescript import { build, type BuildOptions } from 'bunup'; const options: BuildOptions = { entry: ['src/index.ts'], format: ['esm', 'cjs'], }; await build(options); ``` The full type definition can be found in the [bunup source code](https://github.com/arshad-yaseen/bunup/blob/main/src/options.ts#L37). ## Using Plugins Plugins can be used programmatically the same way they are used in the configuration file: ```typescript import { build } from 'bunup'; import { injectStyles } from 'bunup/plugins'; await build({ entry: ['src/index.ts'], plugins: [injectStyles({ minify: true, targets: { chrome: 95 } })] }); ``` --- --- url: /docs/scaffold-with-bunup.md --- # Scaffold with Bunup Quickly scaffold modern TypeScript and React libraries in just 10 seconds with Bun. Powered by Bunup - the fastest bundler available ⚡️. * 🚀 **Instant Setup**: Scaffold, code, edit README, and publish with a single command - with nothing to rename or configure * 📦 **Modern**: ESM/CJS formats, TypeScript declarations, and optional monorepo support * 🛠️ **DX First**: Integrated Bun-powered testing, Biome linting and formatting that just works out of the box * 🚢 **Publishing**: One-command releases with automatic semantic versioning, GitHub tags, and detailed release notes * ⚡️ **Mind-Blowing Speed**: Build times so fast they feel instantaneous - a library building experience you've never experienced before ## Getting Started You can create a new project by using: ```sh bunx bunup@latest --new ``` That's it! You can now start coding. ## Setup for Releases 1. Generate an npm token: * Visit [npmjs.com](https://www.npmjs.com/), sign in * Go to profile → Access Tokens → Generate New Token (Classic) * Name it (e.g. "my-ts-lib publishing"), select "Automation" * Generate and copy token 2. Add token to GitHub: * Go to repo Settings → Secrets and variables → Actions * Click "New repository secret" * Set name as `NPM_TOKEN` and paste token value ## Development Workflow After completing the setup, here's how to use your project: ### TypeScript Library Commands ```sh bun run dev # Start development mode with automatic rebuilds bun run test # Run test suite bun run lint # Check code style and find problems bun run lint:fix # Fix linting issues automatically bun run format:fix # Fix code formatting issues bun run tsc # Type check TypeScript code bun run build # Build production bundle ``` ### React Library Development React libraries have a special development workflow optimized for component development: ```sh bun run dev # Watch source files and rebuild library instantly bun run dev:test # Start Next.js preview app at http://localhost:3000 bun run lint # Check code style and find problems bun run lint:fix # Fix linting issues automatically bun run format:fix # Fix code formatting issues bun run tsc # Type check TypeScript code bun run build # Build production bundle ``` #### Full Development Mode For the ultimate development experience with React libraries: 1. **Terminal 1**: Run `bun run dev` - Watches your source files and rebuilds the library instantly on any change 2. **Terminal 2**: Run `bun run dev:test` - Starts a Next.js preview app at http://localhost:3000 🔥 Instant reflection of changes in the live preview app ## CI/CD Workflows The project comes with three GitHub Actions workflows: 1. **CI**: Runs on pull requests and pushes to main, validating types, linting, and tests 2. **Release**: Triggered by tags, builds and publishes the package to npm with provenance 3. **Issue Management**: Automatically marks issues as stale after 30 days of inactivity ## Releasing Your Package When you're ready to release your package, simply run: ```sh bun run release ``` This will: 1. Prompt you for a new version (patch, minor, or major) 2. Update package.json version 3. Create a Git tag 4. Push changes and tag to GitHub The GitHub Actions workflow will automatically: 1. Build the package 2. Generate a GitHub release with changelog 3. Publish to npm with provenance Happy coding! --- --- url: /docs/plugins/shims.md --- # Shims The Shims plugin provides compatibility layers for Node.js globals and ESM/CJS interoperability. It automatically adds appropriate shims when it detects usage of environment-specific features in your code. ## Usage ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { shims } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [shims()], }); ``` For example: * For CJS output, any `import.meta.url` references are transformed to `pathToFileURL(__filename).href` * For ESM output, any `__dirname` and `__filename` references are transformed to use `dirname(fileURLToPath(import.meta.url))` This ensures your code works consistently across different module formats and environments without requiring manual compatibility code. --- --- url: /docs/guide/typescript-declarations.md --- # TypeScript Declarations Bunup automatically generates TypeScript declaration files (`.d.ts`, `.d.mts`, or `.d.cts`) for your library based on your output format, ensuring full type safety for consumers. Built from the ground up, Bunup includes [its own](https://github.com/bunup/typeroll) high-performance TypeScript declaration bundler. It's designed for maximum speed while offering advanced features like splitting and minification, producing minimal and clean declaration files. ## Prerequisites Enable `isolatedDeclarations` in your tsconfig: ```json [tsconfig.json] 4 { "compilerOptions": { "declaration": true, "isolatedDeclarations": true } } ``` Bunup leverages TypeScript's new modern [isolatedDeclarations](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#isolated-declarations) feature to generate declaration files. This approach enforces strict discipline in your type exports—only well-defined, explicit types reach your public API. You get bulletproof type safety, fast declarations, and clear interfaces your users will love. It's like a TypeScript guardian angel for your library's public surface! ## Basic If your entry points are TypeScript files, Bunup will automatically generate declaration files for them. ## Custom Entry Points For more control, you can specify custom entry points for declarations: ```typescript export default defineConfig({ entry: ['src/index.ts', 'src/cli.ts'], dts: { // Only generate declarations for index.ts entry: ['src/index.ts'], }, }); ``` ### Using Glob Patterns Bunup supports glob patterns for both main entries and declaration file entries: ```typescript export default defineConfig({ dts: { entry: [ 'src/public/**/*.ts', '!src/public/dev/**/*' ] } }); ``` You can use: * Simple patterns like `src/**/*.ts` to include files * Exclude patterns starting with `!` to filter out specific files * Both for main entries and declaration entries ## Declaration Splitting Declaration splitting optimizes TypeScript `.d.ts` files when multiple entry points share types. Instead of duplicating shared types across declaration files, Bunup extracts them into shared chunk files that are imported where needed. ```typescript export default defineConfig({ dts: { splitting: true, }, }); ``` **Without splitting:** ``` dist/ ├── index.d.ts # ~45KB └── cli.d.ts # ~40KB ``` **With splitting:** ``` dist/ ├── index.d.ts # ~15KB, imports from shared chunk ├── cli.d.ts # ~10KB, imports from shared chunk └── shared/chunk-abc123.d.ts # ~30KB, shared types ``` The result is clean declarations with no duplicates, improved readability, and reduced bundle size. ## Minification You can minify the generated declaration files to reduce their size: ```typescript export default defineConfig({ dts: { minify: true, }, }); ``` When enabled, minification preserves public (exported) API names while minifying internal type names and removes documentation comments. This significantly reduces file size when bundle size is a priority and JSDoc comments aren't essential. ### Example **Original:** ```ts type DeepPartial = { [P in keyof T]? : DeepPartial }; interface Response { data: T; error?: string; meta?: Record; } declare function fetchData(url: string, options?: RequestInit): Promise>; export { fetchData, Response, DeepPartial }; ``` **Minified:** ```ts type e={[P in keyof T]?:e};interface t{data:T;error?:string;meta?:Record;}declare function n(url:string,options?:RequestInit): Promise>;export{n as fetchData,t as Response,e as DeepPartial}; ``` ## TypeScript Configuration You can specify a custom tsconfig file for declaration generation: ::: code-group ```sh [CLI] bunup src/index.ts --preferred-tsconfig-path ./tsconfig.build.json ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ["src/index.ts"], preferredTsconfigPath: "./tsconfig.build.json", }); ``` ::: ## Resolving External Types When generating declaration files, you might need to include type references from external dependencies. Bunup can automatically resolve these external types: ::: code-group ```sh [CLI - all packages] bunup src/index.ts --resolve-dts ``` ```sh [CLI - specific packages] bunup src/index.ts --resolve-dts=react,lodash ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ['src/index.ts'], dts: { // Enable resolving all external types resolve: true, }, }); ``` ::: The `resolve` option helps when your TypeScript code imports types from external packages. Bunup will look for type definitions in `node_modules` and include them in your declaration files. You can also specify which packages to resolve types for: ```typescript export default defineConfig({ entry: ['src/index.ts'], dts: { // Only resolve types from these specific packages resolve: ['react', 'lodash', /^@types\//], }, }); ``` ## Disabling Declaration Generation While Bunup automatically generates declaration files for TypeScript entries, you can disable this feature if needed: ::: code-group ```sh [CLI] bunup src/index.ts --dts=false ``` ```ts [bunup.config.ts] export default defineConfig({ entry: ["src/index.ts"], dts: false, }); ``` ::: This can be useful when you want to handle declaration generation yourself or when you're working on a project that doesn't need declaration files. --- --- url: /isolated-declarations.md --- ## Understanding isolatedDeclarations Bunup uses TypeScript's [isolatedDeclarations](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#isolated-declarations) feature to generate accurate type declarations. This approach verifies that each file's public API can be described using only its explicit imports and exports, without relying on implicit type relationships. ### Why It Matters Traditional type declaration generation requires the TypeScript compiler to analyze your entire codebase to infer return types and other type information, which is computationally expensive and slow. The isolatedDeclarations approach eliminates this overhead by requiring explicit type annotations on exported items. ### Benefits * **Faster declaration generation**: Eliminates the need for whole-program analysis * **More accurate types**: Types are exactly what you define, not inferred * **Improved encapsulation**: Ensures your module boundaries are clear and well-defined * **Better maintainability**: Prevents unexpected type dependencies between modules * **Enhanced modularity**: Makes your library more reliable for consumers ### Recommendation To catch isolatedDeclarations errors early in your development process (rather than at build time), enable the option in your tsconfig.json: ```json { "compilerOptions": { "declaration": true, "isolatedDeclarations": true } } ``` This will help you identify and fix potential declaration issues in your editor before running the build. For more details about isolatedDeclarations, refer to [TypeScript's explanation on isolatedDeclarations](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#isolated-declarations). --- --- url: /docs/plugins/unused.md --- # Unused This plugin detects and reports unused dependencies in your project. ## Usage ```ts [bunup.config.ts] import { defineConfig } from 'bunup'; import { unused } from 'bunup/plugins'; export default defineConfig({ entry: ['src/index.ts'], plugins: [unused()], }); ``` ## Options ```ts unused({ level: 'error', // Fail the build on unused dependencies, defaults to 'warn' ignore: ['intentionally-unused-pkg'], // Dependencies to ignore when checking for unused dependencies }) ```