请在2024 Clojure状态调查中分享您的想法!

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

0
ClojureScript
我在这里有一个小型(非最小化)的仓库:[https://github.com/au-phiware/boot-parsets](https://github.com/au-phiware/boot-parsets)

该仓库包含一个es6模块和一个cljs文件,它们都依赖于一个node模块,导致以下错误。


正在写入main.cljs.edn...
编译ClojureScript...
• main.js
                                       java.lang.Thread.run                  Thread.java:  748
         java.util.concurrent.ThreadPoolExecutor$Worker.run      ThreadPoolExecutor.java:  617
          java.util.concurrent.ThreadPoolExecutor.runWorker      ThreadPoolExecutor.java: 1142
                        java.util.concurrent.FutureTask.run              FutureTask.java:  266
                                          ...                                   
                        clojure.core/binding-conveyor-fn/fn                     core.clj: 2022
                        adzerk.boot-cljs/compile-1/fn               boot_cljs.clj:  160
                        adzerk.boot-cljs/compile                boot_cljs.clj:  72
                                          boot.pod/call-in*                      pod.clj:  413
                                          ...                                   
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke  ClojureRuntimeShimImpl.java:  102
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke  ClojureRuntimeShimImpl.java:  109
                                          ...                                   
                                          boot.pod/call-in*                      pod.clj:  410
                                      boot.pod/eval-fn-call                      pod.clj:  359
                                         clojure.core/apply                     core.clj:  657
                                          ...                                   
                       adzerk.boot-cljs.impl/compile-cljs                     impl.clj:  151
                                      cljs.build.api/build                     api.clj:  205
                                      cljs.closure/build                  closure.clj: 2595
                            cljs.closure/handle-js-modules                  closure.clj: 2496
                            cljs.closure/process-js-modules                  closure.clj: 2389
                            cljs.closure/convert-js-modules                  closure.clj: 1680
                com.google.javascript.jscomp.Compiler.parse                Compiler.java:  995
          com.google.javascript.jscomp.Compiler.parseInputs                Compiler.java: 1731
      com.google.javascript.jscomp.deps.ModuleLoader.<init>            ModuleLoader.java:   92
com.google.javascript.jscomp.deps.ModuleLoader.resolvePaths            ModuleLoader.java:  276
java.lang.IllegalArgumentException: 解析后重复的模块路径:/home/corin/Projects/Demos/boot-parsets/node_modules/d3/d3.js
        clojure.lang.ExceptionInfo: 解析后重复的模块路径:/home/corin/Projects/Demos/boot-parsets/node_modules/d3/d3.js
    来自: :boot-cljs
        clojure.lang.ExceptionInfo: 解析后重复的模块路径:/home/corin/Projects/Demos/boot-parsets/node_modules/d3/d3.js
    行: 33


运行 `boot cljs` 重新生产问题。

此次补丁在预处理源文件集合之前移除了重复项。使用此补丁,仓库可正确编译。

13 个回答

0
by

评论由:mfikes 发布

嗨 Corin,

  1. 你是否已签署 CA?(你的名字没有出现在https://clojure.org/community/contributors
  2. 你能提供不使用下游工具的最小复现示例?(错误提交详细信息请参阅https://script.clojure.org/community/reporting-issues
0

评论由:phiware所做

  1. 我已经签署了CA(我在提交这个bug之后才做的)。
  2. 这不是问题,我会在今天稍后处理这个问题。可以在GitHub上链接项目,或者我应该上传一个tarball吗?
0

评论由:mfikes 发布

嗨Corin,不能链接到GitHub,任何重现问题都不应该使用任何下游工具(Leiningen、Boot等)——这意味着重现应该理想地仅依赖于随附的{{cljs.jar}}可执行文件,就像快速入门中的示例https://script.clojure.org/guides/quick-start

0

评论由:mfikes 发布

Hey Corin,你可能想要按照https://script.clojure.org/community/patches中的说明提交补丁(你当前的补丁使用{{git am}}无法应用,这可能是David最终使用的)。

0
_评论由:mfikes所做_

在应用{{patch}}时{{lein test}}失败了


在》(commonjs-module-processing)失败(module_processing_tests.clj:54)
处理的模块被添加到:libs
期望: (= {:foreign-libs [], :ups-foreign-libs [], :libs [(test/platform-path "out/src/test/cljs/reactJS.js") (test/platform-path "out/src/test/cljs/Circle.js")], :closure-warnings {:non-standard-jsdoc :off}} (env/with-compiler-env cenv (closure/process-js-modules {:foreign-libs [{:file "src/test/cljs/reactJS.js", :provides ["React"], :module-type :commonjs} {:file "src/test/cljs/Circle.js", :provides ["Circle"], :module-type :commonjs, :preprocess :jsx}], :closure-warnings {:non-standard-jsdoc :off}})))
  实际:(not (= {:foreign-libs [], :ups-foreign-libs [], :libs ["out/src/test/cljs/reactJS.js" "out/src/test/cljs/Circle.js"], :closure-warnings {:non-standard-jsdoc :off}} {:foreign-libs [], :closure-warnings {:non-standard-jsdoc :off}, :libs ["out/src/test/cljs/Circle.js" "out/src/test/cljs/reactJS.js"], :ups-foreign-libs []}))
0

评论由:phiware所做

谢谢Mike,

我将努力遵循所有那些说明,但我不知道我应该如何提供重现(没有链接,没有附件)...应该使用内联代码块吗?

另外,我会在提交下一个补丁之前确保运行 {{lein test}}。我注意到差异仅仅是 {{:libs}} 向量中项的顺序,你能建议一下顺序是否重要吗?

0

评论由:mfikes 发布

嗨 Corin,

是的,内联代码块非常好。任何只有 {{cljs.jar}} 就能体现问题的最小化代码(无论是直接在你的 REPL 中,还是通过构建 API 编译)。这里有一个使用构建 API 的近期示例:https://dev.clojure.org/jira/browse/CLJS-2397?focusedCommentId=47278&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-47278

除了 {{lein test}} 以外,其实还有其他一些测试。请参阅 https://script.clojure.org/community/running-tests

我还没有查看这个问题的详细信息,所以不能说明项的顺序是否重要。

0
评论者:phiware_

h2. 重复问题的步骤。

考虑以下三个源文件

{code:title=src/distinct_inputs/core.cljs}
(ns distinct-inputs.core
  (:require [d3]
              [circle :refer [circle]]))

(-> d3
    (.select "body")
    (.append "svg")
    (.attr "width" 200)
    (.attr "height" 200)
    (.call circle "steelblue"))


{code:title=es6/circle.js}
import * as d3 from 'd3';

export function circle(sel, color) {
  return sel
    .append("circle")
    .attr("cx", "100px")
    .attr("cy", "100px")
    .attr("r",  "100px")
    .attr("fill", color);
}


{code:title=build.clj}
(require 'cljs.build.api')

(cljs.build.api/build
  "src"
  {:main 'distinct-inputs.core
   :output-to "out/main.js"
   :install-deps true
   :foreign-libs [{:file "es6"
                   :module-type :es6}]
   :npm-deps     {:d3 "3.5.16"}})


执行 {{cljs}}

{code:none}
java -cp cljs.jar:src clojure.main build.clj


h2. 预期结果

{{cljs}} 应该没有向标准输出产生任何内容,干净退出并生成以下文件(大约)。

{code:title=out/main.js}
var CLOSURE_UNCOMPILED_DEFINES = {};
var CLOSURE_NO_DEPS = true;
if(typeof goog == "undefined") document.write('<script src="out/goog/base.js"></script>');
document.write('<script src="out/goog/deps.js"></script>');
document.write('<script src="out/cljs_deps.js"></script>');
document.write('<script>if (typeof goog == "undefined") console.warn("ClojureScript could not load :main, did you forget to specify :asset-path?");</script>');
document.write('<script>goog.require("process.env");</script>');
document.write('<script>goog.require("distinct_inputs.core");</script>');


{code:title=out/distinct_inputs/core.js}
goog.provide('distinct_inputs.core');
引入goog的核心库。
引入module$distinct_inputs$node_modules$d3$d3库。
引入module$distinct_inputs$es6$circle库。
module$distinct_inputs$node_modules$d3$d3.select("body").append("svg").attr("width",(200)).attr("height",(200)).call(module$distinct_inputs$es6$circle.circle,"steelblue");

跳转源映射文件路径:core.js.map


{code:title=out/es6/circle.js}
goog.provide("module$distinct_inputs$es6$circle");goog.require("module$distinct_inputs$node_modules$d3$d3");function circle$$module$distinct_inputs$es6$circle(sel,color){return sel.append("circle").attr("cx","100px").attr("cy","100px").attr("r","100px").attr("fill",color)}module$distinct_inputs$es6$circle.circle=circle$$module$distinct_inputs$es6$circle


2. 实际结果。

{{cljs}} 程序以退出码1退出,并产生以下标准输出。

{code:none|title=stdout}
在主线程中发生异常:java.lang IllegalArgumentException:解析后的重复模块路径:/distinct_inputs/node_modules/d3/d3.js,在编译时:(
    at clojure.lang.Compiler.load(Compiler.java:7391)
    at clojure.lang.Compiler.loadFile(Compiler.java:7317)
    at clojure.main$load_script.invokeStatic(main.clj:275)
    at clojure.main$script_opt.invokeStatic(main.clj:335)
    at clojure.main$script_opt.invoke(main.clj:330)
    at clojure.main$main.invokeStatic(main.clj:421)
    at clojure.main$main.doInvoke(main.clj:384)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:379)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
由以下案例引起:
    at com.google.javascript.jscomp.deps.ModuleLoader.resolvePaths(ModuleLoader.java:276)
    at com.google.javascript.jscomp.deps.ModuleLoader.<init>(ModuleLoader.java:92)
    at com.google.javascript.jscomp compilers.parseInputs(Compiler.java:1731)
    at com.google.javascript.jscomp compilers.parse(Compiler.java:995)
    at cljs c closure$convert_js_modules.invokeStatic(closure.clj:1680)
    at cljs c closure$process_js_modules.invokeStatic(closure.clj:2371)
    at cljs c closure$handle_js_modules.invokeStatic(closure.clj:2495)
    at cljs c closure$build.invokeStatic(closure.clj:2592)
    at cljs build.api$build.invokeStatic(api.clj:204)
    at cljs build.api$build.invoke(api.clj:189)
    at cljs build.api$build.invokeStatic(api.clj:192)
    at cljs build.api$build.invoke(api.clj:189)
    at user$eval24.invokeStatic(build.clj:3)
    at user$eval24.invoke(build.clj:3)
    at clojure.lang.Compiler.eval(Compiler.java:6927)
    at clojure.lang.Compiler.load(Compiler.java:7379)
    ... 11 more


没有生成上述任何预期文件。

异常的原因。

由{{ModuleLoader#resolvePaths}}引发的异常是因为相同的输入文件(即{{node_modules/d3/d3.js}})被多次指定给{{Compiler#initModules}}。在{{Compiler#getAllInputsFromModules}}中有如下注释:

{code:title=src/com/google/javascript/jscomp/Compiler.java}
        // 注释(nicksantos):如果输入存在于多个模块中,
        ,// 它将在输入列表中出现两次,然后我们
        // 将在后续过程中得到错误。


{{cljs c closure/process-js-modules}}提供了一个{{:foreign-libs}}向量,其中包含{{node_modules/d3/d3.js}}的重复条目(以及它的{{package.json}})。该向量是{{cljs c closure/node-inputs}}多次调用的结果;一次是为{{out/cljs$node_modules.js}}(这可能是{{distinct_inputs/core}}中的依赖项的结果)而进行的,另外一次是为{{es6/circle.js}}而进行的。

简而言之,D3的依赖关系通过ClojureScript源文件和JavaScript模块源文件同时被拉入。

2. 建议的解决方案。

在这种情况下,尽管在{{cljs c closure/node-inputs}}中使用了{{distinct}},但{{:foreign-libs}}向量中仍然包含重复的条目。一个可能的解决方案是不在{{cljs c closure/node-inputs}}中使用{{distinct}},并要求调用{{cljs c closure/node-inputs}}的人使用{{distinct}}。

{code:title=解决方案A}
从063e35080c14d35189ab7827f25f071e958ab5b4 Mon Sep 17 00:00:00 2001
来自:Corin Lawson <[email protected]>
日期:星期二,2017年11月21日 01:31:53 +1100
主题:[补丁] CLJS-2402:确保 :foreign-libs 向量包含独立的条目。
 

---
 src/main/clojure/cljs/closure.clj | 19 ++++++++++---------
 1 文件更改,增加 10 行,减少 9 行

diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj
 index a686f878..74a0cc86 100644
 --- a/src/main/clojure/cljs/closure.clj
 +++ b/src/main/clojure/cljs/closure.clj
@@ -2219,7 +2219,7 @@
      (when env/*compiler*
        (:options @env/*compiler*))))
   ([entries opts]
-         (into [] (distinct (mapcat #(node-module-deps % opts) entries)))))
+         (into [] (mapcat #(node-module-deps % opts) entries))))
 
 (defn index-node-modules
   ([modules]
@@ -2480,14 +2480,15 @@
        output-dir (util/output-directory opts)
        opts (update opts :foreign-libs
                (fn [libs]
-                 (into (if (= target :nodejs)
-                         []
-                         (index-node-modules node-required))
-                   (into expanded-libs
-                           (node-inputs (filter (fn [{:keys [module-type]}]
-                                            (and (some? module-type)
-                                                       not= module-type :amd)))
-                                    expanded-libs))))))
+                 (distinct
+                   (into (if (= target :nodejs)
+                         []
+                         (index-node-modules node-required))
+                         (into expanded-libs
+                               (node-inputs (filter (fn [{:keys [module-type]}]
+                                                    and (some? module-type)
+                                                              (not= module-type :amd)))
+                                    expanded-libs)))))))
         opts (if (some
                      (fn [ijs]
                      (let [dest (io/file output-dir (rel-output-path (assoc ijs :foreign true) opts))]
--
2.13.0



一个更通用的解决方案是 {{cljs.closure/process-js-modules}} 必须确保输入文件集(即 {{js-modules}})是唯一的。这个补丁会更简单(例如,不会干扰我不理解的代码)并且更接近对 Google Closure Compiler 的调用。

{code:title=解决方案 B}
From 6bf11a24b93642e118e6d29c5af8a137fa01ea94 Mon Sep 17 00:00:00 2001
来自:Corin Lawson <[email protected]>
Date: Sun, 19 Nov 2017 20:25:31 +1100
Subject: [PATCH] CLJS-2402: Ensure input source files are distinct.

---
 src/main/clojure/cljs/closure.clj | 3 ++-
 修改了1个文件,插入2个(+),删除1个(-)

diff --git a/src/main/clojure/cljs/closure.clj b/src/main/clojure/cljs/closure.clj
index a686f878..24421bde 100644
 --- a/src/main/clojure/cljs/closure.clj
 +++ b/src/main/clojure/cljs/closure.clj
@@ -2364,7 +2364,8 @@
   (从:foreign-libs(编译器选项)和:ups-foreign-libs(deps.cljs)模块中
         共同处理,以便两个来源的文件可以彼此依赖。
         例如,commonjs模块在:foreign-libs可以依赖于:ups-foreign-libs中的commonjs模块。
-        js-modules(filter :module-type (concat (:foreign-libs opts) (:ups-foreign-libs opts)))
+        js-modules(filter :module-type(concat (:foreign-libs opts) (:ups-foreign-libs opts)))
+        js-modules(distinct js-modules)
     (if (seq js-modules)
       (util/measure (:compiler-stats opts)
         "处理JS模块"
--
2.13.0



FWIW:我更喜欢解决方案B。
0

评论由:phiware所做

附加了提出的解决方案B

0

评论由:phiware所做

嗨,Mike,

我希望这能满足你(以及BDFL)的要求;我为这两个提议的解决方案都运行了{{lein test}},我没有收到任何失败的报告。然而,我确实收到了一些错误,这些错误不会在断言中出现。我假设原因是我的设置中有什么奇怪(或缺乏)的东西。如果你还需要我做什么,请告诉我。

祝好,
Corin。

0

评论由:mfikes 发布

谢谢Corin。使用你最新的补丁,整个测试套件对我都通过了。

0

评论由:mfikes 发布

在补丁寄售中添加了CLJS-2402.patch(i)

0
参考: https://clojure.atlassian.net/browse/CLJS-2402 (由phiware报告)
...