or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binding.mdconditional.mdcontainer.mddecorators.mdindex.mdlifecycle.mdmodules.md
tile.json

modules.mddocs/

0

# Module System

1

2

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.

3

4

## ContainerModule Class

5

6

```typescript { .api }

7

class ContainerModule {

8

constructor(

9

registry: (

10

bind: BindFunction,

11

unbind: UnbindFunction,

12

isBound: IsBoundFunction,

13

rebind: RebindFunction

14

) => void

15

);

16

}

17

18

type BindFunction = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindInFluentSyntax<T>;

19

type UnbindFunction = (serviceIdentifier: ServiceIdentifier) => void;

20

type IsBoundFunction = (serviceIdentifier: ServiceIdentifier) => boolean;

21

type RebindFunction = <T>(serviceIdentifier: ServiceIdentifier<T>) => BindInFluentSyntax<T>;

22

```

23

24

## Module Loading Options

25

26

```typescript { .api }

27

interface ContainerModuleLoadOptions {

28

skipDeactivation?: boolean;

29

}

30

```

31

32

## Basic Module Creation

33

34

### Simple Module

35

36

```typescript

37

import { ContainerModule } from "inversify";

38

39

// Create a module for authentication services

40

const authModule = new ContainerModule((bind) => {

41

bind<IAuthService>("AuthService").to(JwtAuthService).inSingletonScope();

42

bind<ITokenService>("TokenService").to(JwtTokenService).inSingletonScope();

43

bind<IPasswordService>("PasswordService").to(BcryptPasswordService).inSingletonScope();

44

bind<IUserRepository>("UserRepository").to(DatabaseUserRepository).inSingletonScope();

45

});

46

47

// Load the module

48

container.load(authModule);

49

```

50

51

### Module with All Registry Functions

52

53

```typescript

54

const databaseModule = new ContainerModule((bind, unbind, isBound, rebind) => {

55

// Conditional binding

56

if (!isBound("DatabaseConnection")) {

57

bind<IDatabaseConnection>("DatabaseConnection")

58

.to(PostgreSQLConnection)

59

.inSingletonScope();

60

}

61

62

// Repository bindings

63

bind<IUserRepository>("UserRepository").to(DatabaseUserRepository);

64

bind<IProductRepository>("ProductRepository").to(DatabaseProductRepository);

65

bind<IOrderRepository>("OrderRepository").to(DatabaseOrderRepository);

66

67

// Rebind if testing environment

68

if (process.env.NODE_ENV === "test") {

69

rebind<IDatabaseConnection>("DatabaseConnection").to(InMemoryConnection);

70

}

71

72

// Clean up any existing cache bindings

73

if (isBound("Cache")) {

74

unbind("Cache");

75

}

76

77

bind<ICache>("Cache").to(RedisCache).inSingletonScope();

78

});

79

```

80

81

## Module Categories and Examples

82

83

### Infrastructure Module

84

85

```typescript

86

const infrastructureModule = new ContainerModule((bind) => {

87

// Logging

88

bind<ILogger>("Logger").to(WinstonLogger).inSingletonScope();

89

90

// Configuration

91

bind<IConfigService>("ConfigService").to(EnvironmentConfigService).inSingletonScope();

92

93

// Caching

94

bind<ICache>("Cache").to(RedisCache).inSingletonScope();

95

96

// Message Queue

97

bind<IMessageQueue>("MessageQueue").to(RabbitMQService).inSingletonScope();

98

99

// Health Monitoring

100

bind<IHealthCheckService>("HealthCheck").to(HealthCheckService).inSingletonScope();

101

});

102

```

103

104

### Business Logic Module

105

106

```typescript

107

const businessModule = new ContainerModule((bind) => {

108

// Domain Services

109

bind<IUserService>("UserService").to(UserService);

110

bind<IProductService>("ProductService").to(ProductService);

111

bind<IOrderService>("OrderService").to(OrderService);

112

bind<IPaymentService>("PaymentService").to(PaymentService);

113

114

// Business Rules

115

bind<IPricingEngine>("PricingEngine").to(DynamicPricingEngine).inSingletonScope();

116

bind<IInventoryManager>("InventoryManager").to(InventoryManager).inSingletonScope();

117

bind<INotificationService>("NotificationService").to(EmailNotificationService);

118

});

119

```

120

121

### Data Access Module

122

123

```typescript

124

const dataModule = new ContainerModule((bind) => {

125

// Database Connection

126

bind<IDatabaseConnection>("DatabaseConnection")

127

.toDynamicValue(() => {

128

const config = container.get<IConfigService>("ConfigService");

129

return new PostgreSQLConnection(config.getDatabaseUrl());

130

})

131

.inSingletonScope();

132

133

// Repositories

134

bind<IUserRepository>("UserRepository").to(UserRepository);

135

bind<IProductRepository>("ProductRepository").to(ProductRepository);

136

bind<IOrderRepository>("OrderRepository").to(OrderRepository);

137

138

// Query Builders

139

bind<IQueryBuilder>("QueryBuilder").to(SqlQueryBuilder);

140

141

// Migrations

142

bind<IMigrationService>("MigrationService").to(MigrationService);

143

});

144

```

145

146

### External Services Module

147

148

```typescript

149

const externalServicesModule = new ContainerModule((bind) => {

150

// Payment Processors

151

bind<IPaymentProcessor>("PaymentProcessor")

152

.to(StripePaymentProcessor)

153

.whenTargetTagged("provider", "stripe");

154

155

bind<IPaymentProcessor>("PaymentProcessor")

156

.to(PayPalPaymentProcessor)

157

.whenTargetTagged("provider", "paypal");

158

159

// Email Service

160

bind<IEmailService>("EmailService").to(SendGridEmailService).inSingletonScope();

161

162

// SMS Service

163

bind<ISmsService>("SmsService").to(TwilioSmsService).inSingletonScope();

164

165

// File Storage

166

bind<IFileStorage>("FileStorage").to(S3FileStorage).inSingletonScope();

167

168

// Analytics

169

bind<IAnalyticsService>("AnalyticsService").to(GoogleAnalyticsService).inSingletonScope();

170

});

171

```

172

173

## Module Loading and Management

174

175

### Loading Multiple Modules

176

177

```typescript

178

// Load multiple modules at once

179

container.load(

180

infrastructureModule,

181

dataModule,

182

businessModule,

183

externalServicesModule

184

);

185

186

// Load modules sequentially

187

container.load(infrastructureModule);

188

container.load(dataModule);

189

container.load(businessModule);

190

```

191

192

### Async Module Loading

193

194

```typescript

195

// Load modules asynchronously

196

await container.loadAsync(

197

infrastructureModule,

198

dataModule,

199

businessModule

200

);

201

202

// Individual async loading

203

await container.loadAsync(infrastructureModule);

204

await container.loadAsync(dataModule);

205

```

206

207

### Module Unloading

208

209

```typescript

210

// Unload specific modules

211

container.unload(externalServicesModule);

212

213

// Unload multiple modules

214

container.unload(businessModule, dataModule);

215

216

// Async unloading

217

await container.unloadAsync(externalServicesModule);

218

```

219

220

### Conditional Module Loading

221

222

```typescript

223

// Environment-based module loading

224

if (process.env.NODE_ENV === "production") {

225

container.load(productionModule);

226

} else if (process.env.NODE_ENV === "test") {

227

container.load(testModule);

228

} else {

229

container.load(developmentModule);

230

}

231

232

// Feature-based module loading

233

if (process.env.FEATURE_ANALYTICS === "enabled") {

234

container.load(analyticsModule);

235

}

236

237

if (process.env.FEATURE_PREMIUM === "enabled") {

238

container.load(premiumFeaturesModule);

239

}

240

```

241

242

## Advanced Module Patterns

243

244

### Environment-Specific Modules

245

246

```typescript

247

// Base module with common bindings

248

const baseModule = new ContainerModule((bind) => {

249

bind<ILogger>("Logger").to(ConsoleLogger);

250

bind<IConfigService>("ConfigService").to(ConfigService).inSingletonScope();

251

});

252

253

// Development overrides

254

const developmentModule = new ContainerModule((bind, unbind, isBound, rebind) => {

255

rebind<ILogger>("Logger").to(VerboseLogger);

256

bind<IMockService>("MockService").to(MockService).inSingletonScope();

257

258

// Override email service with mock

259

if (isBound("EmailService")) {

260

rebind<IEmailService>("EmailService").to(MockEmailService);

261

} else {

262

bind<IEmailService>("EmailService").to(MockEmailService);

263

}

264

});

265

266

// Production overrides

267

const productionModule = new ContainerModule((bind, unbind, isBound, rebind) => {

268

rebind<ILogger>("Logger").to(WinstonLogger);

269

bind<IMetricsService>("MetricsService").to(PrometheusMetricsService).inSingletonScope();

270

bind<IEmailService>("EmailService").to(SendGridEmailService).inSingletonScope();

271

});

272

273

// Load based on environment

274

container.load(baseModule);

275

if (process.env.NODE_ENV === "production") {

276

container.load(productionModule);

277

} else {

278

container.load(developmentModule);

279

}

280

```

281

282

### Plugin Architecture

283

284

```typescript

285

interface IPlugin {

286

name: string;

287

initialize(): void;

288

destroy(): void;

289

}

290

291

// Plugin registry

292

const pluginRegistry = new Map<string, ContainerModule>();

293

294

// Register plugin

295

function registerPlugin(name: string, pluginModule: ContainerModule) {

296

pluginRegistry.set(name, pluginModule);

297

}

298

299

// Analytics plugin

300

const analyticsPlugin = new ContainerModule((bind) => {

301

bind<IPlugin>("Plugin").to(AnalyticsPlugin).whenTargetNamed("analytics");

302

bind<IAnalyticsService>("AnalyticsService").to(GoogleAnalyticsService).inSingletonScope();

303

});

304

305

registerPlugin("analytics", analyticsPlugin);

306

307

// Load enabled plugins

308

const enabledPlugins = process.env.ENABLED_PLUGINS?.split(",") || [];

309

for (const pluginName of enabledPlugins) {

310

const plugin = pluginRegistry.get(pluginName);

311

if (plugin) {

312

container.load(plugin);

313

}

314

}

315

```

316

317

### Testing Module Overrides

318

319

```typescript

320

// Main application modules

321

const appModule = new ContainerModule((bind) => {

322

bind<IUserService>("UserService").to(UserService);

323

bind<IEmailService>("EmailService").to(SmtpEmailService);

324

bind<IPaymentService>("PaymentService").to(StripePaymentService);

325

});

326

327

// Test overrides module

328

const testModule = new ContainerModule((bind, unbind, isBound, rebind) => {

329

// Override with mock implementations

330

rebind<IEmailService>("EmailService").to(MockEmailService);

331

rebind<IPaymentService>("PaymentService").to(MockPaymentService);

332

333

// Add test-specific services

334

bind<ITestDataService>("TestDataService").to(TestDataService).inSingletonScope();

335

});

336

337

// In test setup

338

container.load(appModule);

339

container.load(testModule); // Overrides production services

340

```

341

342

### Module Dependencies

343

344

```typescript

345

// Core module - must be loaded first

346

const coreModule = new ContainerModule((bind) => {

347

bind<ILogger>("Logger").to(WinstonLogger).inSingletonScope();

348

bind<IConfigService>("ConfigService").to(ConfigService).inSingletonScope();

349

});

350

351

// Database module - depends on core

352

const databaseModule = new ContainerModule((bind, unbind, isBound) => {

353

if (!isBound("ConfigService")) {

354

throw new Error("Database module requires core module to be loaded first");

355

}

356

357

bind<IDatabaseConnection>("DatabaseConnection")

358

.toDynamicValue((context) => {

359

const config = context.container.get<IConfigService>("ConfigService");

360

return new DatabaseConnection(config.getDatabaseUrl());

361

})

362

.inSingletonScope();

363

});

364

365

// Proper loading order

366

container.load(coreModule); // Load core first

367

container.load(databaseModule); // Then database module

368

```

369

370

## Module Best Practices

371

372

### Module Organization

373

374

```typescript

375

// Group related services together

376

const userModule = new ContainerModule((bind) => {

377

// User domain services

378

bind<IUserService>("UserService").to(UserService);

379

bind<IUserRepository>("UserRepository").to(UserRepository);

380

bind<IUserValidator>("UserValidator").to(UserValidator);

381

bind<IPasswordHasher>("PasswordHasher").to(BcryptHasher);

382

});

383

384

// Keep modules focused and cohesive

385

const emailModule = new ContainerModule((bind) => {

386

bind<IEmailService>("EmailService").to(EmailService);

387

bind<IEmailTemplateService>("EmailTemplateService").to(EmailTemplateService);

388

bind<IEmailQueueService>("EmailQueueService").to(EmailQueueService);

389

});

390

```

391

392

### Module Documentation

393

394

```typescript

395

/**

396

* Authentication Module

397

*

398

* Provides all services related to user authentication and authorization.

399

*

400

* Services provided:

401

* - IAuthService: Main authentication service

402

* - ITokenService: JWT token management

403

* - IPasswordService: Password hashing and validation

404

* - IUserRepository: User data persistence

405

*

406

* Dependencies:

407

* - Requires ConfigService from core module

408

* - Requires Logger from infrastructure module

409

*

410

* @example

411

* ```typescript

412

* container.load(coreModule);

413

* container.load(infrastructureModule);

414

* container.load(authModule);

415

* ```

416

*/

417

const authModule = new ContainerModule((bind, unbind, isBound) => {

418

// Validate dependencies

419

if (!isBound("ConfigService")) {

420

throw new Error("Auth module requires ConfigService");

421

}

422

if (!isBound("Logger")) {

423

throw new Error("Auth module requires Logger");

424

}

425

426

bind<IAuthService>("AuthService").to(JwtAuthService).inSingletonScope();

427

bind<ITokenService>("TokenService").to(JwtTokenService).inSingletonScope();

428

bind<IPasswordService>("PasswordService").to(BcryptPasswordService).inSingletonScope();

429

bind<IUserRepository>("UserRepository").to(DatabaseUserRepository).inSingletonScope();

430

});

431

```

432

433

## Best Practices

434

435

1. **Keep modules focused**: Each module should have a single responsibility

436

2. **Document dependencies**: Clearly specify what modules depend on others

437

3. **Validate dependencies**: Check required services are bound before adding new bindings

438

4. **Use environment modules**: Create environment-specific override modules

439

5. **Load order matters**: Load dependency modules before dependent modules

440

6. **Test module isolation**: Ensure modules can be loaded/unloaded independently

441

7. **Use descriptive names**: Module names should clearly indicate their purpose

442

8. **Handle cleanup**: Implement proper cleanup in deactivation handlers for module services