Un framework JavaScript léger créé from scratch sans utiliser React, Angular, Vue ou autres frameworks existants.
- 🎯 Virtual DOM : Manipulation du DOM via des Virtual Nodes (VNodes)
- 🧭 Routing : Système de navigation hash-based (#/)
- 📦 State Management : Store réactif avec pattern Observer/Publisher-Subscriber
- ⚡ Event Handling : Système d'événements custom (alternative à addEventListener)
- 📱 Composants : Architecture basée sur des composants réutilisables
- 🔄 Réactivité : Mise à jour automatique de l'interface lors des changements d'état
Une implémentation complète de TodoMVC est fournie comme démonstration des capacités du framework.
Fonctionnalités TodoMVC :
- ✅ Ajouter/supprimer des tâches
- ✅ Marquer comme complété/non complété
- ✅ Édition en place (double-clic)
- ✅ Filtrage (All/Active/Completed)
- ✅ Compteur des tâches restantes
- ✅ Supprimer toutes les tâches complétées
- ✅ Marquer tout comme complété/non complété
Un serveur HTTP local pour servir les fichiers (requis pour les modules ES6).
# Option 1 : Avec Node.js/npx
npx http-server .
# Option 2 : Avec Python
python -m http.server 8080
# Option 3 : Avec Live Server (VS Code)
# Installer l'extension "Live Server" puis clic droit sur le fichier HTML# Démarrer le serveur
npx http-server .
# Ouvrir dans le navigateur
http://localhost:8080/app/todoMVC/todo.html
# Avec données de démonstration
http://localhost:8080/app/todoMVC/todo.html?demo=true# Ouvrir dans le navigateur
http://localhost:8080/app/exemples/index.htmlLa documentation technique détaillée se trouve dans : framework/README.md
Elle contient :
- Guide d'utilisation complet
- API Reference
- Exemples de code avancés
- Architecture du framework
- Explications des concepts
import { App } from './framework/app.js';
import { createStore } from './framework/store.js';
// Créer un store
const store = createStore({ count: 0 });
// Créer un composant
function Counter() {
const state = store.getState();
return {
tag: 'div',
children: [
{
tag: 'p',
children: [`Compteur : ${state.count}`]
},
{
tag: 'button',
attrs: {
onclick: () => store.setState({ count: state.count + 1 })
},
children: ['Incrémenter']
}
]
};
}
// Configurer l'application
App.defineRoutes({ '/': Counter });
App.startRouting();
// Réactivité : re-render à chaque changement
store.subscribe(() => App.handleRouteChange());mini-framework/
├── README.md # Ce fichier
├── framework/ # Core du framework
│ ├── README.md # Documentation technique détaillée
│ ├── app.js # Système de routing
│ ├── dom.js # Abstraction DOM (Virtual Nodes)
│ └── store.js # Gestion d'état global
└── app/ # Applications de démonstration
├── exemples/ # Exemples de test du framework
│ ├── index.html # Page HTML
│ └── main.js # Code de test (routing, state, events)
└── todoMVC/ # Application TodoMVC complète
├── todo.html # Page HTML
├── todoStyles.css # Styles conforme TodoMVC
├── todoStore.js # Store spécialisé pour todos
├── todoComponents.js # Composants TodoMVC
└── todoMain.js # Point d'entrée
const element = {
tag: 'div',
attrs: {
class: 'container',
id: 'main',
style: 'color: blue;'
},
children: ['Hello World!']
};const nested = {
tag: 'div',
children: [
{
tag: 'h1',
children: ['Titre']
},
{
tag: 'ul',
children: [
{ tag: 'li', children: ['Item 1'] },
{ tag: 'li', children: ['Item 2'] }
]
}
]
};// Méthode 1 : Via attrs (simple)
{
tag: 'button',
attrs: {
onclick: () => alert('Clicked!')
},
children: ['Click me']
}
// Méthode 2 : Via events (recommandée)
{
tag: 'button',
events: {
click: handleClick,
mouseover: handleHover
},
children: ['Advanced button']
}import { createStore } from './framework/store.js';
// Créer un store
const store = createStore({ count: 0, user: null });
// Lire l'état
const state = store.getState();
// Modifier l'état
store.setState({ count: state.count + 1 });
// S'abonner aux changements
store.subscribe((newState) => {
console.log('State updated:', newState);
});import { App } from './framework/app.js';
// Définir les routes
App.defineRoutes({
'/': HomePage,
'/about': AboutPage,
'/counter': CounterPage
});
// Démarrer le routing
App.startRouting();
// Navigation programmatique
App.navigate('/about');
// Obtenir la route actuelle
const current = App.getCurrentRoute();import { render } from './framework/dom.js';
const vnode = {
tag: 'div',
children: ['Hello']
};
const element = render(vnode);
document.getElementById('app').appendChild(element);Le framework utilise des Virtual Nodes (VNodes) - des objets JavaScript qui représentent la structure du DOM. Ces VNodes sont ensuite convertis en vrais éléments DOM par la fonction render().
Pourquoi ?
- Approche déclarative (on décrit CE qu'on veut, pas COMMENT le faire)
- Plus maintenable
- Pattern utilisé par React, Vue, etc.
Navigation basée sur le hash de l'URL (#/). Le framework écoute les changements de hash et affiche le composant correspondant.
Pourquoi ?
- Permet de créer des Single Page Applications (SPA)
- Pas de rechargement de page
- Historique de navigation
Store centralisé avec pattern Observer/Publisher-Subscriber. Quand l'état change, tous les composants abonnés sont notifiés et se re-rendent automatiquement.
Pourquoi ?
- État global accessible partout
- Évite le "props drilling"
- Centralise la logique métier
- Réactivité automatique
Système d'événements déclaratif qui simplifie l'attachement d'événements aux éléments.
Pourquoi ?
- Plus lisible que
addEventListener()direct - Intégré dans la structure des VNodes
- Facile à maintenir
- JavaScript ES6+ (modules, arrow functions, destructuring, spread operator)
- HTML5
- CSS3
- Aucune dépendance externe (vanilla JavaScript uniquement)
- Ajouter plusieurs tâches
- Marquer certaines comme complétées
- Tester les filtres (All/Active/Completed)
- Double-cliquer pour éditer une tâche
- Utiliser "Toggle all"
- Utiliser "Clear completed"
- Vérifier le compteur "X items left"
- Naviguer entre les pages
- Tester le compteur (increment/decrement)
- Tester les événements (click, hover, input)
- Vérifier qu'il n'y a pas d'erreurs dans la console (F12)
Pour plus de détails sur l'implémentation et des exemples avancés :
User Action → Event Handler → Store Action → State Change →
→ Listeners Notified → Re-render → DOM Update
Flux unidirectionnel : Les données circulent dans une seule direction, ce qui rend l'application prévisible et facile à débugger.
Ce projet permet d'apprendre :
- Comment fonctionnent les frameworks modernes (React, Vue, Angular)
- Le concept de Virtual DOM
- Les systèmes de routing
- La gestion d'état réactive
- L'architecture basée sur des composants
- Les patterns de conception (Observer, Publisher-Subscriber)
Ce framework est éducatif. Il ne contient pas :
- Diffing/reconciliation avancée (re-render complet à chaque changement)
- Paramètres de route dynamiques
- Hooks ou état local des composants
- Optimisations de performance avancées
- Support TypeScript
Pour la production, utilisez des frameworks établis (React, Vue, Svelte, etc.)
MIT - Libre d'utilisation pour vos projets personnels et pédagogiques.
En cas de problème :
- Vérifier la console navigateur (F12)
- Vérifier que le serveur HTTP est lancé
- Vérifier les chemins d'import des modules
- Consulter la documentation technique :
framework/README.md
Créé pour comprendre les fondamentaux des frameworks JavaScript modernes.
Bon apprentissage ! 🚀