Neolithic Programming Machine

    gia

    1.0.1 • Public • Published

    Gia

    Minimalistic JavaScript framework for server rendered websites. 2.68 Kb minified gzipped with all it’s parts loaded with a script tag. Gia is modular in it’s nature. Following is the table of module sizes.

    4.88 Kb Component (with code splitting support)
    1.80 Kb BaseComponent
    1.62 Kb eventbus
    1.39 Kb loadComponents
    1.26 Kb removeComponents
    0.88 Kb destroyInstance
    0.79 Kb createInstance
    0.69 Kb config
    0.56 Kb getComponentFromElement

    Following sizes are for modules included separately (bundled separately). Modules often include common code, so when included and bundled together, final sizes are smaller and don't just add up.

    Installation

    Usage

    Component

    Helpers

    Installation

    Include Gia with scripts tag

    <script src="./dist/gia.min.js"></script>
    <!-- exposes all modules under global gia object -->
     
    <!-- also possible to include only parts -->
    <script src="./dist/BaseComponent.min.js"></script>
    <script src="./dist/loadComponents.min.js"></script>

    or with npm and import

    npm install gia --save
    // import needed modules from npm
    import Component from 'gia/Component';
    import loadComponents from 'gia/loadComponents';

    Usage

    First, a component needs to be created.

    class SampleComponent extends Component {
        mount() {
            console.log("Hello world!");
        }
    }

    Define the element where the component needs to be attached:

    <div g-component="SampleComponent">
        ...
    </div>

    And let the magic begin.

    const components = {
        "SampleComponent": SampleComponent
    }
     
    loadComponents(components);

    This simple setup will give you component with a simple lifecycle, scoped to the DOM element, plus some other super powers!

    Component

    Component is the building stone of Gia architecture. Gia only works with your HTML through components. To create new component, extend Gia default Component, or modified Gia component. If you’re really trying to go for minimal size and code splitting is not going to be needed, it is also possible to use BaseComponent, which does not include polyfills needed for code splitting.

    import Component from 'gia/Component';
     
    class SampleComponent extends Component {
      mount() {
        console.log("Hello world!");
      }
    }

    Variables

    There are several variables available in component by default.

    element

    Variable holding the root element of the component.

    this.element; // DOM element

    ref

    Variable holding object with all the elements marked with g-ref attribute within the root element, where the contents of the attribute is used as ref name. By setting the ref variable, component gets a signal to look for the elements available within the root element of component. So this..

    <div g-component="SampleComponent">
        <div g-ref="singleRef">
        <div g-ref="multipleRefs">
        <div g-ref="multipleRefs">
    </div>
    constructor(element) {
        super(element);
        this.ref = {
            singleRef: null, // looks for single element
            multipleRefs: [], // looks for multiple element
        }
    }

    …will end up in following value of the ref variable.

    console.log(this.ref);
    // { "multipleRefs": [DOM element, DOM element], "singleRef": DOM element }

    In case an empty object is set, component will look for any elements available and assume for all to be multiple (store in array).

    constructor(element) {
        super(element);
        this.ref = {};
        console.log(this.ref);
        // { "multipleRefs": [DOM element, DOM element], singleRef: [ DOM element ] }
    }

    In case some components are overlapping, but you would still like to use a same names for the ref elements, it is also possible to define the component for which the element is intended for inside of g-ref attribute.

    <div g-component="SampleComponent">
        <div g-component="AnotherComponent">
            <div g-ref="SampleComponent:refElement">
        </div>
    </div>

    The refElement will only be selected and stored by SampleComponent, and no others.

    options

    Variable holding options of the component. Default options can be set in constructor of the component. Options get automatically rewritten from the g-options attribute.

    <div g-component="SampleComponent" g-options='{"someOption": "customValue"}'>
    constructor(element) {
        super(element);
        this.options = {
            someOptions: "defaultValue"
        };
        console.log(this.options); // {someOption: "customValue"}
    }

    state

    Variable holding state of the component. It is not necessary to use state at all, as components are not used to actually render HTML. However, in combination with setState and stateChange methods, state can be useful for certain components, like some sort of filter where simple state can be helpful. Another use case is component which often updates DOM, as by using setState and stateChange methods, modifications of DOM are made only when the state actually changed. State should only be changed by setState function and takes a form of object.

    console.log(this.state); // {}

    Methods

    Component has a set of methods that can be used through it's lifecycle.

    require

    Method used for code splitting to require any libraries needed for the component to work. This method is asynchronous and after it is resolved, the execution of mount method follows.

    async require() {
        this.throttle = await import('lodash/throttle');
    }

    mount

    Method called after all assets are loaded - if any defined (after require method is resolved). This is where you would add all your listeners and such...

    mount() {
        this.scrollHandler = this.handleScroll.bind(this);
     
        this.element.addEventListener('click', this.handleClick.bind(this));
        window.addEventListener('scroll', this.scrollHandler);
    }

    unmount

    Method called before the component is destroyed (on removeComponents call). This is where you would remove any global listeners. Note that any listeners attached on or within the component root element are removed when the element is removed from DOM, as the component instance is stored within the element, so there is no need to remove those listeners, in case the element is removed from DOM.

    unmount() {
        this.element.removeEventListener('click', this.handleClick); // mostly not needed
        window.removeEventListener('scroll', this.scrollHandler);
    }

    setState

    Method called to update state of the component. Only the changes of state are required to be passed in a form of object. Component will merge the changes with current state on it's own.

    this.setState({
        a: "a"
    });

    Note that it is recommended to only use simple state with one layer for the state to work correctly. State is here to allow some simple manipulation powered with state, not to store a complex state of whole application.

    this.setState({
        a: "a",
        b: ["a"],
        c: {a: "a"}
    }); // all fine
     
    this.setState({
        a: {
            b: {c: "c"}
        }
    }); // not recommended

    stateChange

    This function gets called by setState method and any changes to state are passed as an argument. Ideally, any manipulation with DOM would be done within this function, as only the actual changes to state are passed on to here in a form of object.

    stateChange(stateChanges) {
       if('a' in stateChanges) {
            // "a" property of state was updated
       }
       console.log(stateChanges, this.state);
    }
    this.setState({ a: "a", b: "b" }); // { a: "a", b: "b" }    { a: "a", b: "b" }
    this.setState({ a: "a", b: "c" }); // { b: "c" }    { a: "a", b: "c" }
    this.setState({ b: "d" }); // { b: "d" }    { a: "a", b: "d" }

    Helpers

    loadComponents

    Initialises components within defined scope. In case an instance of the component already exists on the element, function skips initialisation. That means loadComponents can be always called without a context, but context should be defined for best performance.

    import loadComponents from 'gia/loadComponents';
     
    const components = {
        "SampleComponent": SampleComponent,
    }
     
    loadComponents(components [, context]); // context is optional and defaults to document.documentElement

    removeComponents

    Calls destroy method on every component within the context and removes component instance from the element.

    import removeComponents from 'gia/removeComponents';
     
    removeComponents([context]); // context is optional and defaults to document.documentElement

    createInstances

    Creates and returns instance of component. This function is used by loadComponents, but can be helpful in case of manually creating component instances. Classic use case would be using a set of components with one parent component controlling the others.

    import createInstance from 'gia/createInstance';
     
    let instance = createInstance(element, componentName, component[, options]);
    // options are optional and are passed into component contructor as second argument
     
    instance._load(); // this is necessary

    Note that calling instance._load() is required to start the lifecycle of the component.

    destroyInstances

    Calls unmount method of component and removes instance of component form the element. This function is used by removeComponents.

    import destroyInstance from 'gia/destroyInstance';
     
    destroyInstance(element);

    getComponentFromElement

    Returns instance of component from element.

    import getComponentFromElement from 'gia/getComponentFromElement';
     
    let element = document.getElementById('element');
    let componentInstance = getComponentFromElement(element);

    config

    Config is used as a store for options used in Gia and also as an interface to change default options. Currently, only the log option is available.

    import config from 'gia/config';
     
    config.set('log', false); // disables unnecessary console.log calls

    eventbus

    Eventbus can be used to communicate between components in a clear way. While it is possible to get an instance of another component and modify it directly, eventbus provides a simple interface that makes the interaction clearly visible from within the component.

    import eventbus from 'gia/eventbus';
    import Component from 'gia/Component';
     
    class Component1 extends Component {
        mount() {
            eventbus.on('writeConsole', this.handleEventBusCall);
        }
     
        handleEventBusCall() {
            console.log("Component2 triggered this through evenbus.");
        }
    }
     
    class Component2 extends Component {
        mount() {
            eventbus.emit("writeConsole");
        }
    }
     
    const components = {
        "Component1": Component1,
        "Component2": Component2
    }
     
    loadComponents(components); // will console.log "Component2 triggered this through evenbus."

    on

    Registers handler of event.

    eventbus.on('eventName', handler);

    once

    Registers handler of event, but handler is only called once and then removed.

    eventbus.once('eventName', handler);

    emit

    Calls any handlers previously registered with the same event name. Optional event object can be used as a argument, which gets passed into a handlers as an argument.

    eventbus.emit('eventName'[, eventObject]);

    off

    Unregisters handler of event. In case no handler is defined, eventbus removes all handlers for that event. In case not even event name is defined, eventbus removes all handlers for all events.

    eventbus.off('eventName', handler);

    Keywords

    none

    Install

    npm i gia

    DownloadsWeekly Downloads

    453

    Version

    1.0.1

    License

    MIT

    Unpacked Size

    228 kB

    Total Files

    33

    Last publish

    Collaborators

    • gmrchk