Chapitre 2 : Configuration

Le fichier appConfig.js

Le fichier appConfig.js centralise toute la configuration de l'application. Il est passé au Provider de SmartCommon.

// src/appConfig.js
export const config = {
    // Mode debug
    debug: import.meta.env.DEV,

    // Configuration API
    api: {
        prefixUrl: import.meta.env.VITE_API_URL,
        timeout: 30000,
        debug: import.meta.env.DEV,
        paths: {
            login: "login",
            logout: "logout",
            refresh: "refresh"
        }
    },

    // Persistance localStorage
    storage: {
        local: ["session", "settings"]
    },

    // État global initial
    globalState: {
        reducers: {
            session: null,
            settings: { lng: "fr" },
            items: []
        }
    },

    // Animations de transition
    pages: {
        "/": { "/settings": "slideLeft", "*": "fade" },
        "*": "fade"
    }
};

Détail des options

debug

debug: import.meta.env.DEV

Active les logs de debug dans la console. Utilise la variable d'environnement Vite DEV qui est true en développement.

api

Configuration du client HTTP (ky) avec authentification JWT.

api: {
    // URL de base pour toutes les requêtes
    prefixUrl: import.meta.env.VITE_API_URL,

    // Timeout en millisecondes
    timeout: 30000,

    // Logs des requêtes en console
    debug: import.meta.env.DEV,

    // Endpoints SmartAuth
    paths: {
        login: "login",      // POST pour authentification
        logout: "logout",    // POST pour déconnexion
        refresh: "refresh"   // GET pour renouveler le token
    }
}

storage

Définit quelles clés de l'état global sont persistées en localStorage.

storage: {
    local: ["session", "settings"]
}

Avec cette configuration :

  • session sera sauvegardé dans localStorage.session
  • settings sera sauvegardé dans localStorage.settings
  • Au rechargement de la page, ces valeurs seront restaurées

Cas d'usage :

  • session : tokens JWT et informations utilisateur
  • settings : préférences (langue, thème)

globalState

Initialise l'état global Redux via useGlobalStates.

globalState: {
    reducers: {
        // Utilisateur connecté (null = non connecté)
        session: null,

        // Préférences utilisateur
        settings: { lng: "fr" },

        // Données métier
        items: [],
        currentItem: null
    }
}

Chaque clé devient accessible via useGlobalStates :

const gst = useGlobalStates();

const session = gst.get('session');
const settings = gst.get('settings');
const items = gst.get('items');

// Écriture
gst.set('items', [...items, newItem]);

// Écriture avec persistance localStorage
gst.local.set('session', userData);
gst.local.set('settings', { lng: 'en' });

pages

Configuration des animations de transition entre pages (Framer Motion).

pages: {
    // Depuis la page "/"
    "/": {
        "/settings": "slideLeft",  // Vers settings : glisse à gauche
        "*": "fade"                 // Vers autres : fondu
    },
    // Depuis toute autre page
    "*": "fade"
}

Animations disponibles :

  • fade : fondu enchaîné
  • slideLeft : glisse vers la gauche
  • slideRight : glisse vers la droite
  • slideUp : glisse vers le haut
  • slideDown : glisse vers le bas

Le Provider SmartCommon

Le Provider initialise tous les contextes nécessaires :

// src/App.jsx
import { Provider } from '@cap-rel/smartcommon';
import { Router } from './components/app/Router';
import { config } from './appConfig';

export const App = () => (
    <Provider config={config}>
        <Router />
    </Provider>
);

Props du Provider

Prop Type Description
config object Configuration de l'application (appConfig)
onError function Callback en cas d'erreur
errorFallback ReactNode Contenu de remplacement en cas d'erreur
ErrorFallbackComponent Component Composant de remplacement en cas d'erreur
pwaUpdate object Props transmises à UpdatePrompt (voir chapitre Gestion d'état)

Exemple avec mise à jour PWA

export const App = () => (
    <Provider
        config={config}
        pwaUpdate={{ variant: 'toast', checkInterval: 300000 }}
    >
        <Router />
    </Provider>
);

En interne, le Provider encapsule :

// Équivalent interne (simplifié)
<ErrorBoundary>
    <LibConfigProvider config={config}>
        <ReduxProvider>
            <GlobalStatesProvider>
                <ApiProvider>
                    <ConfirmProvider>
                        <Router>
                            <NavigationProvider>
                                {children}
                            </NavigationProvider>
                        </Router>
                        <Toaster />
                        {pwaUpdate && <UpdatePrompt />}
                    </ConfirmProvider>
                </ApiProvider>
            </GlobalStatesProvider>
        </ReduxProvider>
    </LibConfigProvider>
</ErrorBoundary>

Accéder à la configuration

Dans n'importe quel composant :

import { useLibConfig } from '@cap-rel/smartcommon';

function MyComponent() {
    const config = useLibConfig();

    console.log(config.api.prefixUrl);
    console.log(config.debug);

    return <div>...</div>;
}

Configuration avancée

Internationalisation (i18n)

export const config = {
    // ...
    i18n: {
        defaultLanguage: 'fr',
        supportedLanguages: ['fr', 'en'],
        debug: import.meta.env.DEV
    }
};

Base de données locale (Dexie)

export const config = {
    // ...
    db: {
        name: 'monapp',
        version: 1,
        stores: {
            items: 'id++, name, category',
            logs: 'id++, action, timestamp'
        }
    }
};

Bonnes pratiques

1. Utiliser les variables d'environnement

// .env.development
VITE_API_URL=http://localhost/dolibarr/modules/monmodule/pwa/api.php

// .env.production
VITE_API_URL=https://production.com/modules/monmodule/pwa/api.php

2. Séparer les environnements

const isDev = import.meta.env.DEV;

export const config = {
    debug: isDev,
    api: {
        prefixUrl: import.meta.env.VITE_API_URL,
        timeout: isDev ? 60000 : 30000,  // Plus long en dev
        debug: isDev
    }
};

3. Ne pas stocker de données sensibles

storage: {
    // OK : données non sensibles
    local: ["session", "settings", "cart"],

    // PAS dans le code : mots de passe, clés API côté serveur
}

Exemple complet

// src/appConfig.js
const isDev = import.meta.env.DEV;

export const config = {
    debug: isDev,

    api: {
        prefixUrl: import.meta.env.VITE_API_URL,
        timeout: isDev ? 60000 : 30000,
        debug: isDev,
        paths: {
            login: "login",
            logout: "logout",
            refresh: "refresh"
        }
    },

    storage: {
        local: ["session", "settings"]
    },

    globalState: {
        reducers: {
            // Auth
            session: null,

            // Préférences
            settings: {
                lng: "fr",
                theme: "light",
                notifications: true
            },

            // Données métier
            products: [],
            cart: { items: [], total: 0 },
            currentProduct: null
        }
    },

    pages: {
        "/": {
            "/cart": "slideLeft",
            "/product/*": "slideLeft",
            "*": "fade"
        },
        "/cart": {
            "/": "slideRight",
            "*": "fade"
        },
        "*": "fade"
    },

    i18n: {
        defaultLanguage: 'fr',
        supportedLanguages: ['fr', 'en']
    }
};

Points clés à retenir

  1. appConfig.js centralise toute la configuration
  2. api configure le client HTTP avec JWT
  3. storage.local définit ce qui est persisté
  4. globalState.reducers initialise l'état global
  5. pages configure les animations de transition
  6. Utiliser import.meta.env pour les variables d'environnement

← Chapitre précédent | Retour au module | Chapitre suivant : Flux de données ->