https://github.com/lablnet/flexi
A minimal reactive framework built for learning purposes to understand how modern frontend frameworks like Vue.js and React work under the hood. Flexi demonstrates the core concepts of reactivity and virtual DOM diffing.
https://github.com/lablnet/flexi
algorithm diffing diffing-algorithm dom flexi framework javascript proxy reactive vdom vue
Last synced: about 9 hours ago
JSON representation
A minimal reactive framework built for learning purposes to understand how modern frontend frameworks like Vue.js and React work under the hood. Flexi demonstrates the core concepts of reactivity and virtual DOM diffing.
- Host: GitHub
- URL: https://github.com/lablnet/flexi
- Owner: lablnet
- License: mit
- Created: 2025-08-23T04:16:09.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-08-23T12:39:40.000Z (8 months ago)
- Last Synced: 2025-08-23T18:31:24.060Z (8 months ago)
- Topics: algorithm, diffing, diffing-algorithm, dom, flexi, framework, javascript, proxy, reactive, vdom, vue
- Language: TypeScript
- Homepage:
- Size: 27.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Flexi - A Lightweight Reactive Framework
A minimal reactive framework built for learning purposes to understand how modern frontend frameworks like Vue.js and React work under the hood. Flexi demonstrates the core concepts of reactivity and virtual DOM diffing.
## π― Learning Objectives
This project is designed to help you understand:
- **Reactivity System**: How automatic dependency tracking and re-rendering works
- **Virtual DOM**: How VDOM diffing and patching algorithms function
- **Component Lifecycle**: How frameworks manage component updates
- **State Management**: How reactive state triggers UI updates
## π Quick Start
### Installation
```bash
# Clone the repository
git clone
cd Flexi
# Install dependencies
pnpm install
# Start development server
pnpm dev
```
### Basic Usage
```typescript
import { Flexi } from "./src/index";
import { h } from "./src/vdom";
const app = new Flexi({
el: "#app",
state: { count: 0 },
render: (state) =>
h("div", { class: "counter" }, [
h("h1", {}, [`Count: ${state.count}`]),
h("button", { onClick: () => state.count++ }, ["Increment"]),
h("button", { onClick: () => state.count-- }, ["Decrement"]),
]),
});
```
## π Core Concepts Explained
### 1. Reactivity System (`src/reactivity.ts`)
The reactivity system is the heart of modern frameworks. It automatically tracks dependencies and re-runs effects when data changes.
#### Key Concepts:
- **Reactive Objects**: Wrapped with `Proxy` to intercept property access
- **Dependency Tracking**: Uses `Map` and `Set` to track which effects depend on which properties
- **Effect System**: `autorun` function that automatically re-executes when dependencies change
```typescript
// How it works internally:
const state = reactive({ count: 0 });
autorun(() => {
console.log(`Count is: ${state.count}`); // Automatically tracks state.count
});
state.count++; // Automatically triggers the effect above
```
#### Learning Points:
- **Proxy API**: How JavaScript proxies enable reactive behavior
- **Dependency Collection**: How frameworks know what to re-run
### 2. Virtual DOM (`src/vdom.ts`)
Virtual DOM is an abstraction over the real DOM that enables efficient updates.
#### Key Concepts:
- **VNode Structure**: Lightweight representation of DOM elements
- **Hyperscript Function**: `h()` function for creating VNodes
- **Element Creation**: Converting VNodes to real DOM elements
```typescript
// VNode structure:
interface VNode {
tag: string;
props: Record;
children: Array;
}
// Creating VNodes:
const vnode = h("div", { class: "container" }, [
h("h1", {}, ["Hello World"]),
h("button", { onClick: handleClick }, ["Click me"])
]);
```
#### Learning Points:
- **DOM Abstraction**: Why VDOM exists and its benefits
- **Element Creation**: How VNodes become real DOM elements
- **Props Handling**: How attributes and event handlers are applied
### 3. Diffing and Patching (`src/patch.ts`)
The diffing algorithm compares old and new VNodes to determine the minimal DOM updates needed.
#### Key Concepts:
- **Tree Diffing**: Comparing VNode trees efficiently
- **Keyed Updates**: Optimizing list updates
- **DOM Patching**: Applying changes to the real DOM
```typescript
// The patch function signature:
patch(parent: Node, oldNode: VNode | string | null, newNode: VNode | string)
```
#### Learning Points:
- **Diffing Strategies**: How to efficiently compare trees
- **Update Batching**: Minimizing DOM operations
- **Error Handling**: Dealing with DOM structure mismatches
## ποΈ Architecture Overview
```
src/
βββ index.ts # Main framework class
βββ reactivity.ts # Reactive state management
βββ vdom.ts # Virtual DOM implementation
βββ patch.ts # Diffing and patching algorithm
```
### Framework Flow
1. **Initialization**: Create reactive state and render initial VDOM
2. **Dependency Tracking**: `autorun` tracks which state properties are accessed
3. **State Changes**: When state changes, effects are automatically triggered
4. **Re-rendering**: New VDOM tree is created from current state
5. **Diffing**: Old and new VDOM trees are compared
6. **Patching**: Minimal DOM updates are applied
## π Examples
### Counter Example (`examples/counter.ts`)
A simple counter demonstrating basic reactivity:
```typescript
const app = new Flexi({
el: "#app",
state: { count: 0 },
render: (state) =>
h("div", { class: "counter" }, [
h("h1", {}, [`Count: ${state.count}`]),
h("button", { onClick: () => state.count++ }, ["Increment"]),
h("button", { onClick: () => state.count-- }, ["Decrement"]),
]),
});
```
### Todo List Example
```typescript
const app = new Flexi({
el: "#app",
state: {
todos: [],
newTodo: ""
},
render: (state) =>
h("div", { class: "todo-app" }, [
h("input", {
value: state.newTodo,
onInput: (e) => state.newTodo = e.target.value
}, []),
h("button", {
onClick: () => {
if (state.newTodo.trim()) {
state.todos.push(state.newTodo);
state.newTodo = "";
}
}
}, ["Add Todo"]),
h("ul", {},
state.todos.map(todo => h("li", {}, [todo]))
)
]),
});
```
## π§ Development
### Running Examples
```bash
# Start development server
pnpm dev
# Build for production
pnpm build
```
### Project Structure
```
Flexi/
βββ src/ # Core framework code
βββ examples/ # Example applications
βββ dist/ # Built files
βββ package.json # Dependencies and scripts
```
## π§ Deep Dive: How It All Works Together
### 1. State Changes Trigger Updates
```typescript
// When you do this:
state.count++;
// Here's what happens internally:
// 1. Proxy intercepts the set operation
// 2. Notifies all effects that depend on 'count'
// 3. Triggers re-render
// 4. Creates new VDOM tree
// 5. Diffs with old tree
// 6. Patches DOM with minimal changes
```
### 2. Dependency Tracking in Action
```typescript
autorun(() => {
// This effect depends on state.count
console.log(state.count);
// And this effect depends on state.name
console.log(state.name);
});
// When state.count changes, only the first console.log re-runs
// When state.name changes, only the second console.log re-runs
```
### 3. VDOM Diffing Process
```typescript
// Old VDOM:
h("div", {}, [h("span", {}, ["Hello"])])
// New VDOM:
h("div", {}, [h("span", {}, ["World"])])
// Diffing result:
// - Same tag (div) β
// - Same tag (span) β
// - Different text content β Update textContent
```
## πΊοΈ Roadmap
This roadmap outlines planned features and enhancements for the Flexi framework. Each item represents a learning opportunity to understand how modern frameworks work.
### Core Framework Enhancements
#### Reactivity System
- [x] Basic reactive objects with Proxy
- [x] Dependency tracking with Simple Map and Set
- [x] Autorun effects
- [ ] **Computed Properties**: Derived state that automatically updates
- [ ] **Watchers**: React to specific state changes
- [ ] **Reactive Arrays**: Special handling for array mutations
- [ ] **Deep Reactivity**: Nested object reactivity
- [ ] **Reactive Maps and Sets**: Collection reactivity
#### Virtual DOM Improvements
- [x] Basic VNode structure
- [x] Hyperscript function (h)
- [ ] **Fragment Support**: Multiple root elements
- [ ] **Portal Support**: Render outside component tree
- [ ] **Suspense**: Async component loading
- [ ] **Error Boundaries**: Error handling components
#### Diffing and Patching
- [x] Basic tree diffing
- [ ] **Keyed Lists**: Optimized list rendering
- [ ] **Component Diffing**: Smart component updates
- [ ] **Batch Updates**: Reduce DOM operations
- [ ] **Async Rendering**: Non-blocking updates
### Template Engine
#### Template Compilation
- [ ] **Template Parser**: Parse HTML-like templates
- [ ] **AST Generation**: Abstract Syntax Tree for templates
- [ ] **Code Generation**: Convert templates to render functions
- [ ] **Directive Support**: f-if, f-for, f-model, etc.
#### Template Features
- [ ] **Conditional Rendering**: `f-if` and `f-else`
- [ ] **List Rendering**: `f-for` with keys
- [ ] **Two-way Binding**: `f-model` for forms
- [ ] **Event Handling**: `@click`, `@input`, etc.
- [ ] **Class and Style Binding**: Dynamic styling
- [ ] **Slot System**: Content projection
### Component System
#### Component Architecture
- [ ] **Component Definition**: Reusable component structure
- [ ] **Props System**: Parent-child communication
- [ ] **Emit System**: Child-parent communication
- [ ] **Component Lifecycle**: mounted, updated, unmounted
- [ ] **Component Registration**: Global and local components
#### Advanced Components
- [ ] **Higher-Order Components**: Component composition
- [ ] **Render Props**: Function as children pattern
- [ ] **Context API**: Cross-component state sharing
- [ ] **Provider Pattern**: Dependency injection
### State Management
#### Local State
- [x] Reactive state objects
- [ ] **State Composition**: Combining multiple state sources
- [ ] **State Persistence**: LocalStorage integration
- [ ] **State Validation**: Schema validation
#### Global State
- [ ] **Store Pattern**: Centralized state management
- [ ] **Actions and Mutations**: Predictable state changes
- [ ] **State Subscriptions**: React to global changes
- [ ] **State DevTools**: Debugging and time-travel
### Performance Optimizations
#### Rendering Optimizations
- [ ] **Memoization**: Prevent unnecessary re-renders
- [ ] **Lazy Loading**: Code splitting and dynamic imports
- [ ] **Virtual Scrolling**: Large list optimization
- [ ] **Tree Shaking**: Remove unused code
#### Memory Management
- [ ] **Garbage Collection**: Proper cleanup of effects
- [ ] **Memory Leak Prevention**: Component cleanup
- [ ] **Weak References**: Prevent memory leaks
### Developer Experience
#### Development Tools
- [ ] **Hot Module Replacement**: Fast development cycles
- [ ] **Source Maps**: Debug original code
- [ ] **Error Overlay**: Better error reporting
- [ ] **Performance Profiling**: Identify bottlenecks
#### Debugging
- [ ] **Reactivity Inspector**: Visualize dependency graph
- [ ] **VDOM Inspector**: Examine virtual DOM structure
- [ ] **State Inspector**: Monitor state changes
- [ ] **Timeline**: Track render cycles
### Build System
#### Bundling
- [ ] **Module Bundler**: Rollup/Vite integration
- [ ] **Tree Shaking**: Remove dead code
- [ ] **Code Splitting**: Dynamic imports
- [ ] **Asset Optimization**: CSS, images, fonts
#### Build Features
- [ ] **TypeScript Support**: Full type safety
- [ ] **JSX Support**: Alternative to hyperscript
- [ ] **CSS-in-JS**: Scoped styles
- [ ] **Static Analysis**: Linting and formatting
### Testing Framework
#### Unit Testing
- [ ] **Component Testing**: Test individual components
- [ ] **Reactivity Testing**: Test reactive behavior
- [ ] **VDOM Testing**: Test virtual DOM operations
- [ ] **Mock System**: Mock dependencies
#### Integration Testing
- [ ] **End-to-End Testing**: Full application testing
- [ ] **Visual Regression**: UI consistency testing
- [ ] **Performance Testing**: Benchmark rendering
### Documentation and Examples
#### Learning Materials
- [ ] **Interactive Tutorials**: Step-by-step guides
- [ ] **Code Sandbox**: Online playground
- [ ] **Video Tutorials**: Visual learning
- [ ] **Best Practices**: Framework conventions
#### Example Applications
- [ ] **Todo App**: Basic CRUD operations
- [ ] **Shopping Cart**: State management
- [ ] **Real-time Chat**: WebSocket integration
- [ ] **Dashboard**: Complex UI patterns
- [ ] **Game**: Interactive applications
### Ecosystem
#### Plugins and Extensions
- [ ] **Plugin System**: Extensible architecture
- [ ] **Router**: Client-side routing
- [ ] **HTTP Client**: API integration
- [ ] **Form Validation**: Input validation
- [ ] **Animation**: Transition system
#### Community
- [ ] **Package Registry**: Share components
- [ ] **Template Gallery**: Pre-built templates
- [ ] **Community Examples**: User contributions
- [ ] **Documentation Site**: Comprehensive docs
---
### Progress Tracking
**Current Status**: π‘ In Progress (Core features implemented)
**Next Milestone**: Template Engine and Component System
**Estimated Completion**: Q3 2025
---
## π Learning Resources
To better understand the concepts implemented here:
- **Reactivity**: Read about Vue 3's Composition API and React's useState
- **Virtual DOM**: Study React's reconciliation algorithm
- **Diffing**: Learn about the diffing strategies used in React and Vue
- **Proxy API**: MDN documentation on JavaScript Proxies
## π€ Contributing
This is a learning project! Feel free to:
- Add more examples
- Implement additional features (computed properties, watchers, etc.)
- Improve the diffing algorithm
- Add tests
- Document more learning concepts
## π License
MIT License - feel free to use this for learning and experimentation!
---
**Happy Learning! π**
This framework demonstrates the fundamental concepts that power modern frontend frameworks. Understanding these concepts will make you a better developer and help you appreciate the complexity and elegance of frameworks like React, Vue, and Svelte.