Browserify 在多次 require 调用时只执行一次模块代码

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;

我正在尝试将我的应用程序从 Marionette 模块模式移动到 Browserify。

我在多个文件中调用 require('app'),这会导致每次调用 require('app') 时执行 app.js 中的代码。

因此,我收到 Backbone.history has already been started 的错误。 这个问题的解决方案是代码只在初始化时被调用一次。

如何解决?

您不想将 require 用于实例化对象。它可以使用,但经验表明,虽然模块导出应该被缓存,但在很多情况下它不会被缓存并抛出错误。我发现静态 objects/methods 最好使用 require。确保单例的最佳方法是在根方法中实例化,然后将实例传递到需要它的模块中。

如果您想使用 require 重构现有代码库,您可以将实例化对象绑定到全局对象(如 window),然后检查实例的启动部分这个对象在那个全局对象上,而不是 return 它。

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;
}()

更新:

顺便说一句,Browerify 似乎特别有这个问题(比 CommonJS 或 WebPack 更严重)。也许转移到不同的模块系统将为您解决这个问题。最终,问题仍然是实例化模块有点误用了模式。虽然污染全局范围并不理想,但我认为它更接近您想要的单例模式并且将始终有效,无论构建工具的特定模块缓存方法如何。