Skip to content

babel-plugin-tree-shake-imports

A babel plugin to tree-shake namespace imports.

This babel plugin helps you to use TypeScript namespaces, in particular ambient namespaces, or regular barrel files for the purpose of namespacing by tree-shaking their import declarations:

ts
// Vanilla approach:
import { getUserEmail } from "utils/user/getUserEmail";
const userEmail = getUserEmail(user);

// Using namespaces:
import { User } from "utils";
const userEmail = User.email(user);

// After transforming with babel-plugin-tree-shake-imports:
import { email as _email } from "utils/User/email";
const userEmail = email(user);

Features

  • Works for all (ESM) import specifier types, including mixed ones
  • Allows you to rewire/skip each individual imported module
  • Supports recursive destructuring

Examples

ts
import Foo from "foo";
Foo.bar;
ts
import { bar as _bar } from "foo/bar";
_bar;
ts
import { Foo } from "foo";
Foo.bar;
ts
import { bar as _bar } from "foo/bar";
_bar;
ts
import { Foo as Bar } from "foo";
Bar.bar;
ts
import { bar as _bar } from "foo/bar";
_bar;
ts
import * as Foo from "foo";
Foo.bar;
ts
import { bar as _bar } from "foo/bar";
_bar;
ts
import Foo from "foo";
Foo.bar.baz;
ts
import { baz as _baz } from "foo/bar/baz";
_baz;

Installation

sh
npm -D install @monstermann/babel-plugin-tree-shake-imports
sh
pnpm -D add @monstermann/babel-plugin-tree-shake-imports
sh
yarn -D add @monstermann/babel-plugin-tree-shake-imports
sh
bun -D add @monstermann/babel-plugin-tree-shake-imports

Usage

ts
export default {
    plugins: [["@monstermann/babel-plugin-tree-shake-imports", options]],
};
ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig(() => ({
    plugins: [
        react({
            babel: {
                plugins: [
                    ["@monstermann/babel-plugin-tree-shake-imports", options],
                ],
            },
        }),
    ],
}));

Options

ts
import { A as B } from "c";
A.d;
ts
const options = {
    resolve({
        // The path of the file being transformed: "example.ts"
        filePath,
        // The imported module: "c"
        importPath,
        // The imported identifier: "A"
        importName,
        // The local alias: "B"
        // Same as `importName` if not available.
        localName,
        // The property that was accessed: "d"
        propertyName,
        // The type of the import: "named"
        // One of: "named" | "default" | "wildcard"
        importType,
    }) {
        // Skip this import:
        return null;
        return undefined;
        return false;

        // Transform this to:
        // import { d as _d } from "c/d";
        // _d;
        return {
            type: "named",
            path: `${importPath}/${propertyName}`,
        };

        // Transform this to:
        // import { e as _d } from "c/d";
        // _d;
        return {
            type: "named",
            importName: "e",
            path: `${importPath}/${propertyName}`,
        };

        // Transform this to:
        // import _d from "c/d";
        // _d;
        return {
            type: "default",
            path: `${importPath}/${propertyName}`,
        };
    },
};

Troubleshooting

You can use the debug flag to print the individual transformations being done to each file.

ts
const options = {
    debug: true,
    resolve: () => ({ path, type }),
};