如何选择性地导入 ES2015 模块功能,但使用命名空间?

Posted

技术标签:

【中文标题】如何选择性地导入 ES2015 模块功能,但使用命名空间?【英文标题】:How to import ES2015 modules functions selectively, but with namespacing? 【发布时间】:2017-02-03 00:48:48 【问题描述】:

我开始使用 Rollup 和 D3 版本 4,它是用 ES2015 模块编写的。我使用传统的 D3 命名空间“d3”编写了一些代码。现在我想使用 Rollup 创建一个自定义包。我想使用 tree-shaking,因为我可能只使用了 d3 中大约一半的功能,并且我希望尽可能地简化。

我很清楚我可以有选择地导入函数,例如:

import scaleLinear from "d3-scale";
import 
      event,
      select,
      selectAll
 from "d3-selection";

这很快就会变得非常冗长,因为 d3 的一半是很多函数。我可以忍受这一点。更大的问题是它还需要在没有命名空间的情况下完全重写我所有的函数标识符。我不太关心这个,因为我更喜欢命名库代码。

我知道我可以导入所有模块:

import * as d3 from "d3";

它保留了 d3 对象命名空间,这对我的代码组织很有好处。但是,Rollup 无法将未使用的函数从捆绑包中摇出。

我的梦想是这样的:

import 
      event,
      select,
      selectAll
 as d3 from "d3-selection";

但规范中似乎不存在这种功能/语法。如何有选择地针对模块的各个部分,并在导入期间保留命名空间?

【问题讨论】:

您可以使用 * 导入,只要您不使用命名空间本身(例如,将其传递给函数),Rollup 就会对它们进行树摇动。但是 tree-shaking 并不完美(因为 javascript 的性质),所以直接从 d3 导入将包含未使用的代码(我们正在努力使其变得更好),因此从您需要的模块中选择性地导入将始终为您提供最高度优化的捆绑包。我个人倾向于明确导入我实际使用的函数,但如果你不想这样做,@estus 有正确的想法。 @RichHarris 选择性导入(我假设您的意思是命名导入)如何导致与选择性使用命名空间对象不同的 tree-shaking? @Bergi 因为这样您就可以更轻松地从例如d3-selectiond3-scale 等,而不是 d3 @RichHarris 啊,您指的是选择模块,而不是导入的名称。我没有注意到子模块。 import * as d3 from "d3-selection"; import * as d3 from "d3-scale"; 当然也不起作用。 :-/ 2019 年现在有办法吗,还是这些答案仍然有效? 【参考方案1】:

为此,您需要一个重新导出模块:

export 
      event,
      select,
      selectAll
 from "d3-selection";

import * as d3 from './d3';

【讨论】:

【参考方案2】:

规范中似乎不存在这种功能/语法

不,这确实是不可能的。根据规范,一旦包含一个模块,就会评估并包含整个模块,因此不需要部分包含。命名空间对象始终允许访问模块的所有属性。

但是,Rollup 无法将未使用的函数从捆绑包中摇出。

这可能是 Rollup 的错,但实际上它能够静态分析代码以了解命名空间对象的使用情况,并找出使用了哪些属性。如果对象用于不是点成员访问的任何内容,则此优化可能需要退出,但通常这是很有可能的。如果它没有按预期工作,您可能需要提交错误报告(另请参阅troubleshooting)。

【讨论】:

Rollup 可以像任何其他语句一样摇树 import * as foo 语句——只要你不以导致它被“具体化”的方式使用命名空间(例如,将它传递给函数) @RichHarris 是的,这就是我的意思。 (我想我应该阅读文档以说明它已经实现,而不是要求提交功能请求)

以上是关于如何选择性地导入 ES2015 模块功能,但使用命名空间?的主要内容,如果未能解决你的问题,请参考以下文章

如何有条件地导入ES6模块?

如何有条件地导入 ES6 模块?

ES6,如何在一行中导出导入的模块?

如何使用 ES6 模块导入文件,并将其内容作为字符串读取?

如何将 typescript npm 模块导入语法转换为 ECMA2015 模块导入语法

Webpack es2015 用 React 摇树