GithubHelp home page GithubHelp logo

rlugojr / robojs Goto Github PK

View Code? Open in Web Editor NEW

This project forked from marcog83/robojs

0.0 2.0 0.0 1.16 MB

RoboJS is a library that aims to dynamically load JS modules depending on how the DOM is composed.

License: MIT License

JavaScript 100.00%

robojs's Introduction

RoboJS is a library that aims to dynamically load JS modules depending on how the DOM is composed. Add a node to the DOM and a JS will be loaded! Remove a node and the JS will be disposed!! Not further framework frontend , but a tool that lets you manage the association DOM and JS. (less than 6kb gzipped);

#The idea behind the code To understand how and why I decided to write this tool, please read this post

#Quick Demo A quick demo can be found HERE. It simulate a bunch of modules loaded from server and a page where to place them (on the right).

#Installation

bower install robojs

#How it works. You set a data-mediator attribute with an ID (whatever you want)

    <div data-mediator="my-custom-element">a-2</div>
    <div data-mediator="foo-element">b-1</div>
    <div data-mediator="bar-element">c-1</div>

in definitions.js you define a Map where the key is an ID , and the value is the file to request in order to register the element.

	{
        "my-custom-element": "client/my-custom-element",
        "foo-element": "client/foo-element",
        "bar-element": "client/bar-element"
    }

For instance in this sample I mapped 3 different Mediators.

When the builder finds a match between a data-mediator attribute and an ID from MediatorsMap, it will create a new instance of Mediator, storing the DOM Node into a property named element and executes initialize method

#Usage

rjs.bootstrap({definitions: definitions}) // [Object Promise]

#MediatorsBuilder MediatorsBuilder will iterate the DOM trying to match definitions.js keys with data-mediator attributes. Each time it finds a match, a request is send to load the right script. The first time the script is loaded from network, while the next one is retrived from cache. MutationObserver is used to handle DOM changes, and when it happens MediatorsBuilder iterates over the new added nodes.

#Mediator Object. Mediator is the context where your logic runs for a specific Mediator. When a data-mediator attribute matches an ID from MediatorsMap the Mediator constructor is called and a function returns. The returned function is called later when the module will be disposed. Mediator constructor takes two parameters, node and dispatcher. node is a reference to DOM element, dispatcher is a reference to EventDispatcher Object

    function MediatorA(node,dispacther) {
		return function(){
           // destroy everything, es. handlers
        }
   	}

#Custom Elements RoboJS is a composable library that allow you to change the way you create modules and add logics to your application. data-mediator mechanism is my first solution to the problem, but moving on, custom elements are an easy, native way to deal with it. This is why I decided to add CustomElementHandler Object This function constructor allow you to register and create your Custom Elements.

By default your modules are handled by data-mediator mechanism, but you can set mediatorHandler in order to use custom elements.

 rjs.bootstrap({
            definitions: definitions,
            mediatorHandler:rjs.CustomElementHandler()
        })

HTML markup looks like the following

    <my-custom-element>a-2</my-custom-element>
    <foo-element>b-1</foo-element>
    <bar-element>c-1</bar-element>

Your Custom Element should be defined in a function that returns an Object.

function FooElement() {
		return {
			createdCallback: function () {
				console.log("created foo element", this);
				this.addEventListener("click",function(e){
					e.currentTarget.parentElement.removeChild(e.currentTarget);
					e.stopPropagation();
				})
			},
			attachedCallback: function () {
				console.log("attached foo element", this)
			},
			detachedCallback: function () {
				console.log("deattached foo element", this)
			}
		}
	}

Behind the scene CustomElementHandler creates a new Object extending HTMLElement prototype. Then it assigns your implementation to it. Finally RoboJS registers the new element with document.registerElement API

 var customProto = FooElement();// your function constructor
 var proto = Object.assign(Object.create(HTMLElement.prototype), customProto);
 document.registerElement(id, {prototype: proto});

RoboJS recognizes new element added to DOM, if the new node tagname matches any id in definitions.js map and the element is not registered yet, the right script will be requested and executed. Sample folder contains a demo.

#Loader Object Default loader is SystemJS based.

<script src="system.js"></script>
<script>
	System.config({
		defaultJSExtensions: true,
		paths:{
			robojs:"../../dist/robojs.es6"
		}
	});

	System.import("./client/Application");
</script>

and inside Application.js you invoke bootstrap function

rjs.bootstrap({definitions: definitions})

An example can be found in sample/systemjs folder.

##AMDScriptLoader Object

If your project is AMD-style you can pass AMDScriptLoader to bootstrap spec Object. AMDScriptLoader supposes that require function is in global space.

rjs.bootstrap({definitions: definitions,loader:rjs.AMDScriptLoader()})

You can customize script loading strategy passing a function to AMDScriptLoader.

function loadWithRequire(id,resolve,reject){
    require([id],resolve,reject);
}
rjs.bootstrap({definitions: definitions,loader:rjs.AMDScriptLoader(loadWithRequire)})

###EventDispatcher Object. The EventDispatcher can be your messaging System. It dispatches and listens to Events from your Application. It's meant to be a Singleton in your application.

You can get a new instance of EventDispatcher by calling getEventDispatcher function

var myNewEventDispatcher=rjs.getEventDispatcher();

##RequireJS configuration

This is an example how you can set dependencies using RequireJS

requirejs.config({
	paths: {		
        robojs: "../../dist/robojs.es6"
	}
});

##SystemJS configuration

This is an example how you can set dependencies using SystemJS

System.config({
		defaultJSExtensions: true,
		paths:{
			robojs:"../../dist/robojs.es6"
		}
	});

or using Globals

NB. If you use robojs as global, you need some kind of script loader. If your project has SystemJS or RequireJS, please don't use global.

<script src="../../dist/robojs.es6.js"></script>
<script>
var definitions={
                    "my-custom-element": "client/my-custom-element",
                    "foo-element": "client/foo-element",
                    "bar-element": "client/bar-element"
                }
robojs.bootstrap({definitions:definitions})
</script>

#Dependencies

RoboJS depends on some RamdaJS functions.

	// DomWatcher.js
	//

   import map from "ramda/src/map";
   import flatten from "ramda/src/flatten";
   import pluck from "ramda/src/pluck";
   import compose from "ramda/src/compose";
   //
   // MediatorsBuilder.js
   //
   import curryN from "ramda/src/curryN";
   import find from "ramda/src/find";
   import compose from "ramda/src/compose";
   import map from "ramda/src/map";
   import filter from "ramda/src/filter";
   import flatten from "ramda/src/flatten";

NO needs to import ramda library.

###Build project transpiling es6 sources to es5 is handled by AWESOME project jspm, that is a package manager for the SystemJS universal module loader, built on top of the dynamic ES6 module loader.

jspm bundle-sfx src/org/core/robojs dist/robojs.es6.js --format umd

###Polyfills###

  1. A stand-alone working lightweight version of the W3C Custom Elements specification.document-register-element

MutationObserver: if you need a polyfill you can check

  1. Webcomponents polyfill.
  2. MutationObserver by megawac.

##Articles about Custom Elements##

  1. HTML5 rocks: Excellent article about custom elements, and WebComponents in general.
  2. MDN Custom Elements
  3. MDN Document.registerElement()

robojs's People

Contributors

duzun avatar marcog83 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.