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 spec验证错误。

0

评论者:dnolen

在我看来,ES6默认导入的最佳语法如下

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

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

0

评论者:thheller

我不明白那些建议。默认导出没有名字,{{.default}}属性只在互通转译器中使用。在实际的JS中,使用的是活生生的引用。你将如何将{{RaisedButton}}映射回{{default}}呢?

{{["material-ui/RaisedButton" :default foo]}}是有效的。JS模块实际上还可能有export { RaisedButton },这可能会在猜测错误时导致冲突。默认导出不是模块自身的别名,这是分开的。

我已经创建了一个引用转换表(链接: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-macros 而不是 plain :require + ^:macros 或 :refer (link: ^:macro foo)),我推测可能存在一些我不知道的细微差别,阻止了我实现它。有吗?

0
评论由:thheller_ 提出

在我看来,{{^:default}} 这个提示从实现角度来看似乎更为复杂。

在 Java/JVM 和 Clojure 中没有默认导入/导出的等价项。在 CommonJS 中也没有。这是 ES6 的特有内容。因此,将它们添加到“其他”方法中在我看来是不正确的。

在我个人看法中,它们应该分开的原因是,使用 {{.default}} 属性并不严格正确,而其存在纯粹是为了与 CommonJS 保持兼容。在严格的 ES6 中,它们不是由 {{:as}} 创建的“对象”的一部分。


;; 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

评论者:thheller

实际上我错了。重新阅读规范后,{{.default}} 实际上被定义为 getter,因此它是可以访问的。因此,我的上一条帖子就无所谓了。

但这并不改变我对 {{:default}} 作为简化别名方法的实用性的看法。

0

评论由:pesterhazy 提出

我遇到了在日常应用中常见的 ES6 默认导出问题。人们经常在代码中遇到 default,例如: https://github.com/pesterhazy/cljs-spa-example/issues/13。我想汇报我的发现。

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

请注意,AIUI,因为 default 是 ES3 中的一个严格关键字,您需要设置以下编译器选项才能使其正常工作

:language-out :ecmascript5

否则,default 将被转换为 default$

0
by
参考: https://clojure.atlassian.net/browse/CLJS-2376(由thheller报告)
0
by

该问题的“官方”修复方案已在以下文档中记录:https://clojure.atlassian.net/browse/CLJS-3235

...