PhoneGap Blog

All PhoneGap PhoneGap Build PhoneGap Network
Introducing Cordova-JS
by Fil | 21 Mar 2012 | PhoneGap Blog, News

A lot of exciting things have happened in the past six months or so: my former employer Nitobi got acquired by Adobe and our team of about 18 more or less got split right down the middle. Half are now settling into San Francisco, while the rest (me included) are holding down the Canadian fort in Vancouver and doing our best to represent Adobe up in the Great White North.

I'm still working on PhoneGap, now reborn as an Apache Software Foundation project known as Cordova. My most recent task has involved bringing the disparate implementations of Cordova's JavaScript API - a consistent, cross-platform API - under one repository. Up until this point, each platform maintained its own set of JavaScript files implementing this API. The idea and implementation I'm going to present in this post is that 90+ percent of the JavaScript for any given Cordova platform is identical. Most of the Cordova API boils down to sending simple messages to the native framework, with the expectation that a failure or success callback will be fired in the future back in Cordova's web context. The unified JavaScript project is called cordova-js.

I'm excited to say that in Cordova 1.5 we landed cordova-js in the Android implementation. In Cordova 1.6 we are going to drop it into the iOS implementation! It has already landed in the Apache Cordova iOS master!

The project has been an up-and-down ride. Dave Johnson and Michael Brooks of Nitobi initially championed this idea with the phonegap-js project. Months later, Gord Tanner from RIM (along some daleks) was using the same direction phonegap-js laid down to integrate new APIs in their open source device and API emulation tool, RippleGord and company (mostly the old TinyHippos crew, which got acquired by RIM) reached out to us to show us what they did. What we saw blew our minds: clean, modular syntax for all API definitions with a very clear architecture and obvious mappings to JavaScript properties and globals. Around this time I jumped in to help out where I could and Gord, Ken Wallis and Laurent Hasson from RIM all flew up to Vancouver so that we could discuss the cordova-js implementation and hack on it for a few days (and maybe drink a few beers while we're at it). Turned out to be a very fruitful week with lots of progress made. One of the early contention points of the project was: how are we going to implement the module system? Should we use an existing solution out there or roll our own? Luckily for us peeps in Vancouver, Mozilla has an office and a team up here, and among the talented people working there is James Burke, author of require.js. Who better to talk to about the situation than a man closely involved and directly influencing the various styles of JavaScript modules floating around? We ran a little lunch-n-learn and invited James over to come share ideas. Initially we ended up using almond.js, a small module loader that was compatible with both AMD and CommonJS modules. Later on, to enforce our own requirements (specifically around throwing exceptions for non-existent modules), we forked and cut down almond.js to the bare-bones that we need for cordova-js purposes. Finally we were on track to ship a working version of cordova-js. Android was our first target. Joe Bowser (of Adobe/Nitobi) and Simon MacDonald (of IBM) helped make that happen. Becky Gibson (of IBM) and Shazron Abdullah (Adobe/Nitobi) put a lot of work in to get it going on iOS. Patrick Mueller (IBM), Brian LeRoux (Adobe/Nitobi) and Jesse MacFadyen (Adobe/Nitobi) chimed in to offer advice and guidance. Truly a team and community effort across corporations (warms my heart!). Thanks to everyone involved for making it happen. This lays down the foundation for us to hit our goals for Cordova 2.0.


If it works, why f* with it? The answer lies in the road ahead to Cordova 2.0. We want any arbitrary device APIs - be they Cordova "core" APIs or not - to be installable, discoverable and removable at a developer's discretion. For those familiar with PhoneGap plugins, this is exactly the same idea. A stock Cordova API is no different from a plugin. We've been part of the way there for some time now; all of the various native implementations employ some manner of plugin architecture. The JavaScript, however, has been a wild-west of sorts. We are changing that with the introduction of cordova-js.

The biggest change is the use of modules in JavaScript. CommonJS-inspired but much simpler, it does the job for now. A simple define and require syntax is used and scoped only to the cordova.js file. Within the cordova.js file you'll see things like:

  define('cordova/channel', function() {
    // Amazing code goes here

  // ... somewhere else in the code

  var channel = require('cordova/channel');;

All of the little interesting bits inside the cordova.js file are wrapped in a define call, turning cordova.js into a set of small, focused modules tasked with doing one thing well. Early on we scoped our module syntax globally. This turned out to be a bad idea. Now, define and require are available inside the cordova.js file, or if you want to use it for your own projects you can access these methods via cordova.define or cordova.require.

A side effect of using a CommonJS-inspired module syntax is that we can use the resulting script file interchangeably between node and PhoneGap/Cordova contexts. Due to our simple module system for use in WebView contexts, we can maintain the convention of one-closure-per-file employed in other CommonJS environments, or piggy-back off of node's module system to do cool things such as run unit tests locally in node. Winning!

As for changes introduced with cordova-js, the main one is the name switch in your JS from [PhoneGap]( to cordova.

Next up I'll be aiming to explain a general process for upgrading pre-1.5 plugins to this new approach (perhaps a case study / real world plugin upgrade to go along with it?).

Happy coding!

[This post was originally posted by Fil Maj on]

blog comments powered by Disqus