2024 Clojure现状调查!中分享您的想法。

欢迎!请访问关于页面以了解更多关于如何使用本网站的信息。

0
ClojureScript
大家好,在1.10.439版本中引入外源库时我遇到了错误。

我的项目设置按https://script.clojure.org/guides/javascript-modules,进行,但没有使用leiningen。

所以,有deps.edn,{{\{:deps {org.clojure/clojurescript \{:mvn/version "1.9.908"\}\}\}}}

{code:title=watch.clj}
(require '[cljs.build.api :as b])

(b/watch "src"
  {:output-to    "main.js"
   :output-dir   "out"
   :main         'hello-es6.core
   :target       :nodejs
   :foreign-libs [{:file "src"
                   :module-type :es6}] ;; 或 :commonjs / :amd
   :verbose      true})


以及从那些指示中复制的cljs和js文件

src/
├── hello_es6
│   └── core.cljs
└── js
    └── hello.js


然后我可以执行{{clj ./watch.clj}}(使用clojure 1.9),它工作得很好,{{node main.js}}打印出预期的消息。但是,如果我将deps.edn更改为{{\{:deps \{org.clojure/clojurescript \{:mvn/version "1.10.439"\}\}\}}}, 就会出错。首先是一个关于clj-oss/module-deps的错误,好吧,我本想使用npm的,所以我安装了它。然后在干净和重新编译后失败,错误如下,


$ node main.js
/Users/jb/src/hello-es6/out/hello_es6/core.js:28
return module$Users$jb$src$hello_es6$src$js$hello.sayHello();
                                                  ^

TypeError: module$Users$jb$src$hello_es6$src$js$hello.sayHello is not a function
    at Function.cljs$core$IFn$_invoke$arity$variadic (/Users/jb/src/hello-es6/out/hello_es6/core.js:28:51)
    at hello_es6$core$_main (/Users/jb/src/hello-es6/out/hello_es6/core.js:24:29)
    at Object.cljs$core$apply_to [as apply_to] (/Users/jb/src/hello-es6/out/cljs/core.js:12956:81)
    at Function.cljs$core$IFn$_invoke$arity$2 (/Users/jb/src/hello-es6/out/cljs/core.js:13400:18)
    at cljs$core$apply (/Users/jb/src/hello-es6/out/cljs/core.js:13358:24)
    at Object.<anonymous> (/Users/jb/src/hello-es6/out/AEF573C.js:10:17)
    at Module._compile (internal/modules/cjs/loader.js:722:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)


添加{{:npm-deps true}}到编译器选项后错误仍然存在。

4 个回答

0

评论者:filipematossilva

嗨,按照您的步骤,我可以重现您看到的错误。

当运行 {{clj ./watch.clj}} 时,实际上会有一个警告。

警告:在类路径上发现了库 `js.hello` 的 JavaScript 文件,但未包含相应的 `goog.provide` 声明:file:/D:/sandbox/cljs/modules/src/js/hello.js

我在生成的 JS 文件上做了些改动,运行 {{node ./main.js}},并发现以下情况:
- 加载了 {{./out/src/js/hello.js}}
- 在 {{main.js}} 中定义了 {{module$D_$sandbox$cljs$modules$src$js$hello}},但它是一个空对象 - 在 {{./out/src/js/hello.js}} 中更改 {{module$D_$sandbox$cljs$modules$src$js$hello}} 不会在 {{main.js}} 中更改它
- 从 {{./out/src/js/hello.js}} 中移除 {{var module$D_$sandbox$cljs$modules$src$js$hello={};}} 使程序正常运行

因此,生成的 {{./out/src/js/hello.js}} 声明了一个局部变量,它遮蔽了 GCC 命名空间对象,从而导致局部赋值未使用真正的命名空间对象。

0

评论者:filipematossilva

对这个问题我又调查了一番。应该包含在 https://github.com/clojure/clojurescript/blob/master/src/test/clojure/cljs/build_api_tests.clj#L540-L563 中的测试中。

但是问题并非在构建时出现,而是在运行时出现。我修改了该测试的输出,使其不删除输出目录和 node_modules 目录,并添加以下构建选项:

`

          :target       :nodejs
          :output-to "main.js"
          :main 'foreign-libs-cljs-2334.core

`

然后运行测试,并用 node 运行结果:

kamik@RED-X1C6 MINGW64 /d/sandbox/cljs/clojurescript (master) $ node main.js mylib: #js {}

这个测试本来是用来打印导出一个函数的 JavaScript 库的内容,但打印出了空对象。这与上面的重现类似。

为了检测这样的失败,测试套件还需要用 node 或浏览器执行输出。

据我所知,master 和 {{1.10.516}} 版本(最新版)都生产了不适用于此情况的非工作代码。

但问题来源尚不明确。可能是 GCC 或其配置的问题。

0

评论者:filipematossilva

https://github.com/clojure/clojurescript/blob/c4a5120294aa83b8f69d35ce10e5d03c951d99ea/.travis.yml#L24-L46 中有一个关于此功能的测试,但看起来这个测试没有在 Travis 上失败(https://travis-ci.org/mfikes/clojurescript/builds/540710982#L2084)。我认为回归是意外引入的,因为它没有在 CI 上失败。

0
参考: https://clojure.atlassian.net/browse/CLJS-2992(由 alex+import 报告)
...