How Well Does PhoneGap Scale?

A Look at Client-Side Templating

Mobile Development Comments (10)

If you’re building a PhoneGap app, you’ve got an abundance of resources helping you get started–lots of information about how to set up your project and get it running on the different platforms. PhoneGap even released a really innovative way of compiling your project “in the cloud” for different platforms with PhoneGap Build (still waiting on my invitation…). But there seems to be a lack of help when it comes to structuring a PhoneGap application. There are lots of examples of simple one or two screen apps, but what about an app that may potentially have upwards of 5 or 10 different views? How do you build for that?

It would potentially be an organization nightmare to plop everything into index.html–the DOM structure could get very complicated (plus you’d be loading the HTML for views the user may never even use). But, you definitely don’t want to be navigating away from index.html because you would have to wait for the webview to reload all the resources and it wouldn’t make for a very good user experience.

We decided to explore some options for implementing a templating engine into a PhoneGap project. A templating engine would ideally let us build separate template files for each view (or even parts of a view). We could then load in these templates, as needed, with an AJAX request.

Here’s what we love about the idea of using a templating engine:

  • By splitting up the HTML into separate files and only loading the HTML we need, it allows us to keep our DOM clean and simple at any given time–web applications often suffer from performance issues on mobile devices because of an overly complicated DOM.
  • Using template files will make it really easy to manage the HTML and track changes moving forward.
  • Using a templating engine allows us to effortlessly separate the content from the presentation making it much easier to expand and add functionality to our app in the future (e.g.: adding support for localization).

There are a lot of choices out there when it comes to choosing a JavaScript templating framework. One that caught our eye was ICanHazJS (…it was probably the name). ICanHaz (ICH) extends the templating power of Mustache and brings it to Zepto.js (or jQuery).

ICH is a breeze to implement. First, define the template in a <script> tag in the <head> of your page:

<script id="welcome" type="text/html">
  <p>Welcome, {first_name} {last_name}!</p>
</script>

When the DOM is ready, ICH takes the defined templates and creates a templating function out of them so using them later is as simple as:

var html = ich.welcome(data);

Where data is defined as something like:

var data = {
  first_name:     "Daniel",
  last_name:     "Pfeiffer"
};

html now contains a Zepto/jQuery object with the template and injected data:

<p>Welcome, Daniel Pfeiffer!</p>

Unfortunately, defining templates in <script> tags in the <head> of index.html doesn’t fully solve our problem since it still potentially leaves index.html as being difficult to manage. Fortunately, ICH provides a way to define templates after the DOM is ready with ich.addTemplate(). To take advantage of this, we wrote a simple renderTemplate function:

function renderTemplate(name, data, callback) {
  // Check whether the template has been cached
  if(!ich.templates[name]) {
    // If the template doesn't exist, load it from [name].tpl.html
    $.get(name + ".tpl.html",function(template) {
      // Create a template out the returned data
      ich.addTemplate(name,template);
      // Call the callback function with the rendered HTML
      callback.call(null,ich[name](data));
    });
  } else {
    // The template has already been loaded; we'll use the cached template information
    // Call the callback function with the rendered HTML
    callback.call(null,ich[name](data));
  }
}

When passed with the name of the template, a JavaScript object containing the data to be injected, and a callback function, the function determines if the template has been cached and if not, uses AJAX to load it from [name].tpl.html. Once the template has been loaded, the callback function is called with the rendered HTML.

To demonstrate how easy it is to implement this to quickly get an app up and running, we’ve created a simple web app that simply pulls the latest tweets from the Twitter public timeline at the time of launch (check it out on your mobile device–the demos only work in WebKit-based browsers. It’s possible that by replacing Zepto with jQuery it will work even in non-WebKit-based browsers.).

The template in tweet_list.tpl.html simply looks like this:

<ul id="tweet_list">
  {{#tweets}}
  <li rel="{{index}}">
    <div class="profile_image">
      <img src="{{profile_image_url}}" alt="" />
    </div>
    <div class="tweet">
      <div class="author">{{author}}</div>
      {{tweet}}
    </div>
    <hr class="clear" />
  </li>
  {{/tweets}}
</ul>

When passed data with tweets defined as an array, the templating engine loops through just the {{tweets}} section of the template creating a <li> for each tweet.

To populate the template, we get the public timeline data from Twitter:

$.getJSON("http://api.twitter.com/1/statuses/public_timeline.json?callback=?", onPublicTimelineReturn);

Then in the callback of the AJAX request,

function onPublicTimelineReturn(the_tweets) {
  var tweets = [];
  // We'll need to loop through data returned from Twitter and pull out just our needed information
  the_tweets.forEach(function(tweet) {
    tweets.push({
      author:             tweet.user.name,
      index:              tweets.length,
      profile_image_url:  tweet.user.profile_image_url,
      tweet:              tweet.text
    });
  });
  // Render the template
  renderTemplate("tweet_list", {tweets:tweets}, function(html) {
    // Empty out the container
    $('#container').html('');
    // Add the tweet list
    $('#container').append(html);
  });
}

Take a look at the source of the demo to see the full picture of what’s going on.

Granted, this is a pretty simple example, so let’s add the ability to tap on a tweet to get a little more information.

Still pretty basic, so let’s add the ability to view a user’s bio when tapping his/her profile picture.

Yes, still basic, but you get the idea. Each added function is fairly simple to implement. Plus, with each added function, the size of the web app is hardly increasing and there are really no noticeable performance impacts. After adding some animation and styling, our little demo could easily grow into an app ready for the app store. We could even continue expanding the functionality to eventually become a fully-featured Twitter client.

We’re pretty excited about how implementing a templating engine will improve our PhoneGap projects and allow for easily scalable applications in the future. This isn’t the perfect solution for every app, but we believe a good handful of PhoneGap apps can/will benefit from building on a structure that’s both easy to manage and easy to expand.

Update: We’ve been seeing a good amount of success based on this model of structuring a PhoneGap application. We explored a little more into the performance improvements we were seeing and discovered they were entirely related to the cost of reflow in the DOM. By removing unused elements from the DOM that weren’t being used for the current view, it decreased the time it took a reflow to occur.

Have you used a templating engine in your web/PhoneGap app? We’d like to hear about how a templating engine aided (or could have aided) the development of your app.

If you think PhoneGap would be something you’d want to use for your next mobile learning project, contact us right away.









Follow Float
The following two tabs change content below.

» Mobile Development » How Well Does PhoneGap Scale?
On May 11, 2011
By
,

10 Responses to How Well Does PhoneGap Scale?

  1. AAHHHH!!! CODE!!!! If you’re trying to scare us into leaving the technical development of our mobile apps to pros like you it’s… working!

  2. Chad Udell says:

    Thanks for reading Steven. We’ll admit, the code can be daunting to the non-developer, but really the technical end of mobile development is largely easier than some of the bigger picture items like choosing platforms, dealing with policy and provisioning or even just deciding what your learning objectives are for your mobile efforts.

    We love that stuff, too!

  3. Thanks for the post. Curious if this is an approach that will facilitate rendering long lists in a mobile app using PhoneGap and, say, jQTouch. I’ve created an app that locates local landmarks in a given city, and the user can tap on the list of nearby landmarks to display more info about each one. The complete list of landmarks is just over 1,500.

    In a Palm version of may app (that I wrote using Palm’s native Mojo framework), the app displays the list of all 1,500 sites quickly and smoothly (with well-oiled scrolling through the list, as it were). In Phonegap/jQTouch, the app bogs down if it displays a list with more than 75 or so sites. Based on what I’ve read, a paging (or “more…”) approach is what I need, but the templating approach you describe above is intriguing. Think it’ll address this problem?

  4. ylva says:

    Hi!

    Interesting post! Reading it like this many months and a few versions of Phonegap later, makes me wonder if you have any new insights about the subject? Still writing apps using Phonegap? What approach are you using for bigger apps to not have an overwhelming and unstructured codebase?

    I’m a object oriented/native developer (coming from C, Java, Objective C), now implementing the first Phonegap project targeting iOS and Android, and as a newbie in JavaScript I feel that there are no real natural ways of structuring the code in JavaScript, and it easily becomes messy. Any tips..?

    Thanks! 🙂

    • Daniel Pfeiffer says:

      Hi ylva,

      We are still writing apps using PhoneGap–in fact I’m starting a new one today!

      I too am partial to object-oriented programming and just as Mitul G stated, you can follow some similar design patterns using JavaScript.

      In a recent project, in order to keep the codebase organized, I followed a design pattern that I’ve often heard referred to as “modules” (although not related to CommonJS in this case…similar idea). Each file extended a namespace and performed a specific function. For example: I had a namespace like “floatlearning.game” and a specific file I added to that “floatlearning.game.leaderboard” which contained function specific to managing a leaderboard. I organized each of these “modules” into separate files and then during the Xcode build process, I concatenated/minified them all together into a single file and included that on the index.html. This loaded all the JavaScript I was going to be using into memory right from the start and helped me keep my code very organized.

      I hope that helps!
      –Dan

      • Anthony says:

        Thanks for a great article Daniel. I’ve been using the ‘extended’ module pattern for making my Javascript much more organized.

        I’d be very grateful if you could expand on how you approach concatenating/minifying your separate Javascript files/modules DURING the build process in Xcode. Is this something that can be configured within Phonegap/Xcode or do you use a loading framework like Require.js to do it for you?

        Thanks!
        Anthony

        • Daniel Pfeiffer says:

          Hi Anthony,

          During development, I split up the code in my JavaScipt files in a similar manner as I would if I were developing classes in another language (this is purely to make it easier to navigate). Usually, I define a namespace for the application and each file just extends onto that namespace. So, for example, one file may define a namespace like this:

          var float = {};

          Then in my other files, I may wrap methods or controllers and do something like this:

          float.index = (function(){
          ...code for my "root view controller"...
          // Expose members of my "class"
          return {
           functionName: functionName,
           propertyName: propertyName
          }
          })();

          Then, during compile time, I want to concatenate and minify all of the JavaScript to one file. Although multiple files make for easier development, they also make for a slower application. Here’s what my build script looks like:

          # Remove the old minfied file ignoring any errors
          rm www/js/min.js www/js/concat.js 2>/dev/null
          
          # Concatenate javascript resources
          cat www/js/*.js > www/js/concat.js
          
          # Minify
          java -jar yuicompressor.jar www/js/concat.js -o www/js/min.js --charset utf-8

          Then I only copy min.js to my final application bundle and this is the only file I include on my index.html file.

          In this case, all my JavaScript files are in a js directory (no subdirectories) and I use YUI compressor to minify it. A note here is that it will concatenate your files in alphabetical order, so if you need something to be at the top of the resulting file, at a 0 to the beginning of the file name.

          I hope that helps!
          –Daniel

  5. Mitul G says:

    Hi ylva,

    You should use object oriented javascript; since javascript is now Prototype-based.
    You can try new Object().

    Hope it helps.

    Mitul

  6. Kim Ras says:

    Hi,
    This is interesting, I am building a PhoneGap app. and over the Weekend I got JQuery Mobile working, but have hit .. like most of you. the performance and response issue.. So now I am on the hunt for something faster and maybe simpler (I do not need allot of the other functionality jQuery provides.)..
    For my App I need a Simple UI framework that can use themes, I can build CCS if I need to.. But I now see that the “paging” that jQuery Mobile provides is some thing I need in some shape or form, so now my questions is:
    You mention some different themeing frame works like jQtouch and iUI .. What do you guys use.. It seams to be a jungle, and allot of the projects is still marked Beta.. Should worry?

    Thanks in advance
    Kim

  7. Mat says:

    Hi,

    I work on an application for iPhone. We use jquery mobile with phonegap there. As you browse the webpage, AJAX is used to download other pages. As you use the application, you end up with almost 20 000 elements in the DOM structure. Which as you guess is not what we want.

    So my question is: If we use the template engine, would our DOM structure hold one page at a time?

Leave a Reply

Your email address will not be published. Required fields are marked *

« »