请在 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}} 命令被调用的目录,而不是适配器的目录。(请参见上面的“无法找到模块...”错误)

一种可能的解决方案是使用 {{__dirname}},它总是解析为当前文件的目录。这可能会导致现有设置出现问题。

11 条答案

0

评论由:bensu

我有一个提出的解决方案,但担心“从任何地方运行”会增加最终代码的必要复杂性。我的思考过程

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

  2. 处理相对路径时,整个系统需要建立一个新的“参考框架”,即根路径。ClojureScript 编译器假设编译的路径是那个参考框架,这通常与项目的顶级根相符。通常很随意,但它是最有意义的唯一选择。

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

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

路径代数
{{编译器路径 = __dirname - 输出到}}

Node.js

var 编译器路径 = __dirname 替换 输出到 path.resolve (编译器路径, 输出目录, "goog", "base.js") path.resolve (编译器路径, 输出目录, "cljs_deps.js")

这假设如果输出到是相对的,那么输出目录也是相对的。如果它们不一致,则需要更多工作来保持这种一致性。

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

0

评论者:karolmajta

我发现这种行为真的很奇怪,并倾向于切换到 {{__dirname}}。我也不确定我完全理解这种切换的后果(我有点 clojurescript 经验,更多的是从 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

评论者:pupeno

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

0
0
回答者

评论者:pupeno

似乎可以通过使用:simple优化来解决这个问题。

0
回答者

评论者:thatismatt

我也在编写的electron应用中遇到了这个问题。@pupeno,你开始修复补丁了吗?我也很乐意检查这个补丁。虽然我认为我需要一些指导来开始。

0
回答者

评论者:thatismatt

今天早上的一个快速实验表明,通过替换(链接:https://github.com/clojure/clojurescript/blob/aa5f001300e9aebd976cb180f5b7ccb37fcb6898/src/main/clojure/cljs/closure.clj#L1460-L1461)中的{{path.resolve(".")}}为{{__dirname}},在几个简单的electron和node应用中可以工作。这里的"工作"特别是指即使在应用程序从当前工作目录(与编译目录不同)启动时,也不会出现错误,即代码路径是独立的。

我会在做更多的完整测试后附上补丁。在此之前,任何对这个方法的反馈都会很感激。

0
回答者

评论者:thatismatt

附件是建议使用__dirname而不是"."在生成的脚本中的补丁。我已经在nodejs 6.10.0和electron 1.6.5上测试过了。

0
回答者

评论者:thatismatt

另见:(链接:CLJS-1990)

0
回答者

评论者:matthiasn

在使用electron_builder打包时遇到了同样的问题,无法使用:none优化。是否有可能接受这个建议的补丁?谢谢!

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