@arc-js/config-manager
v0.0.98
Published
CONFIG-MANAGER est un système de gestion de configuration modulaire pour les applications React avec TypeScript/JavaScript. Il fournit une gestion centralisée des configurations, un chargement dynamique des modules, et une intégration transparente avec le
Readme
@arc-js/config-manager
@arc-js/config-manager est un système de gestion de configuration modulaire et performant pour les applications React avec TypeScript/JavaScript. Il fournit une gestion avancée des configurations, un chargement dynamique par scope et module, et une intégration transparente avec l'écosystème Arc.
✨ Fonctionnalités Principales
🌍 Gestion Multi-Scope Avancée
- Support de plusieurs scopes avec persistance automatique
- Chargement dynamique des configurations par scope
- Isolation des configurations entre environnements
- Changement à chaud de scope sans rechargement
📦 Architecture Modulaire
- Configurations par module avec isolation complète
- Chargement à la demande des configurations de modules
- Fusion intelligente des configurations hiérarchiques
- Support des namespaces pour une organisation claire
⚡ Performance Optimisée
- Chargement paresseux des fichiers de configuration
- Mémoire cache des configurations chargées
- Minimal bundle size grâce au code splitting
- Hot reload pendant le développement
🔧 Intégration Facile
- Provider React simple à configurer
- Hooks personnalisés pour une utilisation intuitive
- Compatibilité totale avec TypeScript
- Intégration avec @arc-js/cooks pour la persistance
📦 Installation
Via npm/yarn/pnpm
npm install @arc-js/config-manager @arc-js/cooks react
# ou
yarn add @arc-js/config-manager @arc-js/cooks react
# ou
pnpm add @arc-js/config-manager @arc-js/cooks reactDépendances requises
- React 19+
- @arc-js/cooks 1.0.0+
- TypeScript 5.0+ (recommandé)
🚀 Démarrage Rapide
Structure de projet recommandée
src/
├── configs/
│ ├── app/
│ │ ├── development.ts # Config scope development
│ │ ├── staging.ts # Config scope staging
│ │ └── production.ts # Config scope production
│ ├── modules/
│ │ ├── admin/
│ │ │ └── config.ts # Configuration du module admin
│ │ └── dashboard/
│ │ └── config.ts # Configuration du module dashboard
└── main.tsxConfiguration de base
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ArcConfigProvider } from '@arc-js/config-manager';
const App = () => {
return (
<div>
<h1>Mon Application Configurable</h1>
{/* Votre contenu ici */}
</div>
);
};
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ArcConfigProvider
config={{
base: {
development: async () => (await import('./configs/app/development.ts')).default,
staging: async () => (await import('./configs/app/staging.ts')).default,
production: async () => (await import('./configs/app/production.ts')).default
},
modules: {
admin: async () => (await import('./configs/modules/admin/config.ts')).default,
dashboard: async () => (await import('./configs/modules/dashboard/config.ts')).default
}
}}
supportedScopes={['development', 'staging', 'production']}
>
<App />
</ArcConfigProvider>
</React.StrictMode>
);Fichiers de configuration
// configs/app/development.ts
export default {
api: {
baseUrl: 'https://dev-api.example.com',
timeout: 5000
},
features: {
analytics: true,
debug: true
},
ui: {
theme: 'light',
language: 'en'
}
};
// configs/modules/admin/config.ts
export default {
permissions: {
canEdit: true,
canDelete: false,
canCreate: true
},
settings: {
pagination: 20,
exportFormats: ['csv', 'pdf', 'excel']
}
};📚 Documentation API
Hook useConfig
import { useConfig } from '@arc-js/config-manager';
const MyComponent = () => {
const {
cf, // Fonction d'accès aux configurations
changeScope, // Changer le scope actuel
currentScope, // Scope actuel
isLoading, // État de chargement
loadModule // Charger un module spécifique
} = useConfig('admin'); // Optionnel: nom du module
// Exemple d'utilisation
const handleChangeScope = () => {
changeScope(currentScope === 'development' ? 'staging' : 'development');
};
// Accès aux valeurs de configuration
const apiUrl = cf('api.baseUrl');
const canEdit = cf('permissions.canEdit', { moduleName: 'admin' });
return (
<div>
<h1>Configuration du module Admin</h1>
<p>Scope actuel: {currentScope}</p>
<p>URL API: {apiUrl}</p>
<p>Permission d'édition: {canEdit ? 'Oui' : 'Non'}</p>
<button onClick={handleChangeScope}>
Passer à {currentScope === 'development' ? 'Staging' : 'Development'}
</button>
</div>
);
};ArcConfigProvider
import { ArcConfigProvider } from '@arc-js/config-manager';
// Configuration complète avec modules
<ArcConfigProvider
config={{
base: {
development: async () => (await import('./configs/app/development.ts')).default,
staging: async () => (await import('./configs/app/staging.ts')).default,
production: async () => (await import('./configs/app/production.ts')).default
},
modules: {
admin: {
development: async () => (await import('./configs/modules/admin/development.ts')).default,
staging: async () => (await import('./configs/modules/admin/staging.ts')).default,
production: async () => (await import('./configs/modules/admin/production.ts')).default
},
dashboard: {
development: async () => (await import('./configs/modules/dashboard/development.ts')).default,
staging: async () => (await import('./configs/modules/dashboard/staging.ts')).default,
production: async () => (await import('./configs/modules/dashboard/production.ts')).default
}
}
}}
supportedScopes={['development', 'staging', 'production']}
>
{children}
</ArcConfigProvider>🔧 Utilisation Avancée
Accès aux configurations avec chemins imbriqués
const ConfigComponent = () => {
const { cf } = useConfig();
// Accès à des valeurs imbriquées
const apiConfig = cf('api');
const baseUrl = cf('api.baseUrl');
const debugMode = cf('features.debug');
return (
<div>
<p>URL de base: {baseUrl}</p>
<p>Mode debug: {debugMode ? 'Activé' : 'Désactivé'}</p>
<pre>{JSON.stringify(apiConfig, null, 2)}</pre>
</div>
);
};Valeurs par défaut et fallback
const SafeConfigComponent = () => {
const { cf } = useConfig();
// Avec valeur par défaut
const timeout = cf('api.timeout', { defaultValue: 3000 });
// Accès avec chemin inexistant
const missingValue = cf('non.existent.key', { defaultValue: 'valeur par défaut' });
return (
<div>
<p>Timeout: {timeout}ms</p>
<p>Valeur manquante: {missingValue}</p>
</div>
);
};Chargement dynamique de modules
import { useEffect } from 'react';
import { useConfig } from '@arc-js/config-manager';
const AdminModule = () => {
const { cf, loadModule, isLoading } = useConfig('admin');
useEffect(() => {
// Charger les configurations du module admin à la demande
loadModule('admin');
}, []);
if (isLoading) return <div>Chargement des configurations...</div>;
return (
<div>
<h1>Dashboard Admin</h1>
<p>Pagination: {cf('settings.pagination')} éléments</p>
<p>Formats d'export: {cf('settings.exportFormats').join(', ')}</p>
</div>
);
};Configuration multi-scope par module
// configs/modules/admin/development.ts
export default {
permissions: {
canEdit: true,
canDelete: true,
canCreate: true
},
limits: {
maxUsers: 100,
maxStorage: '10GB'
}
};
// configs/modules/admin/production.ts
export default {
permissions: {
canEdit: true,
canDelete: false,
canCreate: true
},
limits: {
maxUsers: 1000,
maxStorage: '100GB'
}
};🎯 Exemples Complets
Exemple 1 : Sélecteur de scope
import { useConfig } from '@arc-js/config-manager';
const ScopeSwitcher = () => {
const { currentScope, changeScope, cf } = useConfig();
const scopes = [
{ code: 'development', name: 'Développement', description: 'Environnement de développement' },
{ code: 'staging', name: 'Staging', description: 'Environnement de pré-production' },
{ code: 'production', name: 'Production', description: 'Environnement de production' }
];
return (
<div className="scope-switcher">
<h3>Sélecteur d'environnement</h3>
<div className="scope-buttons">
{scopes.map(scope => (
<button
key={scope.code}
className={currentScope === scope.code ? 'active' : ''}
onClick={() => changeScope(scope.code)}
title={scope.description}
>
{scope.name}
</button>
))}
</div>
<p className="current-scope-info">
Environnement actuel: <strong>{currentScope}</strong>
</p>
</div>
);
};Exemple 2 : Configuration dynamique d'API
import { useConfig } from '@arc-js/config-manager';
import { useState, useEffect } from 'react';
const ApiDashboard = () => {
const { cf, currentScope } = useConfig();
const [apiStatus, setApiStatus] = useState('checking');
useEffect(() => {
const checkApiStatus = async () => {
try {
const baseUrl = cf('api.baseUrl');
const timeout = cf('api.timeout', { defaultValue: 5000 });
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
const response = await fetch(`\${baseUrl}/health`, {
signal: controller.signal
});
clearTimeout(timeoutId);
if (response.ok) {
setApiStatus('healthy');
} else {
setApiStatus('unhealthy');
}
} catch (error) {
setApiStatus('unreachable');
}
};
checkApiStatus();
}, [cf, currentScope]);
return (
<div className="api-dashboard">
<h2>Statut de l'API</h2>
<div className="api-info">
<p><strong>Environnement:</strong> {currentScope}</p>
<p><strong>URL de base:</strong> {cf('api.baseUrl')}</p>
<p><strong>Timeout:</strong> {cf('api.timeout')}ms</p>
<p><strong>Statut:</strong>
<span className={`status-\${apiStatus}`}>
{apiStatus === 'healthy' ? '✅ En ligne' :
apiStatus === 'unhealthy' ? '⚠️ Problèmes' :
'❌ Hors ligne'}
</span>
</p>
</div>
</div>
);
};Exemple 3 : Dashboard avec modules multiples
import { useConfig } from '@arc-js/config-manager';
import { useEffect } from 'react';
const Dashboard = () => {
const { cf, loadModule, currentScope, isLoading } = useConfig('admin');
// Charger les configurations de plusieurs modules
useEffect(() => {
const loadModules = async () => {
await loadModule('admin');
await loadModule('analytics');
await loadModule('reports');
};
loadModules();
}, [currentScope]);
if (isLoading) return <div>Chargement des configurations...</div>;
return (
<div className="dashboard">
<header>
<h1>Tableau de bord de configuration</h1>
<p>Environnement: {currentScope}</p>
</header>
<section className="config-cards">
<div className="config-card">
<h3>Configuration Admin</h3>
<ul>
<li>Édition: {cf('permissions.canEdit', { moduleName: 'admin' }) ? '✅' : '❌'}</li>
<li>Suppression: {cf('permissions.canDelete', { moduleName: 'admin' }) ? '✅' : '❌'}</li>
<li>Pagination: {cf('settings.pagination', { moduleName: 'admin' })} éléments</li>
</ul>
</div>
<div className="config-card">
<h3>Configuration Analytics</h3>
<ul>
<li>Tracking: {cf('features.enabled', { moduleName: 'analytics' }) ? 'Activé' : 'Désactivé'}</li>
<li>Rétention: {cf('data.retentionDays', { moduleName: 'analytics' })} jours</li>
</ul>
</div>
<div className="config-card">
<h3>Configuration API</h3>
<ul>
<li>URL: {cf('api.baseUrl')}</li>
<li>Version: {cf('api.version', { defaultValue: 'v1' })}</li>
<li>Debug: {cf('features.debug') ? 'Activé' : 'Désactivé'}</li>
</ul>
</div>
</section>
</div>
);
};📋 API Reference
ArcConfigProvider
| Prop | Type | Description | Required |
|------|------|-------------|----------|
| config | ConfigManagerConfig | Configuration des chargeurs de configuration | Oui |
| supportedScopes | string[] | Scopes supportés (défaut: ['app']) | Non |
| children | React.ReactNode | Composants enfants | Oui |
Hook useConfig
Retourne un objet avec:
cf(key: string, options?: ConfigOptions): Fonction d'accès aux configurationschangeScope(scope: string): Changer le scope actuelcurrentScope: Scope actuelisLoading: État de chargement globalisModuleLoaded: Indique si le module demandé est chargéloadModule(moduleName: string): Charge un module spécifique
Options de Configuration
interface ConfigOptions {
moduleName?: string; // Nom du module (défaut: 'app')
defaultValue?: any; // Valeur par défaut si clé non trouvée
}Structure de configuration
interface ConfigManagerConfig {
base: {
[scope: string]: () => Promise<Record<string, any>>;
};
modules?: {
[moduleName: string]: () => Promise<Record<string, any>>;
};
}Types principaux
export type ConfigScope = string;
export type ConfigMap = { [scope: string]: () => Promise<Record<string, any>> };
export type ModuleConfigs = { [moduleName: string]: () => Promise<Record<string, any>> };🛡️ Gestion des Erreurs
Fallback sécurisé
const SafeComponent = () => {
const { cf } = useConfig();
// Utilisation sécurisée avec valeur par défaut
const apiUrl = cf('api.baseUrl', {
defaultValue: 'https://default-api.example.com'
});
// Accès imbriqué sécurisé
const theme = cf('ui.theme', { defaultValue: 'light' });
return (
<div>
<p>API: {apiUrl}</p>
<p>Theme: {theme}</p>
</div>
);
};Logs en développement
// En mode développement, les clés manquantes sont automatiquement loggées
const MissingConfigs = () => {
const { cf } = useConfig();
// Ceci loggue un avertissement en développement
const missingKey = cf('non.existent.key');
return <div>{missingKey || 'Configuration manquante'}</div>;
};🔧 Configuration TypeScript
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"types": ["vite/client"]
},
"include": ["src", "node_modules/@arc-js/config-manager/**/*"]
}📋 Table des Conventions
Structure des fichiers de configuration
| Chemin | Description | Exemple |
|--------|-------------|---------|
| configs/app/{scope}.ts | Configuration de base par scope | configs/app/development.ts |
| configs/modules/{module}/config.ts | Configuration du module | configs/modules/admin/config.ts |
| configs/modules/{module}/{scope}.ts | Configuration du module par scope | configs/modules/admin/production.ts |
Clés de configuration
| Format | Description | Exemple |
|--------|-------------|---------|
| namespace.key | Clé simple | api.baseUrl |
| namespace.nested.key | Clé imbriquée | features.analytics.enabled |
| moduleName:key | Avec module spécifique | admin:permissions.canEdit |
🔧 Build et Développement
Scripts recommandés
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"type-check": "tsc --noEmit",
"validate-configs": "node scripts/validate-configs.js",
"generate-config-schema": "node scripts/generate-schema.js"
}
}Configuration Vite
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@arc-js/config-manager': '@arc-js/config-manager/index.js'
}
}
});📄 Licence
MIT License - Voir le fichier LICENSE pour plus de détails.
🐛 Signaler un Bug
Envoyez-nous un mail à l'adresse [email protected] pour :
- Signaler un bug
- Proposer une amélioration
- Poser une question sur l'utilisation
- Demander une nouvelle fonctionnalité
@arc-js/config-manager - La solution de gestion de configuration modulaire pour React et TypeScript.
Développé par l'équipe INICODE
