请在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

由 mfikes 发表的评论

嗨,Corin,

  1. 你已经签署了CA吗?(你的名字没有出现在https://clojure.org/community/contributors上)
  2. 你能提供一个不使用下游工具的最小复制示例吗?(错误报告详情请参阅https://script.clojure.org/community/reporting-issues
0

评论者:phiware

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

由 mfikes 发表的评论

嗨Corin,链接到GitHub是不行的,任何重现都不能使用任何下游工具(Leiningen、Boot等)——这意味着重现理想情况下应该只依赖于派送的{{cljs.jar}},如快速入门中的示例https://script.clojure.org/guides/quick-start

0

由 mfikes 发表的评论

嘿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,

是的,内联代码块非常好。任何不需要依赖其他东西(无论是直接在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.require('cljs.core');
需要导入模块'module$distinct_inputs$node_modules$d3$d3';
需要导入模块'module$distinct_inputs$es6$circle';
模块'module$distinct_inputs$node_modules$d3$d3'选择"body",追加"svg"元素,设置其"width"和"height"属性,并调用'module$distinct_inputs$es6$circle.circle'函数,颜色为"steelblue";

sourceMappingURL=core.js.map


{code:title=out/es6/circle.js}
提供模块'module$distinct_inputs$es6$circle'。需要'module$distinct_inputs$node_modules$d3$d3'模块定义circle函数,它返回一个circle元素,位置在(100px, 100px),半径为100px,填充颜色为color参数指定的颜色,此函数被赋值给'module$distinct_inputs$es6$circle.circle';


2. 实际结果。

{{cljs}} 终止时返回退出码1,并产生以下标准输出。

{code:none|title=stdout}
主线程中抛出异常java.lang.IllegalArgumentException: 解析模块路径后重复:/distinct_inputs/node_modules/d3/d3.js,编译:(file:/distinct_inputs/build.clj:3:1)
    在clojure.lang.Compiler.load中
    在clojure.lang.Compiler.loadFile中
    在clojure.main$load_script.invokeStatic中
    在clojure.main$script_opt.invokeStatic中
    在clojure.main$script_opt.invoke中
    在clojure.main$main.invokeStatic中
    在clojure.main$main.doInvoke中
    在clojure.lang.RestFn.invoke中
    在clojure.lang.Var.invoke中
    在clojure.lang.AFn.applyToHelper中
    在clojure.lang.Var.applyTo中
    在clojure.main.main中
由以下原因引起:java.lang.IllegalArgumentException: 解析模块路径后重复:/distinct_inputs/node_modules/d3/d3.js
    在com.google.javascript.jscomp.deps.ModuleLoader.resolvePaths中
    在com.google.javascript.jscomp.deps.ModuleLoader.<init>中
    在com.google.javascript.jscomp.Compiler.parseInputs中
    在com.google.javascript.jscomp.Compiler.parse中
    在cljs.closure$convert_js_modules.invokeStatic中
    在cljs.closure$process_js_modules.invokeStatic中
    在cljs.closure$handle_js_modules.invokeStatic中
    在cljs.closure$build.invokeStatic中
    在cljs.build.api$build.invokeStatic中
    在cljs.build.api$build.invoke中
    在cljs.build.api$build.invokeStatic中
    在cljs.build.api$build.invoke中
    在user$eval24.invokeStatic中
    在user$eval24.invoke中
    在clojure.lang.Compiler.eval中
    在clojure.lang.Compiler.load中
    更多...


没有生成任何预期的文件。

2. 异常原因。

{{ModuleLoader#resolvePaths}}抛出的异常是由于相同的输入文件(即{{node_modules/d3/d3.js}})被指定多次给{{Compiler#initModules}}。在{{Compiler#getAllInputsFromModules}}中有一个注释

{code:title=src/com/google/javascript/jscomp/Compiler.java}
        // NOTE(nicksantos): 如果一个输入属于多个模块,
        // 它会在输入列表中两次出现,然后我们
        // 会在后续步骤中得到错误。


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

简而言之,D3的依赖同时被ClojureScript源文件和JavaScript模块源文件引入。

2. 建议的解决方案。

在此情况下,即使在没有使用{{distinct}}的情况下,{{:foreign-libs}}向量中仍然包含重复的条目。一种可能的解决方案是移除在{{cljs.closure/node-inputs}}中使用{{distinct}},并要求调用{{cljs.closure/node-inputs}}的调用者使用{{distinct}}。

{code:title=方案A}
Mon Nov 21 01:31:53 UTC 2017
作者:Corin Lawson <[email protected]>
日期:2017年11月21日星期二 01:31:53 +1100
主题:[补丁] CLJS-2402: 确保外部库列表中包含唯一的条目。
 

---
 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
+                                          expanded-libs)))))))
+                               (filter (fn [{:keys [module-type]}]
+                                                                      and (some? module-type)
+                                                                        (not= module-type :amd)))
         opts (if (some
                    (fn [ijs]
                      (let [dest (io/file output-dir (rel-output-path (assoc ijs :foreign true) opts))]
--
2.13.0



具有更广泛适用性的解决方案是确保输入文件集(即 {{js-modules}})的唯一性。这个补丁会更简单(即不涉及我不理解的部分),并且更接近对Google Closure Compiler的调用。

{code:title=解决方案B}
从 6bf11a24b93642e118e6d29c5af8a137fa01ea94 Mon Sep 17 00:00:00 2001
作者:Corin Lawson <[email protected]>
日期:周日,19 Nov 2017 20:25:31 +1100
主题:[PATCH] CLJS-2402: 确保输入源文件是唯一的。

---
 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 @@
   (let [;; 来自 :foreign-libs(编译器选项)和 :ups-foreign-libs(deps.cljs)的模块一起处理,
                以便来自这两个来源的文件可以相互依赖。
             例如::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 已添加到 Patch Tender (i)

0
...