Foo.bar;
如果你要针对传统的 JavaScript 客户端(网页浏览器),那么从一开始就需要考虑高级编译。否则你必然会遇到一些问题,而这些问题本来可以通过一些提前的准备轻松避免。一般来说,不要等到尝试高级构建时才开始,你应该定期生成生产构建,以便尽早发现问题。
最好是简单地避免使用外部库,只要在 Google Closure 库或现有的 ClojureScript 库中存在解决方案即可。外部库必须提供 externs,以便高级编译能够始终如一地工作。
当然,在某些情况下,无法避免使用外部库。
如果你必须使用外部库,请使用经过整理的库,例如 CLJSJS 提供的库。这些库打包了 externs,因此你无需自己提供。
偶尔,你可能会发现自己需要一个没有预先打包的外部库。
当使用一个没有提供 externs 的外部库时,请花时间为你要使用的 API 编写 externs 文件。externs 文件非常容易编写。例如,如果外部库有一个名为 Foo.bar
的属性,你希望访问该属性,那么你的 externs 文件应该包含以下条目
Foo.bar;
如果外部库有一个名为 Foo.baz
的方法,你希望调用该方法,那么你的 externs 文件应该包含以下条目
Foo.baz = function() {};
有时,不会有顶级的 API,而会有一些方法命名约定,即一个临时接口/协议。在这种情况下,使用 Object 定义你的 externs
Object.foo = function() {}; Object.bar = function() {};
当然,有时你可能会错过一个 externs 条目,而生产文件会生成一个难以理解的错误。由于 Closure 编译器的一些选项,这些问题现在不再难于调试。
如果你想从 JavaScript 访问 ClojureScript 代码,那么你需要处理这样一个事实,即高级编译会混淆 Var 名字的 JavaScript 表示形式。这可以通过在应该从 JavaScript 访问的 Var 上添加 :export
元数据来轻松解决。
例如,如果你有一个 square
函数,你可以用 ^:export
注释它,如下所示
(ns my-math.core)
(defn ^:export square [x]
(* x x))
这样,你就可以从 JavaScript 中调用你的 square
函数,如下所示
my_math.core.square(3);
这是通过在生成的 JavaScript 中包含 goog.exportSymbol
调用来实现的,无论是在哪里,:export
元数据都与 Var 相关联。
对于每个导出的 Var,都会建立一个额外的未重命名的别名,它指向 Closure 混淆的名称。混淆的名称在优化的代码中继续被内部使用。
|
你可以单独导出与协议方法关联的 Var。在本例中,bar
和 quux
将被导出
(defprotocol IFoo
(^:export bar [this])
(baz [this x])
(^:export quux [this x y]))
将你的生产构建改为使用两个额外的选项 :pseudo-names true
和 :pretty-print true
。现在你的错误将显示一个与原始源代码中的名称相对应的名称。为这个遗漏的用例添加一个 externs 条目。
有关 :foreign-libs
编译器选项语法的更多信息,请参见 依赖项。