1.0.4 β’ Published 8 months ago
@brushy/di v1.0.4
@brushy/di
A powerful and flexible dependency injection system for JavaScript/TypeScript applications, with special support for React.
π§π· DocumentaΓ§Γ£o em PortuguΓͺs
Features
- π Flexible Lifecycle: Singleton, Transient and Scoped
- π§© React Component Injection: Seamless React integration
- π Observability: Detailed monitoring and logging
- π Performance: Smart promise caching
- π§ͺ Testability: Easy to mock for testing
- π¦ Modular: Organization in independent modules
Installation
npm install @brushy/di
# or
yarn add @brushy/di
# or
pnpm add @brushy/diReal-World Problem Solving
Here's how @brushy/di compares to other solutions in solving common real-world problems:
| Problem | @brushy/di | tsyringe | InversifyJS | Angular DI |
|---|---|---|---|---|
| React Integration | β Native support with hooks and components | β οΈ Requires manual setup | β Limited React support | β Not designed for React |
| Server Components | β Full RSC compatibility | β Not compatible | β Not compatible | β Not applicable |
| Promise Caching | β Automatic smart caching | β οΈ Manual implementation | β οΈ Manual implementation | β οΈ Manual implementation |
| Component Injection | β Built-in UI component system | β No UI support | β No UI support | β οΈ Different paradigm |
| Learning Curve | β Moderate | β Moderate | β Steep | β Steep |
| Scope Management | β Built-in request/session scopes | β No scope support | β οΈ Basic scopes | β Built-in scopes |
| Performance | β Optimized resolution | β Fast resolution | β οΈ Moderate | β Heavy runtime |
Legend:
- β Fully Supported
- β οΈ Partially Supported
- β Not Supported/Limited
Basic Usage
import { Container, BrushyDIProvider, useInject, useInjectComponent } from '@brushy/di';
// Define tokens
const TOKENS = {
SERVICES: {
HTTP: Symbol('HTTP_CLIENT'),
USER: Symbol('USER_SERVICE'),
AUTH: Symbol('AUTH_SERVICE')
},
CONFIG: Symbol('CONFIG'),
UI: {
BUTTON: Symbol('BUTTON'),
CARD: Symbol('CARD'),
THEME: Symbol('THEME')
}
};
// Services
class HttpClient {
async fetch(url: string) {
const response = await fetch(url);
return response.json();
}
}
class UserService {
constructor(private http: HttpClient) {}
async getUsers() {
return this.http.fetch('/api/users');
}
async getUserById(id: string) {
return this.http.fetch(`/api/users/${id}`);
}
}
class AuthService {
constructor(
private http: HttpClient,
private config: { apiUrl: string }
) {}
async login(credentials: { username: string; password: string }) {
return this.http.fetch('/api/auth/login');
}
}
// UI Components
const DefaultButton = ({ children, variant = 'default', ...props }) => (
<button className={`btn btn-${variant}`} {...props}>
{children}
</button>
);
const DefaultCard = ({ title, children }) => (
<div className="card">
<div className="card-header">{title}</div>
<div className="card-body">{children}</div>
</div>
);
const DefaultTheme = ({ children }) => (
<div className="light-theme">{children}</div>
);
// Create container with initial configuration
const container = new Container({
providers: [
// Register configuration
{
provide: TOKENS.CONFIG,
useValue: {
apiUrl: 'https://api.example.com',
timeout: 5000
}
},
// Register HTTP client as singleton
{
provide: TOKENS.SERVICES.HTTP,
useClass: HttpClient,
lifecycle: 'singleton'
},
// Register services with dependencies
{
provide: TOKENS.SERVICES.USER,
useClass: UserService,
dependencies: [TOKENS.SERVICES.HTTP],
lifecycle: 'scoped' // New instance per request
},
{
provide: TOKENS.SERVICES.AUTH,
useClass: AuthService,
dependencies: [TOKENS.SERVICES.HTTP, TOKENS.CONFIG],
lifecycle: 'singleton'
},
// Register default UI components
{
provide: TOKENS.UI.BUTTON,
useValue: DefaultButton
},
{
provide: TOKENS.UI.CARD,
useValue: DefaultCard
},
{
provide: TOKENS.UI.THEME,
useValue: DefaultTheme
}
],
debug: true,
name: 'AppContainer'
});
// React Components
function UserList() {
const userService = useInject<UserService>(TOKENS.SERVICES.USER);
const Button = useInjectComponent(TOKENS.UI.BUTTON);
const Card = useInjectComponent(TOKENS.UI.CARD);
const [users, setUsers] = useState([]);
useEffect(() => {
userService.getUsers().then(setUsers);
}, [userService]);
return (
<Card title="Users">
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
<Button variant="link" onClick={() => console.log(user)}>
View Details
</Button>
</li>
))}
</ul>
</Card>
);
}
function LoginForm() {
const authService = useInject<AuthService>(TOKENS.SERVICES.AUTH);
const Button = useInjectComponent(TOKENS.UI.BUTTON);
const [credentials, setCredentials] = useState({ username: '', password: '' });
const handleSubmit = async (e) => {
e.preventDefault();
try {
await authService.login(credentials);
// Handle success
} catch (error) {
// Handle error
}
};
return (
<form onSubmit={handleSubmit}>
<Button type="submit" variant="primary">Login</Button>
</form>
);
}
// Custom theme implementation
const DarkTheme = ({ children }) => (
<div className="dark-theme">{children}</div>
);
// Theme provider to override default theme
const CustomThemeProvider = createComponentsProvider({
[TOKENS.UI.THEME]: DarkTheme
});
// Application with providers
function App() {
const Theme = useInjectComponent(TOKENS.UI.THEME);
return (
<BrushyDIProvider container={container}>
<CustomThemeProvider>
<Theme>
<div>
<LoginForm />
<UserList />
</div>
</Theme>
</CustomThemeProvider>
</BrushyDIProvider>
);
}
// Clean up when done
container.clearRequestScope();To view the documentation locally:
npm run docsCommon Use Cases
Modular React Applications
// Easy module registration const userModule = new Container(); userModule.register(USER_SERVICE, { useClass: UserService }); container.import(userModule, { prefix: "user" });Server-Side Rendering
// Automatic request scope cleanup app.use((req, res, next) => { next(); container.clearRequestScope(); });Component Theming
// Simple component overriding const CustomUIProvider = createComponentsProvider({ [BUTTON]: CustomButton, [THEME]: DarkTheme, });API Integration
// Smart promise caching function UserProfile({ id }) { const userService = useInject(USER_SERVICE); const user = use(userService.getUser(id)); // Cached automatically return <div>{user.name}</div>; }
License
MIT