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 🙏

© 2025 – Pkg Stats / Ryan Hefner

jigjs

v0.0.0-pre-alpha.31

Published

A front-end library

Readme

License: MITJig npm version Coverage Status PRs Welcome

jigjs is a web library that combines reactiveness with OOP. Making it easy to react to object side-effects.

import {observable, observing, observe} from "jigjs/reactive";

@observable()
class Greater {
    @observing()
    private name;

    constructor(name: string) {
        this.name = name;
    }

    say() {
        return `Hello, ${this.name}!`
    }
    
    updateName(name: string) {
        this.name = name;
    }
}

const greater = new Greater("World!");

const subscription = observe(greater, () => {
    console.log(greater.say());   
});

greater.updateName('Universe'); // calls the observer and prints "Hello, Universe"
greater.updateName('Mars'); // calls the observer and prints "Hello, Mars"

subscription.unsubscribe();

greater.updateName('Earth'); // does not prints anything

Installation

npm install -g jigjs 

Components

A component is a small UI peace that manages its own state. Whenever the class fields decorated with @observing changes the component is re-rendered.

import {component, html} from "jigjs/components";
import {observing} from "jigjs/reactive";

@component()
export class CounterComponent {
    @observing()
    private number: number;

    constructor(initialCount = 0) {
        this.number = initialCount;
    }

    reset() {
       this.number = 0;
    }

    render() {
        return html`
            <button onclick="${() => { this.number++ }}">+</button>
            ${this.number}
            <button onclick="${() => { this.number-- }}">-</button>
        `;
    }
}

Using the component:

import {component, html, renderComponent} from "jigjs/components";

@component()
export class CounterPage {
    private readonly counter: CounterComponent;

    constructor() {
        this.counter = new CounterComponent();
    }

    render() {
        return html`
            <h1>Counter</h1>
        
            ${this.counter}

            <hr>
    
            <button onclick=${this.counter.reset()}>Reset counter</button>
        `;
    }
}

renderComponent(document.querySelector('#root'), new CounterPage());

In jigjs you control the component instance. There isn't a magic way to update a component props. The component props is its state, and you update it by using class methods.

Styling the component

There is a css-in-js module for jigjs.

Read more about jigcss here.

Creating an APP

As showed in the previous example, you can use jigjs as a simple library by using the renderComponent function. However, it is also possible to use jigjs as a framework.

To start a jigjs project you can use the cli:

npm install -g jigjs
npx jigjs-new-project

Installation demo

It comes with a Router system that enables Single Page Applications, Native Server Side Rendering and built-in build system.

Routing

A router is composed by a path, a name and handler.

  • path is used to match the user request.
  • name is used to reverse a route.
  • handler is called when the path matches the user request.
new Routes([
    {
        path: '/',
        name: 'index',
        handler(params, render) {
            render(new IndexPage());
        }
    },
    {
        path: '/hello/:name',
        name: 'hello',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    },
    {
        path: '/hello/?name=:name',
        name: 'hello:with-query',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    },
    {
        path: '/hello/#:name',
        name: 'hello:with-hash',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    }
]);

For more examples of router matchers: https://github.com/rcs/route-parser

Navigation

To redirect users to a specific URL you can use the Navigation object.

 const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/',
        name: 'index',
        handler() {
            // ...
        }
    },
    {
        path: '/hello/:name',
        name: 'hello',
        handler() {
            // ...
        }
    }
]));

routerModule.navigation.navigateTo('hello', {name: 'world'});
routerModule.navigation.navigateTo('index');

Async Handlers

When you need to process async functions in your components you can make your handler to return a promise.

const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/user/:id',
        name: 'show-user',
        async handler(params, render) {
            render(new PageLoadingComponent());
            const user = await fetchUser(params.id);
            render(new UserPage(user));
        }
    }
]));

The server will only release the request when the promise is resolved. You can call the render function as much as you want, this is useful to render loading components that will be visible when the code is executed from the client-side.

Custom Response

The handler receives the response object that can be used to add custom headers and status code.

There is no need to specify the response body since it will be always the render result.

const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/user/:id',
        name: 'show-user',
        async handler(params, render, transferState, response) {
            try {
                const user = await fetchUser(params.id);
                render(new UserPage(user));
            } catch(e) {
                response.statusCode = 404;
                response.headers['custom-error'] = 'User not found';

                render(new UserNotFoundPage());
            }
        }
    }
]));

Transfer State

When you make a request to the jigjs server, it will pre-render the entire page and return it as raw HTML. Coming to browser, jigjs will execute the same code that had executed on server. It means that, any request you performed at the server-side will be performed again.

To prevent this kind of behavior you must use TransferState. TheTransferState is a key-value object that can be shared from server to browser. Once the server stores a value using TransferState.setState it will be available to browser thought the TransferState.getState.

const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/my-transfer-state-page',
        name: 'my-transfer-state-page',
        async handler(params, render, transferState) {
            if (transferState.hasState('page-title')) {
                render(new MyPage(transferState.getState('page-title')));
                return;
            }

            render(new PageLoadingComponent());
            const pageTitle = await asyncMethodThatReturnsANicePageTitle();
            transferState.setState('page-title', pageTitle);
            render(new MyPage(pageTitle));
        }
    }
]));

SSR limitations

There is no global variable like window or document because global variables into a back-end application leads to concurrency issues. If you want to access the window or document you can use the window injected into the AppFactory.

For third-party libraries you can use the Platform object to verify if the code is being executed from browser.