eslint-plugin-better-tree-shaking

ESLint plugin to improve tree-shaking of TypeScript code

When bundlers like Webpack, Rollup, or esbuild encounter top-level side effects, they can't safely remove unused code. This plugin detects these patterns and suggests annotating them with /* @__PURE__ */ comments to enable better tree-shaking.

The /* @__PURE__ */ annotation tells the bundler this call has no side effects and can be safely removed if result is unused.

Function Calls

Calling a function at the top level is a side effect because the bundler doesn't know if the function modifies global state.

import { createConfig } from './config';

// ❌
export const config = createConfig();

// ✅
export const config = /* @__PURE__ */ createConfig();

Method Calls

Same applies to method calls - the bundler can't know if obj.method() has side effects.

import Logger from './logger';

// ❌
export const logger = Logger.create();

// ✅
export const logger = /* @__PURE__ */ Logger.create();

Property Access Chains

Accessing nested properties like foo.bar.bazz can trigger getters, which are side effects. Wrap in an IIFE to mark as pure.

import settings from './settings';

// ❌
export const theme = settings.ui.theme;

// ✅
export const theme = /* @__PURE__ */ (() => settings.ui.theme)();

Objects with Side Effects

When an object contains multiple expressions with side effects (calls, computed keys), wrap the entire object in a pure IIFE.

import { getDefault, KEYS } from './utils';

// ❌
export const defaults = {
  value: getDefault(),
  [KEYS.primary]: getDefault('primary'),
};

// ✅
export const defaults = /* @__PURE__ */ (() => ({
  value: getDefault(),
  [KEYS.primary]: getDefault('primary'),
}))();

Usage

Install the eslint-plugin-better-tree-shaking package, add it to the plugins section of your ESLint configuration file, and enable thebetter-tree-shaking/no-top-level-side-effects rule in the rules section.

{
  "plugins": ["better-tree-shaking"],
  "rules": {
    "better-tree-shaking/no-top-level-side-effects": "error"
  }
}
© 2026/Manan Tank