stray-react-di
v3.0.3
Published
Sistema unificado de gerenciamento de dependências para aplicações React com injeção inteligente de dependências, providers, components, services e hooks
Maintainers
Readme
stray-react-di
Stray é um sistema unificado de gerenciamento de dependências para aplicações React com injeção inteligente de dependências, providers, components, services e hooks.
✨ Principais Características
- 🎯 Arquitetura Unificada: Uma única classe
StrayDependencypara gerenciar providers, components, services, hooks e HOCs - 🔧 Detecção Automática de Tipos: Identifica automaticamente o tipo baseado em convenções de nomenclatura
- 📦 TypeScript Nativo: Totalmente tipado com suporte completo ao TypeScript
- 🚀 Injeção de Dependências: Sistema poderoso de DI com resolução automática
- 🔄 Compatibilidade: Mantém compatibilidade com versões anteriores
- ⚡ Performance: Otimizado para aplicações React de alto desempenho
- 🎨 Flexibilidade: Suporte a HOCs, renderização customizada e composição
📦 Instalação
npm install stray-react-diyarn add stray-react-dipnpm add stray-react-di🚀 Início Rápido
Configuração Básica
import { StrayApp } from 'stray-react-di';
import React from 'react';
// Componentes de exemplo
const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<div>{children}</div>
);
const Button: React.FC<{ title?: string }> = ({ title }) => (
<button>{title || 'Click me'}</button>
);
class ApiService {
constructor(private config: any) {}
async getData() {
return fetch(this.config.apiUrl);
}
}
const useAuth = () => {
return { user: null, login: () => {}, logout: () => {} };
};
// Criando a aplicação Stray
const app = new StrayApp();
// Configuração unificada
app
.config('config', {
target: { apiUrl: 'https://api.example.com' },
type: 'dependency'
})
.provider('AuthProvider', {
target: AuthProvider,
props: { theme: 'dark' }
})
.component('Button', {
target: Button,
route: '/',
props: { title: 'Home Button' }
})
.service('ApiService', {
target: ApiService,
dependencies: ['config']
})
.hook('useAuth', {
target: useAuth
});
// Renderizar a aplicação
app.render().then(() => {
console.log('Aplicação iniciada!');
});Detecção Automática de Tipos
O Stray detecta automaticamente o tipo de dependência baseado em convenções:
// Detecção automática por nome
app.config('AuthProvider', { target: AuthProvider }); // → type: 'provider'
app.config('UserService', { target: UserService }); // → type: 'service'
app.config('useAuth', { target: useAuth }); // → type: 'hook'
app.config('withAuth', { target: withAuthHoc }); // → type: 'hoc'
app.config('Button', { target: Button }); // → type: 'component'📚 Guias e Documentação
Métodos de Conveniência
const app = new StrayApp();
// Providers (para Context API)
app.provider('ThemeProvider', {
target: ThemeProvider,
props: { theme: 'dark' },
position: 1 // Ordem de renderização
});
// Components (para roteamento)
app.component('HomePage', {
target: HomePage,
route: '/',
props: { title: 'Welcome' }
});
// Services (injeção de dependência)
app.service('ApiService', {
target: ApiService,
dependencies: ['config', 'httpClient']
});
// Hooks (com dependências injetadas)
app.hook('useApi', {
target: useApi,
dependencies: ['ApiService']
});
// HOCs (Higher-Order Components)
app.hoc('withAuth', {
target: withAuthHoc
});
// Dependências simples (valores, configurações)
app.dependency('config', {
apiUrl: process.env.REACT_APP_API_URL,
timeout: 5000
});Sistema de Dependências
// 1. Configurar dependências
app.dependency('config', {
apiUrl: 'https://api.example.com',
timeout: 5000
});
// 2. Service que depende da configuração
class ApiService {
constructor(private config: any) {}
async request(endpoint: string) {
const response = await fetch(`${this.config.apiUrl}${endpoint}`, {
timeout: this.config.timeout
});
return response.json();
}
}
app.service('ApiService', {
target: ApiService,
dependencies: ['config'] // Será injetado no construtor
});
// 3. Hook que depende do service
const useUsers = (apiService: ApiService) => {
const [users, setUsers] = useState([]);
useEffect(() => {
apiService.request('/users').then(setUsers);
}, []);
return users;
};
app.hook('useUsers', {
target: useUsers,
dependencies: ['ApiService'] // Será injetado como propriedade
});
// 4. Component que usa o hook
const UsersList: React.FC = () => {
const users = app.getHook('useUsers')();
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
};
app.component('UsersList', {
target: UsersList,
route: '/users'
});HOCs (Higher-Order Components)
// 1. Definir HOC
const withLoading = (WrappedComponent: React.ComponentType) => {
return (props: any) => {
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => setLoading(false), 1000);
}, []);
if (loading) return <div>Loading...</div>;
return <WrappedComponent {...props} />;
};
};
app.hoc('withLoading', { target: withLoading });
// 2. Aplicar HOC a componente
app.component('UserProfile', {
target: UserProfile,
route: '/profile',
hocs: ['withLoading'] // Aplicado automaticamente
});Renderização Customizada
const customRenderCallback = (Component: React.ComponentType, props: any, children: React.ReactNode) => {
return (
<ErrorBoundary>
<Component {...props}>
{children}
</Component>
</ErrorBoundary>
);
};
app.provider('ErrorProvider', {
target: ErrorBoundaryProvider,
renderCallback: customRenderCallback
});🔧 API Completa
StrayApp
Métodos de Configuração
| Método | Descrição | Exemplo |
|--------|-----------|---------|
| config(name, config) | Configuração unificada | app.config('Button', { target: Button }) |
| provider(name, config) | Configura provider | app.provider('Theme', { target: ThemeProvider }) |
| component(name, config) | Configura componente | app.component('Home', { target: HomePage }) |
| service(name, config) | Configura service | app.service('Api', { target: ApiService }) |
| hook(name, config) | Configura hook | app.hook('useAuth', { target: useAuth }) |
| hoc(name, config) | Configura HOC | app.hoc('withAuth', { target: withAuth }) |
| dependency(name, value) | Configura valor simples | app.dependency('config', { api: 'url' }) |
Métodos de Consulta
| Método | Descrição | Retorno |
|--------|-----------|---------|
| getProviders() | Lista providers | IStrayDependency[] |
| getComponents() | Lista componentes | IStrayDependency[] |
| getServices() | Lista services | IStrayDependency[] |
| getHooks() | Lista hooks | IStrayDependency[] |
| getHocs() | Lista HOCs | IStrayDependency[] |
| getService(name) | Obtém service instanciado | any |
| getHook(name) | Obtém hook injetado | any |
| has(name) | Verifica se existe | boolean |
| getDependencyConfig(name) | Obtém configuração | IStrayDependency |
Métodos de Renderização
| Método | Descrição |
|--------|-----------|
| render(children?) | Renderiza aplicação |
| createApp(children?) | Alias para render |
| buildProvidersTree(children?) | Constrói árvore de providers |
| buildRoutesTree() | Constrói rotas |
Métodos de Combinação
| Método | Descrição |
|--------|-----------|
| combine(otherApp, options?) | Combina com outra instância |
| export(includeOnly?) | Exporta dependências |
| import(exportedData, options?) | Importa dependências |
| StrayApp.merge(app1, app2, options?) | Merge estático |
StrayDependencyConfig
interface StrayDependencyConfig<T = any> {
name?: string; // Nome único
target: DependencyTarget<T>; // Componente/Service/Hook/etc
type?: DependencyType; // 'provider' | 'component' | 'service' | 'hook' | 'hoc' | 'dependency'
dependencies?: string[]; // Array de dependências
props?: DynamicProps<any>; // Props estáticas ou função
description?: string; // Descrição
route?: string; // Rota (para components)
hocs?: string[]; // HOCs a aplicar
position?: number; // Posição (para providers)
renderCallback?: RenderCallback; // Callback customizado
}🎯 Exemplos Avançados
Aplicação Completa com Roteamento
import { StrayApp, quickSetup } from 'stray-react-di';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const app = quickSetup({
providers: {
'Router': { target: BrowserRouter },
'AuthProvider': { target: AuthProvider },
'ThemeProvider': { target: ThemeProvider, position: 1 }
},
services: {
'ApiService': { target: ApiService, dependencies: ['config'] },
'AuthService': { target: AuthService, dependencies: ['ApiService'] }
},
hooks: {
'useAuth': { target: useAuth, dependencies: ['AuthService'] },
'useTheme': { target: useTheme }
},
components: {
'HomePage': { target: HomePage, route: '/' },
'LoginPage': { target: LoginPage, route: '/login' },
'ProfilePage': { target: ProfilePage, route: '/profile', hocs: ['withAuth'] }
},
dependencies: {
'config': {
target: {
apiUrl: process.env.REACT_APP_API_URL,
appName: 'My App'
}
}
}
});
// Container DOM
const container = document.getElementById('root');
const appWithContainer = new StrayApp({ container });
// Combinar configurações
appWithContainer.combine(app);
// Iniciar aplicação
appWithContainer.createApp();Micro-frontends com Stray
// App Principal
const mainApp = new StrayApp();
mainApp.provider('SharedProvider', { target: SharedContextProvider });
// Micro-frontend 1
const authModule = new StrayApp();
authModule
.service('AuthService', { target: AuthService })
.component('LoginForm', { target: LoginForm });
// Micro-frontend 2
const dashboardModule = new StrayApp();
dashboardModule
.component('Dashboard', { target: Dashboard })
.hook('useDashboard', { target: useDashboard });
// Combinação
const combinedApp = StrayApp.merge(mainApp, authModule);
combinedApp.combine(dashboardModule, { prefix: 'dashboard_' });
combinedApp.createApp();Sistema de Plugins
interface Plugin {
name: string;
dependencies: ExportedDependencies;
}
class PluginManager {
constructor(private app: StrayApp) {}
loadPlugin(plugin: Plugin) {
console.log(`Loading plugin: ${plugin.name}`);
this.app.import(plugin.dependencies);
}
unloadPlugin(pluginName: string) {
// Implementar remoção de dependências
}
}
const app = new StrayApp();
const pluginManager = new PluginManager(app);
// Plugin de autenticação
const authPlugin: Plugin = {
name: 'auth',
dependencies: authModule.export(['AuthService', 'LoginForm'])
};
pluginManager.loadPlugin(authPlugin);🧪 Testes
Configuração de Testes
npm test # Executar todos os testes
npm run test:watch # Modo watch
npm run test:coverage # Com coverageTestando com Stray
import { StrayApp } from 'stray-react-di';
import { render, screen } from '@testing-library/react';
describe('StrayApp Integration', () => {
let app: StrayApp;
beforeEach(() => {
app = new StrayApp();
});
it('should resolve dependencies correctly', async () => {
// Configurar
app.dependency('config', { message: 'Hello World' });
class TestService {
constructor(private config: any) {}
getMessage() { return this.config.message; }
}
app.service('TestService', {
target: TestService,
dependencies: ['config']
});
// Testar
const service = app.getService('TestService');
expect(service.getMessage()).toBe('Hello World');
});
it('should render component tree', async () => {
const TestComponent = () => <div>Test</div>;
app.component('TestComponent', {
target: TestComponent,
route: '/test'
});
const element = await app.buildRoutesTree();
expect(element).toBeDefined();
});
});🔄 Migração v2 → v3
Mudanças Principais
- ✅ Arquitetura Unificada:
StrayDependencysubstitui classes separadas - ✅ TypeScript Nativo: Tipagem completa
- ✅ Métodos Simplificados:
config()como método principal - ✅ Detecção Automática: Tipos detectados por convenção
- ✅ Compatibilidade: Aliases mantidos para código legado
Guia de Migração
// v2 (JavaScript)
const app = new StrayApp();
app.buildProvider('AuthProvider', AuthProviderConfig);
app.buildComponent('HomePage', HomePageConfig);
// v3 (TypeScript) - Recomendado
const app = new StrayApp();
app.provider('AuthProvider', { target: AuthProvider });
app.component('HomePage', { target: HomePage, route: '/' });
// v3 (Compatibilidade) - Funciona mas não recomendado
app.buildProvider('AuthProvider', AuthProviderConfig); // ← Ainda funciona
app.buildComponent('HomePage', HomePageConfig); // ← Ainda funciona📖 Recursos Adicionais
🤝 Contribuindo
Contribuições são bem-vindas! Por favor, leia nosso Guia de Contribuição.
Desenvolvimento Local
git clone https://github.com/teraprox/stray.git
cd stray
npm install
npm run dev
npm testScripts Disponíveis
npm run build # Build de produção
npm run dev # Desenvolvimento com watch
npm test # Executar testes
npm run lint # Linting
npm run format # Formatação de código📄 Licença
MIT © TeraPROX Development Team
🙏 Agradecimentos
- React team pela excelente biblioteca
- TypeScript team pelo sistema de tipos
- Jest team pela ferramenta de testes
- Comunidade open source
🌟 Star no GitHub • 📦 NPM Package • 📖 Documentação
Feito com ❤️ por TeraPROX Development Team
🏗️ Estrutura da Pasta
stray/
├── index.js # Ponto de entrada principal
├── core/ # Módulos principais
│ ├── StrayApp.js # Classe principal do sistema
│ └── DependencyMapping.js # Sistema de mapeamento e resolução de dependências
├── examples/ # Exemplos práticos de uso
│ ├── StrayAppUsage.js # Exemplos básicos de configuração
│ └── StrayAppIntelligentProps.js # Exemplos de props inteligentes
├── docs/ # Documentação detalhada
│ ├── StrayAppConfigDependency.js # Documentação de configuração
│ ├── StrayAppIntelligentProps.js # Documentação de props inteligentes
│ └── INTELLIGENT_PROPS_FINAL_SUMMARY.js # Resumo final da implementação
└── tests/ # Testes do sistema
├── StrayAppConfigTests.js # Testes de configuração
└── StrayAppFinalTest.js # Testes finais integrados🚀 Características Principais
1. Sistema de Props Inteligente
- Detecção automática de dependências baseada no retorno das funções props
- Suporte a formatos JSON (objetos) e Array (strings)
- Carregamento automático de serviços conforme necessidade
2. Mapeamento Isolado de Serviços
DEPENDENCY_MAPPING: Para componentes e providersSERVICES_MAPPING: Para serviços isolados- Resolução automática e inteligente de dependências
3. Flexibilidade de Configuração
- Configuração manual tradicional via
configDependency - Configuração automática via props inteligentes
- Suporte a dependências condicionais e dinâmicas
📖 Como Usar
Importação Básica
import StrayApp from './stray';
// ou
import { StrayApp, DEPENDENCY_MAPPING, SERVICES_MAPPING } from './stray';Configuração Rápida
import { createStrayApp } from './stray';
const strayApp = createStrayApp({
dependencies: {
'UserService': () => import('./services/UserService'),
'ApiService': () => import('./services/ApiService')
}
});Props Inteligentes (Recomendado)
const MyComponent = strayApp.loadProvider('MyProvider', () => ({
userService: null, // Será carregado automaticamente
apiService: null, // Será carregado automaticamente
localData: { ready: true } // Valor local, não é dependência
}));🔄 Migração de Código Existente
Se você estava usando o Stray antes da reorganização, apenas atualize os imports:
Antes:
import StrayApp from './config/StrayApp';
import { DEPENDENCY_MAPPING } from './config/DependencyMapping';Depois:
import StrayApp from './stray';
import { DEPENDENCY_MAPPING } from './stray';🧪 Execução dos Testes
Para executar os testes do sistema Stray:
# Executar testes específicos do Stray
node src/stray/tests/StrayAppFinalTest.js
# Executar testes de configuração
node src/stray/tests/StrayAppConfigTests.js📚 Documentação Detalhada
- Configuração de Dependências: Guia completo de configuração manual
- Props Inteligentes: Documentação do sistema de props inteligentes
- Resumo Final: Resumo completo da implementação
🛠️ Exemplos Práticos
- Uso Básico: Exemplos de configuração e uso básico
- Props Inteligentes: 6 exemplos práticos de props inteligentes
🎯 Benefícios
- Desacoplamento: Separação clara entre componentes, serviços e dependências
- Automação: Redução significativa de código boilerplate
- Inteligência: Detecção automática de dependências sem configuração manual
- Flexibilidade: Suporte a múltiplos padrões de configuração
- Manutenibilidade: Código mais limpo e fácil de manter
- Performance: Carregamento lazy de dependências quando necessário
🔧 Arquitetura
O Stray utiliza uma arquitetura em camadas:
- Core Layer (
StrayApp.js): Gerenciamento principal e orquestração - Mapping Layer (
DependencyMapping.js): Resolução e análise de dependências - Intelligence Layer: Sistema de props inteligentes e detecção automática
- Service Layer: Isolamento e carregamento de serviços
⚡ Performance
- Lazy Loading: Serviços são carregados apenas quando necessário
- Caching: Dependências resolvidas são cacheadas para reutilização
- Smart Detection: Algoritmo otimizado para detecção de dependências
- Minimal Overhead: Impacto mínimo na performance da aplicação
Desenvolvido pela equipe TeraPROX - Versão 1.0.0
