Skip to content
/ Flexi Public

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.

License

Notifications You must be signed in to change notification settings

lablnet/Flexi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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

# Clone the repository
git clone <your-repo-url>
cd Flexi

# Install dependencies
pnpm install

# Start development server
pnpm dev

Basic Usage

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
// 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
// VNode structure:
interface VNode {
  tag: string;
  props: Record<string, any>;
  children: Array<VNode | string>;
}

// 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
// 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:

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

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

# 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

// 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

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

// 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

  • Basic reactive objects with Proxy
  • Dependency tracking with Simple Map and Set
  • 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

  • Basic VNode structure
  • 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

  • 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

  • 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.

About

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.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project