Search code examples
javascriptbackbone.jsmarionettebrowserifycommonjs

Browserify execute a module code only once , on multiple require calls


app.js

var MedicineManager = new Marionette.Application();

MedicineManager.addRegions({
    mainRegion: "#main-region"
});

MedicineManager.navigate = function (route, options) {
    options || (options = {});
    Backbone.history.navigate(route, options);
};

MedicineManager.getCurrentRoute = function () {
    return Backbone.history.fragment;
};

MedicineManager.on("start", function () {
    if (Backbone.history) {
        Backbone.history.start();
    }
});

$(function () {
    MedicineManager.start();
})

module.exports=MedicineManager;

I am trying to move my app from Marionette module pattern to Browserify.

I am calling require('app') in multiple files, and this causes the code in app.js to execute everytime a require('app') call is made.

Because of this I am getting error that Backbone.history has already been started. The solution to this problem is that the code be called only once at initialization.

How do I solve it?


Solution

  • You don't want to use require for instantiated objects. It can be used, but experience has shown that while the module export should be cached, there are many instances when it is not and an error is thrown. I have found that it's best to use require for static objects/methods. The best approach to ensure singletons is to instantiate in your root method, and then pass the instance into modules that require it.

    If you want to use require to refactor an existing code base, you can bind the instantiated object to a global object (like window) and then check in your initiation section for the instance of this object on that global object and return it instead.

    module.exports = function () {
        if (!window.__medicineManager){
            var MedicineManager = new Marionette.Application();
    
            MedicineManager.addRegions({
                mainRegion: "#main-region"
            });
    
            MedicineManager.navigate = function (route, options) {
                options || (options = {});
                Backbone.history.navigate(route, options);
            };
    
            MedicineManager.getCurrentRoute = function () {
                return Backbone.history.fragment;
            };
    
            MedicineManager.on("start", function () {
                if (Backbone.history) {
                    Backbone.history.start();
                }
            });
    
            MedicineManager.start();
            window.__medicineManager = MedicineManager;
        }
        return window.__medicineManager;
    }()
    

    Update:

    As an aside, it seems that Browerify specifically has this issue (more so than CommonJS or WebPack). Perhaps moving to a different module system will resolve this issue for you. Ultimately, the issue remains that instantiated modules are a bit of a misuse of the pattern. While polluting the global scope isn't ideal, I think it's a step closer to the singleton pattern that you are wanting and will always work, regardless of a build tool's particular module caching method.