_评论由 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('');
{code:title=out/distinct_inputs/core.js}
goog.provide('distinct_inputs.core');
goog.require('cljs.core');
goog.require('module$distinct_inputs$node_modules$d3$d3');
goog.require('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");
//# sourceMappingURL=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
h2. 实际结果。
{{cljs}} 以退出代码 1 终止并产生以下标准输出。
{code:none|title=stdout}
在 "main" 线程中抛出异常 java.lang.IllegalArgumentException: 解析模块路径重复:/distinct_inputs/node_modules/d3/d3.js,编译:(/distinct_inputs/build.clj:3:1)
在 clojure.lang.Compiler.load(Compiler.java:7391)
在 clojure.lang.Compiler.loadFile(Compiler.java:7317)
在 clojure.main$load_script.invokeStatic(main.clj:275)
在 clojure.main$script_opt.invokeStatic(main.clj:335)
在 clojure.main$script_opt.invoke(main.clj:330)
在 clojure.main$main.invokeStatic(main.clj:421)
在 clojure.main$main.doInvoke(main.clj:384)
在 clojure.lang.RestFn.invoke(RestFn.java:408)
在 clojure.lang.Var.invoke(Var.java:379)
在 clojure.lang.AFn.applyToHelper(AFn.java:154)
在 clojure.lang.Var.applyTo(Var.java:700)
在 clojure.main.main(main.java:37)
原因如下:java.lang.IllegalArgumentException: 解析模块路径重复:/distinct_inputs/node_modules/d3/d3.js
在 com.google.javascript.jscomp.deps.ModuleLoader.resolvePaths(ModuleLoader.java:276)
在 com.google.javascript.jscomp.deps.ModuleLoader.<init>(ModuleLoader.java:92)
在 com.google.javascript.jscomp.Compiler.parseInputs(Compiler.java:1731)
在 com.google.javascript.jscomp.Compiler.parse(Compiler.java:995)
在 cljs.closure$convert_js_modules.invokeStatic(closure.clj:1680)
在 cljs.closure$process_js_modules.invokeStatic(closure.clj:2371)
在 cljs.closure$handle_js_modules.invokeStatic(closure.clj:2495)
在 cljs.closure$build.invokeStatic(closure.clj:2592)
在 cljs.build.api$build.invokeStatic(api.clj:204)
在 cljs.build.api$build.invoke(api.clj:189)
在 cljs.build.api$build.invokeStatic(api.clj:192)
在 cljs.build.api$build.invoke(api.clj:189)
在 user$eval24.invokeStatic(build.clj:3)
在 user$eval24.invoke(build.clj:3)
在 clojure.lang.Compiler.eval(Compiler.java:6927)
在 clojure.lang.Compiler.load(Compiler.java:7379)
... 11 更多
没有生成上述预期的任何文件。
h2. 异常原因。
{{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}} 被提供一个包含重复条目{{node_modules/d3/d3.js}}的{{:foreign-libs}}向量(以及它的{{package.json}})。这个向量是由多此调用{{cljs.closure/node-inputs}} 生成的;一次是为{{out/cljs$node_modules.js}}(这可能是{{distinct_inputs/core}}中依赖的结果),再一次是为{{es6/circle.js}}。
简而言之,依赖 D3 是通过 ClojureScript 源文件和 JavaScript 模块源文件同时引入的。
h2. 建议的解决方案。
在这种情况下,{{:foreign-libs}}向量中包含重复条目,尽管在{{cljs.closure/node-inputs}}中使用{{distinct}}。一个可能的解决方案是移除在{{cljs.closure/node-inputs}}中使用的{{distinct}},并要求{{cljs.closure/node-inputs}}的调用者使用{{distinct}}。
{code:title=解决方案 A}
来自 063e35080c14d35189ab7827f25f071e958ab5b4 Mon Sep 17 00:00:00 2001
发件人:Corin Lawson <
[email protected]>
日期:周二,21 11月 2017 01:31:53 +1100
主题:[PATCH] 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])
--
2.13.0
[let [dest (io/file output-dir (rel-output-path (assoc ijs :foreign true) opts))]
更通用的解决方案是 {{cljs.closure/process-js-modules}} 必须确保输入文件集(即 {{js-modules}})是唯一的。此补丁会更简单(即不涉及我不理解的代码)并且更接近 Google Closure Compiler 的调用。
From 6bf11a24b93642e118e6d29c5af8a137fa01ea94 Mon Sep 17 00:00:00 2001
发件人:Corin Lawson <
[email protected]>
日期:周天,19 11月 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 @@
(从 :foreign-libs (编译器选项) 和 :ups-foreign-libs (deps.cljs) (依赖) 中的模块一起处理,以便来自两个来源的文件可以相互依赖。
;; 例如,:foreign-libs 中的 CommonJS 模块可以依赖于 :ups-foreign-libs 中的 CommonJS 模块。
;; e.g. commonjs module in :foreign-libs can depend on commonjs module from :ups-foreign-libs.
- 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。