欢迎!有关此工作的更多详细信息,请参阅关于页面。
在路径 {{public/js/out/foo/bar.cljc}} 处有一个 cljc 文件,其 ns 形式为 {{(ns foo.bar)}},这将导致命名空间 {{foo.bar}} 被重新加载。
这很成问题,因为 ClojureScript 编译器将复制所有输入文件到 {{:output-dir}} 以用于 source-map。最近,随着更多库开始使用 cljc,这已经开始在库在 Clojure 环境中使用时产生问题。Cljs 编译将导致库代码重新加载,可以重新定义协议等,从而破坏 Clojure 环境。
我认为 tools.namespace 忽略文件路径和命名空间不匹配的变化是有意义的。另一个问题也许是一个修复方法,理解为什么在以下情况下依赖解析不起作用:依赖于输出目录中 cljc 文件的协议的命名空间不会被重新加载。
评论者:deraen
这几乎与http://dev.clojure.org/jira/browse/TNS-24 相同,但在这个案例中,不一致命名的命名空间将因为正确路径中有副本而重新加载。
带有测试的提议补丁。
{{find-sources-in-dir}} 是做检查的最简单的地方,因为我们需要目录路径。
修复了补丁中的拼写错误。
由 severeoverfl0w 发布的评论:
我也遇到了这个错误。当与双向文本结合时尤其糟糕,因为它使用了协议和记录。这个补丁完美解决了我的问题。
由 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可能超出了范围。
简而言之,如果你接受这个补丁,那么 sane-paths-only? 仅在 repl/refresh 中运行,并且通过参数传递吗?
评论者:malcolmjuxt
我同意你不应该将工件编译到类路径中。
然而,由于 uberjars,这在中世界非常普遍。
我个人并不喜欢 uberjars,但我似乎是个少数派!只要人们在生产中使用 uberjars,他们就会希望在开发中使用类路径来提供服务。
因此,我认为斯图尔特提出的简单解决方案都不令人满意。
这是一个非常令人讨厌的缺陷,任何使用使用 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}} 声明与路径不匹配的文件时,它会打印一条警告到 * },然后从搜索结果中省略它。
这留下了虚假错误信息的问题。如上所述的注释中提到的(链接:https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=45080∈dex=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-45080 文字:Leiningen profiles)和(链接:https://dev.clojure.org/jira/browse/TNS-45?focusedCommentId=44149∈dex=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}} 随机搜索文件系统目录,并不知道这些目录是否在类路径上。不过,如果排除表达为类路径相关的目录路径,它们可以解析为实际的文件系统路径。
还有一个可能性,那就是使用 哈希(hashes) 而不是现在的 时间戳 来确定文件何时“更改”。这将防止因为 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}},所以 tools.namespace 中其他低级 API 的使用不应受到影响。
第一次遇到不匹配 {{scan-dirs}} 的文件时,将打印带有已声明 {{ns}} 名称和不匹配文件路径的警告信息到 *。之后,整个目录将被忽略,并在每次调用 {{scan-dirs}} 时打印通知。我希望这能在信息性消息和过多虚假警告之间取得良好的平衡。
注意:之前的补丁文件 TNS-42-3.patch 虽然被误命名,但它一直旨在应用于 TNS-45。