Files
stack/packages/mosaic/framework/skills/tsdown/references/option-tree-shaking.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

5.1 KiB

Tree Shaking

Remove unused code from bundles.

Overview

Tree shaking eliminates dead code (unused exports) from your final bundle, reducing size and improving performance.

Default: Enabled

Basic Usage

CLI

# Tree shaking enabled (default)
tsdown

# Disable tree shaking
tsdown --no-treeshake

Config File

export default defineConfig({
  entry: ['src/index.ts'],
  treeshake: true, // Default
});

How It Works

With Tree Shaking

Source:

// src/util.ts
export function unused() {
  console.log("I'm unused");
}

export function hello(x: number) {
  console.log('Hello World', x);
}

// src/index.ts
import { hello } from './util';
hello(1);

Output:

// dist/index.mjs
function hello(x) {
  console.log('Hello World', x);
}
hello(1);

unused() function is removed because it's never imported.

Without Tree Shaking

Output:

// dist/index.mjs
function unused() {
  console.log("I'm unused");
}

function hello(x) {
  console.log('Hello World', x);
}
hello(1);

All code is included, even if unused.

Advanced Configuration

Enable (Default)

export default defineConfig({
  treeshake: true,
});

Uses Rolldown's default tree shaking.

Custom Options

export default defineConfig({
  treeshake: {
    moduleSideEffects: false,
    propertyReadSideEffects: false,
    unknownGlobalSideEffects: false,
  },
});

See Rolldown docs for all options.

Disable

export default defineConfig({
  treeshake: false,
});

Side Effects

Package.json sideEffects

Declare side effects in your package:

{
  "sideEffects": false
}

Or specify files with side effects:

{
  "sideEffects": ["*.css", "src/polyfills.ts"]
}

Module Side Effects

export default defineConfig({
  treeshake: {
    moduleSideEffects: (id) => {
      // Preserve side effects for polyfills
      return id.includes('polyfill');
    },
  },
});

Common Patterns

Production Build

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  treeshake: true,
  minify: true,
});

Development Build

export default defineConfig((options) => ({
  entry: ['src/index.ts'],
  treeshake: !options.watch, // Disable in dev
}));

Library with Side Effects

export default defineConfig({
  entry: ['src/index.ts'],
  treeshake: {
    moduleSideEffects: (id) => {
      return id.includes('.css') || id.includes('polyfill') || id.includes('side-effect');
    },
  },
});

Utilities Library

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  treeshake: true,
  dts: true,
});

Users can import only what they need:

import { onlyWhatINeed } from 'my-utils';

Benefits

Smaller Bundles

  • Only includes imported code
  • Removes unused functions, classes, variables
  • Reduces download size

Better Performance

  • Less code to parse
  • Faster execution
  • Improved loading times

Cleaner Output

  • No dead code in production
  • Easier to debug
  • Better maintainability

When to Disable

Debugging

During development to see all code:

export default defineConfig((options) => ({
  treeshake: !options.watch,
}));

Side Effect Code

Code with global side effects:

// This has side effects
window.myGlobal = {};

export function setup() {
  // ...
}

Disable tree shaking or mark side effects:

{
  "sideEffects": true
}

Testing

Include all code for coverage:

export default defineConfig({
  treeshake: false,
});

Tips

  1. Leave enabled for production builds
  2. Mark side effects in package.json
  3. Use with minification for best results
  4. Test tree shaking - verify unused code is removed
  5. Disable for debugging if needed
  6. Pure functions are easier to tree shake

Troubleshooting

Code Still Included

  • Check for side effects
  • Verify imports are ES modules
  • Ensure code is actually unused
  • Check sideEffects in package.json

Missing Code at Runtime

  • Code has side effects but marked as none
  • Set sideEffects: true or list specific files

Unexpected Behavior

  • Module has side effects not declared
  • Try disabling tree shaking to isolate issue

Examples

Pure Utility Functions

// utils.ts - perfect for tree shaking
export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

// Only 'add' imported = only 'add' bundled
import { add } from './utils';

With Side Effects

// polyfill.ts - has side effects
if (!Array.prototype.at) {
  Array.prototype.at = function (index) {
    // polyfill implementation
  };
}

export {}; // Need to export something
{
  "sideEffects": ["src/polyfill.ts"]
}