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

我也遇到了这个bug。由于它使用了协议和记录,当与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)来排除这些目录的工具.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 在它的映射中接受一个参数 sane-paths-only? 并将其传递给它的调用 find/find-sources-in-dir?其中 find-sources-in-dir 接受一个可选的第三个参数来指定是否 sane-paths-only?

find-sources-in-dir 的最后一个参数重构为一个选项映射是件好事,但这可能超出范围。

简洁总结:如果 sane-paths-only? 只在 repl/refresh 中运行并且通过参数传递,您是否愿意接受这个补丁?

0

评论人:malcolmjuxt

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

然而,这种做法在 Clojure 世界上非常普遍,因为 uberbars 的存在。

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

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

这是一个很令人烦恼的 Bug,对于使用 cljc 库(例如 bidi)的人来说。如果能提出另一个解决方案就太好了。

0

评论者:severeoverfl0w

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

我还注意到这个策略的另一个问题是它不处理具有不同 :source-paths 的 Leiningen 配置文件。每次切换配置文件时,都必须修改对 set-refresh-dirs 的调用,并且如果弄错了会感到困扰。

0

评论者:stuart.sierra

tools.namespace 从未被设计用于部署应用,因此我认为现在忽略 uberbars(链接:[text](https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822))的情况是安全的。

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

0
by

评论者:deraen

在谈到为什么 人们 servant 文件来自类路径时,提到了uberjar,并不是因为人们使用c.t.n 部署应用程序。

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

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

定义要忽略的类路径前缀可能与Boot一起工作。

0
by

评论者:stuart.sierra

通过类路径前缀排除可能是可能的,但很棘手。目前,{{t.n.s.dir}} 在不知道这些目录是否在类路径上的情况下搜索任意文件系统目录。但是,如果排除的范围以类路径相对目录路径的方式表示,它们可以解析为实际文件系统路径。

还有另一个可能,我之前应该想到的是,使用文件<强>哈希值而不是当前使用的日期和时间来确定文件何时“更改”。这将防止仅因为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 在 此链接 中的建议进行的。

这仅适用于 {{c.t.n.dir/scan-dirs}},因此 tools.namespace 中较低级别的 API 的其他用途不应受到影响。

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

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

...