在< Entrance�https://www.surveymonkey.com/r/clojure2024中分享您的想法!

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

+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 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`作为映射传递,所以可能需要进行更多的工作以得到完整的解决方案。

11个答案

0

评论者:chancerussell

抱歉用无格式文本弄乱了票据——原以为提交后可以清理。

0

评论者:mfikes

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

0

评论者:thheller

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

0
_评论者:chancerussell_

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

我将今晚查看这个问题——看起来 CLJS-1453 的补丁可能也存在相同的问题。

话虽如此,我想知道当 ns 形式同时包含 :require 和 :use 时,排序列的语义应该是什么?
0

评论者:thheller

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

0

评论者:chancerussell

托马斯是对的,{{:deps}}向量存在且符合预期顺序,因此我已经提交了一个新补丁,使用了这个向量。

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

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

0
by

评论者:mfikes

CLJS-3056.patch在2019年3月24日中午12:58通过CI和 Canary (/)

0
by

评论者:dnolen

{{cljs.core}}必须在{{cljs.core.constants}}之前,因为没有关键字构造定义,{{cljs.core.constants}}不会工作。如果没有保证这种顺序,我们肯定会听到很多失败的高级构建的投诉。

0
by

评论者:chancerussell

大卫,当你说“顺序肯定得到保证”时,你是指{{cljs.core}}和{{cljs.core.constants}},还是整个依赖项?目前的代码是{{conj}}ing到集合中,据我所知,这并不保证维护任何顺序。

0
by

评论者: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
参考:https://clojure.atlassian.net/browse/CLJS-3056(由 chancerussell 报告)
...