Vitus Labs
Tools Rolldown

Tools Rolldown

Rolldown-based build tool for library packages — ESM/CJS/UMD output with DTS generation and platform globals.

@vitus-labs/tools-rolldown is the primary build tool for the vitus-labs ecosystem. It uses Rolldown (a Rust-based bundler) to produce optimized library bundles with automatic TypeScript declaration generation.

Installation

npm install @vitus-labs/tools-rolldown

Quick Start

Add a build script to your package.json:

{
  "scripts": {
    "build": "vl_rolldown_build"
  }
}

Run it:

bun run build

The tool reads your package.json fields (main, module, exports) and generates the appropriate output files in lib/.

How It Works

  1. Reads package.json to determine output formats and entry points
  2. Loads config from vl-tools.config.mjs (via tools-core)
  3. Generates a build pipeline based on exports/main/module fields
  4. Bundles with Rolldown, generates DTS with rolldown-plugin-dts
  5. Injects platform globals (__WEB__, __NATIVE__, etc.)
  6. Outputs source maps, file size stats, and bundle visualization

CLI Commands

vl_rolldown_build

Production build — generates all output formats defined in package.json.

vl_rolldown_build

vl_rolldown_watch

Watch mode — rebuilds on file changes (development).

vl_rolldown_watch

Configuration

Configure via vl-tools.config.mjs under the build key:

// vl-tools.config.mjs
export default {
  build: {
    sourceDir: 'src',           // Input directory (default: 'src')
    outputDir: 'lib',           // Output directory (default: 'lib')
    replaceGlobals: true,       // Inject platform globals (default: true)
    typescript: true,           // Generate .d.ts files (default: true)
    filesize: true,             // Show file sizes in console (default: true)
    visualise: {                // Bundle visualization
      template: 'network',     // 'network' | 'treemap' | 'sunburst'
      gzipSize: true,
      outputDir: 'analysis',
    },
    external: ['react/jsx-runtime'],  // Additional external packages
    exclude: [                  // Patterns to exclude from bundle
      'lib', 'node_modules/**',
      '**/__tests__/**', '**/__stories__/**',
      '*.test.*', '*.stories.*',
    ],
  },
}

Output Format Detection

The tool reads your package.json to determine what to build:

exports Field (Preferred)

{
  "exports": {
    ".": {
      "import": "./lib/index.js",
      "require": "./lib/index.cjs",
      "types": "./lib/index.d.ts"
    }
  }
}
ConditionFormatPlatform
importESMuniversal
requireCJSuniversal
nodeESMnode
defaultESMuniversal

main / module Fields (Fallback)

{
  "main": "lib/index.cjs",
  "module": "lib/index.js"
}
  • main → CJS (or ESM if type: "module")
  • module → ESM
  • react-native → ESM with native platform

Browser Field

If browser differs from main, separate builds are generated:

{
  "main": "lib/index.js",
  "browser": {
    "./lib/index.js": "./lib/browser.js"
  }
}

Platform Globals

When replaceGlobals: true (default), these constants are injected at build time:

GlobalTypeDescription
__VERSION__stringPackage version from package.json
__WEB__booleantrue for web/node/browser platforms
__NATIVE__booleantrue for React Native
__BROWSER__booleantrue for browser-only
__NODE__booleantrue for Node.js
__CLIENT__booleantrue for browser + native

Platform assignment depends on the build variant:

Platform__WEB____NATIVE____BROWSER____NODE____CLIENT__
universal
browsertruefalsetruefalsetrue
nodetruefalsefalsetruefalse
nativefalsetruefalsefalsetrue
webtruefalsefalsefalsefalse

Type Generation

When typescript: true, the first build in the pipeline generates a rolled-up .d.ts file using rolldown-plugin-dts. The output path is read from package.json:

{
  "exports": {
    ".": {
      "types": "./lib/index.d.ts"
    }
  }
}

Only one .d.ts file is generated per build (for the first build variant).

External Dependencies

All dependencies and peerDependencies from package.json are automatically marked as external (not bundled). Additional externals can be added via config:

export default {
  build: {
    external: ['react/jsx-runtime', 'some-other-package'],
  },
}

Bundle Visualization

When visualise is configured, an interactive HTML visualization is generated:

lib/analysis/index.html

Templates: 'network' (default), 'treemap', 'sunburst'

Advanced Build Options

For non-library builds such as Chrome extensions, CLI tools, serverless functions, or Electron apps, you can bypass the package.json-driven pipeline with explicit configuration:

// vl-tools.config.mjs
export default {
  build: {
    // Explicit entries — skips package.json field detection
    entries: [
      { input: 'src/background.ts', file: 'dist/background.js', format: 'iife', env: 'production' },
      { input: 'src/content.ts', file: 'dist/content.js', format: 'iife' },
      { input: 'src/popup.ts', file: 'dist/popup.js', format: 'es' },
    ],

    // Bundle all dependencies (no externals)
    bundleAll: true,

    // Copy static assets after build
    copyFiles: [
      { from: 'src/manifest.json', to: 'dist/manifest.json' },
      { from: 'src/popup.html', to: 'dist/popup.html' },
    ],

    // Inject text at top/bottom of output
    banner: '#!/usr/bin/env node',
    footer: '// Built with @vitus-labs/tools-rolldown',

    // Resolve aliases
    alias: {
      '@': './src',
    },

    // Custom rolldown plugins (appended to built-in ones)
    plugins: [],

    // Disable declarations for non-library builds
    typescript: false,
  },
}
OptionTypeDefaultDescription
entriesArray<{ input, file, format?, env?, platform? }>undefinedExplicit entry points (bypasses package.json detection)
bundleAllbooleanfalseBundle all dependencies instead of externalizing
copyFilesArray<{ from, to }>undefinedCopy static files/directories after build
bannerstringundefinedText injected at the top of each output file
footerstringundefinedText injected at the bottom of each output file
aliasRecord<string, string>undefinedResolve aliases for import remapping
pluginsRolldownPlugin[][]Custom plugins appended to built-in ones

Entry Format Options

Each entry in the entries array supports:

FieldRequiredDefaultValues
inputyesSource file path (e.g., 'src/index.ts')
fileyesOutput file path (e.g., 'dist/index.js')
formatno'es''es', 'cjs', 'umd', 'iife'
envno'development''development', 'production'
platformno'universal''universal', 'browser', 'node', 'native'

Use Cases

  • Chrome extensions — multiple IIFE entries, bundleAll: true, copyFiles for manifest/HTML
  • CLI tools — single entry, banner: '#!/usr/bin/env node', bundleAll: true
  • AWS Lambda — single entry, bundleAll: true, env: 'production'
  • Electron — separate entries for main (node) and renderer (browser)
  • Web Workers — IIFE or ES entry alongside the main app

Build Pipeline

The tool generates multiple builds sequentially. A typical library with ESM + CJS + types produces:

[1/2] Creating build: lib/index.js (ES Module)
[2/2] Creating build: lib/index.cjs (CommonJS)

Each build:

  1. Resolves node modules with platform-specific extensions
  2. Replaces platform globals
  3. Generates source maps
  4. Reports file sizes
  5. Produces visualization (first build only)

On this page