是否可以使用通配符从目录中的所有文件导入module?

IT技术 javascript ecmascript-6 es6-modules
2021-01-11 15:49:29

使用 ES6,我可以从这样的文件中导入多个导出:

import {ThingA, ThingB, ThingC} from 'lib/things';

但是,我喜欢每个文件有一个module的组织。我最终得到这样的进口:

import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';

我希望能够做到这一点:

import {ThingA, ThingB, ThingC} from 'lib/things/*';

或类似的东西,根据理解的约定,每个文件包含一个默认导出,并且每个module的名称与其文件相同。

这可能吗?

6个回答

我不认为这是可能的,但是 afaik module名称的解析取决于module加载器,因此可能有一个加载器实现支持这一点。

在那之前,你可以使用一个中间的“module文件” lib/things/index.js,它只包含

export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';

它可以让你做

import {ThingA, ThingB, ThingC} from 'lib/things';
您是否必须指定索引文件,或者您可以只指定文件夹并加载 index.js 吗?
2021-03-16 15:49:29
@RodrigoMata 不,它实际上只是提供了这种分组(并定义了评估顺序,但这很少需要)。
2021-03-20 15:49:29
是的,如果每个 ThingA.js、ThingB.js 和每个导出的命名导出都有效,那么您的原始答案确实有效。发现。
2021-03-28 15:49:29
谢谢您的帮助。我能得到这个工作与index.js看起来像:import ThingA from 'things/ThingA'; export {ThingA as ThingA}; import ThingB from 'things/ThingB'; export {ThingB as ThingB};其他咒语index.js不会让步。
2021-03-29 15:49:29
嗯,export * from应该工作。您是否尝试过…from './ThingA'export ThingA from …你用的是什么module加载器?
2021-04-07 15:49:29

只是答案中已经提供的主题的一个变体,但是这个怎么样:

Thing,

export default function ThingA () {}

things/index.js,

export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'

然后去消费别处的所有东西,

import * as things from './things'
things.ThingA()

或者只是消费一些东西,

import {ThingA,ThingB} from './things'
这是利用了三摇吗?如果我从 './things' 导入 {ThingA} 也会将 ThingB 和 ThingC 添加到包中吗?
2021-03-15 15:49:29
@Bergi 是的,我认为 wolfbiter 的 ES6 无效。也许他正在使用旧版本的 Babel 或其他一些转译器?
2021-03-27 15:49:29
你不能简单地输入export ThingA from './ThingA'而不是export {default as ThingA} from './ThingA'
2021-03-28 15:49:29
这是如何转译的?导入目录index.js对我来说无法解析我正在使用 SystemJs + Babel
2021-04-02 15:49:29
想看看@wolfbiter 的回答吗?不知道为什么他声称括号不起作用。
2021-04-03 15:49:29

当前的答案提出了一种解决方法,但它让我烦恼,为什么它不存在,所以我创建了一个babel插件来执行此操作。

使用以下方法安装它:

npm i --save-dev babel-plugin-wildcard

然后将其添加到您.babelrc的:

{
    "plugins": ["wildcard"]
}

有关详细的安装信息,请参阅repo


这允许您执行以下操作:

import * as Things from './lib/things';

// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;

再一次,repo包含关于它究竟做了什么的更多信息,但是这样做可以避免创建index.js文件,并且也会在编译时发生以避免readdir在运行时执行s。

同样使用较新的版本,您可以完全按照您的示例进行操作:

 import { ThingsA, ThingsB, ThingsC } from './lib/things/*';

与上述相同。

这是一个好主意,但我也无法让它发挥作用。可能与我的流类型代码有冲突,我不确定,但无论我如何构建导入,我都会收到“ReferenceError: Foo is not defined”。
2021-03-23 15:49:29
警告,我在使用此插件时遇到了严重问题。问题可能来自它的内部缓存,当您的代码完美时,您会费力气,但是您的脚本将无法正常工作,因为您添加了文件./lib/things;并且没有被提取。它引起的问题是荒谬的。我刚刚目睹了这种情况,当使用import *make babel更改文件以获取添加的文件时,但将其更改回来会带来问题,就像它重用更改前的缓存一样。谨慎使用。
2021-03-25 15:49:29
顺便说一句,任何有进一步问题的人,请添加,bpwc clear-cache因为 webpack 和其他构建过程仍将静默缓存
2021-03-27 15:49:29
@ŁukaszZaroda babel 有一个内部缓存~/.babel.json,导致这种奇怪的行为。此外,如果您像观察者或热重载器一样使用,则必须保存新文件,以便使用新目录列表重新编译
2021-04-04 15:49:29
@Downgoat 那么除了删除 babel 的缓存之外如何克服这个问题?顺便说一句。我不认为你的评论是正确的。我禁用了 babel 的缓存,并且该插件出现了如此大的问题。完全不推荐
2021-04-08 15:49:29

您现在可以使用异步导入():

import fs = require('fs');

接着:

fs.readdir('./someDir', (err, files) => {
 files.forEach(file => {
  const module = import('./' + file).then(m =>
    m.callSomeMethod();
  );
  // or const module = await import('file')
  });
});
这个答案帮助了我。由于包含了 Node.js 代码,我会给出一些 Deno 代码作为补充。const directory = new URL(".", import.meta.url).pathname; const fileItr = Deno.readDirSync(directory); const modulePromises = [...fileItr] .map((fileInfo) => import(`${directory}${fileInfo.name}`)); const modules = await Promise.all(modulePromises);
2021-03-24 15:49:29
例如,这可以在某些引导方法中,您希望从控制器文件中注册所有路由。
2021-03-28 15:49:29
我很难弄清楚这会去哪里。这会在index.js文件中找到以加载目录中的所有文件吗?而不是import('file')你也可以export * from 'file'吗?一点帮助?谢谢!
2021-04-03 15:49:29
动态导入就像那样很好。当提出问题时,它们肯定不存在。谢谢你的回答。
2021-04-07 15:49:29

伟大的 gugly muglys!这比它需要的更难。

导出一个平面默认值

这是使用一个很好的机会传播...{ ...Matters, ...Contacts }下面:

// imports/collections/Matters.js
export default {           // default export
  hello: 'World',
  something: 'important',
};
// imports/collections/Contacts.js
export default {           // default export
  hello: 'Moon',
  email: 'hello@example.com',
};
// imports/collections/index.js
import Matters from './Matters';      // import default export as var 'Matters'
import Contacts from './Contacts';

export default {  // default export
  ...Matters,     // spread Matters, overwriting previous properties
  ...Contacts,    // spread Contacts, overwriting previosu properties
};

// imports/test.js
import collections from './collections';  // import default export as 'collections'

console.log(collections);

然后,从命令行(从项目根目录 /)运行 babel 编译的代码

$ npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node 
(trimmed)

$ npx babel-node --presets @babel/preset-env imports/test.js 
{ hello: 'Moon',
  something: 'important',
  email: 'hello@example.com' }

导出一棵树状默认值

如果您不想覆盖属性,请更改:

// imports/collections/index.js
import Matters from './Matters';     // import default as 'Matters'
import Contacts from './Contacts';

export default {   // export default
  Matters,
  Contacts,
};

输出将是:

$ npx babel-node --presets @babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
  Contacts: { hello: 'Moon', email: 'hello@example.com' } }

导出多个命名导出,无默认值

如果您专注于DRY,则导入的语法也会发生变化:

// imports/collections/index.js

// export default as named export 'Matters'
export { default as Matters } from './Matters';  
export { default as Contacts } from './Contacts'; 

这将创建 2 个没有默认导出的命名导出。然后改变:

// imports/test.js
import { Matters, Contacts } from './collections';

console.log(Matters, Contacts);

和输出:

$ npx babel-node --presets @babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello@example.com' }

导入所有命名的导出

// imports/collections/index.js

// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
// imports/test.js

// Import all named exports as 'collections'
import * as collections from './collections';

console.log(collections);  // interesting output
console.log(collections.Matters, collections.Contacts);

请注意上一个示例中解构 import { Matters, Contacts } from './collections';

$ npx babel-node --presets @babel/preset-env imports/test.js
{ Matters: [Getter], Contacts: [Getter] }
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello@example.com' }

在实践中

鉴于这些源文件:

/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js

创建一个/myLib/index.js来捆绑所有文件违背了导入/导出的目的。首先将所有内容设为全局性比通过 index.js“包装文件”导入/导出使所有内容全局化要容易得多。

如果你想要一个特定的文件,import thingA from './myLib/thingA';在你自己的项目中。

仅当您为 npm 或多年多团队项目打包时,为module创建带有导出的“包装文件”才有意义。

走到这一步了吗?有关更多详细信息,请参阅文档

另外,是的,Stackoverflow 终于支持三个`s 作为代码围栏标记。