请分享您的看法 2024 Clojure状态调查!

欢迎!有关如何使用本站,请参阅关于页面以获取更多信息。

+1
ClojureScript
命名空间在运行时加载的顺序与用户代码中命名空间被{{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`作为映射传递,因此可能需要对完整的解决方案进行更多工作。

11 个答案

0
by

评论者:chancerussell

抱歉在我的工单中添加了Markdown——我曾认为我在提交后会清理这些内容。

0
by

评论者:mfikes

CLJS-3056.patch通过了CI和Canary测试(/)

0
by

评论者:thheller

附带的补丁仍然使用{{deps}}映射,该映射只会在达到数组映射阈值之前保持插入顺序,一旦开始使用哈希映射,就不再有序。在shadow-cljs中,我通过除了通常的{{:requires}}映射外还维护一个附加的{{:deps}}向量来处理这个问题。

0
by
_评论者:chancerussell_

这可能是最好的解决方案——我不想尝试修改现有代码中映射的类型。

我今晚会看看这个——修补程序CLJS-1453可能存在相同的问题。

话虽如此,当ns形式同时包含:require和:use时,我对排序的语义感到好奇?
0
by

评论者:thheller

啊,看起来分析器中已经维护了一个{{:deps}}向量,'ns和'ns**。只需在cljs.compiler/emit-source函数中使用它,而不是使用requires/uses映射的值。

0
by

评论者:chancerussell

托马斯是对的,{{:deps}}向量确实存在,并且按预期排序,所以我提交了一个新的补丁使用它。

有一个问题——当两者都存在时,{{cljs.core}} 和 {{cljs.core.constants}} 的顺序应该是什么?显然,之前的代码没有保证顺序,但我想把它弄对。

(测试 test-cljs-1882-constants-table-is-sorted 似乎表明 cljs.core 应该放在前面。)

0

评论者:mfikes

2019年3月24日下午12:58的CLJS-3056.patch 通过了CI和Canary条件测试(/)

0

由dnolen发表的评论

必须将{{cljs.core}}放在{{cljs.core.constants}}之前,因为如果没有定义关键字结构,{{cljs.core.constants}}就不会工作。否则,我们肯定会听到许多关于高级构建失败的投诉。

0

评论者:chancerussell

David,当您说“顺序绝对有保证”,您是指的只是{{cljs.core}}和{{cljs.core.constants}},还是指整个依赖关系?当前的代码是将元素添加到集合中,但据我所知,这并不一定能保持任何顺序。

0

评论者:mfikes

我被冤枉了:CLJS-3056.patch 在Windows CI测试中失败(x)

特别是,它导致{{cljs-2077-test-loader}}堆栈溢出

ERROR in (cljs-2077-test-loader) (core.clj:6077) 397未在断言中捕获到的异常。 398预期:nil 399实际:java.lang.StackOverflowError: null 400 用于 clojure.core$get_in.invokeStatic (core.clj:6077) 401 cljs.module_graph$deps_for.invokeStatic (module_graph.cljc:147) 402 cljs.module_graph$deps_for.invoke (module_graph.cljc:147) 403 clojure.lang.AFn.applyToHelper (AFn.java:160) 404 clojure.lang.AFn.applyTo (AFn.java:144) 405 clojure.core$apply.invokeStatic (core.clj:657) 406 clojure.core$memoize$fn__6665.doInvoke (core.clj:6288) 407 clojure.lang.RestFn.invoke (RestFn.java:436) 408 cljs.module_graph$deps_for$fn__7089.invoke (module_graph.cljc:151) 409 clojure.core$map$fn__5665.invoke (core.clj:2745) 410 clojure.lang.LazySeq.sval (LazySeq.java:40) 411 clojure.lang.LazySeq.seq (LazySeq.java:49) 412 clojure.lang.RT.seq (RT.java:528) 413 clojure.core$seq__5202.invokeStatic (core.clj:137) 414 clojure.core$apply.invokeStatic (core.clj:652) 415 clojure.core$mapcat.invokeStatic (core.clj:2775) 416 cljs.module_graph$deps_for.invokeStatic (module_graph.cljc:147) 417 cljs.module_graph$deps_for.invoke (module_graph.cljc:147) 418 clojure.lang.AFn.applyToHelper (AFn.java:160) 419 clojure.lang.AFn.applyTo (AFn.java:144) 420 clojure.core$apply.invokeStatic (core.clj:657)

CI构建:https://ci.appveyor.com/project/mfikes/clojurescript/builds/24478525

0
by
参考: https://clojure.atlassian.net/browse/CLJS-3056(由chancerussell报告)
...