The ImportInjector class provides a stateful interface for managing multiple import operations with shared configuration. It's ideal for complex Babel plugins that need to inject multiple imports with consistent settings.
Creates a new ImportInjector instance with optional default configuration.
/**
* Creates a new ImportInjector instance
* @param path - Any NodePath within the program (will find the program path automatically)
* @param importedSource - Optional default imported source for all operations
* @param opts - Optional default import configuration
*/
constructor(
path: NodePath,
importedSource?: string,
opts?: Partial<ImportOptions>
);Usage Examples:
import { ImportInjector } from "@babel/helper-module-imports";
// Basic injector
const injector = new ImportInjector(path);
// With default source
const lodashInjector = new ImportInjector(path, "lodash");
// With default options
const reactInjector = new ImportInjector(path, undefined, {
importedType: "es6",
nameHint: "react"
});
// With both source and options
const utilsInjector = new ImportInjector(path, "./utils", {
importedType: "es6",
importPosition: "after"
});Adds a default import using the injector's configuration.
/**
* Adds default import using configured options
* @param importedSourceIn - The source of the import
* @param opts - Additional options (merged with instance defaults)
* @returns Identifier representing the imported default value
*/
addDefault(
importedSourceIn: string,
opts: Partial<ImportOptions>
): t.Identifier | t.MemberExpression | t.SequenceExpression;Usage Examples:
const injector = new ImportInjector(path, undefined, {
importedType: "es6",
nameHint: "lib"
});
// Uses injector's default options
const lodashId = injector.addDefault("lodash", {});
// Generates: import _lib from "lodash";
// Override specific options
const reactId = injector.addDefault("react", { nameHint: "React" });
// Generates: import _React from "react";Adds a named import using the injector's configuration.
/**
* Adds named import using configured options
* @param importName - The name of the export to import
* @param importedSourceIn - The source of the import
* @param opts - Additional options (merged with instance defaults)
* @returns Different types based on options (Identifier, MemberExpression, or SequenceExpression)
*/
addNamed(
importName: string,
importedSourceIn: string,
opts: Partial<ImportOptions>
): t.Identifier | t.MemberExpression | t.SequenceExpression;Usage Examples:
const injector = new ImportInjector(path, "lodash", {
importedType: "es6"
});
// Basic named import
const debounceId = injector.addNamed("debounce", "lodash", {});
// Generates: import { debounce as _debounce } from "lodash";
// Multiple named imports from same source (automatically merged)
const throttleId = injector.addNamed("throttle", "lodash", {});
const pickId = injector.addNamed("pick", "lodash", {});
// Generates: import { debounce as _debounce, throttle as _throttle, pick as _pick } from "lodash";Adds a namespace import using the injector's configuration.
/**
* Adds namespace import using configured options
* @param importedSourceIn - The source of the import
* @param opts - Additional options (merged with instance defaults)
* @returns Identifier representing the imported namespace
*/
addNamespace(
importedSourceIn: string,
opts: Partial<ImportOptions>
): t.Identifier | t.MemberExpression | t.SequenceExpression;Usage Examples:
const injector = new ImportInjector(path, undefined, {
importedType: "es6",
nameHint: "ns"
});
const reactId = injector.addNamespace("react", {});
// Generates: import * as _ns from "react";
const lodashId = injector.addNamespace("lodash", { nameHint: "lodash" });
// Generates: import * as _lodash from "lodash";Adds a side-effect import using the injector's configuration.
/**
* Adds side-effect import using configured options
* @param importedSourceIn - The source of the import
* @param opts - Additional options (merged with instance defaults)
* @returns Identifier representing any incidental binding (usually unused)
*/
addSideEffect(
importedSourceIn: string,
opts: Partial<ImportOptions>
): t.Identifier | t.MemberExpression | t.SequenceExpression;Usage Examples:
const injector = new ImportInjector(path, undefined, {
importedType: "es6"
});
injector.addSideEffect("reflect-metadata", {});
// Generates: import "reflect-metadata";
injector.addSideEffect("./polyfills", {});
// Generates: import "./polyfills";The ImportInjector maintains several private properties for state management:
class ImportInjector {
/** The program path used for manipulation */
private _programPath: NodePath<t.Program>;
/** The scope used to generate unique variable names */
private _programScope: Scope;
/** The file used to inject helpers and resolve paths */
private _hub: HubInterface;
/** Default options for this instance */
private _defaultOpts: ImportOptions;
}// Create injector with common configuration
const injector = new ImportInjector(path, undefined, {
importedType: "es6",
importPosition: "after",
nameHint: "imported"
});
// All operations use the shared configuration
const reactId = injector.addDefault("react", {});
const lodashNs = injector.addNamespace("lodash", {});
const debounceId = injector.addNamed("debounce", "lodash", {});const injector = new ImportInjector(path);
// ES6 imports
const reactId = injector.addDefault("react", { importedType: "es6" });
// CommonJS imports
const lodashId = injector.addDefault("lodash", {
importedType: "commonjs",
importedInterop: "babel"
});const injector = new ImportInjector(path, undefined, {
importedType: "commonjs",
importedInterop: "babel"
});
// Force live reference for dynamic values
const debounceExpr = injector.addNamed("debounce", "lodash", {
ensureLiveReference: true
});
// Result: MemberExpression that accesses the live property// Module-only: imports added after existing imports
const injector = new ImportInjector(programPath, undefined, {
importedType: "es6",
importPosition: "after"
});
// Add imports that will appear after existing imports
const newId = injector.addDefault("new-library", {});The ImportInjector throws the same errors as convenience functions:
"after" position in non-module filestry {
const injector = new ImportInjector(path, undefined, {
importedType: "es6"
});
// This may throw if the file is not a module
const id = injector.addDefault("some-module", {});
} catch (error) {
console.error("Import injection failed:", error.message);
}export default function myBabelPlugin() {
return {
visitor: {
Program(path) {
const injector = new ImportInjector(path);
// Store injector in plugin state
this.injector = injector;
},
CallExpression(path) {
if (needsLodashDebounce(path.node)) {
// Use stored injector
const debounceId = this.injector.addNamed("debounce", "lodash", {});
// Replace call with imported function
path.replaceWith(t.callExpression(debounceId, path.node.arguments));
}
}
}
};
}