create-minijs
v1.0.5
Published
just a mini framework based on react and vue js
Readme
MiniFramework
A minimal JavaScript framework built from scratch demonstrating core framework concepts including DOM abstraction, routing, state management, and event handling.
Features
- Virtual DOM: Efficient DOM manipulation through virtual node representation
- Component System: Class-based components with lifecycle methods
- State Management: Global store with reducers and actions
- Routing: Client-side routing with history API
- Event Handling: Custom event system with framework integration
Getting Started
Installation
node server.mjsVisit http://localhost:3000 to see the todo example.
Framework Architecture
Core Concepts
MiniFramework follows the inversion of control principle - the framework calls your code, not the other way around. This is achieved through:
- Component Lifecycle: Framework manages when components render and update
- Event System: Framework handles event delegation and state updates
- Routing: Framework controls navigation and route matching
- State Management: Framework manages global state and triggers re-renders
Virtual DOM
The framework uses a Virtual DOM to efficiently update the real DOM:
// Virtual nodes are plain objects
const vnode = {
tag: 'div',
attrs: { className: 'container' },
children: ['Hello World']
};Component System
Components extend the base Component class:
import { Component, createNode } from './framework/index.js';
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return createNode('div', {}, [
createNode('p', {}, `Count: ${this.state.count}`),
createNode('button', {
onclick: () => this.handleClick()
}, 'Increment')
]);
}
}API Reference
Creating Elements
Use the createNode function to create virtual DOM nodes:
import { createNode } from './framework/index.js';
// Simple element
const element = createNode('div', { className: 'container' }, 'Hello');
// Element with children
const complex = createNode('div', {}, [
createNode('h1', {}, 'Title'),
createNode('p', {}, 'Content')
]);
// Element with events
const interactive = createNode('button', {
onclick: (e) => console.log('Clicked!'),
className: 'btn'
}, 'Click me');Adding Events
Events are added as attributes starting with 'on':
const button = createNode('button', {
onclick: (event) => {
console.log('Button clicked');
},
onmouseover: (event) => {
console.log('Mouse over');
}
}, 'Interactive Button');Nesting Elements
Elements can be nested by passing children as the third parameter:
const nested = createNode('div', { className: 'parent' }, [
createNode('div', { className: 'child' }, [
createNode('span', {}, 'Deeply nested content')
])
]);Adding Attributes
Attributes are passed as the second parameter:
const input = createNode('input', {
type: 'text',
placeholder: 'Enter text...',
className: 'form-input',
id: 'my-input',
value: 'default value'
});State Management
Local Component State
Components can manage local state using setState:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment() {
this.setState({ count: this.state.count + 1 });
}
render() {
return createNode('div', {}, [
createNode('span', {}, `Count: ${this.state.count}`),
createNode('button', { onclick: () => this.increment() }, '+')
]);
}
}Global State Store
The framework provides a global store for shared state:
// Add a reducer
app.store.addReducer('counter', (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
});
// In components, dispatch actions
this.dispatch({ type: 'INCREMENT' });
// Get state
const count = this.getGlobal('counter');Routing
The framework includes a simple client-side router:
// Navigation in components
this.navigate('/about');
// Check current route
const isHome = this.framework.router.matchRoute('/');
// Route-based rendering
render() {
const route = this.framework.router.getCurrentRoute();
if (route === '/') {
return createNode('div', {}, 'Home Page');
} else if (route === '/about') {
return createNode('div', {}, 'About Page');
}
}Why It Works This Way
Inversion of Control
Traditional libraries require you to call their methods:
// Library approach - you call the library
const element = document.createElement('div');
element.textContent = 'Hello';
document.body.appendChild(element);Frameworks control the flow and call your code:
// Framework approach - framework calls your render method
class MyComponent extends Component {
render() {
return createNode('div', {}, 'Hello'); // Framework calls this
}
}Virtual DOM Benefits
- Performance: Only updates changed elements
- Predictability: Declarative rendering
- Abstraction: Work with objects instead of DOM directly
Component Lifecycle
The framework manages when components:
- Mount (first render)
- Update (state changes)
- Unmount (removed from DOM)
This ensures consistent behavior and optimal performance.
State Management Philosophy
- Local State: Component-specific data
- Global State: Shared application data
- Unidirectional Flow: Actions → Reducers → State → Re-render
This pattern makes applications predictable and debuggable.
TodoMVC Example
The included TodoMVC implementation demonstrates all framework features:
- Components: TodoApp, TodoHeader, TodoList, TodoItem, TodoFooter
- State Management: Todo CRUD operations with reducers
- Routing: Filter-based navigation (All/Active/Completed)
- Events: Form submission, clicks, keyboard input
- DOM Abstraction: Efficient list rendering and updates
Run the example to see the framework in action!
