Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cordova 2.4.0 or 2.5.0 or 2.6.0 and requirejs

Cordova 2.4.0 and up supports AMD for loading into javascript. I am specifically looking to use Cordova 2.5.0 with the latest version of RequireJS, backbone, jquery, jquery mobile.

I have yet to see any tutorial or posting about how to use the new version of Cordova properly with with requirejs. I do see tons of posts about how to incorporate Cordova and requirejs back when Cordova did not support AMD (2.3.0 and prior).

If anyone can post or point me to a simple example of this, it would be greatly appreciated.

Edit: Specifically I am targeting development for iOS.

Edit: I want to be more specific and include the exact problem I am running into.

main.js

require.config({
    paths: {
        cordova: 'libs/cordova/cordova.ios',//cordova-2.5.0',//2.5.0*/
        jquery: 'libs/jquery/jquery.min',//1.9.1
        text: 'libs/require/text',
        domReady: 'libs/require/domReady',
        underscore: 'libs/underscore/underscore-min',
        backbone: 'libs/backbone/backbone-min',
        'jquery.mobile-config': 'libs/jquery-mobile/jqm-config',
        'jquery.mobile': 'libs/jquery-mobile/jquery.mobile.min'
    },
    shim: {
        backbone: {
            deps: ['jquery', 'underscore'],
            exports: 'Backbone'
        },
        underscore: {
            exports: '_'
        },
        'jquery.mobile': {
            deps: ['jquery', 'jquery.mobile-config']
        }
    }
});


require(['app'], function(App){
    App.initialize();
});

app.js

define([
    'cordova',
    'jquery',
    'underscore',
    'backbone',
    'router'
], function(cordova, $, _, Backbone, Router){
    var initialize = function(){
        Router.initialize();
    }
    return {
        initialize: initialize
    };
});

To be clear, everything works fine before I optimize the require.js project. When I try to optimize the project with r.js (part of require.js), the optimizer throws an error which can be seen below.

Error channel.js

I am not sure what channel.js is, and why it is asking for it, but I was able to find it on github here https://github.com/apache/cordova-js/tree/master/lib/common

Once I create the subdirectory it is looking for, I place the channel.js file into it. I no longer get that error, but now a different one, seen below.

enter image description here

I was also able to find that file on the cordova-js github site. Once I place that file into the subdirectory, I don't get any error messages and the project builds successfully.

Now when I try to run the application using the single optimized js file, I get this error in the javascript console, and just a blank white screen on the device.

"ReferenceError: Can't find variable: exports"

Here is my build.js file I am using to run the optimization

({
    baseUrl: "../js",
    mainConfigFile: "../js/main.js",
    name: "../js/main",
    out: "../js/big.js",
    preserveLicenseComments: false,
    paths: {
        requireLib: "../js/libs/require/require"
    },
    include: "requireLib"
})

Edit 4/11/13: Answer Thanks to the help of SA user asgeo1, I got my problem solved. It turns out you cannot name the variable in main.js 'cordova' because it conflicts with an internal variable named 'cordova'.

The solution is below.

main.js

require.config({
    paths: {
        'cordova.ios': 'libs/cordova/cordova.ios',//cordova-2.5.0' THIS IS CHANGED
        jquery: 'libs/jquery/jquery.min',//1.9.1
        text: 'libs/require/text',
        domReady: 'libs/require/domReady',
        underscore: 'libs/underscore/underscore-min',
        backbone: 'libs/backbone/backbone-min',
        'jquery.mobile-config': 'libs/jquery-mobile/jqm-config',
        'jquery.mobile': 'libs/jquery-mobile/jquery.mobile.min'
    },
    shim: {
        backbone: {
            deps: ['jquery', 'underscore'],
            exports: 'Backbone'
        },
        underscore: {
            exports: '_'
        },
        'jquery.mobile': {
            deps: ['jquery', 'jquery.mobile-config']
        }
    }
});


require(['app'], function(App){
    App.initialize();
});

app.js

define([
    'cordova.ios',//THIS IS CHANGED
    'jquery',
    'underscore',
    'backbone',
    'router'
], function(cordova, $, _, Backbone, Router){
    var initialize = function(){
        Router.initialize();
    }
    return {
        initialize: initialize
    };
});

This solution works and was tested with Cordova 2.5.0 and 2.6.0

like image 681
njtman Avatar asked Mar 15 '13 19:03

njtman


2 Answers

I have had this same problem too. It appears to be an issue in how they are building the cordova.ios.js file they distribute with Cordova 2.4 / 2.5

As you found out, the cordova/channel and cordova/utils sections are not in the correct order within the cordova.ios.js file.

That why RequireJS tries to load the individual files since those modules hadn't occurred yet in the cordova.ios.js file yet.

Unfortunately when you put the channel.js and utils.js files in your project, you weren't actually solving the root cause of the issue.

Sure, that allowed it to build, but the ReferenceError: Can't find variable: exports error then occurs because RequireJS will put the contents of utils.js/channel.js above the rest of the cordova.ios.js contents - which is not good because they depend on the exports stuff being setup inside of cordova.ios.js.

Not to mention you now have two copies of the channel.js/utils.js code in your built file as well...

The solution is you must modify cordova.ios.js yourself. Move the cordova/channel and cordova/utils to the top of cordova.ios.js (but after the exports/requirejs stuff is defined)

You can get one that I prepared for myself here: https://gist.github.com/asgeo1/5361227

Also, another tip - in your main.js, don't refer to cordova.ios.js as 'cordova'. That will clash, because cordova.ios.js already uses this module name internally.

Use 'cordova.ios' instead:

require.config({
    paths: {
        'cordova.ios': 'libs/cordova/cordova.ios',
        ...
like image 65
asgeo1 Avatar answered Oct 02 '22 23:10

asgeo1


To use the lazy loading, one option is to use the domReady plugin from requireJS (cf. http://requirejs.org/docs/api.html#pageload).

Once requireJS has confirmed that the DOM was ready, you can then wait for the device to be ready using the regular deviceready listener.

require(['require/domReady','cordova/cordova-ios-2.5.0'], function (domReady) {
    domReady(function () {
    console.log("The DOM is ready - waiting for the device");
    document.addEventListener("deviceready", startWhenReady, false);
    }
 });

function startWhenReady()
{
  console.log("dom and device ready : we can start...");
  // your app
}

Worked for me!

like image 34
Delta Avatar answered Oct 02 '22 23:10

Delta