문제

I'm currently developing a new web application.

This is the first time I'm using requirejs with AMD modules.

It's not that easy to get used to that new paradigm that there are - as I understand it - no variables in the global namespace.

In previous web applications I always had one variable in the global namespace which I could use to share several resources across different modules.

Now with requirejs AMD modules, I use backbone.js and jquery (both amd versions - jquery 1.7.1 and backbone.js 0.5.3-optamd3).

Somewhere in my application I fetch a backbone.js module from the server (user object). I would like to have access to this module from different AMD modules. I also want to have an application wide event object.

Could you tell me: what is the right way in requirejs AMD to share resources across different modules?

도움이 되었습니까?

해결책

I found a solution myself.

Thank you, IntoTheVoid, for your answer, but I was hoping for an AMD-like solution. This means, not again, "polluting" the global namespace.

There were 2 keys to my solution:

"https://github.com/addyosmani/backbone-aura" from Addy Osmani and "https://github.com/amdjs/amdjs-api/wiki/AMD" the The Asynchronous Module Definition (AMD) API specification.

The spec says: "If the factory is a function it should only be executed once."

So, if an amd module is specified multiple times as a dependency in an web application, the dependency is not only NOT LOADED MULTIPLE TIMES, it is also NOT EXECUTED MULTIPLE TIMES, and this is the new thing to me. It is only executed once and the return value of the factory function is kept. Each dependency with the same path has the same object. And this changes everything.

So, you simply define the following amd module:

define([], function() {
    var app_registry = {};
    app_registry.global_event_obj = _.extend({}, Backbone.Events);
    app_registry.models = {};
    return app_registry;
});

Now, in those modules where you want to share resources, you declare this app_registry module as dependency and write in one:

define(['jquery','underscore','backbone','app_registry'], 
  function ($, _, Backbone, app_registry){
    var firstView = Backbone.View.extend({
    initialize: function() {
        _.bindAll (this, 'methodOne'); 
        this.model.bind ('change', this.methodOne);   
        this.model.fetch();
    },  
    methodOne: function() {
        app_registry.models.abc = this.model;
    }
    ...

and in the other:

define(['jquery','underscore','backbone','app_registry'], 
  function ($, _, Backbone, app_registry){
    var secondView = Backbone.View.extend({
    initialize: function() {
       _.bindAll (this, 'methodTwo'); 
        app_registry.global_event_obj.bind ('special', this.methodTwo);
    },  
    methodTwo: function() {
        app_registry. ...
    }
    ...

다른 팁

To answer your question as to how to provide an application wide event object, you can create an amd module called globalContext and instantiate it in the main.js.
Thereafter you can attach settings to the globalContext and use the global context to create subcomponents etc.

    //main.js file
    require([ "./global-context" ], function( GlobalContext) {
             new GlobalContext();
    });

In the global-context.js file we can then perform tasks such as loading child modules

    define(["Boiler", "./settings", "./modules/modules"], 
           function (Boiler, settings, modules) {
                  var GlobalContext = function () {

                //here we use a template javascript class called Boiler.Context
                var globalContext = new Boiler.Context("GlobalModule");

                //add settings to the context which can be obtained globally throughout                    the application
                globalContext.addSettings(settings);

                //here we load the sub modules of the global context
                globalContext.loadChildModules(modules);
};

This is what we have implemented in BoilerplateJS, a reference architecture for large scale javascript product development.

You can use the initialize pattern to inject any value into a requirejs module (aka 'dependency injection').

Do a require call anywhere in your code:

var MyBackboneModule;

MyBackboneModule = someWayToGetAReferenceToIt();

require("module", function(Module) { 
  Module.initialize(MyBackboneModule);
});

With module.js file defined as

define([], function(){
   var BackboneModuleDoingThisAndThat;

   function initialize(pBackboneModule) {
      BackboneModuleDoingThisAndThat = pBackboneModule ;
   };

   function doSomething() {
      var x = BackboneModuleDoingThisAndThat.computeThis(42);
   };


   return { 
      initialize: initialize
   };
});

You can define a single global APP in your entry point AMD module. APP could create and hold a reference to other shared modules:

APP = {
    this.settings : function() {
        if(settingsModule == undefined){
            //require, create and return it
        } else {
            return settingsModule;
        }
    }
}

Just a comment on your own answer - you don't need to define a function in your app_registry module:

define({
  global_event_obj: _.extend({}, Backbone.Events);
  models: {}
});

Should suffice.

See: the docs

Be careful with these things though. There are usecases where shared data modules make sense. But if you end up using it as a pseudo global namespace, it's not much better than just using globals (not saying that's what you're doing though).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top