2024 年 Clojure 调查报告中分享您的看法!

欢迎!请查看 关于页面 以了解此功能的一些更多信息。

0
ClojureScript
大家好,我在版本 1.10.439 的 {{require}} 外部库时遇到错误。

我的项目根据 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` 声明:文件:/D:/sandbox/cljs/modules/src/js/hello.js

我在生成的 JS 中尝试修改,运行 {{node ./main.js}},发现以下情况
- {{./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 中覆盖。

但这个问题在构建时没有表现出来,只在运行时才会发生。我修改了该测试的输出,没有删除 out 和 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 报告)
...