Babel Import Utility
babel-import-util is a utility library designed to simplify the process of manipulating imports within Babel plugins. It provides an API for safely emitting new imported names, ensuring correct composition with other Babel plugins by updating Babel's binding understanding, and automatically deduplicating redundant imports. The library is written in TypeScript and ships with type definitions, making it well-suited for TypeScript-based plugin development. The current stable version is 3.0.1, released in March 2025, indicating active maintenance and a regular release cadence. Key differentiators include its focus on reference-aware APIs (introduced in v3.0.0) that improve safety and correctness when working with Babel's AST, and its ability to handle import deduplication and binding updates transparently, reducing boilerplate for plugin authors.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'replaceWith')
cause The `ImportUtil` instance was not properly initialized or not made available on the `state` object, leading to `state.importUtil` being `undefined` when called.fixInitialize `state.importUtil = new ImportUtil(babel, path);` within the `Program:enter` visitor method of your plugin. Ensure `babel` and `path` are correctly passed. -
ReferenceError: ImportUtil is not defined
cause The `ImportUtil` class was not imported into the plugin file, or an incorrect `require()` syntax was used in an ESM context.fixUse `import { ImportUtil } from 'babel-import-util';` at the top of your plugin file. If in a CommonJS context (though this library is ESM-first), ensure proper interop or migrate to ESM. -
Error: babel-import-util does not export a default export.
cause Attempting to import `babel-import-util` using a default import, but the library only provides named exports.fixChange `import ImportUtil from 'babel-import-util';` to `import { ImportUtil } from 'babel-import-util';`.
Warnings
- breaking Version 3.0.0 introduced 'New reference-aware APIs' which fundamentally changed how `ImportUtil` methods operate, particularly `import()`, `replaceWith`, `insertAfter`, and `insertBefore`. Code written for v2.x might not be directly compatible.
- breaking The release process for v2.1.0 was problematic; it contained a breaking change that led to v2.1.1 reverting to v2.0.3's functionality. The breaking changes from v2.1.0 were subsequently re-released as v3.0.0, causing potential confusion and unexpected behavior for users who might have upgraded to v2.1.0.
- gotcha The `ImportUtil` instance must always be instantiated within the `Program:enter` visitor method of your Babel plugin and stored on the `state` object to ensure it's available throughout the plugin's execution and correctly tracks imports across the entire file.
- gotcha The `import()` method (e.g., `i.import(target, moduleSpecifier, exportedName)`) is considered a lower-level API. Using it directly requires the plugin author to manually manage Babel's scopes and bindings, which can lead to hard-to-debug issues if not handled correctly. Higher-level methods like `replaceWith`, `insertAfter`, or `insertBefore` are generally safer.
Install
-
npm install babel-import-util -
yarn add babel-import-util -
pnpm add babel-import-util
Imports
- ImportUtil
const ImportUtil = require('babel-import-util').ImportUtil;import { ImportUtil } from 'babel-import-util'; - NodePath
import type { NodePath } from '@babel/traverse'; - t
import type * as t from '@babel/types';
Quickstart
import type { NodePath } from '@babel/traverse';
import type * as t from '@babel/types';
import { ImportUtil } from 'babel-import-util';
function testTransform(babel: { types: typeof t }) {
return {
visitor: {
Program: {
enter(path: NodePath<t.Program>, state: { importUtil?: ImportUtil }) {
// Always instantiate the ImportUtil instance at the Program scope
state.importUtil = new ImportUtil(babel, path);
}
},
CallExpression(path: NodePath<t.CallExpression>, state: { importUtil?: ImportUtil }) {
const callee = path.get('callee');
if (callee.isIdentifier() && callee.node.name === 'myTarget') {
if (!state.importUtil) {
throw new Error('ImportUtil not initialized. Ensure it is instantiated in Program:enter.');
}
state.importUtil.replaceWith(callee, (i) =>
i.import(callee, 'my-implementation', 'theMethod')
);
}
}
}
};
}