ClojureScript

共享 AOT 缓存

2018 年 3 月 28 日
Mike Fikes

当您编译 ClojureScript 代码时,会生成几个工件,包括 JavaScript、分析元数据和源映射。这些文件会在本地缓存,位于输出子目录(通常为“out”或“target”)。

由于这些工件的生成成本很高,因此将它们包含在发布的库 JAR 文件中很诱人。但是,这些工件会根据使用的编译器版本以及生效的构建影响编译器选项(例如 :target:elide-asserts:static-fns)而有所不同,因此这种方法不可行。

ClojureScript 中的一项新功能可以有效地解决这个问题:启用后,从 JAR 文件生成的编译工件将放置在共享缓存中。这意味着您可以编译 core.async 0.4.474 一次

共享缓存可以在您计算机上的不同 ClojureScript 项目之间重复使用。如果您在项目中执行“清理”并从头开始构建,它也可以用作源来填充您的输出目录。这可以大幅减少构建时间,因为您只编译了项目本身的源代码。

由于 ClojureScript 本身通常是 JAR 依赖项,因此共享 AOT 缓存机制(以典型的 Lisp 元循环方式)适用于 ClojureScript 本身,缓存为 cljs.core 和 ClojureScript 附带的其他命名空间生成的工件。

这使 cljs.main 的一项新功能成为可能:对于某些用例,例如仅使用它来运行脚本、使用 -e 评估表单或仅启动 REPL,cljs.main 将使用临时输出目录,而不是通过创建您运行 cljs.main 的位置的“out”目录来弄乱文件系统。能够使用 AOT cljs.core 使此用例既高效又便捷。

AOT 缓存逻辑足够智能,可以处理不同的编译器版本、构建影响选项和 JAR 名称,并使用这些信息将工件变体分别存储在缓存中。而且,虽然 AOT 缓存功能的动机是发布的 JAR 文件中的代码是不可变的,但它认识到这在快照 JAR 文件或本地部署的 JAR 文件修订版的情况下并不成立。在这些情况下,JAR 文件时间戳的更改将使缓存失效。

AOT 缓存逻辑无法处理发布的 JAR 文件使用宏的情况,这些宏会咨询周围环境以影响为这些 JAR 文件中发布的源代码生成的代码。

一个例子可能是使用宏来使编译后的代码反映配置,就像您在 Figwheel 或 Dirac 中使用 :external-config 时一样。

在这些情况下,建议库和工具使用 goog.define,也许可以使用 :closure-defines,因为这使 JAR 文件成为缓存友好型。

默认情况下,此功能处于禁用状态,除非 ClojureScript 是通过 cljs.main 使用的。您可以通过显式使用新的 :aot-cache 编译器选项来覆盖默认值。

由于此策略不依赖于 AOT 工件包含在发布的 JARS 中,因此它应该适用于 Git Deps。这可能将在 ClojureScript 的未来版本中实现。

我们鼓励您试用此功能。我们希望此功能是您最终甚至不会考虑的功能,并且它只是进一步帮助您进行日常开发!