1.0.4 β€’ Published 8 months ago

@brushy/di v1.0.4

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

@brushy/di

Coverage - Statements Coverage - Branches Coverage - Functions Coverage - Lines

npm downloads npm bundle size npm version

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/di

Real-World Problem Solving

Here's how @brushy/di compares to other solutions in solving common real-world problems:

Problem@brushy/ditsyringeInversifyJSAngular 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 docs

Common Use Cases

  1. Modular React Applications

    // Easy module registration
    const userModule = new Container();
    userModule.register(USER_SERVICE, { useClass: UserService });
    container.import(userModule, { prefix: "user" });
  2. Server-Side Rendering

    // Automatic request scope cleanup
    app.use((req, res, next) => {
      next();
      container.clearRequestScope();
    });
  3. Component Theming

    // Simple component overriding
    const CustomUIProvider = createComponentsProvider({
      [BUTTON]: CustomButton,
      [THEME]: DarkTheme,
    });
  4. 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

1.0.4

8 months ago

1.0.3

8 months ago

1.0.2

8 months ago

1.0.0

8 months ago