All Projects → carlosmaniero → jigjs

carlosmaniero / jigjs

Licence: MIT license
🧩 A front-end framework

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to jigjs

attain
Deno API middleware Server
Stars: ✭ 79 (+259.09%)
Mutual labels:  front-end, server-side-rendering
babelfish
🐡 Straightforward library for translations and dictionaries
Stars: ✭ 47 (+113.64%)
Mutual labels:  lib
front-end-challenge
Desafio para candidatos a front-end.
Stars: ✭ 170 (+672.73%)
Mutual labels:  front-end
buttono
A flexible Sass mixin for creating BEM-style buttons.
Stars: ✭ 82 (+272.73%)
Mutual labels:  front-end
node-amazon
E-commerce website done in Node, and Angular 11 (SSR)
Stars: ✭ 48 (+118.18%)
Mutual labels:  server-side-rendering
Emory-BMI-GSoC
Emory BMI GSoC Project Ideas
Stars: ✭ 27 (+22.73%)
Mutual labels:  front-end
universal-react-redux-typescript-starter-kit
A minimal starter kit with React, Redux, server side rendering, hot reloading, and Webpack 2. 100% TypeScript.
Stars: ✭ 12 (-45.45%)
Mutual labels:  server-side-rendering
teams-api
Unofficial Microsoft Teams Library
Stars: ✭ 92 (+318.18%)
Mutual labels:  lib
ui-engineering-questions
Questions for UI engineers and front-end developers
Stars: ✭ 13 (-40.91%)
Mutual labels:  front-end
kaonjs
Kaon.js is a react isomorphic app solution. It contains webpack build, hot reloading, code splitting and server side rendering.
Stars: ✭ 21 (-4.55%)
Mutual labels:  server-side-rendering
awesome-astro
Curated resources on building sites with Astro, a brand new way to build static and server rendered sites, with cross-framework components, styling and reactive store support.
Stars: ✭ 210 (+854.55%)
Mutual labels:  server-side-rendering
metalsmith-paths
Metalsmith plugin that adds file path values to metadata
Stars: ✭ 19 (-13.64%)
Mutual labels:  lib
yhtml5-tutorial
the tutorial for learning Front-end technology
Stars: ✭ 19 (-13.64%)
Mutual labels:  front-end
weblocks
This fork was created to experiment with some refactorings. They are collected in branch "reblocks".
Stars: ✭ 80 (+263.64%)
Mutual labels:  server-side-rendering
universal-react-webpack-boilerplate
unireact - quickly bootstrap your universal react-app
Stars: ✭ 27 (+22.73%)
Mutual labels:  server-side-rendering
antony-nuxt
👏 Codes that Power ouorz.com | A Tiny Little Nuxt.js + WP REST API App 博客前端
Stars: ✭ 21 (-4.55%)
Mutual labels:  server-side-rendering
ustyle
A living styleguide and pattern library by uSwitch.
Stars: ✭ 18 (-18.18%)
Mutual labels:  front-end
ng-thingsboard
Angular 8 Thingsboard UI
Stars: ✭ 27 (+22.73%)
Mutual labels:  front-end
py-emmet
Emmet abbreviation parser and expander, implemented in Python
Stars: ✭ 32 (+45.45%)
Mutual labels:  front-end
fs-pochta-api
Библиотека для работы с API Почты России
Stars: ✭ 15 (-31.82%)
Mutual labels:  lib

jigjs

a front-end framework

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.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].