简体   繁体   English

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

[英]How can I load my own js module with goog.provide and goog.require?

We are trying to switch the packaging for our project from dojo to google closure, but we haven't had any luck so far. 我们正在尝试将我们项目的包装从dojo切换到谷歌关闭,但到目前为止我们还没有运气。 Here is a simple example that illustrates what we are trying to accomplish: 这是一个简单的例子,说明了我们要完成的任务:


<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>

Then in /foo/bar.js I have: 然后在/foo/bar.js我有:


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

The errors I receive in firebug are as follows: 我在firebug中收到的错误如下:

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

When I look in the Net tab, there isn't an http request out to fetch a file - I was expecting the closure library to generate a script tag to fetch bar.js . 当我查看Net选项卡时,没有一个http请求来获取文件 - 我希望闭包库生成一个脚本标记来获取bar.js

help! 救命! ;) ;)

I figured it out and it's not very hard, but there are a few gotchas. 我想通了,这不是很难,但有一些问题。

Basically, you can use the dependency generating script calcdeps.py ( you should read calcdeps.py docs ) in one of several modes: 基本上,您可以使用以下几种模式之一使用依赖关系生成脚本calcdeps.py( 您应该阅读calcdeps.py文档 ):

  1. Generating deps.js file 生成deps.js文件
  2. Concatenating everything into a single file, optionally compiling it using the closure compiler. 将所有内容连接到一个文件中,可选择使用闭包编译器对其进行编译。

For development you should use (1), since it allows you to not run the calcdeps.py after editing the JS sources, unless you make changes to the dependency tree. 对于开发,您应该使用(1),因为它允许您在编辑JS源之后不运行calcdeps.py,除非您对依赖关系树进行了更改。 The rest of the answer is about this way, I haven't tried the other one yet. 其余的答案是这样的,我还没有尝试过另一个。

Here's what I did to generate it: 以下是我为生成它所做的事情:

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

...assuming the following directory structure: ...假设以下目录结构:

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

(the -p parameter traverses all js files in the specified directory and the docs say you can specify multiple directories to search if you have to.) -p参数遍历指定目录中的所有js文件,文档说您可以指定要搜索的多个目录。)

The above call creates a my-deps.js file next to the main app.html, which I use to run the application. 上面的调用在主app.html旁边创建了一个my-deps.js文件,我用它来运行应用程序。 The created file contains information about my JS files in js/ and looks like this: 创建的文件包含有关js/我的JS文件的信息,如下所示:

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

- where the first string it the path to my JS file relative to closure-library/closure/goog/base.js (this is important!), the second array is the list of goog.provide -d strings, and the last array is the list of goog.require -d strings. - 第一个字符串,它是我的JS文件的路径相对于closure-library / closure / goog / base.js (这很重要!),第二个数组是goog.provide -d字符串列表,最后一个数组是goog.require -d字符串的列表。

Now in app.html I have: 现在在app.html我有:

<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>

Note: 注意:

  1. In addition to including closure's base.js, I include my generated deps.js 除了包含closure的base.js之外,我还包括我生成的deps.js
  2. As mentioned in the tutorial the goog.require call has to be in a separate script tag , because it appends a script tag to load the required scripts and they are loaded after the current script tag finished processing. 正如教程中所提到的goog.require调用必须位于单独的脚本标记中 ,因为它附加了一个脚本标记来加载所需的脚本,并在当前脚本标记完成处理后加载它们。

Gotchas: 陷阱:

  1. The described above issue with paths being relative to base.js. 路径相对于base.js的上述问题。 goog.require creates the script URL to load by concatenating the base.js base URL (ie without base.js leafname) and the first parameter to goog.addDependency in deps.js. goog.require通过将base.js基本URL(即没有base.js leafname)和第一个参数连接到deps.js中的goog.addDependency来创建要加载的脚本URL。
  2. calcdeps.py doesn't work well on Windows, in particular using the backslashes in the deps.js string literals calcdeps.py在Windows上运行不正常,特别是使用deps.js字符串文字中的反斜杠
  3. If something doesn't work well, you may want to look through all issues mentioning calcdeps and make sure you have an up to date checkout. 如果某些内容不能正常工作,您可能需要查看提及calcdeps的所有问题并确保您拥有最新的结帐。

Update!!! 更新!

New version of calcdeps.py changes the game a little bit. 新版本的calcdeps.py稍微改变了游戏规则。 To create your deps.js you now need to use the -d flag. 要创建deps.js,您现在需要使用-d标志。 eg: 例如:

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

To compile: 编译:

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

So the process is actually now a lot easier, but you have to use your powers of ESP to find out about it as its totally undocumented. 所以这个过程实际上现在变得容易多了,但是你必须利用你的ESP的力量来发现它完全没有文档。 The calcdeps.py now also does not work with Python 3.1 on windows so that is also heaps of fun. calcdeps.py现在也无法在Windows上使用Python 3.1,因此这也是很有趣的。 A few hacks got it working for me (which I will not put here as I'm not a python programmer and there must be better ways to do it). 一些黑客让它为我工作(我不会放在这里,因为我不是一个python程序员,必须有更好的方法来做到这一点)。

Generally the last day has been super fun, hope this post helps someone avoid the same enjoyment. 一般来说,最后一天一直非常有趣,希望这篇文章可以帮助别人避免同样的享受。

Guido 圭多

I was able to get it to work by adding the following to deps.js : 我可以通过在deps.js添加以下内容来deps.js
goog.addDependency('../../../foo/bar.js', ['foo.bar'], []);

Firefox now makes an http request to /foo/bar.js when it encounters the goog.requires statement. Firefox现在在遇到goog.requires语句时向/foo/bar.js发出http请求。

However, the file contains this comment: 但是,该文件包含以下注释:
// This file has been auto-generated by GenJsDeps, please do not edit.

According to this , GenJsDeps is the same as calcdeps.py . 根据这个GenJsDeps是一样的calcdeps.py If you look at the documentation, it looks like there is an -o deps switch which will re-generate deps.js so it isn't edited manually. 如果您查看文档,看起来有一个-o deps开关将重新生成deps.js因此不会手动编辑。

Yes you should use calcdepds.py. 是的,你应该使用calcdepds.py。 I created a big blog post after much trial and error to figure out the best way to do this, I also go over the differences between dojo.require and goog.require: 经过多次试验和错误后,我创建了一篇很棒的博文,找出了最好的方法,我也回顾了dojo.require和goog.require之间的区别:

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

solution: 解:

  • download closure to your project externals (or assets, whatever). 下载关闭到您的项目外部(或资产,无论如何)。

  • don't bother with setting onload, delay, playing with async, etc.. 不要打扰设置onload,延迟,玩异步等。

  • they won't work (they are also very poor design pattern and extremely lame..) 他们不会工作(他们的设计模式也非常差,非常蹩脚..)

- this is your main.js where you dynamically injecting your code into the DOM (for example creating a bookmarklet or something): - 这是你的main.js ,你动态地将你的代码注入DOM(例如创建一个bookmarklet或其他东西):

/**
 * 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...");
};

now: 现在:

  • edit your base.js 编辑你的base.js

add the the end of the file 添加文件的结尾

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

/**
 * run the method when done load. just like JSONProtocol.
 */
window.setTimeout(function() {
  window['starter']();
}, 5);
  • your " callback " simply activates starter when the file has done rendering, 你的“ 回调 ”只是在文件完成渲染后激活启动器,

  • it works perfectly and it keeps loading every resource asynchronously. 它完美地工作,它不断异步加载每个资源。

ps PS

  1. the window['....'] syntax is so you could safely use closure-compiler to the max and always use the same name (although there are another ways to do so, but this is the simple "always working" way..). window ['....']语法是这样你可以安全地使用closure-compiler到max并且总是使用相同的名字(虽然还有其他方法可以这样做,但这是简单的“始终工作”方式。 )。

2. on base.js you could also avoid the timeout and just use 2.在base.js你也可以避免超时并且只是使用

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

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

but as a rule of thumb modern browsers acts better when you wrap those "don't care, just do this stuff at the end, like JSONProtocol callback" stuff- 但是作为一个经验法则,现代浏览器在包装那些“不关心,最后只做这些东西,如JSONProtocol回调”的东西时效果更好 -

timeouts (mostly used with values from 0-5) are not interrupted as timeouts but as a way to breaks the synchronicity of the code-block allowing truly "context-switch"-like behavior. 超时(主要用于0-5的值)不会作为超时中断,而是作为一种打破代码块同步性的方法,允许真正的“上下文切换”行为。

although there is an extra overhead there. 虽然那里有额外的开销。

Here's a little project that I've been working on that might be helpful to you: http://github.com/fintler/lanyard 这是我一直在努力的一个小项目,可能对您有所帮助: http//github.com/fintler/lanyard

Take a look at the build.xml, the file named lanyard.js, and all of the files located in src/geom/*. 查看build.xml,名为lanyard.js的文件以及位于src / geom / *中的所有文件。

The build.xml has an example of how to call calcdeps.py through ant for all of the js located in src. build.xml有一个如何通过ant为src中的所有j调用calcdeps.py的示例。 It may not be the best way to do things, but it's been working for me so far. 它可能不是最好的做事方式,但到目前为止它一直在为我工作。

Either way to get custom modules working, at least for development version, is to include manually js files in head section of html page, after google's base.js file inclusion. 无论哪种方式使自定义模块工作,至少对于开发版本,是在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>
...

But, you should care about sequence of inclusion by yourself. 但是,你应该自己关心包容的顺序。 For not very large custom files sets it works good. 对于不是很大的自定义文件集,它运行良好。 For production version you still had better use js source compiling to get all benefits of closure library. 对于生产版本,您仍然最好使用js源代码编译来获得闭包库的所有好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM