【问题标题】:Externs of constructed objects for Google's Closure Compiler谷歌闭包编译器的构造对象的外部
【发布时间】:2013-09-05 13:15:02
【问题描述】:

首先:我知道this SO questionexterns extractor here

我正在使用ThreeJS 开发我的第一个游戏项目。由于我以模块化方式构建它,因此我打算使用Google's Closure Compiler 最后打包我的结果。一个小测试表明编译(使用高级优化)也会缩小构造对象的方法和属性,例如THREE.GeometryTHREE.Color

检查生成的 externs 文件,这是我在 THREE.Color 的第 78 行(ThreeJS r60)找到的:

"Color": function () {},

显然它缺少方法和属性,所以闭包编译器不会知道它不应该重命名这些。

我有另一个解决方案,即在单独的文件中定义 exposures 并将其与源代码一起编译。它工作得很好,但是以这种方式定义每个使用的方法和属性需要大量的手动工作。这也只是一个骇人听闻的解决方法。闭包编译器根本不重命名对象上出现的任何这些名称。

例如,所有这些都具有相同的效果:

/** @expose */
THREE.Geometry.vertices;

/** @expose */
THREE.vertices;

/** @expose */
Object.vertices;

window.vertices = function() {
    console.log("foo");
};

window.vertices 不会被重命名。因此,这不是一个理想的解决方案。

实际的问题是:闭包编译器甚至能够做到这一点吗?还是我应该将这些依赖项放入我的编译中并让它重命名我使用的所有方法和属性?

【问题讨论】:

    标签: javascript google-closure-compiler


    【解决方案1】:

    如果我正确理解了您的问题,您正在尝试编译您的 awesomeGame.js - 它依赖于threejs.js - 但是您对threejs.js 的引用被闭包的重命名过程破坏了。

    我同意自动化外部脚本可能还有很多开发工作,可能不是一个可靠的解决方案。

    我的项目有一个非常相似的问题。我可以提供两种可能的解决方案。每个都有取舍。我个人不是threejs用户,这里只说明一般约定。

    1)从window对象开始,用括号语法调出你需要的对象

    根据this discussion,在库执行并将其根对象放置在全局上下文中之后,您可以从window 开始找到它 - 并且永远不会重命名窗口对象。此外,括号语法永远不会被重命名。因此,您的编译代码可以在window['THREE']THREE.Geometrywindow['THREE']['Geometry'] 中找到THREE,等等。此外,jQuery 将在 window['jQuery'] 中找到,并且在 window['_'] 中找到下划线。

    我建议任何时候你需要从编译后的代码中访问外部对象或函数,比如threejs.js,在文件顶部声明一些全局定义,如下所示:

    // awesomeGame.js:
    
    // global defines:
    var three_vertex        = window['THREE']['Geometry']['vertex'],
        three_rectangle     = window['THREE']['Geometry']['rectangle'],
        three_crossproduct  = window['THREE']['Math']['crossproduct'],
        jquery_ajax         = window['jQuery']['ajax'];
    
    // game assets:
    var myVertex         = new three_vertex(10,10),
        myRectangle      = new three_rectangle(10,10,10,10);
    
    // do stuff:
    console.log(myVertex['x'] + ' ' + myVertex['y']);
    console.log(three_crossproduct(myVertex, myVertex));
    
    myRectangle['paint']('black');
    

    如果您在漂亮/高级模式下将上述内容粘贴到Compiler Service,您会产生以下内容。

    var a = window.THREE.Geometry.rectangle,
        b = window.THREE.Math.crossproduct,
        c = new window.THREE.Geometry.vertex(10, 10),
        d = new a(10, 10, 10, 10);
    
    console.log(c.x + " " + c.y);
    console.log(b(c, c));
    d.paint("black");
    

    正面: 完整的threejs.js 引用仅在全局定义中打印一次。从那时起,闭包将打印一个容器“a”或“b”。因此,与您讨论的外部方法不同,您可以获得大部分压缩优势。

    否定: threejs.js 对象的方法和属性 - 必须以括号语法一致地命名。请注意,如果 ['x'] 和 ['y'] 属性以及 ['paint'] 方法没有被括号括起来,它们将被重命名。将 Closure 设置为 --warning_level=VERBOSE,注意 JSC_INEXISTENT_PROPERTY 错误,并将它们括起来。如果你忘记了什么,编译器会提醒你。 Error Reference.

    如果您的linter 对所有括号感到不满,请使用--sub 说服它,如“容忍下标”。 All jsLint errors/options.

    2) 将 threejs.js 和 awesomeGame.js 连接成一个 temp.js

    另一种方法:为自己设置一个构建脚本,将所有源文件按依赖顺序连接到一个大型临时文件中。如果您是 unix-y,您的脚本可能如下所示:

    #!/bin/bash
    # build_and_run.sh
    # get updates to google closure: http://code.google.com/p/closure-compiler/downloads/list
    #
    # local jslint:
    # sudo apt-get install nodejs npm
    # sudo npm jslint -g
    
    rm temp.js
    rm final.js
    
    cat threejs.js \
        awesomeGame_moduleOne.js \
        awesomeGame_moduleTwo.js \
        > temp.js
    
    # docs: http://www.jslint.com/lint.html
    
    jslint  temp.js \
            --maxerr=50 --sloppy --white --sub --plusplus \
            --nomen --bitwise --browser \
            --predef unescape \
            --predef Uint8Array \
            --predef Blob
    
    java    -jar                compiler-20130823.jar \
            --compilation_level ADVANCED_OPTIMIZATIONS \
            --formatting        pretty_print \
            --language_in=ECMASCRIPT5 \
            --js                temp.js \
            --js_output_file    final.js
    
    #maybe
    nodejs  final.js
    
    # or
    # https://developers.google.com/chrome/web-store/docs/get_started_simple
    
    chromium --load-and-launch-app=./
    
    # rinse, repeat
    

    正面: 没有括号,没有定义,没有扩展,没有中间件。谷歌关闭看到了一切。最终产品的最大压缩。运输项目的完整 linting(扫描原始的、分割的源文件可能会使 linter 感到困惑)。发送单个集成文件。

    否定: 沉浸在上游源代码中。这可能会或可能不会让您同意。对上游源代码进行检查会特别诱使您在上游强加代码样式。反抗,反抗。另一方面,了解您所依赖的中间件也有优势。

    还涉及到 master.js 文件的调试,因为将报告 final.js 的行号,并且您需要在阅读时识别源文件。使用漂亮的模式、更温和的编译设置、@preserve cmets 和大量的console.log,你就会掌握它。

    最后,根据threejs 的优先级和代码约定,Closure 中的编译可能不受支持,或者可能会引入细微的行为变化。如果是这种情况,请排除此选项。例如,jQuery 与闭包的兼容性是 actively being discussed


    无论如何,我希望这能回答你的问题。如果我不符合要求,请回复。那里也有很多“包含/模块化”框架。也许有人可以填写该主题。

    【讨论】:

    • 好的,非常感谢您的回答。有趣的是,我已经有了这样一个构建脚本,它并没有真正连接所有源,而是简单地生成必要的--js 参数。我也知道括号符号的处理,但我发现它有点太乏味了。我不知道--warning_level=VERBOSE 也给了我可能不一致的命名。总的来说,感谢您的确认。也很详细。公认。不要以为我会得到更好的东西。
    猜你喜欢
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多