A powerful and lightweight inversion of control container for JavaScript and Node.js apps powered by TypeScript.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
InversifyJS provides a module system for organizing and packaging related service bindings into reusable units. Container modules allow you to group related configurations, support dynamic loading/unloading, and enable modular application architecture.
class ContainerModule {
constructor(
registry: (
bind: BindFunction,
unbind: UnbindFunction,
isBound: IsBoundFunction,
rebind: RebindFunction
) => void
);
}
type BindFunction = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindInFluentSyntax<T>;
type UnbindFunction = (serviceIdentifier: ServiceIdentifier) => void;
type IsBoundFunction = (serviceIdentifier: ServiceIdentifier) => boolean;
type RebindFunction = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindInFluentSyntax<T>;interface ContainerModuleLoadOptions {
skipDeactivation?: boolean;
}import { ContainerModule } from "inversify";
// Create a module for authentication services
const authModule = new ContainerModule((bind) => {
bind<IAuthService>("AuthService").to(JwtAuthService).inSingletonScope();
bind<ITokenService>("TokenService").to(JwtTokenService).inSingletonScope();
bind<IPasswordService>("PasswordService").to(BcryptPasswordService).inSingletonScope();
bind<IUserRepository>("UserRepository").to(DatabaseUserRepository).inSingletonScope();
});
// Load the module
container.load(authModule);const databaseModule = new ContainerModule((bind, unbind, isBound, rebind) => {
// Conditional binding
if (!isBound("DatabaseConnection")) {
bind<IDatabaseConnection>("DatabaseConnection")
.to(PostgreSQLConnection)
.inSingletonScope();
}
// Repository bindings
bind<IUserRepository>("UserRepository").to(DatabaseUserRepository);
bind<IProductRepository>("ProductRepository").to(DatabaseProductRepository);
bind<IOrderRepository>("OrderRepository").to(DatabaseOrderRepository);
// Rebind if testing environment
if (process.env.NODE_ENV === "test") {
rebind<IDatabaseConnection>("DatabaseConnection").to(InMemoryConnection);
}
// Clean up any existing cache bindings
if (isBound("Cache")) {
unbind("Cache");
}
bind<ICache>("Cache").to(RedisCache).inSingletonScope();
});const infrastructureModule = new ContainerModule((bind) => {
// Logging
bind<ILogger>("Logger").to(WinstonLogger).inSingletonScope();
// Configuration
bind<IConfigService>("ConfigService").to(EnvironmentConfigService).inSingletonScope();
// Caching
bind<ICache>("Cache").to(RedisCache).inSingletonScope();
// Message Queue
bind<IMessageQueue>("MessageQueue").to(RabbitMQService).inSingletonScope();
// Health Monitoring
bind<IHealthCheckService>("HealthCheck").to(HealthCheckService).inSingletonScope();
});const businessModule = new ContainerModule((bind) => {
// Domain Services
bind<IUserService>("UserService").to(UserService);
bind<IProductService>("ProductService").to(ProductService);
bind<IOrderService>("OrderService").to(OrderService);
bind<IPaymentService>("PaymentService").to(PaymentService);
// Business Rules
bind<IPricingEngine>("PricingEngine").to(DynamicPricingEngine).inSingletonScope();
bind<IInventoryManager>("InventoryManager").to(InventoryManager).inSingletonScope();
bind<INotificationService>("NotificationService").to(EmailNotificationService);
});const dataModule = new ContainerModule((bind) => {
// Database Connection
bind<IDatabaseConnection>("DatabaseConnection")
.toDynamicValue(() => {
const config = container.get<IConfigService>("ConfigService");
return new PostgreSQLConnection(config.getDatabaseUrl());
})
.inSingletonScope();
// Repositories
bind<IUserRepository>("UserRepository").to(UserRepository);
bind<IProductRepository>("ProductRepository").to(ProductRepository);
bind<IOrderRepository>("OrderRepository").to(OrderRepository);
// Query Builders
bind<IQueryBuilder>("QueryBuilder").to(SqlQueryBuilder);
// Migrations
bind<IMigrationService>("MigrationService").to(MigrationService);
});const externalServicesModule = new ContainerModule((bind) => {
// Payment Processors
bind<IPaymentProcessor>("PaymentProcessor")
.to(StripePaymentProcessor)
.whenTargetTagged("provider", "stripe");
bind<IPaymentProcessor>("PaymentProcessor")
.to(PayPalPaymentProcessor)
.whenTargetTagged("provider", "paypal");
// Email Service
bind<IEmailService>("EmailService").to(SendGridEmailService).inSingletonScope();
// SMS Service
bind<ISmsService>("SmsService").to(TwilioSmsService).inSingletonScope();
// File Storage
bind<IFileStorage>("FileStorage").to(S3FileStorage).inSingletonScope();
// Analytics
bind<IAnalyticsService>("AnalyticsService").to(GoogleAnalyticsService).inSingletonScope();
});// Load multiple modules at once
container.load(
infrastructureModule,
dataModule,
businessModule,
externalServicesModule
);
// Load modules sequentially
container.load(infrastructureModule);
container.load(dataModule);
container.load(businessModule);// Load modules asynchronously
await container.loadAsync(
infrastructureModule,
dataModule,
businessModule
);
// Individual async loading
await container.loadAsync(infrastructureModule);
await container.loadAsync(dataModule);// Unload specific modules
container.unload(externalServicesModule);
// Unload multiple modules
container.unload(businessModule, dataModule);
// Async unloading
await container.unloadAsync(externalServicesModule);// Environment-based module loading
if (process.env.NODE_ENV === "production") {
container.load(productionModule);
} else if (process.env.NODE_ENV === "test") {
container.load(testModule);
} else {
container.load(developmentModule);
}
// Feature-based module loading
if (process.env.FEATURE_ANALYTICS === "enabled") {
container.load(analyticsModule);
}
if (process.env.FEATURE_PREMIUM === "enabled") {
container.load(premiumFeaturesModule);
}// Base module with common bindings
const baseModule = new ContainerModule((bind) => {
bind<ILogger>("Logger").to(ConsoleLogger);
bind<IConfigService>("ConfigService").to(ConfigService).inSingletonScope();
});
// Development overrides
const developmentModule = new ContainerModule((bind, unbind, isBound, rebind) => {
rebind<ILogger>("Logger").to(VerboseLogger);
bind<IMockService>("MockService").to(MockService).inSingletonScope();
// Override email service with mock
if (isBound("EmailService")) {
rebind<IEmailService>("EmailService").to(MockEmailService);
} else {
bind<IEmailService>("EmailService").to(MockEmailService);
}
});
// Production overrides
const productionModule = new ContainerModule((bind, unbind, isBound, rebind) => {
rebind<ILogger>("Logger").to(WinstonLogger);
bind<IMetricsService>("MetricsService").to(PrometheusMetricsService).inSingletonScope();
bind<IEmailService>("EmailService").to(SendGridEmailService).inSingletonScope();
});
// Load based on environment
container.load(baseModule);
if (process.env.NODE_ENV === "production") {
container.load(productionModule);
} else {
container.load(developmentModule);
}interface IPlugin {
name: string;
initialize(): void;
destroy(): void;
}
// Plugin registry
const pluginRegistry = new Map<string, ContainerModule>();
// Register plugin
function registerPlugin(name: string, pluginModule: ContainerModule) {
pluginRegistry.set(name, pluginModule);
}
// Analytics plugin
const analyticsPlugin = new ContainerModule((bind) => {
bind<IPlugin>("Plugin").to(AnalyticsPlugin).whenTargetNamed("analytics");
bind<IAnalyticsService>("AnalyticsService").to(GoogleAnalyticsService).inSingletonScope();
});
registerPlugin("analytics", analyticsPlugin);
// Load enabled plugins
const enabledPlugins = process.env.ENABLED_PLUGINS?.split(",") || [];
for (const pluginName of enabledPlugins) {
const plugin = pluginRegistry.get(pluginName);
if (plugin) {
container.load(plugin);
}
}// Main application modules
const appModule = new ContainerModule((bind) => {
bind<IUserService>("UserService").to(UserService);
bind<IEmailService>("EmailService").to(SmtpEmailService);
bind<IPaymentService>("PaymentService").to(StripePaymentService);
});
// Test overrides module
const testModule = new ContainerModule((bind, unbind, isBound, rebind) => {
// Override with mock implementations
rebind<IEmailService>("EmailService").to(MockEmailService);
rebind<IPaymentService>("PaymentService").to(MockPaymentService);
// Add test-specific services
bind<ITestDataService>("TestDataService").to(TestDataService).inSingletonScope();
});
// In test setup
container.load(appModule);
container.load(testModule); // Overrides production services// Core module - must be loaded first
const coreModule = new ContainerModule((bind) => {
bind<ILogger>("Logger").to(WinstonLogger).inSingletonScope();
bind<IConfigService>("ConfigService").to(ConfigService).inSingletonScope();
});
// Database module - depends on core
const databaseModule = new ContainerModule((bind, unbind, isBound) => {
if (!isBound("ConfigService")) {
throw new Error("Database module requires core module to be loaded first");
}
bind<IDatabaseConnection>("DatabaseConnection")
.toDynamicValue((context) => {
const config = context.container.get<IConfigService>("ConfigService");
return new DatabaseConnection(config.getDatabaseUrl());
})
.inSingletonScope();
});
// Proper loading order
container.load(coreModule); // Load core first
container.load(databaseModule); // Then database module// Group related services together
const userModule = new ContainerModule((bind) => {
// User domain services
bind<IUserService>("UserService").to(UserService);
bind<IUserRepository>("UserRepository").to(UserRepository);
bind<IUserValidator>("UserValidator").to(UserValidator);
bind<IPasswordHasher>("PasswordHasher").to(BcryptHasher);
});
// Keep modules focused and cohesive
const emailModule = new ContainerModule((bind) => {
bind<IEmailService>("EmailService").to(EmailService);
bind<IEmailTemplateService>("EmailTemplateService").to(EmailTemplateService);
bind<IEmailQueueService>("EmailQueueService").to(EmailQueueService);
});/**
* Authentication Module
*
* Provides all services related to user authentication and authorization.
*
* Services provided:
* - IAuthService: Main authentication service
* - ITokenService: JWT token management
* - IPasswordService: Password hashing and validation
* - IUserRepository: User data persistence
*
* Dependencies:
* - Requires ConfigService from core module
* - Requires Logger from infrastructure module
*
* @example
* ```typescript
* container.load(coreModule);
* container.load(infrastructureModule);
* container.load(authModule);
* ```
*/
const authModule = new ContainerModule((bind, unbind, isBound) => {
// Validate dependencies
if (!isBound("ConfigService")) {
throw new Error("Auth module requires ConfigService");
}
if (!isBound("Logger")) {
throw new Error("Auth module requires Logger");
}
bind<IAuthService>("AuthService").to(JwtAuthService).inSingletonScope();
bind<ITokenService>("TokenService").to(JwtTokenService).inSingletonScope();
bind<IPasswordService>("PasswordService").to(BcryptPasswordService).inSingletonScope();
bind<IUserRepository>("UserRepository").to(DatabaseUserRepository).inSingletonScope();
});