blog

  • Home
  • blog
  • Lazy Loading Images with the Igaro App JavaScript Framework

Lazy Loading Images with the Igaro App JavaScript Framework

A while back I wrote about the Igaro App JS Framework (disclaimer: I’m the framework author).

“Sigh! Not another framework” I hear you say (and probably rightly so). Well, let me tell you what sets Igaro app apart.

Igaro App is NOT yet another framework that plugs into your HTML. It’s a completely different approach that offers potentially the highest performance of any web-app framework out there. It’s based on the latest standardized technologies such as promises (and zero callbacks), as well as an event driven architecture. There’s superb error management and recovery, a lazy loading architecture using CommonJS style modules, many widgets to get you started, and zero dependencies (no jQuery).

In this article I’ll be demonstrating how to build an unveil widget (lazy loading images when they come into view) for Igaro App and will highlight many of the concepts that make the framework shine along the way.

Setting Up the Environment

[author_more]

The first thing to do is to grab a copy of the framework from its GitHub repo.

mkdir igaro
git clone https://github.com/igaro/app.git igaro/git

Then install a couple of dependencies:

npm install -g grunt-cli
gem install compass
cd igaro/git
npm install

Grunt’s command line interface (grunt-cli) is an npm package, which means you’ll need Node.js and npm installed on your machine. Compass is a Ruby gem, which means you’ll need to install Ruby as well. The installation procedure will vary depending on the operating system. The best thing to do is follow the instructions on the respective projects’ home page (Node, Ruby).

With that done, you can kick things off with a simple:

grunt

Once cloned and running, the user has a development environment ready to go. Igaro compiles into two modes — debug and deploy and a web server for each can be found on ports 3006 and 3007 respectively. These will reload automatically as you work.

Screen shot of a standard Igaro App install

Outlining the Widget Specifications

In the course of building the widget, I’ll be covering Igaro’s bless, a means of pre-configuring objects, and will explain how it allows objects to tidy up after themselves. For an SPA this is important to thwart memory leaks and security issues, i.e if an authenticated page (Igaro App refers to these as routes) contains several widgets of the type we’re about to create, and credentials are invalidated (i.e the user has logged out) then it’s not just the DOM elements which must be removed, but events and dependencies must also be released.

Most frameworks expect you to reload the app “refresh the page” to clear historical objects (even if the DOM side of things are removed or hidden) or to handle the process of clearing variables manually. One feature of Igaro’s “bless” is two way communication between objects, so in this case when the route is destroyed, the widget goes with it. Similarly, if we destroy the widget, the route is notified and it’s removed from a siblings array pool.

As a disclaimer, I prefer code which flows and reads like a book in a fashion that is self documenting to anyone that has experience in the language type. For that reason you will find all the following code is undocumented, condensed, and yet surprisingly readable, in no small thanks to the use of ES6 Promises. You should have a good level of JavaScript fundamentals or be prepared to learn.

Without further ado, here’s the specification for our widget:

  1. The container should be an empty <div>.
  2. On window scroll or resize, detect whether vertical position is within viewport and if so add a loading CSS class.
  3. Fetch any resource and if an image switch <div> to <img> and write data out.
  4. Support a callback function after the Ajax call*. This could inject other DOM elements or handle custom data.
  5. On error, add error CSS class, remove loading class.

*The Ajax call may require headers for authentication or CORS support. A mechanism to allow for customizing the request must be implemented.

Now we know how the widget should behave, let’s start to code.

Creating the Necessary Files

Let’s examine the four main files necessary for our widget.

instance.unveil.js

Create a file named instance.unveil.js in compile/cdn/js/ and enter the code below:

module.requires = [
  { name:'instance.unveil.css' }
];

module.exports = function(app) {
  "use strict";
  var InstanceUnveil = function(o) {}
  return InstanceUnveil;
};

When the widget is instantiated an object literal o is passed. This is used to bless the object (more on this later).

instance.unveil.scss

Next, create a file named instance.unveil.scss in sass/scss and enter the code below.

.instance-unveil {
  display:inline-block
}

.instance-unveil-loading {
  background: inline-image("instance.unveil/loading.gif") no-repeat 50% 50%;
  background-size: 3em;
}

.instance-unveil-error {
  background: inline-image("instance.unveil/error.svg") no-repeat 50% 50%;
  background-size: 3em;
}

Find a suitable loading gif and a suitable error image on the web. Put these into a folder named sass/images/instance.unveil and ensure the name and extension match those in the file you just created.

route.main.unveiltest.scss

A test page (route) containing multiple instantiations of our widget will be accessible through http://localhost:3006/unveiltest.

Create a file named route.main.unveiltest.scss in sass/scss and enter the code below.

@import "../sass-global/mixins.scss";

body >.core-router >.main >.unveiltest >.wrapper {
  @include layoutStandard;
}

route.main.unveiltest.js

Create a file named route.main.unveiltest.js in compile/cdn/js and enter the code below.

//# sourceURL=route.main.unveiltest.js

module.requires = [
  { name: 'route.main.unveiltest.css' },
];

module.exports = function(app) {
  "use strict";
  return function(route) {

    var wrapper = route.wrapper,
    objectMgr = route.managers.object;

    return route.addSequence({
      container:wrapper,
      promises:Array.apply(0,new Array(50)).map(function(a,i) {
        return objectMgr.create(
          'unveil',
          {
            xhrConf : {
              res:'http://www.igaro.com/misc/sitepoint-unveildemo/'+i+'.jpeg'
            },
            loadImg : true,
            width:'420px',
            height:'240px'
          }
        );
      })
    });
  };
};

In Igaro App, when a page is requested, the router (core.router) asks a provider for a source, instantiates a new route and passes it to the source for customization. In the route file you just created, fifty unveil widgets are created and passed to a sequencer. The sequencer ensures that as the returned promises resolve, the images are placed on the page in the original order.

The create method is provided by a manager. It lazy loads the module and creates an instantiation (pre-load a module by adding it to the requires list at the top of the file). At this point, the widget is also dependency linked to the route so that when the route is destroyed, clean up operations are run.

Continue reading %Lazy Loading Images with the Igaro App JavaScript Framework%

LEAVE A REPLY