命名空间在运行时加载的顺序与用户代码中命名空间被{{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("\/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文件,{{cls_deps.js}}的输出最终由{{cljs.compiler/emit-source}}的输出确定。那里的代码通过类似于在CLJS-1453之前在{{cljs.analyzer}}的{{'ns}}解析方法中执行的方式来去除重复的依赖项。
附带的补丁解决了我的特定用例的问题,但我认为底层函数正在将`:uses`和`:requires`作为映射传递,因此可能需要对完整的解决方案进行更多工作。