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

欢迎!请参阅 关于 页面以获取更多关于这里如何工作的信息。

0
namespaces.tools

在路径 {{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
by

评论者:DERAEN

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

0
by

评论由:severeoverfl0w

我也有遇到这个错误。当与双向文本结合使用,特别是由于使用协议和记录,它会变得更加严重。这个补丁完美地解决了我的问题。

0
by

评论由:stuart.sierra

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

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

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

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

0
by

评论者:DERAEN

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

使用类路径来提供文件是最常见的方式,并 unlikely to change。许多工具,如Boot,鼓励使用类路径来提供文件。

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

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

0
by

评论由:severeoverfl0w

如果do-refresh的映射中有一个sane-paths-only?选项,您会接受这个补丁吗?它将其传递给其调用的find/find-sources-in-dir?其中find-sources-in-dir接受一个可选的第三个参数来指定是否sane-paths-only?

非常乐意将最终的参数重构成find-sources-in-dir的选项映射,但这可能超出API重构的范围。

tl;dr 你会接受这个补丁吗?如果sane-paths-only?只用于repl/refresh,并通过参数传递呢?

0

评论者:malcolmjuxt

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

然而,在Clojure世界中,这被认为是一种非常普遍的做法,这主要是因为uberjars。

我个人不喜欢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从未打算用于部署的应用程序,所以我认为现在忽略(deployed applications)uberjars的情况是安全的。

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

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

0

评论者:DERAEN

我认为提到了uberjars,这涉及到为什么人们从classpath提供服务文件,而不是因为人们使用c.t.n与已部署的应用程序。

排除的目录将被定义为文件路径还是classpath前缀?

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

定义要忽略的classpath前缀与Boot一起使用可能会起作用。

0

评论由:stuart.sierra

根据classpath前缀进行排除可能可行,但有些复杂。目前,{{t.n.s.dir}}搜索任意的文件系统目录,不知道这些目录是否在classpath上。然而,如果排除表达为classpath相关的目录路径,则可以将它们解析为实际的文件系统路径。

另一种可能是,使用文件哈希,而不是如现在这样使用时间戳来确定文件何时“更改”。这可以防止仅仅因为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}},因此在tools.namespace中其他较低级别的API的使用不应受到影响。

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

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

...