运行时命名空间加载的顺序与用户代码中命名空间被require的顺序无关。这似乎影响了所有优化级别。这意味着开发者不能依赖于在特定命名空间中的副作用代码在依赖该副作用的另一个命名空间加载之前执行。
复现步骤
运行以下命令
clj --main cljs.main --compile-opts '{:target :nodejs :main a}' --compile a
将编译在{{a.cljs}}中定义的{{a}}命名空间。该命名空间通过在ns宏的{{:require}}形式中按字母顺序require命名空间{{b}}到{{g}}。
编译后,观察以下内容
在输出文件{{out/cljs_deps.js}}中,对于{{a.js}}的{{goog.addDependency}}调用包含其依赖项的任意顺序。例如,在我的机器上的一次运行结果是:
goog.addDependency("../../../a.js", ['a'], ['cljs.core', 'e', 'c', 'g', 'b', 'd', 'f']);
运行编译后的代码并使用{{node out/main.js}}提供的控制台输出表明运行时加载顺序与在{{out/cljs_deps.js}}中反映的顺序相同
body of e
body of c
body of g
body of b
body of d
body of f
分析
看起来确保编译时顺序的工作是作为[CLJS-1453](
https://dev.clojure.org/jira/browse/CLJS-1453)的一部分进行的,但似乎在{{cljs_deps.js}}发出之前,顺序可能会弄乱。
似乎特定ClojureScript文件的{{ cljs_deps.js}}输出最终由{{ cljs.compiler/emit-source }}的输出决定。那里的代码以与CLJS-1453之前{{ cljs.analyzer }}中'ns'解析方法相同的方式去除重复的依赖项。
附加的补丁解决了我的狭窄用例的问题,但我认为基础的函数正在以映射的形式传递`:uses`和`:requires`,所以可能还需要更多的工作来实现完整的解决方案。