打字稿和谷歌关闭

时间:2012-11-29 22:26:19

标签: javascript obfuscation typescript google-closure-compiler

我使用Typescript命令(tsc)创建一个包含所有平台类的Javascript文件。

tsc "./Main.ts" -out "./script/myProject_debug.js" --declarations

然后,我想用Google Closure(compiler.jar)来混淆这个文件,如下所示:

java -jar ./compiler/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js "./script/myProject_debug.js" > "./script/myProject.js".

但是当我执行生成的混淆/优化代码时,我得到以下错误:Uncaught TypeError:无法读取未定义的属性'prototype'

匹配以下非混淆的JS代码(由tsc命令生成):

var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
}

此部分用于翻译“extends”Typescript关键字,而b的等价物未定义。

是否有人遇到类似错误或/并获得解决方案,以便能够使用Typescript编译文件与Google Closure进行混淆?

我尝试使用uglifyjs命令并且输出文件完美地工作,但我想要完全混淆(类,参数,变量,方法等)。此外,欢迎Google Closure提供的额外优化。

谢谢!

2 个答案:

答案 0 :(得分:3)

__extends的定义存在一个很可能导致您看到错误的问题。

var __extends = this.__extends || function (d, b) { ... };

this.__extends引用与window.__extends的含义相同,但Closure编译器不知道(或甚至尝试)实现对this的引用全局上下文实际上是window对象。编译为--warning_level=VERBOSE编译器将发出警告:

Dangerous use of the global this object at line 1 character 16
var __extends = this.__extends || function (d, b) {
                ^

此外,this.__extends是对外部/未定义属性的引用,编译器也会在VERBOSE级别上发出警告。

我使用Closure-compiler Service UI修改并注释了要编译的定义而没有警告:

// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @warning_level VERBOSE
// @output_file_name default.js
// @formatting pretty_print
// ==/ClosureCompiler==

var __extends = window['__extends'] || function (d, b) {
  /** @constructor */
  function __() { this.constructor = d; }
  __.prototype = b.prototype;
  d.prototype = new __();
}

/**
 * @constructor
 * @extends {String}
 */
function foo2() {this.foo = 'bar'; }
__extends(foo2, String);

var bar2 = new foo2;
alert(bar2.toLowerCase);

A JSFiddle of the modified and compiled code

答案 1 :(得分:0)

好的,我发现了问题。

正如我先前所说,b未定义于:

var __extends = this.__extends || function (d, b) {
   function __() { this.constructor = d; }
   __.prototype = b.prototype;
   d.prototype = new __();
}

当typescript“编译”成javascript时,如果你按项目获得了一个命名空间,但是你在分离的文件中编写了与这个命名空间相关的所有类,那么Typescript会在最终生成的js文件中执行以下操作:

var namespace;
(function (namespace) {

    var Class1 = (function (dependency) {
        [...]
        return Class1;
    })(namespace.dependency);

    namespace.Class1 = Class1;
})(namespace || (namespace= {}));

var namespace;
(function (namespace) {

    var Class2 = (function (dependency) {
        [...]
        return Class2;
    })(namespace.dependency);

    namespace.Class2 = Class2;
})(namespace || (namespace= {}));

var namespace;
(function (namespace) {

    var Main = (function (dependency) {
        [...]
        return Main;
    })(namespace.Class2);

    namespace.Main = Main;
})(namespace || (namespace= {}));

我不确切知道它是如何工作的,但某些地方google-closure-compiler删除了一些类,即使这个代码没有问题,JS也可以处理它。因此缺少一些依赖关系而b未定义。

所以我发现如果你像下面这样声明你的命名空间,你就不会再遇到错误了(只要使用了“Main”类,你就会将所有类保留在最终混淆的js文件中)在全局窗口对象中引用命名空间:

var namespace;
(function (namespace) {

    var Class1 = (function (dependency) {
        [...]
        return Class1;
    })(namespace.dependency);

    namespace.Class1= Class1;

    var Class2 = (function (dependency) {
        [...]
        return Class2;
    })(namespace.dependency);

    namespace.Class2= Class2;

    var Main = (function (dependency) {
        [...]
        return Main;
    })(namespace.Class2);

    namespace.Main = Main;
})(namespace || (namespace= {}));

我想我会在typescriptlang.org上打开一个问题。它顺便优化了生成的文件大小。

感谢您的回答!