GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - webpro-nl/unbarrelify: Barrel file removal tool for JavaScript & TypeScript projects (ESM-only)

BranchesTags
Open more actions menu

Latest commit

 

History

30 Commits
30 Commits

Folders and files

NameName
Last commit message
Last commit date
.github/workflows
.github/workflows
 
 
fixtures
fixtures
 
 
scripts
scripts
 
 
src
src
 
 
test
test
 
 
.gitignore
.gitignore
 
 
.oxfmtrc.json
.oxfmtrc.json
 
 
.release-it.json
.release-it.json
 
 
README.md
README.md
 
 
knip.json
knip.json
 
 
package.json
package.json
 
 
pnpm-lock.yaml
pnpm-lock.yaml
 
 
tsconfig.json
tsconfig.json
 
 

Repository files navigation

unbarrelify

Barrel file removal tool for JavaScript & TypeScript projects (ESM-only).

What are barrel files?

Barrel files are index files that only contain re-exports from other modules:

export { formatDate } from "./date.ts";
export { formatCurrency } from "./currency.ts";
export { capitalize } from "./string.ts";

Why avoid barrel files?

Barrel files are convenient, but they often come with trade-offs including:

  • Performance and memory: they artificially inflate the module graph and slow down startup times, HMR, and CI pipelines.
  • Tree-shaking failures: they often confuse tree-shakers, risk entire libraries to be bundled when only a single function is needed.
  • Circular dependencies: they frequently create "import cycles", crashing bundlers or causing confusing errors.

Resources

  • Speeding up the JavaScript ecosystem - The barrel file debacle (Marvin Hagemeister, 2023-10-08)
  • How we optimized package imports in Next.js (Shu Ding, 2023-10-13)
  • A practical guide against barrel files for library authors (Pascal Schilp, 2024-06-01)
  • Please Stop Using Barrel Files (Dominik Dorfmeister, 2024-07-26)

Features

  • Automated rewiring of consumers to import directly from source
  • Preserves path aliases
  • Skips barrel files that are entry points (package.json#exports etc.)
  • Auto-detects or enforces file extensions to match project style
  • Optional --organize-imports to dedupe and clean up after rewrites
  • Granular control with --skip, --only or add --barrel-like files
  • Use --check for CI to fail if barrel files are detected
  • Go all out with --unsafe-namespace to namespace imports (warning: naive)
  • Verified on non-trivial repositories to not break the build/tests

Usage

Without installation

npx unbarrelify
npx unbarrelify --help

It runs safe in dry-mode until you add --write

Installation

npm install -D unbarrelify

CLI Usage

unbarrelify - Remove barrel files and rewire imports

Usage: unbarrelify [options]

Options:
  -c, --cwd <dir>         Working directory (default: ".")
  -o, --only <file>       Process only selected barrel file (can be repeated)
  -s, --skip <pattern>    Barrel files to skip (glob, can be repeated)
  -b, --barrel <pattern>  Extra files to treat as barrels (glob, can be repeated)
  -f, --files <pattern>   Set file coverage (glob, can be repeated, default: use tsconfig.json)
  -e, --ext <ext>         Extension for rewritten imports (default: auto-detect)
  -w, --write             Write changes to disk (default: false/dry-run)
      --organize-imports  Run TypeScript's "Organize Imports" after rewrites to dedupe imports
      --check, --ci       Check mode for CI; non-zero exit if there are changes
      --unsafe-namespace  Rewrite namespace imports; may include types (bad) and cause identifier collisions (also bad)
  -h, --help              Show this help message

Examples:
  unbarrelify
  unbarrelify --cwd ./src
  unbarrelify --only ./src/utils/index.ts
  unbarrelify --skip ./public-api.ts
  unbarrelify --barrel looks/like/barrel.ts
  unbarrelify --files "src/**/*.ts" --files "lib/**/*.ts"
  unbarrelify --ext .js
  unbarrelify --write
  unbarrelify --check
  unbarrelify --unsafe-namespace

Programmatic API

import { unbarrelify } from "unbarrelify";

const result = await unbarrelify({
  cwd: "./src",
  files: ["**/*.ts"],
  skip: [],
  ext: ".ts",
  write: false,
});

console.log(`Modified ${result.modified.length} files`);
console.log(`Deleted ${result.deleted.length} barrel files`);

API Reference

unbarrelify(options: Options): Promise<Result>

The main function that processes files and removes barrel files.

Options

interface Options {
  cwd: string;
  only?: string[];
  files?: string[];
  skip?: string[];
  barrel?: string[];
  ext?: string;
  write: boolean;
  check?: boolean;
  unsafeNamespace?: boolean;
  organizeImports?: boolean;
  progress?: (event: ProgressEvent) => void;
}

Result

interface Result {
  modified: string[];
  deleted: string[];
  preserved: PreservedBarrel[];
}

interface PreservedBarrel {
  path: string;
  reason: "skip" | "namespace-import" | "non-ts-import" | "dynamic-import";
  consumers: string[];
}

How does it work?

  1. Identify barrel files (files containing only re-export statements)
  2. Build import/export maps to track dependencies
  3. Rewire imports in consuming files to point directly to exporting source files
  4. Remove barrel files

Before

// utils/index.ts
export { formatDate } from "./date.ts";
export { capitalize } from "./string.ts";

// module.ts
import { formatDate, capitalize } from "./utils/index.ts";

After

// utils/index.ts - DELETED

// module.ts
import { formatDate } from "./utils/date.ts";
import { capitalize } from "./utils/string.ts";

Preserved barrel files

This prevents barrel files from getting deleted:

  • File is in package.json such as main or exports field.
  • File is index.* at root level (of each workspace).
  • File is in --skip argument.
  • Dynamic import calls are not modified, so the imported barrel file is not deleted (e.g. import("barrel.ts")).
  • Non-JS/TS files are not modified, so the imported barrel file is not deleted (e.g. *.mdx).
  • Namespace imports are not modified, use --unsafe-namespace to rewrite (e.g. import * as NS from "barrel").

The output in CLI prints "Preserved barrel files" with details.

License

ISC

About

Barrel file removal tool for JavaScript & TypeScript projects (ESM-only)

Topics

barrelcodemodesmfilesimportsrefactortypescript

Resources

Readme
Activity
Custom properties

Stars

203 stars

Watchers

2 watching

Forks

4 forks
Report repository

Releases

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.