RequireJS - 无法访问外部模块功能

时间:2017-02-23 16:31:22

标签: javascript jquery html dependency-injection requirejs

我遇到了 RequireJS 的问题。从本质上讲,我无法访问另一个文件中定义的函数。

我需要这样做,因为我想导出一个给定的函数子集,如

define('submodule', [], function() {

    let myFunction1 = function(){ return "Hello"; }
    let myFunction2 = function(){ return " From"; }
    let myFunction3 = function(){ return " Submodule!"; }

    return {
             myFunction1 : myFunction1,
             myFunction2 : myFunction2,
             myFunction3 : myFunction3,
    };

});

从其他文件访问它们

define('main', ['config', 'sub1', 'sub2', 'submodule'],   
        function(config, sub1, sub2, submodule) {

  //Config
  alert(config.conf);

  //Submodule
  let callSubmodule = function() {
    alert(submodule.myFunction1() + 
          submodule.myFunction2() + 
          submodule.myFunction3());
  }

  //sub1
  let callSub1 = function() {
    alert(sub1.myFunction1());
  }

  //sub2
  let callSub2 = function() {
    alert(sub2.myFunction1());
  }

});
  

事实上,我通常可以使用 sub1 和    sub2 ,但是,使用子模块,我根本无法做到。我认为这是由 require.config.js 中的依赖项引起的。

我的 require.config.js

require(['common'], function () { //contains vendors
    require(['config'], function () { //contains a js config file
        require(['main'], function () { //main file
            require(['sub1', 'sub2'], function () { //some subfiles
                require(['submodule']);
            });
        });
    });
});

对于 submodule.myFunction1()以及我得到的两个相关函数:

  

Uncaught(承诺)TypeError:无法读取未定义的属性'myFunction1'

这很奇怪,因为我能够在其他情况下这样做,我真的不明白为什么会这样。例如,我可以从主文件和其他文件调用 sub1 sub2 函数,但特别是子模块

的index.html

//Taken from Plunker
. . .
<script data-main="common"  data-require="require.js@2.1.20" data-semver="2.1.20" src="http://requirejs.org/docs/release/2.1.20/minified/require.js"></script>
<script src="require.config.js"></script>

. . .
<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>

common.js 包含供应商,这里只是一个例子

requirejs.config({
   baseUrl : "",
    paths : {
             "jquery" : "http://code.jquery.com/jquery-latest.min.js"
    }
});

sub1.js

define('sub1', ['submodule'], function(submodule) {

    let myFunction1 = function(){ return "called sub1"; }

    return {
             myFunction1 : myFunction1
    };

});

sub2.js

define('sub2', ['submodule'], function(submodule) {

    let myFunction1 = function(){ return "called sub2"; }

    return {
             myFunction1 : myFunction1
    };

});

我设置了Plunker with @SergGr help尝试复制应用程序的结构,但所有模块在点击时都未定义。在实际应用中,这不会发生。

我该如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

这是你的代码:

define('main', ['submodule'], function(submod) {
   console.log(submodule.myFunction());
});

参数列表中有submod。但是,您然后尝试访问submodule。请注意,您直接从模块返回函数(return myFunction),因此您的模块具有函数myFunction的值,因此模块就是您应该调用的模块。代码应该是:

define('main', ['submodule'], function(submod) {
   console.log(submod());
});

答案 1 :(得分:2)

我管理来解决这个问题。本质上,它是由模块之间的循环依赖引起的。因此, a 需要 b b 需要 a 导致其中一个在依赖项解析中未定义。< / p>

我在requirejs module is undefined的@jgillich提供的答案中找到了解决方法。

所以,我设法在主

中解决使用问题
define('main', ['config', 'sub1', 'sub2', 'require'],   
    function(config, sub1, sub2, submodule, require) {

  //Config
  alert(config.conf);

  //Submodule
  let callSubmodule = function() {
    alert(require('submodule').myFunction1() + 
          require('submodule').myFunction2() + 
          require('submodule').myFunction3());
  }

});

正如@jgillich所说:

  

如果你定义一个循环依赖(“a”需要“b”而“b”需要“a”),那么在这种情况下,当调用“b”的模块函数时,它将获得一个未定义的值“一个”。 “b”可以在使用require()方法定义模块之后获取“a”(确保将require指定为依赖项,以便使用正确的上下文查找“a”):

//Inside b.js:
define(["require", "a"],
    function(require, a) {
        //"a" in this case will be null if "a" also asked for "b",
        //a circular dependency.
        return function(title) {
            return require("a").doSomething();
        }
    }
);

http://requirejs.org/docs/api.html#circular

答案 2 :(得分:2)

您为模块命名的方式我希望它们都来自require配置文件。我不希望requirejs知道如何在没有某种显式编译过程的情况下加载这些文件。我还怀疑你的服务器正在返回一些东西,因为404几乎能够解释而不会爆炸。

您的设置似乎和命名方案似乎很奇怪。如果你有能力从头开始,我的建议就是。

建议:

  • 我注意到您正在使用绝对路径。我强烈建议使用相对路径。这有很多原因。
  • 您的数据主要应该是您所说的&#34; require.config.js&#34;。你的common.js实际上是一个require.config.js。
  • 使用脚本标记分别加载require.config.js(这是您的主要版本)。你可以做到这一点,但这很奇怪。
  • 您可以使用&#34; commonjs&#34;样式语法要求文件而不需要使用数组来定义所有依赖项。我推荐。

这是我对设置的建议:

index.html

<script src="/js/config.js" />
<script src="http://requirejs.org/docs/release/2.1.20/minified/require.js" />
<script>
      require('/js/main', function(main) {
          main({});
      });
</script>

/js/config.js

// setting requirejs to an object before its loaded will cause requirejs to use it as the config
window.requirejs = {
   baseUrl : "/",
    paths : {
        "jquery" : "http://code.jquery.com/jquery-latest.min.js"
    }
};

/js/main.js

define(function(require) {
    const sum = require('./sum');
    return (a, b) => sum(a, b);
});

/js/sum.js

define(function(require) {
    return (a, b) => a + b;
});

答案 3 :(得分:1)

更新(2017年3月2日)

您的plunker显然无法正常工作,因为您可以直接从HTML调用模块函数。

<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>

RequireJS无法正常工作。 RequireJS的一个关键目的是提供模块隔离,因此它无法以这种方式工作:想象一下,如果几个不同的模块具有函数callSubmodule

据我所知,无法将来自HTML的调用绑定到RequireJS模块中的代码,它应该是另一种方式:模块绑定到HTML。如果您解决了这些问题,那么一切正常,我可以看到fork of your plunker

<小时/> 旧答案

该错误发生在 subModule.js

define('submodule', [], function() {

    let myFunction = function(){ return "Hello"; }

    //return myFunction;     // old, wrong
    return { myFunction: myFunction }; 
});

即使您只想返回1个函数,也不应该按原样返回它,您应该将它包装到一个对象中并给它一个明确的名称。

P.S。如果这不是您真正的问题,请提供真实的Minimal, Complete, and Verifiable example