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 应该忽略文件路径和命名空间不匹配的情况下的更改。
另一个问题以及可能的解决方案,是要了解为什么在这种情况下依赖项解析不起作用:依赖 output-dir 中 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

这个问题的根本原因是在 {{resources/public}} 上放置编译后的 "Web 资产"(如编译后的 ClojureScript 代码),这是 Java 类路径中的常见做法。

目前有这两种简单解决方案可用

  1. 配置 ClojureScript 以将编译文件放在不在类路径上的目录中
  2. 使用 (链接: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 在其 sane-paths-only? 路径字典中添加一个选项,并通过其调用传递到 find/find-sources-in-dir?其中 find-sources-in-dir 接受一个可选的第三个参数,指定是否 sane-paths-only?

find-sources-in-dir 的最后一个参数重构到选项映射中将是一个不错的想法,但这可能会打破API,或许这不在范围之内。

简而言之,您是否接受这个补丁,如果 sane-paths-only? 仅在 repl/refresh 中运行,并通过参数传递下去?

0

评论者:malcolmjuxt

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

然而,这Clojure界中极为普遍的做法,因为uberjars。

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

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

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

0

评论人:severeoverfl0w

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

我发现这种策略的另一个问题是它无法处理具有不同 :source-paths 的leiningen配置文件。每次切换配置文件时,你必须修改对 set-refresh-dirs 的调用(并且当你出错时会感到困惑)。

0

评论人:stuart.sierra

tools.namespace Never intended to be used in production applications, so I think it is safe to ignore the case of (link: https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822 text: uberjars) for now.

If files in unexpected paths are skipped silently, it would be difficult to understand why a mis-named file is not being loaded. As a possible compromise, {{c.t.n.find}} could print a warning to * } when it encounters a file whose {{ns}} declaration does not match its path, and omit it from the search results.

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

0
by

由 deraen 发布的评论

觉得uberjars被提及是因为人们从classpath中提供文件,而不是因为人们在使用c.t.n部署应用程序时使用c.t.n。

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

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

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

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

评论人: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。

...