ArcGIS JavaScript API 3.0, Dojo 1.7 and AMD Modules

Diving in

For a while now, I have been keeping my JavaScript development modular by using Require.js as I have discussed before. Require.js provides AMD module loading for JavaScript projects. If you are not familiar with AMD, take a look here. Dojo 1.7 is AMD compliant and uses require/define methods to load modules. Up until now, the ArcGIS JavaScript API has been using Dojo < 1.7 for its core. I posted before how I used Require.js to load the API into my applications. Recently, the ArcGIS JavaScript API has been updated to 3.0 and is now using Dojo 1.7 for it’s core. I was pretty excited about this, mainly for AMD modules.

As soon as I saw that 3.0 was out, I dived right in, went straight past go, updated the CDN url in one of my apps and crossed my fingers. Of course it didn’t work. So I did what any dev should do. RTFM. That gave me a little insight, but I figured there must be something in my Require.js config I need to set up, so I went to check out the How to use RequireJS with Dojo page. I know I’ve seen samples of Require.js loading Dojo modules, so I set out to hack away at it. The Require.js/Dojo template was a good read, but has since been abandoned in favor of a non-Require.js template.

Trimming it down

After some fiddling around, I found out the issue of using Require.js with Dojo 1.7 via a CDN was that you can’t and you shouldn’t. When you load Dojo via a CDN, the dojo loader will create a global define and require, negating the need to use Require.js in this case. If I was loading Dojo locally, I could continue using Require.js and load individual Dojo modules as I was initially expecting to do. Now that we know that Require.js is no longer required (pun intended), we can remove that from our upgrade path equation.

I broke it

Let’s return to the ArcGIS JS 3.0 migration page. It explains how to load custom modules while using the CDN. I tried this, and hit a snag. jQuery was broken, which broke my Backbone lib too. I use Backbone a lot. So ok, more digging. I went through this page on Using Custom Modules with a CDN. It seemed pretty straightforward, but jQuery was still broken and other modules were not working.
Part of my problem was I was trying to define my package like this.

1
2
3
4
5
packages: [
{
name: "module",
location: location.pathname.replace(/\/[^/]+$/, "") + "src/moduleFolder/moduleFile"
} ]

Where “moduleFile” is actually a JavaScript file. You don’t need to add the *.js, the require function knows what to do. The regex is needed when using the CDN so that the path will point to the server your app sits on, or else it looks in the CDN directories and you just get lots of “file not found” errors. I thought I could bypass the regex with “./src” and so on, don’t bother, do it this way, don’t be dumb like me. So I went back and read up on some more documentation. Turns out, I am dumb. Packages simply defines the path to a folder. If you want the name to point to a specific file, you need to define the main field.

1
2
3
4
5
6
packages: [
{
name: "module",
location: location.pathname.replace(/\/[^/]+$/, "") + "src/moduleFolder",
main: "moduleFile"
} ]

I fixed it

At this point, I think I’m good to go, but jQuery is still broken and I’m getting pretty pissed, but I was on a roll, so I plowed right through with various config options, then I found this article. I followed this and it worked. jQuery worked, Backbone worked, everything was working. Now I had to know why. It turns out this was the magic piece to get jQuery to work.

1
2
// Add this before first require to launch app
define.amd.jQuery = true;

There is even a page explaining about using jQuery and AMD loaders.

I have put together a sample project using ArcGIS JavaScript API 3.0, jQuery and Backbone. You can find the source on github. I add a lot of comments to the config file, but I use CoffeeScript, so look at those files for comments. To load configs, like you would inside an HTML page creating a dojoConfig, you call require passing it an object with your configs defined.

1
require({ async: true, packages: [{...}] });

Caveats and Tips

So what does all this mean to ArcGIS JavaScript developers. It means you should write your modules as AMD compliant. As of right now, a few ESRI modules work as AMD compliant, meaning you can do this.

1
2
3
define(['esri/dijit/Popup'], function(){
    return new esri.dijit.Popup({...});
});

BUT, it doesn’t work everywhere. Not all ESRI modules are AMD compliant, so for now I would suggest using the standard dojo.require() method.

If you are used to using the text plugin for Require.js to load html templates, have no fear, Dojo has you covered with dojo/text. I just had to change my modules where I called text! to dojo/text!.

1
2
3
4
5
6
7
define(['text!templates/home.html'], function(template){
    ...
});
// Became this
define(['dojo/text!templates/home.html'], function(template){
    ...
});

I tried creating an alias for this in my dojo config, but couldn’t get it to work. If someone does, I’d love to hear about it. I was able to fix this by forming my alias as a proper array or arrays in my config.
In the config, especially if you are using jQuery, async: true is an important parameter. jQuery won’t work without it. This specifies that Dojo should be loaded asynchronously. You can also use it in your require/define methods similar to the order! plugin for Require.js.

1
2
3
4
// 1 means true, 0 means false
require({async:1},['modules/myModule'], function(myModule){
    ...
});

I have not tried this method yet, but if I have a need, now I know.

Go forth and update…

The biggest hurdle for me was getting the config to work as I needed it to work. Now that I have a better understanding of how Dojo defines packages and loads them, I’ll be moving forward with the ArcGIS JavaScript API 3.x updates. Future updates when the ESRI modules become AMD compliant should be less painful. My old Require.js modules will load just fine now. Most people may not need to move on from Require.js, so you should have a clean slate to work from. Hopefully some of these tips help get you on the track to creating modular apps with the new API.

  • Scott Davis

    Very helpful. Thanks!
    How do you build your projects? Dojo build system?

  • odoe

    Thank you!
    Up to this point, I have been using r.js to optimize/build my projects written with Require.js.
    https://github.com/jrburke/r.js/

    Now that I’ll most likely be sticking with Dojo 1.7 require/define, I’ll need to learn how to use the Dojo build system. I haven’t quite gotten that far with Dojo 1.7 yet :)

  • Simon Speich

    It seems that it’s not possible to set async=true, when using esri.tasks.GeometryService. I guess that’s because the service is not loaded yet and you can’t require it in directly (module not in AMD format yet?). Any ideas?

  • Pingback: ArcGIS JavaScript API 3.0, Dojo 1.7 and AMD Modules | odoenet - Web 2.0 BLOG | Web 2.0 BLOG

  • d3020

    You likely have answered this somewhere in the post, but I’m very new to ArcGIS and have a pretty simple question. Any help would be great.

    I’m trying to use ArcGIS 3.0 and require.js. I’ve made a local .js file that has the 3.0 API. I’ve named it arc_3_0.js.

    In my tag I have my require.js and call my “main” .js file. In that main.js file I just have..
    require(['jquery', 'arc_3_0'], function ($) { alert(“test”) });

    With just that though it gives me errors. I assume there is something I’m missing with loading arc_3_0 like that, but I’m not sure what.

    Any help would be appreciated.

  • odoe

    I responded to your question in this post.
    http://odoe.net/blog/?p=345
    Since the ArcGIS JSAPI updated with Dojo 1.7, you no longer need to use require.js for loading, as Dojo implements all that on it’s own. The key is setting up a proper main.js file with the correct set up and path configurations. In my case, I was able to update my main.js in a couple of apps without having to go through and change any other modules. The transition from require.js to Dojo 1.7 was pretty smooth once I got over the initial hump.

  • Ryan Twilley

    I really like this approach, and have started a new project focusing on building AMD loadable elements. We’ve found one thing that’s tough to work around, though. How do you force the browser to load the current version of js files? The dojo cacheBust option completely breaks the esri map…

  • odoe

    That’s an interesting problem. So far, I have not run into that issue. I’d check with the ESRI forums if there isn’t some undocumented cache setting in the cdn.

  • Ryan Twilley

    Good news! Updating to v3.2 of the API fixed my cacheBust problem. I don’t know where they addressed the issue, but I’m pleased with the timing. Also, the ‘disable cache’ setting in the chrome dev tools is another viable option for those stuck in <3.2

  • Pingback: Embrace Your Modules | odoenet

  • Mordor_master

    This article is excelent. Does this approach let me use jquery selectors for dijit form elements?