DEV Community

Cover image for FrontEnd Dependency Injection with iocello
Anas AbdelHadi
Anas AbdelHadi

Posted on

FrontEnd Dependency Injection with iocello

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.

  1. Shelves (Domains): Each shelf represents a domain, and the lowest shelf (domain) is numbered 0.
  2. Books (Classes/Services): Books are your injectable classes or services, which can be stored on any shelf.
  3. Cross-Referencing: At runtime, you can fetch and construct books (instances of classes) from the current domain or any specified domain.
  4. 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.
  5. 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
Enter fullscreen mode Exit fullscreen mode

You will also need to install the shared kernel corello

npm install corello
Enter fullscreen mode Exit fullscreen mode

Basic Usage

  1. Mark Classes as Injectable: Use the @Service decorator.
  2. Inject Dependencies: Use the @Inject decorator for properties in your classes.
  3. Register Services: Add services to the IoC container using ioc.add(ServiceClass).
  4. 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);
Enter fullscreen mode Exit fullscreen mode

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() {}
}
Enter fullscreen mode Exit fullscreen mode

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() {}
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Key Features of iocello

  1. Domain-Specific Injection: Fetch instances from specific domains using tags.
  2. Dynamic Replacement: Services can override others in a domain using the enforce property.
  3. Circular Dependency Handling: iocello resolves circular dependencies automatically.
  4. 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)