如何使用goog.provide和goog.require加载我自己的js模块?

时间:2009-12-17 01:51:12

标签: javascript dojo google-closure google-closure-library

我们正在尝试将我们项目的包装从dojo切换到google关闭,但到目前为止我们还没有运气。这是一个简单的例子,说明了我们要完成的任务:


<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script type="text/javascript" src="runtime/src/core/lib/goog-rev26/base.js"></script>
        <script>
            goog.require("foo.bar");
            function main() {foo.bar.echo("hello world")}
        </script>
    </head>
<body onload="main()">
</body>
</html>

然后在/foo/bar.js我有:


goog.provide("foo.bar");
foo.bar.echo = function(s) {console.debug(s);}

我在firebug中收到的错误如下:

goog.require could not find: foo.bar
foo is not defined

当我查看Net选项卡时,没有提取文件的http请求 - 我希望闭包库生成一个脚本标记来获取bar.js

帮助! ;)

7 个答案:

答案 0 :(得分:13)

我想出来并且不是很难,但有一些陷阱。

基本上,您可以在以下几种模式之一中使用依赖关系生成脚本calcdeps.py(you should read calcdeps.py docs):

  1. 生成deps.js文件
  2. 将所有内容连接到一个文件中,可选择使用闭包编译器对其进行编译。
  3. 对于开发,您应该使用(1),因为它允许您在编辑JS源之后不运行calcdeps.py,除非您对依赖关系树进行了更改。其余的答案是这样的,我还没有尝试过另一个。

    以下是我为此制作的内容:

    #!/bin/bash
    cd closure-library/closure/goog
    python ../bin/calcdeps.py -p ../../../js -o deps > ../../../my-deps.js
    

    ...假设以下目录结构:

    project/
      closure-library/ (as checked out from SVN)
      js/ (my JS code)
      app.html
    

    -p参数遍历指定目录中的所有js文件,文档说您可以指定多个目录进行搜索(如果必须)。)

    上面的调用会在主app.html旁边创建一个my-deps.js文件,用于运行该应用程序。创建的文件包含js/中有关我的JS文件的信息,如下所示:

    goog.addDependency('../../../js/controllers.js', ['proj.controllers'], []);
    goog.addDependency('../../../js/ui.js', ['proj.ui'], ['proj.controllers']);
    

    - 第一个字符串是我的JS文件的路径相对于closure-library / closure / goog / base.js (这很重要!),第二个数组是{的列表{1}} - d字符串,最后一个数组是goog.provide - d字符串列表。

    现在在app.html中我有:

    goog.require

    注意:

    1. 除了包含closure的base.js之外,我还包括我生成的deps.js
    2. 正如教程the goog.require call has to be in a separate script tag中所提到的,因为它附加了一个脚本标记来加载所需的脚本,并在当前脚本标记处理完毕后加载它们。
    3. 陷阱:

      1. 路径相对于base.js的上述问题。 <script src="closure-library/closure/goog/base.js"></script> <script src="my-deps.js"></script> <script> goog.require("proj.ui"); </script> <script> // here we can use the required objects </script> 通过将base.js基本URL(即没有base.js leafname)和第一个参数连接到deps.js中的goog.addDependency来创建要加载的脚本URL。
      2. calcdeps.py在Windows上运行不正常,尤其是using the backslashes in the deps.js string literals
      3. 如果某些内容无效,您可能需要查看all issues mentioning calcdeps并确保您拥有最新的结帐。

答案 1 :(得分:8)

更新!!!

新版本的calcdeps.py稍微改变了游戏规则。要创建deps.js,您现在需要使用-d标志。例如:

python path-to-closure-library/closure/bin/calcdeps.py -i path-to-your-src/requirements.js -o deps -d path-to-closure-library/closure/ -p path-to-your-src/ --output_file=path-to-your-src/deps.js

编译:

python path-to-closure-library/closure/bin/calcdeps.py -i path-to-your-src/requirements.js -d path-to-closure-library/closure/ -p ./ --output_file=path-to-your-release/scripts.min.js -c path-to-compiler/compiler.jar -f "--compilation_level=ADVANCED_OPTIMIZATIONS" -f "--debug=true" -f "--process_closure_primitives=true" -f "--manage_closure_dependencies=true" -o compiled

所以这个过程实际上现在变得容易多了,但是你必须利用ESP的力量来发现它完全没有文档。 calcdeps.py现在也无法在Windows上使用Python 3.1,因此这也是很有趣的。一些黑客让它为我工作(我不会放在这里,因为我不是一个python程序员,必须有更好的方法来做到这一点。)

一般来说,最后一天非常有趣,希望这篇文章可以帮助别人避免同样的享受。

答案 2 :(得分:1)

我可以通过将以下内容添加到deps.js来使其工作:
goog.addDependency('../../../foo/bar.js', ['foo.bar'], []);

当Firefox遇到/foo/bar.js语句时,它会向goog.requires发出http请求。

但是,该文件包含以下评论:
// This file has been auto-generated by GenJsDeps, please do not edit.

根据thisGenJsDepscalcdeps.py相同。如果您查看文档,看起来有一个-o deps开关会重新生成deps.js,因此不会手动编辑。

答案 3 :(得分:1)

是的,你应该使用calcdepds.py。经过多次试验和错误后我创建了一篇很棒的博客文章,找出了最好的方法,我也回顾了dojo.require和goog.require之间的差异:

http://apphacker.wordpress.com/2009/12/28/howto-how-to-use-goog-require-and-goog-provide-for-your-own-code/

答案 4 :(得分:0)

这是我一直在努力的一个小项目,可能对您有所帮助:http://github.com/fintler/lanyard

查看build.xml,名为lanyard.js的文件以及位于src / geom /*中的所有文件。

build.xml有一个如何通过ant为src中的所有j调用calcdeps.py的示例。这可能不是最好的做事方式,但到目前为止它一直在为我工作。

答案 5 :(得分:0)

无论哪种方式使自定义模块工作,至少对于开发版本,都是在google的base.js文件包含之后在html页面的head部分包含手动js文件。

<script type="text/javascript" src="js/closure/goog/base.js"></script>
<script type="text/javascript" src="js/closure/custom/custom.js"></script>
<script type="text/javascript" src="js/closure/custom/sub/sub.js"></script>
...

但是,你应该自己关心包容的顺序。对于不是很大的自定义文件集,它运行良好。对于生产版本,您仍然最好使用js源代码编译来获得闭包库的所有好处。

答案 6 :(得分:0)

溶液:

  • 将关闭下载到您的项目外部(或资产,无论如何)。

  • 不要打扰设置onload,延迟,玩异步等等。

  • 他们不会工作(他们的设计模式也非常差,非常蹩脚......)

- 这是你动态将代码注入DOM的main.js(例如创建书签或其他内容):

/**
 * loads the base.js of google closure.
 * http://code.google.com/p/closure-library/
 */

(function() {
  var s = document.createElement('script');
  s.type = "text/javascript";
  s.src = "./assets/closure/goog/base.js";
  s.async = true;
  document.getElementsByTagName("body")[0].appendChild(s);
}());

/**
 * activated from the base.js as JSONProtocol.
 */
window['starter'] = function() {
  console.log("hi...");
};

现在:

  • 修改 您的base.js

添加文件末尾

......
.......
........

/**
 * run the method when done load. just like JSONProtocol.
 */
window.setTimeout(function() {
  window['starter']();
}, 5);
  • 您的“回调”只需在文件完成渲染后激活启动器,

  • 它完美无缺,并且不断异步加载每个资源。

P.S。

  1. window ['....']语法是这样你可以安全地使用closure-compiler到max并且总是使用相同的名字(虽然还有另外一种方法可以这样做,但这很简单“总是在工作“方式..)。
  2. 2。在base.js上你也可以避免超时并只使用

    ......
    .......
    ........
    
    /**
     * run the method when done load. just like JSONProtocol.
     */
    window['starter']();
    

    但是根据经验,现代浏览器在包装那些“不关心,最后只做这些东西,比如JSONProtocol回调”的东西时效果会更好 -

    超时(主要用于0-5的值)不会因为超时而中断,而是作为一种打破代码块同步性的方法,允许真正的“上下文切换”行为。

    虽然那里有额外的开销。