2024 年 Clojure 投票调查中分享您的想法!

欢迎!有关此如何工作的更多信息,请参阅关于页面。

0
tools.namespace

在路径 {{public/js/out/foo/bar.cljc}} 下的 cljc 文件,ns 表达式为 {{(ns foo.bar)}},这将导致命名空间 {{foo.bar}} 需要重新加载。

这是有问题的,因为 ClojureScript 编译器会复制所有输入文件到 {{:output-dir}} 以供源映射使用。最近随着越来越多的库开始使用 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

我也遇到了这个错误。当它与使用协议和记录的bidi结合时特别糟糕。这个补丁完美地解决了我的问题。

0

评论者:stuart.sierra

这个问题的根本原因是将编译后的“Web资产”如编译后的ClojureScript代码放在{{resources/public}}的Java类路径上的通用做法。

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

  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

评论者:deraen

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

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

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

在Boot上这不可能。在Boot中,类路径由Boot管理,一个目录将包含来自多个源文件,例如Boot-clj和学生路径。

0

评论者:severeoverfl0w

如果do-refresh在它的映射中接受sane-paths-only?选项,您会接受这个补丁吗?它在调用下方find/find-sources-in-dir时传递该参数?在哪里find/find-sources-in-dir取一个可选的第三个参数来指定是否使用sane-paths-only?

最好能够将 find-sources-in-dir 的最终参数重构成一个选项映射,但打破这个API可能超出了范围。

简单地说,你能否接受这个补丁,如果 sane-paths-only? 只在 repl/refresh 过程中运行,并且通过参数传递下去?

0
回答人:

评论者:malcolmjuxt

我同意你不需要把编译后的工件编译到类路径中。

然而,这种情况在 Clojure 世界的实践中非常普遍,因为存在 uberjar。

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

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

这是一个对使用 cljc 库(例如 bidi)的人来说非常烦人的错误。如果能提出另一种解决方案那就太好了。

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 文本:uberjars)这种情况。

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

这留下了一个问题,即虚假的错误信息。如上文注释所述,(链接:[Leiningen profiles](https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=45080&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-45080) 和 [Boot](https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44149&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44149))使得静态定义应该扫描源文件的目录集变得困难。如果我们能指定要从搜索中排除的目录,这会否足以解决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 打印警告并将忽略的目录添加到跟踪器中,遵循 Dominic Monroe 在以下链接中的建议(链接:[https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=47280&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-47280](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}} 的文件时,将打印出一个警告,警告 περιέχει το.Named {{ns}} 名字和文件路径。之后,整个目录将被忽略,并且在每次调用 {{scan-dirs}} 时将打印出一个通知。我希望能在这类信息和过多的虚假警告之间找到一个很好的平衡。

注意:之前的补丁文件 TNS-42-3.patch 被误命名,但本意是应用于 TNS-45。

...