levit_scope
Type-safe, hierarchical dependency injection for Dart. Explicit. Scoped. Deterministic.
levit_scope is a pure Dart dependency injection and service locator designed for applications requiring predictable lifecycles and explicit scoping. It provides a robust, reflection-free mechanism for managing services and controllers across the Levit ecosystem.
Purpose & Scope
levit_scope provides the container infrastructure for the Levit framework. Its primary responsibilities include:
- Managing a registry of typed dependencies with optional tagging.
- Enforcing hierarchical isolation between different layers of the application.
- Orchestrating lifecycle hooks (
onInit,onClose) for managed components.
By maintaining a pure Dart profile, it ensures that your dependency graph remains testable and portable across CLI, server, and multi-platform environments.
Conceptual Overview
Core Abstractions
LevitScope: A container that holds dependency registrations. Scopes can be nested to form a tree.LevitScopeDisposable: An interface that allows components to react to their own initialization and disposal.- Ambient Scoping: While
levit_scopeis the low-level engine, it is often used via the ambientLevitinterface inlevit_dartfor boilerplate-free resolution.
Getting Started
Hierarchical Scoping
// Create a root scope
final root = LevitScope.root();
// Register a singleton
root.put(() => AuthService());
// Create a child scope for a specific feature
final featureScope = root.createScope('payment_flow');
featureScope.put(() => PaymentProcessor());
// Resolve from child (falls back to parent)
final auth = featureScope.find<AuthService>();
Lifecycle Hooks
Implement LevitScopeDisposable to manage resources:
class Database implements LevitScopeDisposable {
@override
void onInit() => print('Connecting...');
@override
void onClose() => print('Closing connection...');
}
Design Principles
Explicitness over Magic
There is no hidden reflection or code generation. Every dependency is registered and resolved via typed builder functions.
Deterministic Teardown
When a scope is disposed, every disposable dependency it owns is guaranteed to have its onClose method called. This is critical for preventing memory leaks in complex applications.
Isolation
Child scopes can override parent dependencies locally. This enables powerful testing patterns where you can "mock" a dependency for a specific subtree of your application without affecting the global state.
Libraries
- levit_scope
- Type-safe, hierarchical dependency injection for Dart.