--- url: /docs/guide/workspaces.md --- # Bunup Workspaces Effortlessly manage **multiple packages in a monorepo** with Bunup’s built-in workspace support. This eliminates the need for separate config files and multiple commands for each package. With a single configuration file and a single command, you can build and watch all your packages at once with a great ui and experience. ![Bunup Workspaces](/bunup-workspaces.gif) ## Creating a Workspace Configuration Define your workspace using the `defineWorkspace` function: ```ts [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace([ // Package configurations go here ]); ``` ## Package Configuration Each package requires three properties: | Property | Type | Description | | -------- | ------------------------------ | ------------------------------------------------------------ | | `name` | `string` | Unique identifier for the package | | `root` | `string` | Path to the package directory, relative to the monorepo root | | `config` | `BunupConfig \| BunupConfig[]` | Optional build configuration(s) for this package | πŸ‘‰ If you omit `config`, Bunup will use **defaults**: * Build as ESM-only * Use [default entry points](/#default-entry-points) (e.g. `src/index.ts`) * Generate TypeScript declaration files (`.d.ts`) for entry points that need them ## Basic Usage A minimal workspace with two packages: ```ts [bunup.config.ts] import { defineWorkspace } from "bunup"; export default defineWorkspace([ { name: "core", root: "packages/core", config: { // Bunup finds 'src/index.ts' by default // Or specify exactly which files to build // entry: ["src/index.ts", "src/plugins.ts"], format: ["esm", "cjs"], }, }, { name: "utils", root: "packages/utils", // Uses default entry points // Uses default format: esm // Generates .d.ts declaration files }, ]); ``` Here, **`core`** has custom formats, while **`utils`** works out of the box with defaults. ## Shared Options You can define **shared options** for all packages, reducing repetition: ```ts [bunup.config.ts] export default defineWorkspace( [ { name: "core", root: "packages/core", config: { format: ["esm"], // overrides shared format }, }, { name: "utils", root: "packages/utils", // config is optional, shared options apply }, ], { // Shared options format: ["esm", "cjs"], exports: true, }, ); ``` ## Multiple Build Configurations Each package can have multiple builds by passing an array. ::: info Named Configurations When using an array of build configurations, the `name` property is **required** for each configuration to identify the builds in logs and reports. ::: ```ts [bunup.config.ts] export default defineWorkspace([ { name: "web", root: "packages/web", config: [ { entry: "src/index.ts", name: "node", format: "esm", target: "node", }, { entry: "src/browser.ts", name: "browser", format: ["esm", "iife"], target: "browser", outDir: "dist/browser", }, ], }, ]); ``` **Another example:** if you have different entry points that need different build configurations, you can specify them separately. For instance, your main module might need both ESM and CJS formats, while a CLI entry point might only need ESM: ```ts [bunup.config.ts] export default defineWorkspace([ { name: "main", root: "packages/main", config: [ { entry: "src/index.ts", name: "main", format: ["esm", "cjs"], }, { entry: "src/cli.ts", name: "cli", format: ["esm"], }, ], }, ]); ``` ## Path Resolution All paths in package configs are **relative to the package root**: ``` myproject/ β”œβ”€β”€ packages/ β”‚ β”œβ”€β”€ core/ <- package root β”‚ β”‚ β”œβ”€β”€ src/ <- entries resolved here β”‚ β”‚ └── dist/ <- outputs here β”‚ └── utils/ β”œβ”€β”€ bunup.config.ts └── package.json ``` Example: ```ts { 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 Paths When using plugins (like [`copy`](/docs/builtin-plugins/copy)), paths are also resolved relative to the **package root**. For example, `copy("assets/**/*.svg")` in the `core` package will copy from `packages/core/assets`. ::: ## Building Packages ### Build all packages ```sh bunx bunup ``` ### Watch mode ```sh bunx bunup --watch ``` Bunup will watch **all packages** and rebuild only those that change. ### Build specific packages Use the `--filter` option with package names: ```sh bunx bunup --filter core,utils # or in watch mode bunx bunup --filter core,utils --watch ``` ::: info Incremental Builds Workspaces are **incremental**: only changed packages are rebuilt. ::: --- --- url: /docs/guide/cli-options.md --- # CLI Options ```ansi [...entries] Entry point files to bundle Flags:  --entry   Entry file or glob pattern  --entry   Multiple entry files or globs  -c, --config   Path to a custom configuration file Example: ./configs/custom.bunup.config.js  --config  Whether to use a configuration file (default: true)  --no-config  Explicitly disable config  --filter   Filter workspace packages or config array items by name  --name   Name of the build configuration (for logging and identification) Example: my-library  -o, --out-dir   Output directory for bundled files (default: "dist")  --format   Single output format  --format   Multiple output formats  --minify  Enable all minification options (whitespace, identifiers, syntax)  --no-minify  Explicitly disable minify  --minify-whitespace  Minify whitespace in the output to reduce file size  --no-minify-whitespace  Explicitly disable minify whitespace  --minify-identifiers  Minify identifiers by renaming variables to shorter names  --no-minify-identifiers  Explicitly disable minify identifiers  --minify-syntax  Minify syntax by optimizing code structure  --no-minify-syntax  Explicitly disable minify syntax  --watch  Watch for file changes and rebuild automatically  --no-watch  Explicitly disable watch  --clean  Clean the output directory before building (default: true)  --no-clean  Explicitly disable clean  -q, --silent  Disable logging during the build process  --no-silent  Explicitly disable silent  --splitting  Enable code splitting (enabled by default for ESM format)  --no-splitting  Explicitly disable splitting  --conditions   Package.json export conditions for import resolution  -t, --target   Target environment for the bundle (default: "node")  --external   External packages that should not be bundled  --no-external   Packages that should be bundled even if listed in external  --packages   Bundle all dependencies or externalize all dependencies. Use "bundle" to include all deps in output, or "external" to exclude all deps  --shims  Enable shims for Node.js globals and ESM/CJS interoperability  --no-shims  Explicitly disable shims  --report.gzip  Enable gzip compression size calculation (default: true)  --no-report.gzip  Explicitly disable report gzip  --report.brotli  Enable brotli compression size calculation  --no-report.brotli  Explicitly disable report brotli  --report.max-bundle-size   Maximum bundle size in bytes. Will warn if exceeded  --dts.entry   Single entrypoint for declaration file generation  --dts.entry   Multiple entrypoints for declaration file generation  --dts.resolve  Resolve types from dependencies  --dts.resolve   Names or patterns of packages from which to resolve types  --no-dts.resolve  Explicitly disable dts resolve  --dts.splitting  Enable declaration file splitting  --no-dts.splitting  Explicitly disable dts splitting  --dts.minify  Minify generated declaration files  --no-dts.minify  Explicitly disable dts minify  --dts.infer-types  Use TypeScript compiler (tsc) for declarations generation (removes need for explicit type annotations)  --no-dts.infer-types  Explicitly disable dts infer types  --dts.tsgo  Use TypeScript's native compiler (tsgo), 10x faster than tsc (only applicable with inferTypes enabled)  --no-dts.tsgo  Explicitly disable dts tsgo  --dts  Generate TypeScript declaration files (.d.ts)  --no-dts  Explicitly disable dts  --dts-only  Only emit TypeScript declaration files without building JavaScript output  --no-dts-only  Explicitly disable dts only  --preferred-tsconfig   Path to a custom tsconfig.json file used for path resolution during both bundling and TypeScript declaration generation. Example: ./tsconfig.build.json  --sourcemap  Generate a sourcemap (uses the inline type by default)  --sourcemap   Generate a sourcemap with a specific type  --no-sourcemap  Explicitly disable sourcemap  --define.   Define global constants replaced at build time Example: --define.PACKAGE_VERSION='"1.0.0"'  --env.   Explicit env var mapping Example: --env.NODE_ENV="production" --env.API_URL="https://api.example.com"  --env   inline: inject all, disable: inject none  --env   Inject env vars with this prefix Example: MYAPP_* (Environment prefix must end with *)  --banner   Banner text added to the top of bundle files  --footer   Footer text added to the bottom of bundle files  --drop   Remove function calls from bundle Example: --drop console,debugger  --loader.   File extension to loader mapping Example: --loader.'.css'=text --loader.'.txt'=file  --public-path   Public path prefix for assets and chunk files Example: https://cdn.example.com/  --source-base   Base directory for entry points to control output structure Example: ./src  --jsx.runtime   JSX runtime mode  --jsx.import-source   Import source for JSX functions  --jsx.factory   JSX factory function name  --jsx.fragment   JSX fragment function name  --jsx.side-effects  Whether JSX functions have side effects  --no-jsx.side-effects  Explicitly disable jsx side effects  --jsx.development  Use jsx-dev runtime for development  --no-jsx.development  Explicitly disable jsx development  --ignore-dce-annotations  Ignore dead code elimination annotations (@__PURE__, sideEffects)  --no-ignore-dce-annotations  Explicitly disable ignore dce annotations  --emit-dce-annotations  Force emit @__PURE__ annotations even with minification  --no-emit-dce-annotations  Explicitly disable emit dce annotations  --on-success   Command to run after successful build  --exports.exclude   Configure automatic package.json exports generation - Entry points to exclude from exports field  --exports.exclude-cli  Whether to exclude CLI entry points (cli/bin files) from exports field (default: true)  --no-exports.exclude-cli  Explicitly disable exports exclude cli  --exports.exclude-css  Whether to exclude CSS files from exports field  --no-exports.exclude-css  Explicitly disable exports exclude css  --exports.include-package-json  Whether to include "./package.json" in exports field (default: true)  --no-exports.include-package-json Explicitly disable exports include package json  --exports.all  Whether to add wildcard export for deep imports  --no-exports.all  Explicitly disable exports all  --exports   --no-exports  Explicitly disable exports  --unused.level   Detect unused or incorrectly categorized dependencies - The level of reporting for unused or incorrectly categorized dependencies (default: "warn")  --unused.ignore   Dependencies to ignore when checking  --unused   --no-unused  Explicitly disable unused  --css.typed-modules  Generate TypeScript definitions for CSS modules (default: true)  --no-css.typed-modules  Explicitly disable css typed modules  --css.inject.minify  Inject CSS styles into document head at runtime - Whether to minify the styles being injected  --no-css.inject.minify  Explicitly disable css inject minify  --css.inject   --no-css.inject  Explicitly disable css inject -h, --help  Display this menu and exit Examples: bunup # Basic build bunup src/index.ts # Single entry file bunup src/**/*.ts # Glob pattern for multiple files bunup --watch # Watch mode bunup --format cjs,esm # Multiple formats bunup --target bun # Bun target bunup src/cli.ts # Multiple entries bunup --dts.splitting # Declaration splitting bunup --dts-only # Only emit declaration files bunup --no-clean # Disable cleaning output directory before build ``` --- --- url: /docs/advanced/compile.md --- # Compile to Executable Bunup supports creating standalone executables using the `compile` option. This allows you to bundle your code and the Bun runtime into a single executable file that can be distributed and run without requiring Bun to be installed. ## Use Case The `compile` option is useful when you want to: * Distribute CLI tools that users can run without installing Bun * Create standalone executables for scripts and utilities * Package your code with all dependencies included ## Output Directory Compiled executables output to `bin/` by default, unlike normal builds which output to `dist/` by default. If you want to change the output location, you can use the `outDir` option to specify a different directory like `dist/` or any other location. ## Basic Usage ```typescript [bunup.config.ts] export default defineConfig({ entry: "src/cli.ts", compile: true, // Create executable for current platform }); ``` This will output the executable to the `bin/` directory. ## Customizing Output Directory You can change the output directory using the `outDir` option: ```typescript [bunup.config.ts] export default defineConfig({ entry: "src/cli.ts", compile: true, outDir: "dist", // Output to dist/ instead of bin/ }); ``` ## Cross-Compilation Target specific platforms: ```typescript [bunup.config.ts] export default defineConfig({ entry: "src/cli.ts", compile: "bun-linux-x64", // Cross-compile for Linux }); ``` ## Advanced Configuration ```typescript [bunup.config.ts] export default defineConfig({ entry: "src/cli.ts", compile: { target: "bun-linux-x64", outfile: "./bin/my-app", windows: { hideConsole: true, icon: "./icon.ico", }, }, }); ``` ## Multiple Entrypoints Only one entrypoint can be compiled at a time. If you want to compile multiple entrypoints, you need to use a build config array with separate configurations: ```typescript [bunup.config.ts] export default defineConfig([ { name: "main", entry: "src/main.ts", compile: true, }, { name: "cli", entry: "src/cli.ts", compile: { outfile: "my-cli", }, }, ]); ``` This will create separate executables for each entrypoint. ## Cross-Compiling for Multiple Targets If you want to cross-compile the same entrypoint for multiple targets, or use different configurations for different targets, you can create separate objects in the config array: ```typescript [bunup.config.ts] export default defineConfig([ { name: "cli-linux", entry: "src/cli.ts", compile: "bun-linux-x64", }, { name: "cli-windows", entry: "src/cli.ts", compile: { target: "bun-windows-x64", outfile: "./bin/my-app-windows.exe", windows: { hideConsole: true, icon: "./icon.ico", }, }, }, { name: "cli-macos", entry: "src/cli.ts", compile: { target: "bun-darwin-arm64", outfile: "./bin/my-app-macos", }, }, ]); ``` This approach allows you to: * Build executables for multiple platforms in a single build command * Apply platform-specific configurations (like Windows console hiding or custom icons) * Customize the output filename for each target platform ## Mixing Executables and Library Builds You can also mix executable compilation with normal library builds in the same config array. This is useful when you want to build both a library and CLI tools: ```typescript [bunup.config.ts] export default defineConfig([ { name: "library", entry: "src/index.ts", format: ["esm", "cjs"], dts: true, // Normal library build }, { name: "cli", entry: "src/cli.ts", compile: true, // Compile to executable }, ]); ``` This allows you to build your library and create executables in a single build process. ## Learn More For detailed information about available targets and configuration options, see the [Bun documentation on executables](https://bun.com/docs/bundler/executables). --- --- url: /docs/guide/config-file.md --- # Config File Centralize your build settings with a configuration file when CLI options aren't enough. ## Getting Started Create a `bunup.config.ts` file in your project root: ```ts [bunup.config.ts] import { defineConfig } from "bunup"; export default defineConfig({ // ...your configuration options go here }); ``` This is the simplest way to centralize and reuse your build configuration. See [Options](/docs/guide/options) for all the available options. ## Multiple Configurations Bunup supports exporting an **array of configurations**, useful when you want to build for multiple environments or formats in a single run. ::: info Named Configurations When using an array of configurations, the `name` property is **required** for each configuration to identify the builds in logs and reports. ::: ```ts [bunup.config.ts] export default defineConfig([ { entry: "src/index.ts", name: "node", format: "esm", target: "node", }, { entry: "src/browser.ts", name: "browser", format: ["esm", "iife"], target: "browser", outDir: "dist/browser", }, ]); ``` With this setup, Bunup will build both Node.js and browser bundles. **Another example:** if you have different entry points that need different build configurations, you can specify them separately. For instance, your main module might need both ESM and CJS formats, while a CLI entry point might only need ESM: ```ts [bunup.config.ts] export default defineConfig([ { entry: "src/index.ts", name: "main", format: ["esm", "cjs"], }, { entry: "src/cli.ts", name: "cli", format: ["esm"], }, { entry: "src/browser.ts", name: "browser", format: ["esm", "iife"], outDir: "dist/browser", }, ]); ``` ## Filtering Configurations When you have multiple configurations in an array, you can use the `--filter` option to build only specific configurations by name: ```sh [CLI] # Single bunup --filter main # Multiple bunup --filter main,browser ``` Only the configurations matching these names will be built - perfect for testing specific builds without running the entire suite. ## Custom Configuration Path If you need to use a configuration file with a non-standard name or location, you can specify its path using the `--config` CLI option: ::: code-group ```sh [CLI] bunup --config ./configs/custom.bunup.config.ts # or using alias bunup -c ./configs/custom.bunup.config.ts ``` ::: This allows you to keep your configuration files organized in custom locations or use different configuration files for different environments. ## Disabling Configuration Files To explicitly disable config file usage and rely only on CLI options: ```sh [CLI] bunup --no-config ``` --- --- url: /docs/builtin-plugins/copy.md --- # Copy The copy plugin copies files and directories to your build output. It supports glob patterns, direct folder copying, file transformation with filename changes, and can copy to specific destinations or rename files and folders. ## Basic Usage ```ts [bunup.config.ts] import { defineConfig } from "bunup"; import { copy } from "bunup/plugins"; export default defineConfig({ plugins: [copy(["README.md", "assets/**/*"])], }); ``` This will copy the `README.md` file and all files in the `assets` directory to your build output directory. Use `copy(pattern)` to copy files or folders. Optionally, add `.to(destination)` to set the output name or location, `.with(options)` for extra settings, and `.transform(fn)` to modify files during copy. By default, everything is copied to your build output directory. ## Examples Below are some examples of how to use the copy plugin. ### Basic File Operations ```ts // Copy single file copy("README.md"); // Copy multiple specific files copy(["README.md", "LICENSE", "CHANGELOG.md"]); // Copy and rename a file copy("README.md").to("documentation.md"); ``` ### Directory Operations ```ts // Copy entire directory as is (preserves structure) copy("assets"); // β†’ dist/assets/ // Copy and rename directory copy("assets").to("static"); // β†’ dist/static/ // Copy multiple directories copy(["assets", "public", "docs"]); ``` ### Glob Patterns ```ts // Copy all markdown files recursively copy("**/*.md"); // Copy all files in assets directory copy("assets/**/*"); // Copy with multiple patterns copy([ "assets/**/*", // All files in assets "docs/**/*.md", // Markdown files in docs "src/**/*.css", // CSS files in src ]); ``` ### Pattern Exclusions ```ts // Exclude specific files and patterns copy([ "assets/**/*", // Include all assets "!**/*.tmp", // Exclude temporary files "!**/*.log", // Exclude log files "!**/node_modules", // Exclude node_modules "!**/.DS_Store", // Exclude system files ]); ``` ### Flattening Structure ```ts // Flatten all files from subdirectories copy("assets/**/*").to("static"); // All files β†’ dist/static/ // Flatten specific file types copy("src/**/*.css").to("styles"); // All CSS β†’ dist/styles/ copy("images/**/*.{png,jpg,svg}").to("assets"); // All images β†’ dist/assets/ ``` ### Multiple Copy Operations You can add multiple copy plugins for different copy operations: ```ts export default defineConfig({ plugins: [ copy("README.md"), copy("assets/**/*").to("static"), copy("docs/**/*.md").to("documentation"), ], }); ``` ## Transform Files Transform files on the fly during the copy operation using the `transform()` method. The transform function receives a context object with file content, paths, and build options. ```ts // Simple transformation - minify JSON files copy("data/**/*.json").transform(({ content }) => { // Return content only - keeps original filename return JSON.stringify(JSON.parse(content.toString())); }); // Transform with filename change - TypeScript to JavaScript copy("scripts/**/*.ts").transform(async ({ content, path }) => { const transpiler = new Bun.Transpiler({ loader: "ts" }); // Return object to change both content and filename return { content: transpiler.transformSync(content.toString()), filename: basename(path).replace(".ts", ".js"), }; }); // Access full context including build options copy("config/**/*").transform(({ content, path, destination, options }) => { // options contains build configuration (outDir, minify, etc.) // destination is where the file will be written const processed = content .toString() .replace("__BUILD_MODE__", options.watch ? "development" : "production") .replace("__OUT_DIR__", options.outDir); return processed; }); ``` ## Options The copy plugin supports additional options via the `with()` method to customize copy behavior. ### `followSymlinks` Whether to follow symbolic links when copying files. By default, symbolic links are not followed. ```ts [bunup.config.ts] copy("assets/**/*").with({ followSymlinks: true, }); ``` ### `excludeDotfiles` Whether to exclude dotfiles (files starting with a dot) from being copied. By default, dotfiles are included in the copy operation. ```ts [bunup.config.ts] copy("assets/**/*").with({ excludeDotfiles: true, }); ``` ### `override` Whether to override existing files in the destination. By default, existing files are overwritten. ```ts [bunup.config.ts] // Skip files that already exist in the destination copy("assets/**/*").with({ override: false, }); ``` ### `watchMode` Controls the behavior of the copy plugin in watch mode. Available options: * `'changed'` (default): Only copy files that have been modified since the last build * `'always'`: Copy all files on every build, regardless of changes * `'skip'`: Skip copying entirely in watch mode ```ts [bunup.config.ts] // Only copy changed files in watch mode (default) copy("assets/**/*").with({ watchMode: "changed", }); // Always copy all files, even in watch mode copy("config/**/*").with({ watchMode: "always", }); // Skip copying in watch mode (useful for large static assets) copy("videos/**/*").with({ watchMode: "skip", }); ``` --- --- url: /docs/guide/css.md --- # CSS Bunup handles CSS automatically. Just import it and it works. ## Quick Start Import CSS in your TypeScript files: ```typescript [src/index.ts] import "./styles.css"; import { Button } from "./components/button"; export { Button }; ``` ```css [src/styles.css] .button { background-color: #007bff; color: white; padding: 8px 16px; border: none; border-radius: 4px; } ``` Bunup automatically bundles your CSS into `dist/index.css` with cross-browser compatibility. Any CSS imports encountered in your files will be bundled together into `dist/index.css`. To generate separate CSS files instead of a single `index.css` output, add them as entry points rather than importing them in your files: ```typescript [bunup.config.ts] import { defineConfig } from 'bunup'; export default defineConfig({ entry: [ 'src/index.ts', 'src/components/button.css' 'src/components/alert.css' ], }); ``` This creates individual CSS files in your build output: ```plaintext dist/ β”œβ”€β”€ index.js └── components/ β”œβ”€β”€ button.css └── alert.css ``` ## CSS Modules CSS modules prevent style conflicts by automatically scoping class names. Just add `.module.css` to your filename: ::: tip New to CSS modules? Check out [this guide](https://css-tricks.com/css-modules-part-1-need/) to learn what they are and why they're useful. ::: ```css [src/components/button.module.css] .primary { background-color: #007bff; color: white; padding: 8px 16px; border: none; border-radius: 4px; } ``` ```tsx [src/components/button.tsx] import styles from "./button.module.css"; export function Button({ children }) { return ; } ``` That's it! Bunup handles the rest automatically. ### Sharing Styles Reuse styles with the `composes` property: ```css [src/components/button.module.css] {9,15} .base { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; } .primary { composes: base; background-color: #007bff; color: white; } .secondary { composes: base; background-color: transparent; color: #007bff; border: 1px solid #007bff; } ``` **Rules:** * `composes` must come first in the class * Works only with single class selectors (not `#id` or `.class1, .class2`) **From other files:** ```css [src/components/button.module.css] {2} .primary { composes: base from "../shared.module.css"; background-color: #007bff; color: white; } ``` ::: warning Avoid conflicting properties when composing from separate files. ::: ## Distributing CSS Export CSS files for package consumers: ```json [package.json] { "exports": { ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" }, "./styles.css": "./dist/index.css" // [!code ++] } } ``` Users can then import your styles: ```javascript import "your-package/styles.css"; import { Button } from "your-package";