_评论由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。