欢迎!请查阅 关于 页面以了解更多关于其工作方式的信息。
在路径 {{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 文件的协议的命名空间不会被重新加载。
评论者:deraen
这与 http://dev.clojure.org/jira/browse/TNS-24 几乎相同,但在这个案例中,不一致命名的 ns 将会被重新加载,因为在正确的路径上有一个副本。
带有测试的提议补丁。
{{find-sources-in-dir}} 是进行此检查的最简单位置,因为我们需要目录路径。
在补丁中修复了拼写错误。
评论者:severeoverfl0w
我也遇到了这个错误。当与双向结合使用时尤其糟糕,因为它使用了协议和记录。这个补丁完美地解决了我的问题。
评论者:stuart.sierra
这个问题的根本原因是在 {{resources/public}} 上放置编译后的 "Web 资产"(如编译好的 ClojureScript 代码)的常用做法。
目前有两种简单的解决方案:
修改工具命名空间行为(特别是底层 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的范围。
简单地说,如果你接受这个补丁,其中 sane-paths-only? 只在 repl/refresh 中运行,并通过参数传递,你会怎样?
评论者:malcolmjuxt
我同意你不应该将构建物编译到类路径上。
但是,由于 uberjar 的存在,这已经在 Clojure 离散界变得非常普遍。
我个人不喜欢 uberjar,但似乎我是少数派!只要人们在生产中使用 uberjar,他们就会希望在开发中使用类路径。
因此,我认为 Stuart 提出的简单解决方案都令人不满意。
这是一个真的很烦人的错误,对于使用 cljc 库(例如 bidi)的人来说。如果能提出另一种解决方案那就太好了。
我注意到这个策略的另一个问题是它没有处理具有不同 :source-paths 的 leiningen 配置文件。每次切换配置文件时,你必须修改对 set-refresh-dirs 的调用(并且在你搞错时感到困惑)。
:source-paths
set-refresh-dirs
tools.namespace 从未打算用于已部署的应用程序,因此我认为现在可以安全地忽略有关 (链接: https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44822&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-44822 文本: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}}文件复制到资源目录的问题是否足够呢?
我认为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 的所需行为。
这可能是一个足够的折衷方案,尽管我对不良命名的文件被 silently 忽略导致困惑仍然略感担忧。
可以将废弃的文件/命名空间添加到跟踪器中,以减少混淆。然后刷新功能将像现在一样用prn警告这些文件。
prn
需要某种东西能够将文件从废弃列表中移除,以防文件变得有效。
我不确定这应该阻塞TNS-45,但可能有人会将其作为后续行动。
新的补丁文件TNS-45-4.patch将显示警告并将忽略的目录添加到跟踪器中,遵循Dominic Monroe在(link: 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}},所以其他工具.ns使用中较低层的API不应受到影响。
第一次遇到不匹配{{scan-dirs}}的文件时,将打印警告并将声明的{{ns}}名称和未匹配的文件路径打印到*上。之后,将忽略整个目录,并在每次调用{{scan-dirs}}时打印通知。我希望这在这两种信息性消息和不要太多的虚假警告之间取得了一个良好的平衡。
注意:之前的补丁文件TNS-42-3.patch被误命名,但始终旨在应用于TNS-45。