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

欢迎!请参阅 关于 页面以获取更多关于如何使用本网站的信息。

0
ClojureScript

ES6 使用特殊语法进行 "默认" 导入,但目前 CLJS 在使用导入的 ES6 代码时没有等效功能。

`
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

评论者:deraan

首先考虑实现。本实现将{{:default name}}重写为{{:refer [default] :rename {default name}}}在最底层({{parse-require-spec}})进行,因此我认为不需要更改其他函数。

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

0

评论者:dnolen

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

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

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

0

评论者:thheller

我不明白这个建议。默认导出没有名字,{{.default}}属性仅在交互中由转译器使用。在实际的JavaScript中,使用的是活引用。你如何将{{RaisedButton}}映射回{{default}}?

{{["material-ui/RaisedButton" :default foo]}}是有效的。JavaScript模块实际上还可以有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
_评论由: 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}}被定义为getters,因此它是可访问的。那么就忽略我之前的帖子吧。

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

0

_评论由: pesterhazy_发表

我遇到了ES6默认导出的情况,这在现在很常见。大家在代码中都会遇到default,例如:https://github.com/pesterhazy/cljs-spa-example/issues/13。我想报告我的发现。

正如此问题描述中解释的那样,您可以使用:refer:rename的一组组合来去除代码中对:default的引用,将其移入命名空间声明中。这不是最优雅的解决方案,但能完成工作并与全局导出一起工作:https://github.com/pesterhazy/cljs-spa-example/pull/14/files

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

:language-out :ecmascript5

否则,default将被转换为default$

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

关于这个问题的“官方”修复方案请在这里查阅: https://clojure.atlassian.net/browse/CLJS-3235

...