4.1.0 • Published 7 years ago

loadlify v4.1.0

Weekly downloads
33
License
MIT
Repository
gitlab
Last release
7 years ago

Loadlify

npm version pipeline status FOSSA Status Known Vulnerabilities

NPM

Fully customizable, secure, and simple loader for web assets with support for ES6 modules and SRI Hashes. Demo

About Loadlify

It makes use of the native Promise and ES6 classes to make it's job, so is expected to run it on a ES6 capable browser. It's tested on Chrom{e,ium} and Firefox, always in the latest version.

Loadlify makes simple the process to load scripts and also, dependencies, don't worry about loading dependencies before running a script, set them like loadlify.deps["myscript.js"]=["jquery", "vue"];. Of course you can make sure of a module is loaded in a part of your script that requires it, following the previous line of code, here is an example:

/*myscript.js*/
//Here jquery and vue are loaded
jQuery("#myItem")...
var app=new Vue(...);
//Some lines of code later...
makeSomethingAwesome(...args){
    //Some awesome lines...
    load("awesomescript.js") //It's not yet loaded, but I'll need it later... the load process is asynchronous, so let's continue doing things...
    //Some lines later...
    load("awesomescript.js").then(module=>{ //Let's see the progress of the load process and set a handler for the Promise
        //Here the script is loaded (and all of its dependencies), in the very expected moment.
        module.exports.awesomescript.awesomefunction();
        //More of your awesome core
    });
}

Basic usage

The function load, declared in the global scope is a shorthand for loadlify.load This function has two arguments, one is mandatory:

	load(script, flags);
	//The first argument can be an array or a string (or an array containing more arrays and so on...)
	//The second argument can be a string, an array or undefined. This flags are inherited by default, but this feature can be disabled
	//The return is a promise and it's value is an object as defined below

Return value

The return value is a Promise. This is the structure for the first argument in .then function.

	{
		apply:[ //This is the return value of the handler for each type of asset. The return value of the built-in application/javascript handler is:
			function, //The newly constructed function. Here you can for example run again the function.
			{
				err: undefined, //If an error occurred in the apply function Promise will be rejected, so this property is commonly undefined.
				flags: ["es6", "noflagsindeps"], // Contains the array of flags passed to the 'load' function.
				rv: undefined, //Return value from function (undefined is the most common),
				url: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" //URL string from where the asset was loaded
			}
		],
		blob: blob, //This blob contains the loaded asset as a blob
		deps:[...], //Array with the dependencies loading progress (all are resolved before the main Promise)
		exports: {}, //This object is explained in the 'exports' section of this file
		internalURL: "blob:https://hostname/ed6a295a-35e0-44d4-93f9-ab1b045e8ded", //URL created in order to access the asset.
		link: URL, //Not the same as the apply[1].url because of this URL is on object created with the URL constructor.
		name: string, //Name of the module (taken from the first parameter passed to loadlify.load)
		text: string, //Loaded asset in plain text.
		type: "application/javascript" //From blob.type. Used to choose the correct handler
	}

Examples

  • Load it with script tags

    	````html
    		<!-- Minified version -->
    		<script src="https://unpkg.com/loadlify@latest/loadlify.min.js"></script>
    		<!-- Normal version -->
    		<script src="https://unpkg.com/loadlify@latest/loadlify.js"></script>
    		<!--
          Please, don't use the unminified version in production environments, it has lots of comments and garbage. Let the browser load the source map.
      -->
    	 ````
    • Alternatively, you can use eval() or the Function() constructor, loadlify will jump anyway to the global scope (using the self variable)
  • Now, the load function, the loadlify object and the loadlifyJS class have jumped to the global scope

  • To load an asset, just:
    	````javascript
    		load("bootstrap").then(a=>{
    			//Code with bootstrap and jQuery (jQuery is loaded as a dependency of bootstrap)
    		});
    		load(["your/library.js", "your/library.css"]).then(a=>{
    			//When loading libraries this way, loadlify takes loadlify.props.prefix as a prefix for your path. It defaults to ./lib/ (as defined in loadlify.props.prefix)
    		});
    		load("https://unpkg.com/vue@latest/vue.min.js").then(a=>{
    			//When loading libraries this way, loadlify fetches the URL as provided.
    		});
    	````

In-Depth Usage

Inside

The loadlify.load method has control over the load process. It loads the asset and calls the handler for the type of asset. self.load is an alias of loadlify.load. Call it as you like, but keep in mind that self.load will call self.loadlify, so if you build a new instance, you will need to call yournewinstance.load in order to use it instead on the global.

The loadlify object and FLAGS!

  • Use loadlify.load(asset) function to load assets
    • You can modify defs, deps and other variables on the run.
    • load() function supports flags. load(asset, [flags])
      • Flags are inherited from assets to its dependencies so they will load with the same flags as the main asset.
      • noflagsindeps dependencies won't inherit flags from the parent asset.
      • noconcatflags the global flags won't be concatenated to the ones in the script.
      • nodeps won't load dependencies.
      • nocache Loadlify Cache won't be checked and will add cache: no-cache to the Request (loadlify can't control the caches directly, simply adds the instruction and lets the browser do the rest).
      • force will load the asset ignoring the warnings and cache (loadlify cache and any who reads the cache-control header).
      • astag will load the script in a <script> tag and CSS in a <link> tag. - reapply will make a downloaded item to be processed again.
      • noprefix won't add the prefix (defined at loadlify.props (or properties while instantiating) to the URL.
      • notext Loadlify won't convert the blob to text (save time if only the blob is needed).
      • requirejs Only JavaScript. Will put requireJS before the script.
      • type: mimetype Replace the auto detection of the type with a custom type. For example text/html or application/javascript. Remember that the handler for this type must exist.
      • allowedheader: value If allowedheader is in loadlify.props.configurable or in the default array of properties ["method", "mode", "cache", "credentials", "redirect", "referrer", "integrity"], value will be added to the init object when creating a Request.

The loadlifyJS class

  • loadlifyJS variable contains the constructor. Customize your own loadlify instance by constructing the class
  • loadlifyJS will take from the object in the first parameter the config values. The not supplied variables, will be taken from defaults
var loader=new loadlifyJS({
	defs: yourOwnDefinitions,
	deps: yourOwnScriptDependencies,
	flags: yourDefaultFlags,
	properties: yourOwnProperties
});

Subresource integrity

The Subresource Integrity (better explained in the MDN docs) is a very important security feature on modern browsers. It can avoid unwanted scripts or assets being injected into the Web App. Now Loadlify can handle the SRI Hashes to avoid all of this trouble. Unlike the <script>or <link> tags, loadlify can add the SRI to any asset loaded with it (like HTML, images or any other file).

How can be configured

There are two methods to configure a SRI hash for an asset.

	//As a header flag (has priority over any other method)
	load("jquery", ["integrity: sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"]);
	//This is directly added to the Request init. (Of course this flag will be removed in order to avoid trouble with dependencies)
	
	//This method sets the SRI hash if there isn't a flag with the SRI. This is necessary to set SRI hashes for dependencies.
	loadlify.integrity["https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"]="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT";

Modules

Modules are a very important feature in loadlify. They are making a change in the web of today, so are essential on a new loader. Modules aren't enabled by default. Loadlify, by default exposes the self.exports object, but the es6 flag is not set, so modules cannot see that object. You must set it in order to work with modules by passing it to determinate modules or enabling it for everything with loadlify.flags.push("es6")

How are modules recognized (Loaded script side)

Loadlify exposes a exports object in the function. Everything added to this object should be inside a object to keep the compatibility between modules. Example:

	exports["module2"]=functionsToexport;

And this would be the result (a module was loaded before this);

    exports: {
		module1: {
			method1:function(){/*do things...*/}
		},
		module2: {
			method1:function(){/*Same function name in a different module*/} //Those functions are compatible
		}
	};

How do modules work when loaded from loadlify

A object called exports is exposed to the global object (it can be prevented with self.noExports=true). This object is hotlinked between the two scopes (global and function). Also there is a exports object in the return value of the load object.

Known bugs and caveats

  • Not compatible with NodeJS (Because of the usage of the self variable).
  • Please, avoid dependency loops, will result in a everlasting Promise.
  • Don't point to the same dependency twice (solved from Loadlify 3.2.0)
  • exports object is not updated inside scripts (was copied from the global exports object) in Loadlify <3.2.0

License

FOSSA Status

4.1.0

7 years ago

4.0.1

7 years ago

4.0.0

7 years ago

3.3.2-2

7 years ago

3.3.2-1

7 years ago

3.3.1

7 years ago

3.2.1

7 years ago

3.2.0

7 years ago

3.1.0

7 years ago

3.0.1

7 years ago

3.0.0

7 years ago

2.3.3

8 years ago

2.3.2

8 years ago

2.3.1

8 years ago

2.3.0

8 years ago

2.2.2

8 years ago

2.2.1

8 years ago

2.2.0

8 years ago

2.1.3

8 years ago

2.1.2

8 years ago

2.1.1

8 years ago

2.1.0

8 years ago

2.0.2

8 years ago

2.0.1

8 years ago

2.0.0

8 years ago

1.2.2

8 years ago

1.2.1

8 years ago

1.2.0

8 years ago

1.1.1

8 years ago

1.1.0

8 years ago

1.0.0

8 years ago