bunchee

repository·main·Indexed 23 days ago

https://github.com/huozhi/bunchee

A zero-configuration bundler for JS/TS/JSX libraries that uses the `exports` field in `package.json` as the source of truth to generate CommonJS and ESModule outputs. Powered by Rollup and SWC, bunchee 7.0.0 supports TypeScript 5, 6, and 7 (via @typescript/typescript6), and requires Node.js 22.12 or newer. It features built-in support for path aliases, shared modules via underscore prefixes, and non-JS assets like CSS and text files.

Tokens
5.9K
Snippets
17
Records
50
Agent score
77%

What's inside bunchee

  1. Understand Output Formats and Extensions

    main

    Bunchee detects the output format based on the package.json field or the file extension.

    Mapping package.json fields to formats

    • main or exports: Default format
    • types or exports.types: TypeScript declaration
    • exports.require: CommonJS
    • exports.import: Default
    • bin: Default

    Default format by extension

    • .js: Determined by package.json#type (CommonJS by default)
    • .cjs: Always CommonJS
    • .mjs: Always ECMAScript Modules
  2. How bunchee determines entry files

    main
    Bunchee adheres to the exports field in your package.json. It automatically aligns entry file conventions with your defined exports, ensuring that the generated output matches your package's intended public API. This allows for a zero-configuration workflow where the bundler understands which files to process based on standard Node.js resolution logic.
  3. Understand bunchee 7 output chunks

    main

    bunchee 7 uses a shared module graph to build entries. This approach:

    • Avoids rebuilding common modules.
    • Improves declaration performance.
    • Keeps directive layers (such as use client, use server, and use cache) separate.

    Note for consumers: If your package inspects generated chunk names, treat these names as build artifacts. You should update any snapshots after migrating to bunchee 7.

  4. Use Shared Modules with Underscore Prefix

    main

    To share a chunk across multiple bundles (e.g., a single instance of React context or shared utils) without making them public entry points, prefix the file or directory with an underscore (_).

    Files like src/_util.js or src/_components/** are treated as shared modules. Bunchee will bundle them into a separate private chunk that is referenced by multiple entry bundles, ensuring they remain a single instance across different runtime bundles.

    // src/_util.js
    export function sharedUtil() { ... }
    
    // src/index.js
    import { sharedUtil } from './_util'
  5. Quick Start with bunchee

    main

    Bunchee is a zero-config bundler that uses your package.json exports field as the single source of truth for entry points.

    To get started:

    1. Install bunchee and typescript.
    2. Define your package metadata and entry points in package.json.
    3. Run the bunchee command via your build script.
    {
      "name": "coffee",
      "type": "module",
      "main": "./dist/index.js",
      "scripts": {
        "build": "bunchee"
      }
    }
  6. Import CSS and Text Files

    main

    Bunchee provides built-in support for importing non-JS assets:

    CSS

    Importing .css files will bundle the CSS into the JS bundle and automatically insert a <style> tag into the document head at runtime.

    Text and Data Files

    • Files with .txt or .data extensions are bundled as string content.
    • You can use the ?raw query parameter to import any file type as raw text content.
    // Bundles as string content
    import data from './data.txt'
    
    // Raw import for any file type
    import readme from './README.md?raw'
    import config from './config.json?raw'
  7. Configure Entry Files and Exports

    main

    Bunchee uses files in your src directory as entry points. It automatically matches these files to the exports field in your package.json.

    For example, src/index.ts matches the . export, src/lite.ts matches ./lite, and src/react/index.ts matches ./react.

    Wildcard Exports

    You can use wildcard patterns in the exports field to automatically generate exports for multiple files. The * is substituted in both the export path and the output path.

    {
      "exports": {
        ".": "./dist/index.js",
        "./features/*": "./dist/features/*.js"
      }
    }
  8. Build Binary CLI Executables

    main

    To build executable files defined in the bin field of package.json, create a bin directory under src/. The source file matching follows the same convention as entry files.

    For multiple binaries, the filename under src/bin/ must match the key name in the bin field.

    // package.json
    {
      "bin": {
        "foo": "./dist/bin/a.js",
        "bar": "./dist/bin/b.js"
      }
    }

    Directory structure:

    |- src/
      |- bin/
        |- a.ts
        |- b.ts
  9. Manage External Dependencies

    main

    By default, dependencies and peerDependencies are marked as external and will not be included in the bundle.

    • To include them in the bundle, use the --no-external CLI option.
    • Alternatively, you can import devDependencies in your source code to have them bundled.
    • You can also manually specify extra external dependencies using --external=dep1,dep2.
  10. Configure Path Aliases

    main

    Bunchee supports path aliasing via TypeScript paths configuration or the Node.js imports field in package.json. It will resolve these aliases to the correct file paths during bundling.

    // package.json
    {
      "imports": {
        "#util": "./src/utils.ts"
      }
    }
  11. Use ESM imports for bunchee 7

    main

    The bunchee package is now an ESM-only package. If you are consuming the bunchee Node.js API, you must replace CommonJS require statements with ESM import statements.

    -const { bundle } = require('bunchee')
    +import { bundle } from 'bunchee'
  12. Run Bunchee benchmarks

    main

    Bunchee includes a benchmark harness that generates temporary TypeScript packages and invokes dist/bin/cli.js directly. This method avoids npx, network access, or package-manager startup overhead in measurements.

    By default, the harness preserves output between runs to focus measurements on build work. To include the removal of previous output in the measurement, pass the --clean flag.

    Each scenario validates expected files and records a SHA-256 digest of the complete output. The report provides metrics including median and p95 wall time, CPU time, maximum resident memory, JS and declaration graph time (which includes TypeScript Program setup), and output writes.

    # Build Bunchee, then benchmark 1, 8, and 57-entry packages.
    pnpm benchmark
    
    # A quick smoke run.
    pnpm benchmark -- --entries 1 --iterations 1 --warmup 0
    
    # Include the larger worker-threshold fixture.
    pnpm benchmark -- --entries 57,256 --iterations 10
    
    # Preserve a JSON report without the preceding build command's output.
    pnpm build
    node ./scripts/benchmark.js --entries 57,256 --iterations 10 --json > benchmark.json