请在 2024 国家 Clojure 调查!分享您的想法。

欢迎!有关如何操作,请参阅关于页面以获取更多信息。

0
tools.namespace

在路径 {{public/js/out/foo/bar.cljc}} 有一个 cljc 文件,其 ns 形式为 {{(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发表

这个问题的根本原因是将编译的“网络资源”如编译的ClojureScript代码放入{{resources/public}}下的Java类路径的常见做法。

目前有两种简单的解决方案

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

任何更改tools.namespace行为的东西,特别是在底层API中,都有可能打断其他用例,所以必须仔细考虑。例如,代码检查器可能使用{{find-sources-in-dir}}来搜索所有Clojure源文件,包括具有无效{{ns}}声明的文件。

0

评论由:deraen 制作

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

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

  1. 使用set-refresh-dirs省略这些目录的工具.namespace搜索。

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

0

评论由:severeoverfl0w发表

您是否接受这个补丁,如果do-refresh在其调用find/find-sources-in-dir时通过其选项映射传递了一个sane-paths-only?选项?其中find-sources-in-dir接受一个可选项的第三个参数,指定是否运行sane-paths-only?

将最后参数重构到find-sources-in-dir为一个选项映射是个好主意,但打破那个API或许超出了范围。

tl;dr 如果这个补丁中只有sane-paths-only?运行于REPL/refresh中,并且通过参数传递,你会接受它吗?

0

评论者:malcolmjuxt

我同意你不应该将构件编译到类路径中。

然而,由于uberjars,这在Clojure社区中是一个非常普遍的做法。

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

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

这是一个对使用cljc(例如bidi)库的人来说非常烦人的bug。如果能提出另一种解决方案将非常棒。

0

评论由:severeoverfl0w发表

  1. 使用set-refresh-dirs省略这些目录的工具.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)的情况。

如果省略了意外的路径中的文件,就会很难理解为什么一个重命名的文件没有被加载。作为一个可行的折衷方案,当{{c.t.n.find}}遇到{{ns}}声明与路径不匹配的文件时,它应该在* }中打印警告,并将其从搜索结果中省略。

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

0

评论由:deraen 制作

我猜测 uberjars 是提及为什么人们从类路径提供服务的原因,而不是因为人们在使用部署应用时使用 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 会打印警告并将被忽略的目录添加到跟踪器中,遵循 (链接:https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=47280&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-47280) 中 Dominic Monroe 的建议。

这仅适用于 {{c.t.n.dir/scan-dirs}},因此 tools.namespace 的低级别 API 的其他使用不应该受到影响。

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

注意:之前的补丁文件 TNS-42-3.patch 虽然误命名,但一直是打算应用于 TNS-45。

...