2
votes

I'm following Uzi Kilon's BackboneJS / RequireJS / backbone.LocalStorage example at http://kilon.org/blog/2012/08/build-backbone-apps-using-requirejs/.

When I git clone https://github.com/uzikilon/Todos it works just fine - but it uses older versions of backbone.localstorage. If I replace lib/backbone.localStorage with the newer version http://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.1.0/backbone.localStorage-min, though, then I get "Uncaught TypeError: undefined is not a function" here: https://github.com/uzikilon/Todos/blob/master/js/models/Todo.js#L3 - why? I think this has something to do with the tricky details at http://requirejs.org/docs/api.html#config-shim or perhaps this: http://blog.mostlystatic.com/2013/01/backbone-localstorage-uncaught.html.

require.config({
  baseUrl: "./js/",
  paths: {
    jquery: 'lib/jquery-1.8.2',
    underscore: 'lib/underscore-1.4.2',
    backbone: 'lib/backbone-0.9.2',
//    'backbone.localStorage': 'lib/backbone.localStorage'
    'backbone.localStorage': 'http://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.1.0/backbone.localStorage-min'

  },
  shim: {
    underscore: {
      exports: "_"
    },
    backbone: {
      deps: ['underscore', 'jquery'],
      exports: 'Backbone'
    },
    'backbone.localStorage': {
      deps: ['backbone'],
      exports: 'Backbone'
    }
  }
});
1
Which line is it firing on in the debugger? Chrome dev tools show you which line is breakingPW Kad
I've updated the example with the line. Basically, RequireJS is not including it properly - why?Myer

1 Answers

9
votes

The problem lies with the fact that the latest Backbone localStorage is AMD compatible, where as the version in that example is not, hence the shim config.

The fix

Remove the shim config for backbone.localStorage, you won't be needing it:

'backbone.localStorage': {
  deps: ['backbone'],
  exports: 'Backbone'
}

Then, in Todo.js change the define call from:

define(['underscore', 'backbone.localStorage'], function(_, Backbone) {

to:

define(['underscore', 'backbone', 'backbone.localStorage'], function(_, Backbone) {

Why?

The shim exports config was being used to say 'When I ask for backbone.localStorage, return me Backbone'.

This allowed 'backbone.localStorage' to be used simply as Backbone inside the Todo module.

But now backbone.localStorage supports AMD and explicitly returns a value from the define call. So the value of Backbone in Todo.js is no longer the Backbone library, but is actually a constructor for Backbone.LocalStorage

As far as I understand, the shim config is ignored for AMD modules, or at least should not be used:

Only use other "shim" modules as dependencies for shimmed scripts, or AMD libraries that have no dependencies and call define() after they also create a global (like jQuery or lodash). Otherwise, if you use an AMD module as a dependency for a shim config module, after a build, that AMD module may not be evaluated until after the shimmed code in the build executes, and an error will occur. The ultimate fix is to upgrade all the shimmed code to have optional AMD define() calls.

To fix things up the additional dependency needs to be added in Todo.js so that so that the callback parameters match up.

Hopefully that makes sense.