2024年Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面了解有关此工作的一些更多信息。

0 投票
ClojureScript

ES6有特定的语法来使用“默认”导入,而当使用导入的ES6代码时,CLJS中没有等效的功能。

`
import * as name from "module-name";
(:require ["module-name" :as name])

import { export } from "module-name";
(:require ["module-name" :refer (export)])

import { export as alias } from "module-name";
(:require ["module-name" :refer (export) :rename {export alias}])

import defaultExport from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
;; 无法轻松访问defaultExport
`

我建议在{{:require}}中添加一个{{:default}}。

(:require ["module-name" :as mod :default foo])

这使得从CLJS中使用重写的ES6代码变得非常方便。如果"module-name"有默认导出,当前您必须到处编写{{mod/default}},因为无法轻易地对默认别名。

`
(:require ["material-ui/RaisedButton" :as RaisedButton])
;; :as 是错误的,现在用户必须使用
RaisedButton/default

(:require ["material-ui/RaisedButton" :default RaisedButton])
;; 将允许直接使用
RaisedButton
`

内部,Closure编译器(以及由babel重写的ES6代码)会将默认导出重写为{{.default}}属性,因此{{:default}}实际上仅仅是一个方便的方式来访问它。

已经可以工作的是长版本

(:require ["material-ui/RaisedButton" :refer (default) :rename {default RaisedButton}])

当ES6变得更加普及时,我们应该有方便的方式来正确地引用“默认”导出。

(链接:1) https://mdn.org.cn/en-US/docs/Web/JavaScript/Reference/Statements/import

10 个答案

0 投票

评论者:deraen

首先谈谈实施情况。这种实现方式在最低层({{parse-require-spec}})将{{:default name}}重写为{{:refer [default] :rename {default name}}},因此我认为不需要更改其他函数。

我还没有更新require规范验证错误。

0 投票

评论者:dnolen

在我看来,ES6默认导入的最理想语法是以下这种

(:require ["material-ui/RaisedButton" :refer [RaisedButton]])

我不明白我们为什么不能让它工作?

0 投票

评论者:thheller

我不理解这个提议。默认导出没有名称,{{.default}}属性仅在转译器交互中使用。在实际的JavaScript中,使用一个活动引用。您如何将{{RaisedButton}}映射回{{default}}?

{{["material-ui/RaisedButton" :default foo]}}将是有效的。JS模块实际上可能有export { RaisedButton }export default ...两种导出声明,这可能导致您猜测错误名称时发生冲突。默认导出不是模块本身的别名,这是分开的。

我创建了一个参考翻译表(链接:1),添加{{:default}}别名是唯一可靠映射所有ES6导入/导出功能的方式。我看不出有办法让{{:refer}}工作,而不会完全不直观且不可靠。

import defaultExport, * as name from "module-name";

(链接:1) https://shadow-cljs.github.io/docs/UsersGuide.html#_using_npm_packages

0 投票

评论者:dnolen

请在这个讨论中不要涉及修辞,专注于技术细节。我只是不想在ns形式中包含另一个指令,我更倾向于避免这种方法的方案。从我的观点来看,对那个替代方案的研究还没有足够。

这个工单主要关注便利性,我认为我们在这件事情上需要多思考一段时间才能做出决定。

0 投票

评论者:jcr

我们为什么要使用元数据来处理这个问题呢?也就是说。

(:require ["material-ui/RaisedButton" :refer [^:default RaisedButton]]) (:require ["module-name" :as mod :refer [^:default foo]) (:require ["module-name" :refer [^:default foo, bar, baz]])

这不需要额外的ns指令,也不会引起任何歧义。

由于这个(:require)没有被用于宏(即我们使用 :require-macros 而不是 plain :require + ^:macros 或 :refer (link: ^:macro foo)),我假设可能存在一些我不太了解的细微差别,阻止了它的实现。有吗?

0 投票
by
_由 thheller 评论

从实现的角度来看,{{^:default}} 指示对我而言似乎变得更为复杂。

在 Java/JVM 和 Clojure 中没有默认导入/导出的等价项。在 CommonJS 中甚至也没有。这严格来说是 ES6 的事情。因此,将其附加到“其他”方法在我看来是错误的。

在我看来,它应该独立存在的原因是使用 {{.default}} 属性不是严格正确的,而其存在纯粹是为了与 CommonJS 兼容。在严格的 ES6 中,它们不是由 {{:as}} 创建的“Object”部分。


;; a.js
export let a = 1;
export let b = 2;
export default 3;

;; b.js
import x, * as y from "./a.js"

// 这些是存在的
y.a
y.b
// 在 ES6 中这是无效的,也不存在
y.default
// 相反,必须使用 x
x


考虑到 CLJS 不生成 ES6,我们目前确实依赖于 {{.default}} 属性的存在。{{webpack}} 已经更改了处理默认导出的方式,我预期未来 Closure Compiler 也会进行类似的操作。
0 投票
by

评论者:thheller

事实上,我是错的。我重新阅读了规范和 {{.default}} 实际上被定义为一个 getter,因此它是可访问的。那么我之前的帖子就忽略了吧。

但这并没有改变我对 {{:default}} 作为更简单别名的有用性的看法。

0 投票
by

由 pesterhazy 评论

我遇到了常见的 ES6 默认导出,人们在代码中通常会犯错,例如: https://github.com/pesterhazy/cljs-spa-example/issues/13。我想报告我的发现。

正如问题的描述中所解释的,您可以使用 :refer:rename 的组合来从代码中删除对 :default 的引用,将其移动到 NS 声明中。这不是最优雅的解决方案,但可以完成任务,并且可以与全局导出一起工作:https://github.com/pesterhazy/cljs-spa-example/pull/14/files

注意,根据我的理解,因为 default 在 ES3 中是一个严格的保留字,您需要设置以下编译器选项才能使这一操作有效

:language-out :ecmascript5

否则 default 会被修改为 default$

0 投票
已回答 jira
参考:https://clojure.atlassian.net/browse/CLJS-2376(由thheller报告)
0 投票
已回答 Orestis Markou

对此的“官方”修复方案在此处文档化:https://clojure.atlassian.net/browse/CLJS-3235

...