Clojure 2024 调查 中分享您的想法!

欢迎!有关本网站的更多详细信息,请参阅 关于 页面。

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
`

我建议在(ns :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 spec验证错误。

0

评论人:dnolen

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

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

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

0

评论人:thheller

我不理解这个建议。默认导出没有名字,{{.default}}属性仅在_transpilers的互操作性中使用。在实际的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 (链接:^:macro foo)),我假设可能有一些我不了解的细微差别阻止了实施。有这些细微差别吗?

0
by
评论者:thheller_

The {{^: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

注意,根据 AIUI,因为 default 是 ES3 中的严格关键字,您需要设置以下编译器选项才能使它工作

:language-out :ecmascript5

否则 default 将被重新命名为 default$

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

有关此问题的“官方”修正方法,请参阅此处:https://clojure.atlassian.net/browse/CLJS-3235

...