在运行时配置RequireJS

时间:2012-11-26 22:32:02

标签: javascript dependency-injection requirejs

是否可以在运行时修改requirejs(或任何AMD加载器)配置?

作为一个例子,我有两个日志模块:一个只是包装console.log,另一个是日志到服务器。我希望模块只需要log(require(['log'], function(log) { ... });)而不关心它正在使用哪个logger。

我可以将'log'设置为require的主配置中的包,这样可以正常工作。但我宁愿做的是根据一些条件在main.js中设置此选项。类似的东西:

if( ... ) {
    require.config({
        packages: [
            { name: 'log', location: 'app/base/utils/consolelog' }
        ]
    });
}

但这似乎不起作用。有没有办法做到这一点,或者我是否将requirejs的功能作为依赖注入框架?

干杯

1 个答案:

答案 0 :(得分:3)

任何依赖注入框架的一般检测是,您有一种简单的方法来配置它将在运行时解析哪种依赖容器,并且它只构造一次并在应用程序的生命周期内保持静态。

这是专门针对您不会遇到依赖关系可能在应用程序中的某个点发生更改的情况。有了这个概念,你的一个或所有应用程序源可能需要在从容器中消耗一些或任何依赖性之前请求许可而不是仅仅在容器上使用nom是一个有很多缺点的可怕想法。主要的缺点是你知道,accounts.all().each().withdraw(billing.MONTHLY_SERVICE_FEE).return()中的任何引用都可能在任何时候表现不同,没有明显的原因。如果Accounts更改且new Accounts().all()未返回任何帐户,或者billing.MONTHLY_SERVICE_FEE突然发生变化,并且您向某些帐户收取X金额而其他帐户收取Y,则会很糟糕。< / p>

所以,简短的回答是否定的,你不能动态配置RequireJS。 RequireJS将始终只加载一次模块,因此回调返回值始终是一个静态对象,或者如果您更愿意,当您查看模块源时,您知道它的define()将仅被评估一次对于文件的生命周期。

在运行时如何抽象对象的特定实现是几种非常简单的方法。您只需使用回调创建多个模块,这些回调返回具有相同公共接口的对象,但具有不同的行为,然后您可以静态或动态地解析要返回的对象。

// core/logging/base.js
define(function() {
  var static;
  var base =  {
      _log: undefined,
      create: function(name) {},
      // ..
  }

  return base;
});

// core/logging/client.js
define(function(['core/logging/base'], function(base) {
  var client = extend(base, {_log: console.log});
  return client;
});

// core/logging.js
define(['core/logging/server', 'core/logging/client', 'core/conf/settings'], 
  function(server, client, environment) {
  if(settings.LOGGER === 'server') {
    return server;
  } else {
    return client;
  }
};

// app/foo.js
define(['core/logging'], function(logging) {
  var log = logging.createLog('foo');
  log.info('bar');
  // > INFO foo: bar
  // or...
  // POST http://server/log {type: 2, name: 'foo', message: 'bar'}
}

有几种方法可以设计这样的支持,但是这个方法很简单,适用于您的特定情况。通常,您可以在模块中静态执行此解决方案,也可以通过getter函数在任何块中动态执行此解析,模块回调本身也可以返回构造函数或函数,而不仅仅是对象。