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

我也有过这个错误的经历。当与双向文本结合使用时,由于它使用了协议和记录,这个问题尤为严重。这个补丁完美解决了我的问题。

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-cljs和{{source-paths}})的文件。

0投票

评论者:severeoverfl0w

如果您接受这个补丁,如果do-refresh在其传递给find/find-sources-in-dir的映射关系中将sane-paths-only?作为一个选项考虑,那么如何处理?其中find-sources-in-dir提供了一个可选的第三个参数来指定sane-paths-only? behave?

find-sources-in-dir的最后一个参数重构为一个选项映射是个不错的选择,但这也许超出了 API 打破的范围。

简要地说,如果您接受这个补丁,那么sane-paths-only?是否仅作用于 repl/refresh,并通过参数传递下级调用?

0投票
提出了答案,提出时间为 ,作者为

评论者:malcolmjuxt

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

然而,在 Clojure 界,这种做法因为 uberjars 而变得非常普遍。

就我个人而言,我不喜欢 uberjars,但我觉得我是少数人!只要在生产中使用 uberjars,他们在开发中就会希望从类路径中提供服务。

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

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

0投票
提出了答案,提出时间为 ,作者为

评论者:severeoverfl0w

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

我发现这种方法还存在另一个问题,即它不能处理每个 Leiningen profile 中不同的 :source-paths。你必须每次更换 profile 时都修改调用set-refresh-dirs(当出错时可能会感到困惑)。

0投票
提出了答案,提出时间为 ,作者为

评论者:stuart.sierra

tools.namespace 从未被设计为在部署的应用程序中使用,因此我认为我们可以忽略现在关于 (link: https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822 text: uberjars) 的情况。

如果忽略不在预期路径中的文件,那么很难理解为什么一个误命名的文件没有被加载。作为一个可能的折衷方案,当 {{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投票
by

评论由:deraen 提供

我认为提到uberjars是为了解释为什么人们从classpath提供服务文件,而不仅仅是因为人们在部署的应用程序中使用c.t.n。

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

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

为Boot定义要忽略的classpath前缀可能可行。

0投票
by

评论者:stuart.sierra

通过classpath前缀排除可能可行,但可能比较棘手。目前,{{t.n.s.dir}}搜索任意文件系统目录,而不知道这些目录是否在classpath中。然而,如果排除是按classpath相关的目录路径表达的,那么可以将它们解析为真实文件系统路径。

另一种可能性是使用文件哈希值,而不是现在所使用的文件时间戳来确定文件何时“改变”。这将防止由于ClojureScript编译器复制了这些文件而重新加载{{.cljc}}文件。另一方面,这将是一个更大的更改,并且将防止使用{{touch}}(或在编辑器中重新保存)强制重新加载文件。

0投票
by

评论者: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投票
by

评论者:severeoverfl0w

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

如果这些文件变得有效,则需要删除废弃列表中的文件。

我不确定这应该阻止TNS-45,但可能有人可以跟进。

0投票
by

评论者: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}},因此tools.namespace中低级别API的其他使用不应受到影响。

在首次发生与{{scan-dirs}}不匹配的文件时,将向*打印警告,并列出声明的{{ns}}名称和未匹配的文件路径。之后,将忽略整个目录,并在每个{{scan-dirs}}调用时打印通知。我希望这能在信息性消息和太多虚假警告之间取得良好平衡。

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

...