npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

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

  1. Component Lifecycle: Framework manages when components render and update
  2. Event System: Framework handles event delegation and state updates
  3. Routing: Framework controls navigation and route matching
  4. 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

  1. Performance: Only updates changed elements
  2. Predictability: Declarative rendering
  3. 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!