In this article, we will analyze why Rollup's tree-shaking may fail, explore debugging techniques, and provide best practices to ensure optimal bundle size reduction.

Understanding Tree-Shaking Failures in Rollup

Tree-shaking is an optimization technique that removes unused code from the final bundle. However, certain coding patterns, library dependencies, or improper Rollup configurations can prevent tree-shaking from working effectively.

Common Causes

  • Using CommonJS modules instead of ES modules.
  • Side-effect-heavy dependencies that prevent elimination.
  • Incorrect package.json settings, such as missing "module" fields.
  • Improper rollup.config.js settings preventing dead code removal.

Common Symptoms

  • Unexpectedly large output bundles.
  • Unused code still appearing in the final build.
  • Third-party libraries remaining in the bundle despite not being used.

Diagnosing Tree-Shaking Issues

1. Inspecting the Generated Bundle

Use the treeshake option and analyze the bundle contents:

rollup --config --treeshake --visualize

2. Checking for Unshaken Imports

Manually inspect the bundle output to see if unused modules persist:

grep "unused" dist/bundle.js

3. Enabling Debug Mode

Modify rollup.config.js to enable verbose logging:

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'es'
  },
  treeshake: true,
  onwarn (warning, warn) {
    if (warning.code === 'UNUSED_EXTERNAL_IMPORT') return;
    warn(warning);
  }
};

Fixing Tree-Shaking Failures

Solution 1: Enforcing ES Module Imports

Ensure dependencies use ES modules instead of CommonJS:

import { myFunction } from 'myLibrary';

Instead of:

const myFunction = require('myLibrary');

Solution 2: Configuring package.json Correctly

Ensure the package.json file has a valid module field:

{
  "name": "my-package",
  "main": "dist/index.js",
  "module": "dist/index.esm.js"
}

Solution 3: Using external to Exclude Unused Dependencies

Modify rollup.config.js to exclude unused external modules:

export default {
  input: 'src/index.js',
  external: ['lodash', 'moment'],
  output: {
    file: 'dist/bundle.js',
    format: 'es'
  }
};

Solution 4: Avoiding Side-Effect Imports

Some libraries have side effects that prevent tree-shaking. Use named imports:

import { specificFunction } from 'lodash-es';

Instead of:

import * as _ from 'lodash';

Best Practices for Tree-Shaking Optimization

  • Prefer ES module imports over CommonJS (import instead of require).
  • Check package.json for a valid module field.
  • Use rollup-plugin-terser to remove dead code.
  • Manually inspect bundle output using rollup --visualize.
  • Use named imports instead of wildcard imports to avoid side effects.

Conclusion

Tree-shaking failures in Rollup can significantly impact bundle size and performance. By enforcing ES module imports, configuring package.json correctly, and excluding unused dependencies, developers can optimize their Rollup builds for better efficiency.

FAQ

1. Why is Rollup not removing unused code?

Common reasons include using CommonJS modules, side-effect-heavy dependencies, or improper Rollup configurations.

2. How do I check if tree-shaking is working?

Use rollup --config --treeshake --visualize to inspect the bundle and verify unused code removal.

3. Can Rollup tree-shake CommonJS modules?

By default, Rollup struggles with CommonJS modules. Use rollup-plugin-commonjs to improve compatibility.

4. How do I reduce bundle size in Rollup?

Ensure dependencies support ES modules, remove unused imports, and use rollup-plugin-terser for minification.

5. What is the best way to handle third-party libraries in Rollup?

Use named imports to avoid unnecessary code inclusion and configure external in rollup.config.js to exclude large dependencies.