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

turbo-web

v4.5.0

Published

---

Readme

TURBO-WEB FRAMEWORK

I. OVERVIEW


Lightweight JavaScript framework based on a book "Build a Frontend Web Framework (from scratch)" by Angel Sola Orbaiceta with additional features sprinkled on top.

II. INSTALLATION


There are 4 ways to utilize this framework: NPM installation, SETUP script (NODE), locally and through CDN.

(1) NPM Installation

To install Turbo-Web framework, run in your terminal npm install turbo-web

(2) NODE initialization script

To install the framework with pre-configured templates using CLI, run in your terminal npx turbo-web PROJECT_NAME This will create a starting kit: project directory, package.json, index.html + src/ with router.js, main.js and store.js

// script exists under bin/turbo-charge.js

(3) Locally

To import the framework locally - you must include the bundled file located in ./framework/runtime/dist/turbo.js as imports

// This file can be generated using script npm run build

Example:

'import {createApp, defineComponent, h, hFragment,} from '../../../framework/runtime/dist/turbo.js'

(4) Using CDN (Content Delivery Network)

You can import any version of the framework directly into your JS file:

import {createApp, defineComponent, h, hFragment,} from 'https://unpkg.com/turbo-web'

CDN Version control ( version 1x.2x.3x):

  1. x MAJOR: @1 or @^1.0.0 - fetches latest compatible minor and path release
  2. x MINOR: @1.2 or @~1.2.0 - fetches latest compatible patch release of a certain MINOR version 0.X.0
  3. x PATCH: @1.2.3 - fetches a specific build with full version control

import ... from 'https://unpkg.com/turbo-web@2' - will import latest minor + patch version of 2.X.X.

III. GETTING STARTED


[1] IMPORT

  1. (2.) NPM installation & NODE script: Import from packages:

import { createApp, defineComponent, h, hFragment } from 'turbo-web'

  1. (4.) Locally & CDN: You must use relative paths (./ or ../):

import { createApp, defineComponent, h, hFragment } from './framework/runtime/index.js'

[2] LAUNCH

You can run server using npm run serve:examples.

If you change code inside examples/ make sure to do a hard reset for changes to apply:

F12 -> right-click on the REFRESH button -> Empty Cache & Hard Reload OR ( Ctrl + Shift + R )

IV. FEATURES


[CORE] Feature 1: Declarative UI

Abstraction principle: Using declarative methods to define final UI instead of manually handling DOM elements. "What the UI looks like vs step-by-step imperative programming"

component.js

[CORE] Feature 2: Virtual DOM

Inversed Control principle - the user doesn't need to manipulate the DOM directly, the framework creates a lightweight JavaScript object tree that represents the UI.

patch-dom.js

[CORE] Feature 3: Reconciliation Algorithm

Inversed Control principle - optimizing DOM manipulations by the process of diffing and patching only the required nodes (improves DOM re-rendering & re-painting).

patch-dom.js

[CORE] Feature 4: Components

Encapsulation & Reusability principles: making UI building blocks with better combined hierarchical tree structure.

// Events accept additional modificator .stop .prevent to stop event bubbling and prevent default browser behaviour.

component.js // building scheme: h(tagOrComponent, { attributes, class, style, on: events }, [children])

Feature 5: Client-Side Router (#hash-based)

Allows for the SPA design (Single Page Application) with route guards (fn: checkNavigation) and a common "catch-all route" (cases: route not found). Based on a hash part of the URL, implemented with regex pattern matching by simulating URL path, parameters and query as part of the hash fragment itself.

router.js, route-matchers.js

Feature 6: Centralized Store

Separation of Concerns & Single Source of Truth principles: Allows for a global state handling and eliminates the need for prop drilling. store.js

Feature 7: Persistent Storage

Single Source of Truth principle: App's state is persistent between sessions.

store.js

Feature 8: built-in HTTP module.

Abstraction principle: simplifies development by abstracting imperative logic in HTTP request handling.

http.js

Feature X: Node-based Initialization through CLI

Scaffolding setup script that creates base structure with required templates for the App

Script: npx turbo-web ${PROJECT_NAME} creates "Project" & src directory + main.js, router.js, store.js + package.json

V. BEST PRACTICES


[1] Router

Define Routes with Guards - Use the beforeEnter guard to protect routes (e.g., authentication).

The router supports asynchronous guards that can either return a boolean or redirect to a different path string

beforeEnter: async (from, to, params, query) => {
    const isAuthenticated = localStorage.getItem('auth_token');
    if (!isAuthenticated) return '/login'; // Redirects to login
    return true; // allows navigation
}

[2] RouterLink

Always use the built-in RouterLink component instead of standard anchor tags (<a href="...">) for internal navigation.

export const Navbar = defineComponent({
    render() {
        return h('nav', {}, [
            h(RouterLink, { to: '/' }, ['Home']),
            h(RouterLink, { to: '/dashboard' }, ['Dashboard'])
        ]);
    }
});

[3] Components

Never mutate this.state directly. Always use this.updateState() to trigger the virtual DOM patching process.

State initialization should be done via the state() function

increment() {
    // Correct: Triggers VDOM diffing and patching
    this.updateState({ count: this.state.count + 1 });
        
    // Incorrect: Will not update the UI
    // this.state.count++; 
}

[4] Centralized Store

Mutations must be strictly synchronous as they immediately write to localStorage and trigger state-change events. Use actions for asynchronous operations like HTTP requests, and have the action commit the mutation.

mutations: {
    setLoading(state, status) {
        state.isLoading = status; // Synchronous
    },
    setUsers(state, users) {
        state.users = users; // Synchronous
    }
},
actions: {
    async fetchUsers({ commit, state }) {
        commit('setLoading', true);
        // Async operation
        const response = await fetch('https://api.example.com/users');
        const data = await response.json();
        commit('setUsers', data);
        commit('setLoading', false);
    }

[5] Subscribe to Store Changes in Components

To make a component react to global state changes, subscribe to the store in onMounted and trigger a local re-render.

You must unsubscribe in onUnmounted!!!.

onMounted() {
    this.unsubscribe = this.appContext.store.subscribe(() => {
        this.updateState({}); // Force re-render
    });
    this.appContext.store.dispatch('fetchUsers');
},
onUnmounted() {
    if (this.unsubscribe) this.unsubscribe();
},

[6] Event bubbling & default browser behaviour override

It is possible to prevent both by passing additional modificators with functions.

on: { 'click.stop': () => this.addLog('Button with .stop Clicked') }
on: { 'click.prevent': () => this.addLog('Link with .prevent Clicked') }