命名空间在运行时加载的顺序与用户代码中命名空间的require顺序无关。这似乎影响所有优化级别。这意味着开发者不能依靠给定命名空间中的副作用代码在依赖于副作用的另一个命名空间加载之前执行。
重现步骤
运行以下命令
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 elementary../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`作为映射传递,所以可能需要进行更多的工作以得到完整的解决方案。