欢迎!请查看关于页面以了解更多关于其工作方式的信息。
在路径 {{public/js/out/foo/bar.cljc}} 中有一个 cljc 文件,并且 ns 形式为 {{(ns foo.bar)}},会导致命名空间 {{foo.bar}} 重新加载。
这是有问题的,因为 ClojureScript 编译器会为 source-map 的使用将所有输入文件复制到 {{:output-dir}}。最近,随着更多库开始使用 cljc,这已经开始在库在 Clojure 环境中使用时引起问题。Cljs 编译会导致库代码的重新加载,这可以重新定义协议等,从而破坏 Clojure 环境。
我认为对于 tools.namespace 而言,忽略文件路径和命名空间不匹配时的更改是有意义的。另一个问题是,或许也是解决问题的方法,是了解为什么依赖解析在此情况下不起作用:依赖于输出目录上 cljc 文件中协议的命名空间不会重新加载。
由:deraen
这与http://dev.clojure.org/jira/browse/TNS-24几乎相同,但在这个案例中,不一致命名的 ns 将会被重新加载,因为正确的路径中有一个副本。
带有测试的修复补丁。
{{find-sources-in-dir}}是做检查最容易的地方,因为我们需要目录路径。
在补丁中修复了一个打字错误。
评论者为:severeoverfl0w
我也遇到过这个bug。尤其是在结合bidi(双向文本)时,由于它使用协议和记录,问题尤其严重。这个补丁完美解决了我的问题。
评论者为:stuart.sierra
这个问题的根本原因是将编译后的“Web资产”如编译后的ClojureScript代码放在Java类路径下的{{resources/public}}的常见做法。
目前有两种简单的解决方案可供选择
任何更改工具命名空间行为的东西,尤其是在更低级别的API中,都有可能破坏其他用例,因此必须仔细考虑。例如,一个代码检查器可能会使用{{find-sources-in-dir}}来搜索所有Clojure源文件,包括那些具有无效的{{ns}}声明。
配置ClojureScript,将编译文件放在不在类路径上的目录中
使用类路径来服务文件是最常见的方式,并且不太可能改变。许多工具,如Boot,鼓励使用类路径来服务文件。
使用set-refresh-dirs来从工具命名空间搜索中排除这些目录。
在Boot上不可能实现这一点。在Boot中,类路径由Boot管理,一个目录将包含来自多个来源的文件,例如Boot-cljs和{{source-paths}}。
您是否接受这个补丁,如果 do-refresh 在它的 sane-paths-only? 字典中接收一个选项,并将其传递到其调用链中的 find/find-sources-in-dir 中?其中 find-sources-in-dir 接收一个可选的第三个参数,指定是否 sane-paths-only??
do-refresh
sane-paths-only?
find/find-sources-in-dir
find-sources-in-dir
将 find-sources-in-dir 的最后一个参数重构为选项字典会很理想,但破坏那个 API 可能超出了范围。
tl;dr 这个补丁如果允许 sane-paths-only? 只在 repl/refresh 中运行,并通过参数传递,您是否会接受它?
评论者:malcolmjuxt
我同意你不应该将构建工件编译到类路径中。
然而,由于 ubерб蔟,这在 Clojure 世界中是一个非常普遍的做法。
我个人不喜欢 ubерб蔟,但似乎我是少数派!只要人们在生产中使用 ubέρjars,他们就会希望在开发中从类路径中提供服务。
因此,我认为 Stuart 提出的简单解决方案都不令人满意。
这是一个非常令人烦恼的 bug,对于使用 cljc(例如 bidi)库的人来说更是如此。如果能提出另一个解决方案那就太好了。
我发现这个策略的另一个问题是,它不处理具有不同 :source-paths 的 leiningen 配置文件。每次切换配置文件时,你必须改变对 set-refresh-dirs 的调用(并且当你出错时会感到困惑)。
:source-paths
set-refresh-dirs
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: ubérerjars) 的情况是安全的。
如果意外路径中的文件被静默跳过,将很难理解为什么一个文件名错误的文件没有被加载。作为可能的妥协,当 {{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}} 文件复制到资源目录的问题?
我认为在提到人们从类路径中提供文件的原因时,uberjars 被提到了,并不是因为使用 c.t.n 部署应用程序的用户。
排除的目录是定义为文件路径还是类路径前缀?
在 Boot 中,用户无法控制类路径中包含的目录。相反,Boot 创建了一些它控制的临时目录,这些目录包含在类路径中。来自几个来源(项目资源路径、Cljs 艺术品等)的文件都被复制到同一个临时目录,因此无法根据这一点排除 Cljs 艺术品。
定义要忽略的类路径前缀可能适用于 Boot。
使用类路径前缀进行排除可能可行,但方法可能略显复杂。目前,{{t.n.s.dir}} 在不知道这些目录在类路径上的情况下搜索任意文件系统目录。尽管如此,如果排除表达为类路径相关的目录路径,它们可以解析为实际的文件系统路径。
还有一个可能,我之前应该想到,那就是使用文件 哈希 而不是现在的日期时间来确定文件何时“更改”。这将防止仅因为 ClojureScript 编译器已将它们复制,就重新加载 {{.cljc}} 文件。另一方面,这将是一个更大规模的改变,并且它将阻止使用 {{touch}}(或在编辑器中重新保存)强制重新加载文件。
新补丁 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 的预期行为。
这可能是一个可以接受的折衷方案,尽管我仍然担心可能因文件重命名不当而静默忽略错误导致混淆。
可以将已丢弃的文件/命名空间添加到跟踪器中,以减轻混淆。刷新时可以像现在一样对那些文件发出prn警告。
prn
如果文件再次变得有效,则需要删除文件从丢弃列表中。
我不确定这应该阻止TNS-45,但这可能是有人跟进的事项。
新补丁文件TNS-45-4.patch将打印警告并将忽略的目录添加到跟踪器中,根据Dominic Monroe在(a链接: 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。