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

欢迎!请在 关于 页面查看更多关于这是如何工作的信息。

0
ClojureScript

现在没有时间提供完整的重现,但基本问题可以通过以下内容说明

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

throw err;
      ^

错误:无法找到模块 '/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
开始...
`

这是通过 boot 编译的,因为这是我目前手头上的东西。编译的桥接器看起来像这样

`
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}} 命令的目录,而不是桥接器所在的目录。(参见上述“Cannot find module...”错误)

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

11 答案

0

评论作者:bensu

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

  1. 相对路径是理想的,以产生“无上下文代码”。如果用户选择绝对路径,那么这种行为将被尊重,无需处理(没有“路径代数”)。

  2. 处理相对路径时,整个系统需要建立一个“参考框架”,即根路径。ClojureScript编译器假定它的编译路径作为该参考框架,这通常与项目的顶层根路径相一致。虽然它是任意的,但它是有意义的唯一选择。

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

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

路径代数
{{编译器路径 = __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
by

由:karolmajta 评论

我发现这种行为真的很奇怪,我倾向于切换到{{__dirname}}。我也不确定我完全理解这种切换的后果(我在cljs方面的经验不多,更偏向于从nodejs用户的角度来看)。我的观点是:当前的行为使得clojurescript难以用于命令行和桌面应用程序(特别是electron)。

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

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

我很幸运,我的代码不需要使用真正的CWD,但这更多的是一种权宜之计,而不是真正的解决方案。

从nodejs的角度来看

  1. 使用绝对路径被认为是一种不良实践。
  2. 不使用外部包(不依赖 node_modules)的Nodejs程序可以从任何CWD运行
  3. 依赖于 node_modules 的Nodejs程序如果从包含 node_modules 的不同目录运行,将会出错,但这是预期的行为。
0
by

由:pupeno 评论

当我尝试开发一个Electron应用程序时,我遇到了这个问题。目前它的工作方式实际上不能打包。我认为让它作为一个选项来使用这个行为会很不错,我也愿意为此制作补丁。

0
0

由:pupeno 评论

一种潜在的解决方法是使用:simple优化。

0

评论者:thatismatt

我也正在构建一个electron应用程序时遇到了这个问题。@pupeno 关于你提出的修复补丁,你进展如何?我也乐意为这个补丁操刀。尽管我认为我需要一些指导才能开始。

0

评论者:thatismatt

今天早上进行的一项快速实验表明,将 {{path.resolve(".")}} 替换为 {{__dirname}} 在(链接:https://github.com/clojure/clojurescript/blob/aa5f001300e9aebd976cb180f5b7ccb37fcb6898/src/main/clojure/cljs/closure.clj#L1460-L1461)对于几个简单的electron和node应用程序发挥了作用。我特别指的是,即使在启动应用程序的工作目录与编译目录不同的情况下,也不会出现错误,即代码是与路径无关的。

我将对这个问题进行更完整的测试,然后再提交补丁。在此期间,对该方法的任何反馈都将受到欢迎。

0

评论者:thatismatt

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

0

评论者:thatismatt

另请参阅:[CLJS-1990](link: CLJS-1990)

0

评论者:matthiasn

遇到了相同的问题,我无法在用 electron-builder 打包时使用 :none 优化选项。有没有可能接受所建议的补丁?谢谢!

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