Clojure 2024 调查问卷 中分享您的想法!

欢迎!请参阅 关于 页面以了解更多关于这是如何工作的信息。

+1 投票
ClojureScript
名称空间在运行时加载的顺序与用户代码中名称空间要求(require)的顺序无关。这似乎影响所有优化级别。这意味着开发者不能依赖于给定名称空间中的副作用代码在依赖该副作用的另一个名称空间加载之前运行。

重现步骤

运行以下命令


clj --main cljs.main --compile-opts '{:target :nodejs :main a}' --compile a


将编译定义在 a.cljs 中的 a 名称空间。通过 ns 宏的 :require 表达式,该名称空间按照字母顺序要求名称空间 bg

编译后观察以下内容

* 在输出文件 out/cljs_deps.js 中,对于 a.jsgoog.addDependency 调用包括其在任意顺序中的依赖项。例如,在我机器上的一次运行产生了以下结果:


goog.addDependency("../a.js", ['a'], ['cljs.core', 'e', 'c', 'g', 'b', 'd', 'f']);


* 通过运行编译代码并将 node out/main.js 运行编译后的代码,给出的控制台输出指示运行时加载顺序与 out/cljs_deps.js 中反映的顺序相同


body of e

body of c

body of g

body of b

body of d

body of 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

为对工单的Markdown格式造成混乱表示歉意——我以为提交后会将其清理干净。

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映射的vals值。

0 投票

评论由:chancerussell

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

一个问题——当{{cljs.core}}和{{cljs.core.constants}}都存在时,它们的排序应该如何?很明显,前一段代码的排序是不确定的,但我想确保这一点。

(测试test-cljs-1882-constants-table-is-sorted似乎表明cljs.core应该排在第一位。)

0 投票

评论由:mfikes

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

0 投票

评论人:dnolen

{{cljs.core}}必须在{{cljs.core.constants}}之前,因为如果不定义关键字结构,{{cljs.core.constants}}将无法工作。否则,我们肯定会听到很多关于高级构建失败的抱怨,从而确保排序是正确的。

0 投票

评论由:chancerussell

David,当你说“排序肯定是有保证的”,你是指{{cljs.core}}和{{cljs.core.constants}},还是整个依赖?当前的代码是在集合上使用{{conj}},这不一定能保持任何顺序,据我所知。

0 投票

评论由:mfikes

哦,我弄错了:CLJS-3056.patch在Windows CI上失败(×)

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

ERROR在(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报告)
...