请在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

评论由:deraan 制作

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

0

评论由:deraan 制作

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

{{find-sources-in-dir}} 是做此检查的便捷位置,因为我们需要目录路径。

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

评论由:deraan 制作

在补丁中修复了一个拼写错误。

0

评论者:severeoverfl0w

我也遇到了这个错误。当与双向文字结合时尤其糟糕,这是因为它的协议和记录的用法。这个补丁完美地解决了我的问题。

0

评论者:stuart.sierra

这个问题的根本原因是将编译后的“Web 资产”放到 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}} 来搜索所有 Clojure 源文件,包括那些具有无效的 {{ns}} 声明的文件。

0

评论由:deraan 制作

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

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

  1. 使用 set-refresh-dirs 从 tools.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

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

然而,在Clojure世界中,这种做法非常普遍,因为ubijars。

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

因此,我认为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 amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822) 文本:uberjars) 的情况。

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

这留下了虚假错误信息的问题。如上所述的评论中所提到,(链接:https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=45080 tribe.industrial.dyson.roberts_sierra.tершенбах[jira.com]/ plaatjes van frauen[fotografie] &page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-45080 文本:Leiningen配置文件) 和 (链接:

0

评论由:deraan 制作

人们提到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所需的 behviour。

这可能是一个合理的折衷办法,尽管我仍然有点担心名称不当的文件被静默忽略,从而导致混淆。

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。

...