Welcome to iocello, a library that simplifies the concepts of Dependency Injection (DI) and Inversion of Control (IoC) in your applications. With iocello, you can dynamically manage your application’s dependencies and domains while maintaining flexibility and control.
In this tutorial, we’ll explore the key concepts of iocello, walk through its setup, and demonstrate how to use it effectively.
The Concept
Imagine your application as a library of bookshelves.
-
Shelves (Domains): Each shelf represents a domain, and the lowest shelf (domain) is numbered
0
. - Books (Classes/Services): Books are your injectable classes or services, which can be stored on any shelf.
- Cross-Referencing: At runtime, you can fetch and construct books (instances of classes) from the current domain or any specified domain.
- Tagging and Customization: When registering a book (class), you assign it a unique tag and specify the shelf (domain) where it belongs. This ensures easy management and retrieval.
-
Inversion of Control: You can dynamically change the container (shelf/domain) where books are fetched from, using
ioc.setContainerDomain()
.
Setup
To get started with iocello, install the package and set up your environment:
Installation
npm install iocello
You will also need to install the shared kernel corello
npm install corello
Basic Usage
-
Mark Classes as Injectable: Use the
@Service
decorator. -
Inject Dependencies: Use the
@Inject
decorator for properties in your classes. -
Register Services: Add services to the IoC container using
ioc.add(ServiceClass)
. -
Dynamic Instantiation: Use
ioc.construct<Type>(TagName, domain?)
to create instances dynamically.
Example: Building with iocello
Let’s create an example application with Pet
and Person
services.
Step 1: Create Services
import { Service, Inject } from 'iocello';
// Define the Pet class and mark it as a service
@Service({ tag: 'Pet' })
class Pet {
// Inject a dependency of type Person from domain 1
@Inject({ tag: 'Person', domain: 1 }) person!: Person;
walk() {
console.log('PET IS WALKING');
}
dispose() {}
}
// Add the Pet service to the IoC container
ioc.add(Pet);
Step 2: Cross-Referencing with Injection
@Service({ tag: 'Person' })
class Person {
hello: string = 'Hello!';
// Inject an instance of Pet from domain 1 with a custom name
@Inject({ domain: 1, tag: 'Pet' }) semsem!: Pet;
dispose() {}
}
Step 3: Enforcing Domain Rules
You can replace a service at a specific domain by using the enforce
property:
@Service({ tag: 'Person', enforce: { domain: 0 } })
class Person2 extends Person {
@inject() Pet!: Pet;
dispose() {}
}
Step 4: Constructing and Using Instances
Now that our services are registered, we can create and use them dynamically:
ioc.add(Person);
ioc.add(Person2);
// Construct an instance of Person from domain 100
const person = ioc.construct<Person>('Person', 100);
// Use the dynamically injected properties
person.Pet.walk(); // Outputs: PET IS WALKING
console.log(person);
Key Features of iocello
- Domain-Specific Injection: Fetch instances from specific domains using tags.
-
Dynamic Replacement: Services can override others in a domain using the
enforce
property. - Circular Dependency Handling: iocello resolves circular dependencies automatically.
- Warnings and Logs: Alerts for missing services or unintended overwrites.
Tips and Best Practices
- Use Tags Wisely: Ensure tags are unique for each service to avoid conflicts.
-
Dispose Resources: Implement the
dispose
method in services for proper cleanup. - Monitor Logs: Watch for warnings about missing services or overwrites to debug effectively.
Conclusion
With iocello, managing dependencies becomes intuitive and scalable. By organizing your services into domains and leveraging dynamic instantiation, you can achieve a clean, maintainable architecture for your applications. Whether you're building a simple project or a complex enterprise application, iocello empowers you to take control of your IoC needs effortlessly.
Check out source code for the sample application (Vue+vite)
Happy coding! 🎉
Top comments (0)