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

欢迎!请参阅关于页面了解有关如何运行的更多信息。

0投票
tools.namespace

在路径{{public/js/out/foo/bar.cljc}}处有一点名为cljc的文件,并且形式为{{(ns foo.bar)}},这将导致命名空间{{foo.bar}}被重新加载。

这很成问题,因为ClojureScript编译器将复制所有输入文件到{{:output-dir}}以供source-map使用。最近,随着越来越多的库开始使用cljc,这开始导致在库在Clojure环境中使用时产生问题。Cljs编译将导致库代码的重新加载,这可以重新定义协议等,并破坏Clojure环境。

我认为对于tools.namespace来说,忽略文件路径和命名空间不匹配的更改是有意义的。
另一个问题是,要了解为什么在以下情况下依赖关系解析不起作用:依赖于输出目录中cljc文件的协议的命名空间没有被重新加载。

19 个答案

0投票

评论人:deraen

这几乎与http://dev.clojure.org/jira/browse/TNS-24相同,但在这个情况下,不一致命名的命名空间将被重新加载,因为正确的路径中有一个副本。

0投票

评论人:deraen

提供了一个带测试的补丁。

{{find-sources-in-dir}}是进行该检查的最容易的地方,因为我们需要目录路径。

  • 可能会破坏直接使用{{find-sources-in-dir}}的用户?
  • 现在{{find-sources-in-dir}}和{{file/files-and-deps}}都需要读取ns形式。
0投票

评论人:deraen

在补丁中修复了一个错别字。

0投票

评论由:severeoverfl0w

我也遇到了这个bug。由于它使用协议和记录,结合bidi特别糟糕。这个补丁完美解决了我的问题。

0投票

评论由:stuart.sierra

这个问题的根源是将编译后的“web资源”如编译后的ClojureScript代码放在Java类路径的{{resources/public}}的常见做法。

目前有两个简单的解决方案可用

  1. 配置ClojureScript将编译文件放在不在类路径上的目录中
  2. 使用(链接: http://clojure.github.io/tools.namespace/#clojure.tools.namespace.repl/set-refresh-dirs 文本:set-refresh-dirs)来排除这些目录从tools.namespace搜索中。

任何改变tools.namespace行为的内容,尤其是在底层的API中,都有可能破坏其他用例,因此必须仔细考虑。例如,代码检查器可能会使用{{find-sources-in-dir}}来搜索包括无效{{ns}}声明在内的所有Clojure源文件。

0投票

评论人:deraen

  1. 配置ClojureScript将编译文件放在不在类路径上的目录中

使用类路径来服务文件是最常见的方式,不太可能改变。许多工具,如Boot,鼓励使用类路径来服务文件。

  1. 使用set-refresh-dirs来排除这些目录从tools.namespace搜索中。

在Boot上这不可能。在Boot中,类路径由Boot管理,一个目录将包含来自几个来源的文件,例如Boot-cljs和{{source-paths}}。

0投票

评论由:severeoverfl0w

如果你接受这个补丁的话,那么如果 do-refresh 在它的映射 sane-paths-only? 中接受一个选项,并将其传递到其调用 find/find-sources-in-dir 中,你会怎么做?其中 find-sources-in-dir 接受一个可选的第三个参数,指定是否启用 sane-paths-only? 吗?

find-sources-in-dir 的最后参数重构为选项映射是件好事,但打破这个 API 可能超出了范围。

简单地说,你会接受这个补丁,让 sane-paths-only? 仅在 repl/refresh 中运行,并通过参数传递吗?

0投票

评论者:malcolmjuxt

我同意你不应该在类路径上编译构件。

然而,由于有 uberjars,这在 Clojure 世界中是非常普遍的做法。

我个人不喜欢 uberjars,但我似乎是个异数!只要人们在生产中使用 uberjars,他们就会希望在开发中使用类路径来服务。

因此,我认为 Stuart 提出的简单解决方案都是不令人满意的。

这是一个对任何使用 cljc 库(例如 bidi)的人来说都非常棘手的 bug。如果能提出另一个解决方案那就太好了。

0投票

评论由:severeoverfl0w

  1. 使用set-refresh-dirs来排除这些目录从tools.namespace搜索中。

我发现这个策略的另一个问题是它没有处理具有不同 :source-paths 的 Leiningen 配置文件。每次切换配置文件时,你必须修改对 set-refresh-dirs 的调用(并且当出错时可能会感到困惑)。

0投票

评论由:stuart.sierra

tools.namespace 从未打算用于已部署的应用程序,因此我认为现在可以安全地忽略(链接:[https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822](https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822))uberjars 的情况。

如果意外路径中的文件被静默跳过,那么很难理解为什么一个文件名错误的文件没有被加载。作为可能的折中方案,当 {{c.t.n.find}} 遇到一个其 {{ns}} 声明与其路径不匹配的文件时,它可以打印一条警告到 * },并将其从搜索结果中省略。

这留下了一个虚假错误消息的问题。如上述评论中所述,(链接:<a rel="nofollow" href="https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=45080&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-45080" target="_blank">https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=45080&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-45080</a>文本:Leiningen 配置文件)和(链接:<a rel="nofollow" href="https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44149&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44149" target="_blank">https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44149&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44149</a>文本:Boot)使得静态定义应该扫描源文件的目录集合变得困难。如果我们能指定要排除搜索的目录,这对解决 ClojureScript 将 {{.cljc}} 文件复制到资源目录的问题是否足够?

0投票

评论人:deraen

我认为有人提到 uberjar 与为什么人们从类路径中提供文件有关,但这不是因为人们在与部署的应用程序一起使用 c.t.n。

要排除的目录是否会定义为文件路径或类路径前缀?

在 Boot 中,用户无法控制包含在类路径中的目录。相反,Boot 创建了它控制的一些临时目录,并将它们包含在类路径中。来自多个来源的文件(项目资源路径、Cljs 项等)都复制到同一个临时目录中,因此基于这一点无法排除 Cljs 项。

定义要忽略的类路径前缀可能会在 Boot 中起作用。

0投票

评论由:stuart.sierra

通过类路径前缀进行排除可能可行,但可能有点棘手。目前,{{t.n.s.dir}} 搜索任意文件系统目录,并不知道这些目录是否在类路径上。尽管如此,如果排除是以类路径相关目录路径的形式表达的,它们可以解析为真实的文件系统路径。

还有一个可能的方案,就是使用文件 哈希值 而不是现在的最后修改时间来确定文件何时“已更改”。这将防止仅因为 ClojureScript 编译器已将它们复制,就重新加载 {{.cljc}} 文件。另一方面,这将是一个更大的变化,并且它将防止使用 {{touch}}(或在编辑器中重新保存)来强制重新加载文件。

0投票

评论由:stuart.sierra

新补丁 TNS-42-3.patch 将责任提升一层,从 c.t.n.find 到 c.t.n.dir。这将避免对 c.t.n.find/find-sources-in-dir 进行任何破坏,同时实现 c.t.n.repl/refresh 的期望行为。

这可能是一种足够的折衷方案,尽管我仍然对无声忽略错误命名的文件而导致混淆表示略微担心。

0投票

评论由:severeoverfl0w

可以将在废弃的文件/命名空间添加到跟踪器中,以减轻混淆。刷新时可以像现在一样警告这些文件带有prn

如果这些文件最终变得有效,则需要某种机制从废弃列表中删除这些文件。

我不确定这应该阻止TNS-45,但这可能是某人跟进的后续事项。

0投票

评论由:stuart.sierra

新的补丁文件TNS-45-4.patch会打印警告,并将忽略的目录添加到跟踪器中,这是根据Dominic Monroe在链接https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=47280&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-47280的评论中的建议实现的。

这仅适用于{{c.t.n.dir/scan-dirs}},因此工具命名空间中的较低级别API的其他用途不应受到影响。

第一次遇到不符合{{scan-dirs}}的文件时,将打印一个警告,警告内容包括声明的{{ns}}名称和未匹配的文件路径。之后,将忽略整个目录,并在每次调用{{scan-dirs}}时打印一个通知。我希望这能在信息性消息和过多的虚假警告之间取得良好平衡。

注意:之前的补丁文件TNS-42-3.patch被误命名了,但它始终旨在应用于TNS-45。

...