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

首先关于实现的提法。这个实现将{{:default name}}重写为{{:refer [default] :rename {default name}}}最低层({{parse-require-spec}}),因此我认为其他函数无需更改。

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

0

评论者:dnolen

在我看来,ES6默认导入的理想语法如下

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

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

0

评论者:thheller

我不明白这个建议。默认导出没有名称,{{.default}}属性仅在转译器中的交互中使用。在真正的JS中,使用的是活动引用。你将如何将{{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-macros代替plain:require + ^:macros或:refer (link: ^:macro foo)),我猜测可能有些我不太了解的细微之处阻止了它的实现。有吗?

0
by
评论者: thheller

对我来说,{{^:default}} 这个提示在实现上似乎更加复杂。

Java/JVM和Clojure没有默认import/export的等价实现。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
by

评论者:thheller

实际上,我是错的。重新阅读说明,{{.default}}实际上被定义为getter,因此它是可访问的。那么我之前的帖子就失效了。

但这并没有改变我认为 {{:default}} 作为更简单的映射方法的实用性。

0
by

评论者: 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

请注意,根据我的理解,由于 default 是ES3中严格的keyword,您需要设置以下编译器选项才能使这可行

:language-out :ecmascript5

否则,default会被破坏成default$

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

此问题的“官方”解决方案在此处记录:https://clojure.atlassian.net/browse/CLJS-3235

...