For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/year/pending/proposal-export-star-default.md.
  • 简体中文
  • export all from S1

    中文标题:导出全部

    提案概览
    提案速览

    该提案旨在更改 export * from 'module' 的行为,使其也包含默认导出,目前默认导出被排除在外。这将消除额外显式重新导出语句的需要,并简化模块包装和索引模块模式。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    ECMAScript 提案:在 export * from 'module' 中包含默认导出

    阶段: 1

    作者:Nicolò Ribaudo(前作者:Guy Bedford)

    审阅者: Guy Bedford, Caio Lima

    规范: http://tc39.es/proposal-export-star-default/

    演示文稿:

    • 2016-11:为阶段 1 演示,未达成共识(笔记
    • 2026-05:为阶段 1 演示,达成共识(幻灯片笔记

    动机

    在当前规范中,export * from 'module' 将导出所有命名导出,但默认导出除外

    然而,有些用例需要能够在内部私有模块中定义 default 导出,并通过 export * 将其暴露出来。

    1. 与命名导出的对称性

    考虑一个模块 X,既有命名导出又有默认导出,并通过另一个模块重新导出。我们然后在 reexport1.js 中用显式名称重新导出该模块,在 reexport2.js 中用 export * 重新导出:

    x.js

    export default 'default';
    export let name = 'name';

    重新导出的变体:

    reexport1.js

    export { name, default } from './x.js';

    reexport2.js

    export * from './x.js';

    在第一个变体中,我们可以像显式导出一样导入默认导出:

    import { name } from './reexport1.js';
    import { default } from './reexport1.js';
    
    import * as A from './reexport1.js';
    A.default;
    // -> 'default'

    而在 export * 重新导出的变体中,默认导出不可用:

    import { name } from './reexport2.js';
    import { default } from './reexport2.js';
    // Syntax Error: 'default' is not exported
    
    import * as B from './reexport2.js';
    B.default
    // -> undefined

    这打破了用户直觉,即 default 像其他任何命名导出一样是命名导出。

    2. 创建索引模块

    在 NodeJS 中,约定使用 index.js 作为包的主要入口点。

    如果我们想使用 export * 语句来暴露子文件夹中的模块,从而创建这个模块,我们不能以这种方式导出默认导出:

    index.js

    export * from './lib/package-core.js';
    export let extraInfo = 'abc';

    如果 lib/package-core.js 包含默认导出,我们将无法暴露它。

    我们需要显式导出默认导出:

    index.js

    export * from './lib/package-core.js';
    export { default } from './lib/package-core.js';
    export let extraInfo = 'abc';

    以确保获得预期的入口点模块值。

    问题在于,如果我们从 lib/package-core.js 中移除默认导出,我们将在 index.js 中得到一个 SyntaxError,提示默认导出不再存在。移除默认导出的更改需要在两个地方进行。

    上述模式也已在 npm 上的 index.js 模块中广泛出现,形式如下:

    module.exports = require('./lib/package.js');

    我们知道 index.js 模块将与内部模块完全匹配。

    3. 动态包装

    重新导出默认导出的情况也可以扩展到这样的用例:我们希望动态生成一个模块包装器,暴露另一个模块的导出,而无需提前知道其导出名称。

    考虑一个 npm CDN 的用例,它允许像 https://npmcdn.com/lodash 这样的快捷 URL,然后暴露一个完整版本化 URL 的模块,如 https://npmcdn.com/lodash@4.17.2/index.js

    https://npmcdn.com/lodash 动态生成的模块可能如下所示:

    export * from './lodash@4.17.2/index.js';

    但如果存在默认导出,我们必须提供不同的响应:

    export * from './lodash@4.17.2/index.js';
    export { default } from './lodash@4.17.2/index.js';

    如果我们不包含需要的默认导出,可能会遗漏 default;但如果我们在不需要时包含它,则会出错。因此,这种限制给原本简单的服务器响应增加了一个新的静态分析关注点。

    提案

    该提案旨在从当前规范中移除 export *default 的特殊处理,以简化 export * 的对称性,并启用上述更简单的模块包装用例。

    此更改与现有规范向后兼容,结果是禁用通过 export * 导入默认导出时的语法错误,并使 default 在这种情况下的模块命名空间对象上作为命名导出可用。

    http://guybedford.github.io/proposal-export-star-default/

    处理歧义

    将默认导出包含在 export * 中的一个担忧是如何处理冲突,但 export * 已经设计得很好处理歧义——当一个模块中的两个 export * 语句解析到相同的导出名称时,会抛出 SyntaxError,如 15.2.1.16.4 12.d.ii) 所述:

    x.js

    export default 'x';
    export let name = 'nameX';

    y.js

    export default 'y';
    export let name = 'nameY';

    z.js

    export * from './x.js';
    export * from './y.ys';

    当我们尝试通过

    import { name } from './z.js';

    导入 name 时,我们将得到 SyntaxError,提示 name 是歧义的。

    可以通过显式指示一个模块来导出 name 来解决此冲突:

    z.js

    export * from './x.js';
    export * from './y.ys';
    export { name } from './x.js';

    现在当我们从 z.js 导入 name 时,它将正确解析。

    通过此规范更改,相同的歧义解析过程将应用于默认导出:

    import { default } from './z.js';

    将抛出 SyntaxError。

    z.js

    export * from './x.js';
    export * from './y.ys';
    export { default } from './x.js';

    将提供显式优先级来解决该 SyntaxError,从而在通过 export * 处理命名导出和默认导出之间的冲突时提供对称性。