4

我使用 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: Cannot read property 'prototype' of undefined

匹配以下非混淆 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 提供的额外优化。

谢谢!

4

2 回答 2

3

的定义__extends有一个问题,这很可能导致您看到的错误。

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

引用意味着与this.__extends相同window.__extends,但是闭包编译器不知道(甚至从未尝试)意识到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 服务 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);

修改和编译代码的 JSFiddle

于 2012-11-30T14:35:22.857 回答
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= {}));

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

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

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 上打开一个问题。顺便说一下,它正在优化生成的文件大小。

谢谢您的回答!

于 2012-12-01T13:32:40.260 回答