Closure Compiler 编译的 es6 模块库没有导出符号
No exported symbols with es6 modules library compiled by Closure Compiler
起点: 许多js文件被Closure Compiler(ADVANCED_OPTIMIZATIONS级别)编译成功(没有warning/error)在一个单独的库文件中。
在这些 js 文件中:
goog.require
和goog.provide
习惯了import/export他们之间的事情
/** @export */
前面用whatever
(const/function/Class/var)需要库外
一些 HTML 文件包括库和一些未编译的 js 成功访问所有 whatever
在这个库中定义。
我想要的:移动到 es6 模块语法
我对每个js文件做了什么:
goog.require
被 import
替换为 Class 的列表,来自另一个 js 文件的函数
goog.provide
删除并在每个 Class 前面添加 export
,另一个 js 文件所需的函数等
- 尝试 1:每次在库外需要
whatever
时,/** @export */
没有变化。
- 尝试 2:所有
/** @export */ whatever
替换为 goog.exportSymbol('whatever', whatever)
编译成功(没有warning/error,还是ADVANCED_OPTIMIZATIONS级别)。
问题: 现在,对于相同的 HTML 文件,库中定义的所有 whatever
都被 "undefined" 看到浏览器。实际上,当我在控制台中键入 Object.keys( window )
时,我可以看到编译器更改了所有符号名称(aa
、ba
、ca
等)但是 none 我导出的符号 whatever
.
示例:demoVisitors
是库中定义的 const array
,外部需要。
之前在库文件中,我可以看到 ... w("demoVisitors",[Oa,La,Ma,Na]); ...
并且内容在 HTML 页面中正确可见。 es6 模块更改后,我可以看到尝试 1 的 ... H("demoVisitors$$module$filemane",Oa); ...
(filename
是定义 demoVisitors
的文件名)和尝试 2 的 H("demoVisitors",[Na,Ka,La,Ma]);
。demoVisitors
在同一页面的浏览器中未定义。
经过进一步调查,我找到了解决方案。
虽然在浏览器中加载时在控制台中没有任何错误(当然 undefined whatever
除外),但我的库没有执行。我只是将闭包库移动到要编译的文件堆栈之前,然后浏览器正确执行我的库,并正确导出我的符号。详情见下文。
导出符号的 3 种方式在已编译的 es6 模块中有效:/** @export */ whatever
、goog.exportSymbol('whatever', whatever)
、window['whatever'] = whatever
。第一个 2 是第三个的便捷方式(对于根符号)。
然而 /** @export */ myClass
生成了一个不友好的未混淆名称,如 myClass$$module$source-filename-with-path
。
为了获得未混淆的名称 myClass
,避免在我的代码中使用 goog
函数并巧妙地启用两种 compiled/uncompiled 模式,我删除了 /** @export */
并在 class myClass { ... }
。这是我的 "own" 函数,直接受到闭包库中定义的 exportSymbol
函数的启发。这仅对像 classes 这样的根符号是必需的,您可以为 class.
中定义的所有符号(属性、函数等)保留 /** @export */
这里是源代码:
export function unobfuscateSymbol(publicPath, object, objectToExportTo = window) {
// Same code can be used compiled and not compiled so unobfuscation only in case of obfuscation
if (unobfuscateSymbol.name !== 'unobfuscateSymbol') {
const /** Array<string> */ parts = publicPath.split('.');
let /** Object */ objToExportTo = objectToExportTo;
let /** string */ part;
const /** number */ nbOfParts = parts.length;
for (let /** number */ i = 0; i < nbOfParts; i += 1) {
part = parts[i];
if ((i === (nbOfParts - 1)) && object) {
objToExportTo[part] = object;
} else if (objectToExportTo[part] && objectToExportTo[part] !== Object.prototype[part]) {
objToExportTo = objectToExportTo[part];
} else {
objToExportTo[part] = {};
objToExportTo = objToExportTo[part];
}
}
}
}
我是如何详细确定问题的:
为了理解导出问题,我尝试在浏览器中加载我的 HTML 测试页面时在闭包库中定义的 exportSymbol 函数中放置一个断点:没有中断...
我通过添加 console.log("my library is being executed") 仔细检查了这个执行问题:我能够在 goog.require
/goog.provide
我的图书馆的版本,但不是 es6 import
/export
版本。没有执行,当然没有符号导出。
我用 IIFE 包装了我的库。 Closure compiler argument: --output_wrapper "(function(){%output%})()"
and an execution error message in my library 出现在浏览器控制台中。我发现 Closure 库的基本命名空间 goog.global
在休息时间是 undefined
。
我把闭包库移到了要编译的文件栈前面。关闭编译器参数:–js closure-lib-path/base.js –js myfile1.js –js myfile2.js …
以确保编译的 goog
内容在第一个 /** @export */
编译生成的第一个 exportSymbol
调用之前。
然后在浏览器中执行和导出就可以了。我刚刚添加了如上所述的 unobfuscateSymbol
函数以获得与我的库的 goog.require
/goog.provide
版本相同的友好导出名称。
起点: 许多js文件被Closure Compiler(ADVANCED_OPTIMIZATIONS级别)编译成功(没有warning/error)在一个单独的库文件中。
在这些 js 文件中:
goog.require
和goog.provide
习惯了import/export他们之间的事情/** @export */
前面用whatever
(const/function/Class/var)需要库外
一些 HTML 文件包括库和一些未编译的 js 成功访问所有 whatever
在这个库中定义。
我想要的:移动到 es6 模块语法
我对每个js文件做了什么:
goog.require
被import
替换为 Class 的列表,来自另一个 js 文件的函数goog.provide
删除并在每个 Class 前面添加export
,另一个 js 文件所需的函数等- 尝试 1:每次在库外需要
whatever
时,/** @export */
没有变化。 - 尝试 2:所有
/** @export */ whatever
替换为goog.exportSymbol('whatever', whatever)
编译成功(没有warning/error,还是ADVANCED_OPTIMIZATIONS级别)。
问题: 现在,对于相同的 HTML 文件,库中定义的所有 whatever
都被 "undefined" 看到浏览器。实际上,当我在控制台中键入 Object.keys( window )
时,我可以看到编译器更改了所有符号名称(aa
、ba
、ca
等)但是 none 我导出的符号 whatever
.
示例:demoVisitors
是库中定义的 const array
,外部需要。
之前在库文件中,我可以看到 ... w("demoVisitors",[Oa,La,Ma,Na]); ...
并且内容在 HTML 页面中正确可见。 es6 模块更改后,我可以看到尝试 1 的 ... H("demoVisitors$$module$filemane",Oa); ...
(filename
是定义 demoVisitors
的文件名)和尝试 2 的 H("demoVisitors",[Na,Ka,La,Ma]);
。demoVisitors
在同一页面的浏览器中未定义。
经过进一步调查,我找到了解决方案。
虽然在浏览器中加载时在控制台中没有任何错误(当然 undefined whatever
除外),但我的库没有执行。我只是将闭包库移动到要编译的文件堆栈之前,然后浏览器正确执行我的库,并正确导出我的符号。详情见下文。
导出符号的 3 种方式在已编译的 es6 模块中有效:/** @export */ whatever
、goog.exportSymbol('whatever', whatever)
、window['whatever'] = whatever
。第一个 2 是第三个的便捷方式(对于根符号)。
然而 /** @export */ myClass
生成了一个不友好的未混淆名称,如 myClass$$module$source-filename-with-path
。
为了获得未混淆的名称 myClass
,避免在我的代码中使用 goog
函数并巧妙地启用两种 compiled/uncompiled 模式,我删除了 /** @export */
并在 class myClass { ... }
。这是我的 "own" 函数,直接受到闭包库中定义的 exportSymbol
函数的启发。这仅对像 classes 这样的根符号是必需的,您可以为 class.
/** @export */
这里是源代码:
export function unobfuscateSymbol(publicPath, object, objectToExportTo = window) {
// Same code can be used compiled and not compiled so unobfuscation only in case of obfuscation
if (unobfuscateSymbol.name !== 'unobfuscateSymbol') {
const /** Array<string> */ parts = publicPath.split('.');
let /** Object */ objToExportTo = objectToExportTo;
let /** string */ part;
const /** number */ nbOfParts = parts.length;
for (let /** number */ i = 0; i < nbOfParts; i += 1) {
part = parts[i];
if ((i === (nbOfParts - 1)) && object) {
objToExportTo[part] = object;
} else if (objectToExportTo[part] && objectToExportTo[part] !== Object.prototype[part]) {
objToExportTo = objectToExportTo[part];
} else {
objToExportTo[part] = {};
objToExportTo = objToExportTo[part];
}
}
}
}
我是如何详细确定问题的:
为了理解导出问题,我尝试在浏览器中加载我的 HTML 测试页面时在闭包库中定义的 exportSymbol 函数中放置一个断点:没有中断...
我通过添加 console.log("my library is being executed") 仔细检查了这个执行问题:我能够在
goog.require
/goog.provide
我的图书馆的版本,但不是 es6import
/export
版本。没有执行,当然没有符号导出。我用 IIFE 包装了我的库。 Closure compiler argument:
--output_wrapper "(function(){%output%})()"
and an execution error message in my library 出现在浏览器控制台中。我发现 Closure 库的基本命名空间goog.global
在休息时间是undefined
。我把闭包库移到了要编译的文件栈前面。关闭编译器参数:
–js closure-lib-path/base.js –js myfile1.js –js myfile2.js …
以确保编译的goog
内容在第一个/** @export */
编译生成的第一个exportSymbol
调用之前。然后在浏览器中执行和导出就可以了。我刚刚添加了如上所述的
unobfuscateSymbol
函数以获得与我的库的goog.require
/goog.provide
版本相同的友好导出名称。