请分享您的想法,参与 2024 年 Clojure 状况调查!

欢迎!请查看 关于 页面以获取更多关于该功能的详细信息。

0 投票
ClojureScript

暂时没有时间提供一个合适的重现示例,但基本问题可以用以下示例说明

`
~/c/boot-cljs-example (master=) node target/main.js
module.js:338

throw err;
      ^

Error: Cannot find module '/Users/martin/code/boot-cljs-example/out/goog/bootstrap/nodejs.js'

at Function.Module._resolveFilename (module.js:336:15)
at Function.Module._load (module.js:278:25)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object.<anonymous> (/Users/martin/code/boot-cljs-example/target/main.js:6:1)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)

~/c/boot-cljs-example (master=) cd target/
~/c/b/target (master=) node main.js
Starting...
`

这是使用 boot 编译的,因为这是我目前手头的工具。编译后的 shim 如下所示

`
var path = require("path");
try {

require("source-map-support").install();

} catch(err) {
}
require(path.join(path.resolve("."),"out","goog","bootstrap","nodejs.js"));
require(path.join(path.resolve("."),"out","cljs_deps.js"));
goog.global.CLOSURE_UNCOMPILED_DEFINES = {"cljs.core._STAR_targetSTAR":"nodejs"};
goog.require("boot.cljs.main");
goog.require("cljs.nodejscli");
`

这里的问题在于 {{path.resolve(".")}} 将返回 ${node} 命令调用的目录,而不是 shim 的目录。(请参见上面的 "Cannot find module..." 错误)

一种可能的解决方案是使用 {{__dirname}},它始终解析为当前文件的目录。这可能会对现有的设置造成一些破坏。

11 答案

0 投票

评论者:bensu

我有一个解决方案提议,但我担心支持“从任何地方运行”会增加代码实现的复杂性。我的思考过程

  1. 相对路径更适合生成“无需上下文代码”。如果用户选择绝对路径,则尊重该行为,无需处理(无需处理 "路径代数")。

  2. 处理相对路径时,整个系统需要建立一个“参考框架”,即根路径。ClojureScript 编译器假定编译所使用的路径是该参考框架,这通常与项目的顶级根目录相符合。虽然没有固定模式,但它是唯一有意义的选项。

  3. 参考框架在代码中没有明显声明,因为它被定义为 {{"."}}。如果它是明确的,比如 {{"/home/some-user/their-folder/this-project/"}},它将揭示上下文。

  4. 当我们从另一个参考点(即从另一个目录执行脚本)来看代码时,我们首先需要找到原始的编译器路径(参考点),然后从这个路径解析所有路径。编译器使用 cljs.closure/path-relative-to 来完成这个目的。

路径代数
{{compiler-path = __dirname - output-to}}

Node.js

var compiler-path = __dirname.replace(output-to, "") path.resolve (compiler-path, output-dir, "goog", "base.js") path.resolve (compiler-path, output-dir, "cljs_deps.js")

这假设如果output-to被指定为相对路径,那么output-dir也是相对的。如果它们不一致,则需要做更多的工作来保持一致性。

决定额外的复杂性是否值得使用不是我的事情。实际上,我希望有更简单的解决方案来解决这个问题,而这个解决方案我还没有看到。

0 投票
来自

由 karolmajta 评论

我发现这种行为真的很奇怪,并倾向于切换到 {{__dirname}}。我也不确定我完全理解这种切换的后果(我有点clojurescript的经验,主要从nodejs用户的角度来看)。我的观点是:当前的行为使得clojurescript在命令行和桌面应用程序(尤其是electron)中使用起来很困难。

对于命令行和桌面应用程序,不能假设当前工作目录(CWD)。目前,我通过一个bootstrap脚本JS脚本来运行我的应用程序

process.chdir(__dirname); require('./target/out');

我很幸运,我的代码不需要使用真实的CWD,但这更像是一种 hack 而非真正的解决方案。

从Node.js的角度来看

  1. 无论如何,使用绝对路径都被认为是不良的做法。
  2. 没有使用外部包(不依赖于 node_modules)的Node.js程序可以从不包含 node_modules 的任何CWD运行
  3. 如果Node.js程序依赖于 node_modules 并从包含 node_modules 的目录之外运行,则会出错,但这是一种预期行为。
0 投票
来自

来自于 pupeno 的评论

当尝试开发一个Electron应用程序时,我遇到了这个问题。目前它的工作方式基本上是无法打包的。我认为将这种行为作为一个选项将很好,并且我很乐意为此工作。

0 投票
来自
0 投票
来自

来自于 pupeno 的评论

似乎可以采用简单优化作为替代方法。

0 投票

评论者:thatismatt

我在构建的Electron应用中也遇到了这个问题。@pupeno,你提出的补丁进度如何?我也乐意看一下这个补丁。虽然我认为我需要一些指导才能开始。

0 投票

评论者:thatismatt

今天早上进行的一项快速实验表明,在 (链接:https://github.com/clojure/clojurescript/blob/aa5f001300e9aebd976cb180f5b7ccb37fcb6898/src/main/clojure/cljs/closure.clj#L1460-L1461) 将 {{path.resolve gesamdego}} 替换为 {{__dirname}},对于几个简单的Electron和Node应用来说有效。我所说的有效是指,即使当应用从与编译目录不同的当前工作目录启动时,也不会出现错误,即代码是路径无关的。

一旦我进行了一些更全面的测试,我会附上补丁。在此之前,对这种方法的任何反馈都将受到欢迎。

0 投票

评论者:thatismatt

附上使用 __dirname 替代 . 在生成的脚本中的一个补丁的建议。我已经在 nodejs 6.10.0 和 electron 1.6.5 上进行了测试。

0 投票

评论者:thatismatt

也参见:(链接:CLJS-1990)

0 投票

评论者:matthiasn

在使用 electron_builder 打包时遇到了相同的问题,无法使用优化:none。是否有机会接受所提出的补丁?谢谢!

0 投票
参考:[CLJS-1444](https://clojure.atlassian.net/browse/CLJS-1444)(martinklepsch 报告)
...