命名空间在运行时加载的顺序与用户代码中指定命名空间要求顺序无关。这似乎影响所有优化级别。这意味着开发者不能依赖当依赖它的命名空间加载之前,某个命名空间中有副作用的代码被运行。
复现步骤
运行命令
clj --main cljs.main --compile-opts '{:target :nodejs :main a}' --compile a
将编译由={{a.cljs}}定义的{{a}}命名空间。该命名空间通过{{ns}}宏的{{: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}}中反映的顺序相同
{{e}}的内容
{{c}}的内容
{{g}}的内容
{{b}}的内容
{{d}}的内容
{{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`作为映射传递,所以可能需要更多的工作才能找到完整的解决方案。