欢迎!有关本网站如何运作的更多信息,请查阅关于 页面。
在路径 {{public/js/out/foo/bar.cljc}} 有一个名为{{(ns foo.bar)}}的 cljc 文件,这将导致命名空间 {{foo.bar}} 被重新加载。
这成问题,因为 ClojureScript 编译器会将所有输入文件复制到 {{:output-dir}} 以用于 source-map。最近,随着更多库开始使用 cljc,这已开始在使用 Clojure 环境的库中引起问题。 Clojure 编译将导致库代码重新加载,这可以重新定义协议等,并破坏 Clojure 环境。
我认为 tools.namespace 忽略文件路径和命名空间不匹配的更改是有意义的。另一个问题是,了解为什么依赖解析在这种情况下不起作用:依赖在输出目录上的 cljc 文件的协议的命名空间没有被重新加载。
评论者:deraen
这与 http://dev.clojure.org/jira/browse/TNS-24 几乎一样,但是在这种情况下,不一致命名的 ns 将因为正确的路径中有一个副本而被重新加载。
带有测试的修补程序。
{{find-sources-in-dir}} 是做检查的最简单的地方,因为我们需要目录路径。
修复了补丁中的错误。
评论人:severeoverfl0w
我也遇到了这个错误。当它与双向协议结合使用时尤其糟糕,因为它的使用导致了记录的使用。这个补丁完美地解决了我的问题。
评论人:stuart.sierra
此问题根本原因是将编译的“Web资源”如编译好的ClojureScript代码放在Java类路径上的{{resources/public}}的常见做法。
目前有以下两种简单解决方案
更改tools.namespace行为的内容(特别是较低级别的API)可能会破坏其他用例,所以必须仔细考虑。例如,代码质量检查器可能会使用{{find-sources-in-dir}}来搜索所有Clojure源文件,包括那些具有无效{{ns}}声明。
配置ClojureScript,将编译文件放在一个不在类路径上的目录中
使用类路径来提供文件是常见的方式,不太可能有变化。像Boot这样的许多工具都鼓励使用类路径来提供文件。
使用set-refresh-dirs省略这些目录的搜索。
在Boot上这是不可能的。在Boot中,类路径由Boot管理,一个目录将包含来自多个来源的文件,例如Boot-cljs和{{source-paths}}。
如果do-refresh在它的map中包含了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的最后一个参数重构为options map很好,但这可能超出了API破坏的范围。
tl;dr 如果 +sane-paths-only? 只在 repl/refresh 运行,并且通过参数传递,您会接受这个补丁吗?
+sane-paths-only?
评论者:malcolmjuxt
我同意你不应该在类路径中编译工件。
然而,由于 uberjars 的存在,这在 Clojure 世界中是一个非常普遍的做法。
我个人不喜欢 uberjars,但好像我是少数派!只要人们在生产中使用 uberjars,他们就会希望在开发中使用类路径。
因此我认为,Stuart 提出的两个简单解决方案都无法令人满意。
这是任何使用 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: uberjars)的情况。
如果略过意外路径中的文件是静默的,那么将很难理解为什么一个打错了名字的文件没有被加载。作为可能的折衷方案,{{c.t.n.find}}在遇到其 {{ns}} 声明与路径不匹配的文件时可以打印警告到 * },并将其从搜索结果中排除。
这留下了假错误消息的问题。如上所述的备注中所述,(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}} 文件复制到资源目录的问题吗?
我认为在提及为什么人们从类路径提供服务文件时提到了uberjars,并不是因为人们使用 c.t.n 与已部署的应用程序。
被排除的目录将定义为文件路径还是类路径前缀?
在启动时,用户无法控制类路径中包含的目录。相反,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在(链接: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}},因此工具.namespace中更低级别的API的其他使用不应受到影响。
在第一次遇到与{{scan-dirs}}不匹配的文件时,会打印警告并在*中打印声明的{{ns}}名称以及不匹配的文件路径。此后,整个目录将被忽略,并在每次调用{{scan-dirs}}时打印通知。我希望这能在信息性消息和过多的虚假警告之间找到一个好的平衡。
注意:之前的补丁文件TNS-42-3.patch被错误地命名,但始终打算应用于TNS-45。