Javascript 是否可以使用通配符从目录中的所有文件导入模块?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29722270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to import modules from all files in a directory, using a wildcard?
提问by Frambot
With ES6, I can import several exports from a file like this:
使用 ES6,我可以从这样的文件中导入多个导出:
import {ThingA, ThingB, ThingC} from 'lib/things';
However, I like the organization of having one module per file. I end up with imports like this:
但是,我喜欢每个文件有一个模块的组织。我最终得到这样的进口:
import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';
I would love to be able to do this:
我希望能够做到这一点:
import {ThingA, ThingB, ThingC} from 'lib/things/*';
or something similar, with the understood convention that each file contains one default export, and each module is named the same as its file.
或类似的东西,根据理解的约定,每个文件包含一个默认导出,并且每个模块的名称与其文件相同。
Is this possible?
这可能吗?
采纳答案by Bergi
I don't think this is possible, but afaik the resolution of module names is up to module loaders so there might a loader implementation that does support this.
我不认为这是可能的,但是 afaik 模块名称的解析取决于模块加载器,因此可能有一个加载器实现支持这一点。
Until then, you could use an intermediate "module file" at lib/things/index.jsthat just contains
在那之前,你可以使用一个中间的“模块文件” lib/things/index.js,它只包含
export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';
and it would allow you to do
它可以让你做
import {ThingA, ThingB, ThingC} from 'lib/things';
回答by Jed Richards
Just a variation on the theme already provided in the answer, but how about this:
只是答案中已经提供的主题的一个变体,但是这个怎么样:
In a Thing,
在Thing,
export default function ThingA () {}
In things/index.js,
在things/index.js,
export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'
Then to consume all the things elsewhere,
然后去消费别处的所有东西,
import * as things from './things'
things.ThingA()
Or to consume just some of things,
或者只是消费一些东西,
import {ThingA,ThingB} from './things'
回答by Downgoat
The current answers suggest a workaround but it's bugged me why this doesn't exist, so I've created a babelplugin which does this.
当前的答案提出了一种解决方法,但它让我烦恼为什么它不存在,所以我创建了一个babel插件来做到这一点。
Install it using:
使用以下方法安装它:
npm i --save-dev babel-plugin-wildcard
then add it to your .babelrcwith:
然后将其添加到您.babelrc的:
{
"plugins": ["wildcard"]
}
see the repofor detailed install info
有关详细的安装信息,请参阅repo
This allows you to do this:
这允许您执行以下操作:
import * as Things from './lib/things';
// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;
again, the repocontains further information on what exactly it does, but doing it this way avoids creating index.jsfiles and also happens at compile-time to avoid doing readdirs at runtime.
同样,repo包含有关它究竟做什么的更多信息,但这样做可以避免创建index.js文件,并且也会在编译时发生以避免readdir在运行时执行s。
Also with a newer version you can do exactly like your example:
同样使用较新的版本,您可以完全按照您的示例进行操作:
import { ThingsA, ThingsB, ThingsC } from './lib/things/*';
works the same as the above.
与上述相同。
回答by Michael Cole
Great gugly muglys! This was harder than it needed to be.
伟大的咕噜咕噜!这比它需要的更难。
Export one flat default
导出一个平面默认值
This is a great opportunity to use spread(...in { ...Matters, ...Contacts }below:
这是使用一个很好的机会传播(...在{ ...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: '[email protected]',
};
// 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);
Then, to run babel compiled code from the command line(from project root /):
然后,从命令行(从项目根 /)运行 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: '[email protected]' }
Export one tree-like default
导出一棵树状默认值
If you'd prefer to not overwrite properties, change:
如果您不想覆盖属性,请更改:
// imports/collections/index.js
import Matters from './Matters'; // import default as 'Matters'
import Contacts from './Contacts';
export default { // export default
Matters,
Contacts,
};
And the output will be:
输出将是:
$ npx babel-node --presets @babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
Contacts: { hello: 'Moon', email: '[email protected]' } }
Export multiple named exports w/ no default
导出多个命名导出,无默认值
If you're dedicated to DRY, the syntax on the imports changes as well:
如果您专注于DRY,则导入的语法也会发生变化:
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
This creates 2 named exports w/ no default export. Then change:
这将创建 2 个没有默认导出的命名导出。然后改变:
// imports/test.js
import { Matters, Contacts } from './collections';
console.log(Matters, Contacts);
And the output:
和输出:
$ npx babel-node --presets @babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: '[email protected]' }
Import all named exports
导入所有命名的导出
// 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);
Notice the destructuringimport { Matters, Contacts } from './collections';in the previous example.
请注意上一个示例中的解构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: '[email protected]' }
In practice
在实践中
Given these source files:
鉴于这些源文件:
/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js
Creating a /myLib/index.jsto bundle up all the files defeats the purpose of import/export. It would be easier to make everything global in the first place, than to make everything global via import/export via index.js "wrapper files".
创建一个/myLib/index.js来捆绑所有文件违背了导入/导出的目的。首先将所有内容设为全局性比通过 index.js“包装文件”导入/导出使所有内容全局化要容易得多。
If you want a particular file, import thingA from './myLib/thingA';in your own projects.
如果你想要一个特定的文件,import thingA from './myLib/thingA';在你自己的项目中。
Creating a "wrapper file" with exports for the module only makes sense if you're packaging for npm or on a multi-year multi-team project.
仅当您为 npm 或多年多团队项目打包时,为模块创建带有导出的“包装文件”才有意义。
Made it this far? See the docsfor more details.
走到这一步了吗?有关更多详细信息,请参阅文档。
Also, yay for Stackoverflow finally supporting three `s as code fence markup.
另外,是的,Stackoverflow 终于支持三个`s 作为代码围栏标记。
回答by mr_squall
You can use async import():
您可以使用异步导入():
import fs = require('fs');
and then:
进而:
fs.readdir('./someDir', (err, files) => {
files.forEach(file => {
const module = import('./' + file).then(m =>
m.callSomeMethod();
);
// or const module = await import('file')
});
});
回答by Nicolas
Similar to the accepted question but it allows you to scale without the need of adding a new module to the index file each time you create one:
类似于已接受的问题,但它允许您在每次创建一个新模块时无需向索引文件添加新模块的情况下进行扩展:
./modules/moduleA.js
./modules/moduleA.js
export const example = 'example';
export const anotherExample = 'anotherExample';
./modules/index.js
./modules/index.js
// require all modules on the path and with the pattern defined
const req = require.context('./', true, /.js$/);
const modules = req.keys().map(req);
// export all modules
module.exports = modules;
./example.js
./example.js
import { example, anotherExample } from './modules'
回答by Jamesernator
I've used them a few times (in particular for building massive objects splitting the data over many files (e.g. AST nodes)), in order to build them I made a tiny script (which I've just added to npm so everyone else can use it).
我已经使用过它们几次(特别是用于构建将数据拆分到多个文件(例如 AST 节点)的大型对象),为了构建它们,我制作了一个小脚本(我刚刚添加到 npm 以便其他人可以使用)。
Usage (currently you'll need to use babel to use the export file):
用法(目前你需要使用 babel 来使用导出文件):
$ npm install -g folder-module
$ folder-module my-cool-module/
Generates a file containing:
生成包含以下内容的文件:
export {default as foo} from "./module/foo.js"
export {default as default} from "./module/default.js"
export {default as bar} from "./module/bar.js"
...etc
Then you can just consume the file:
然后您可以使用该文件:
import * as myCoolModule from "my-cool-module.js"
myCoolModule.foo()
回答by Ashok Vishwakarma
Just an other approach to @Bergi's answer
只是@Bergi 回答的另一种方法
// lib/things/index.js
import ThingA from './ThingA';
import ThingB from './ThingB';
import ThingC from './ThingC';
export default {
ThingA,
ThingB,
ThingC
}
Uses
用途
import {ThingA, ThingB, ThingC} from './lib/things';
回答by mr_squall
You can use require as well:
您也可以使用 require:
const moduleHolder = []
function loadModules(path) {
let stat = fs.lstatSync(path)
if (stat.isDirectory()) {
// we have a directory: do a tree walk
const files = fs.readdirSync(path)
let f,
l = files.length
for (var i = 0; i < l; i++) {
f = pathModule.join(path, files[i])
loadModules(f)
}
} else {
// we have a file: load it
var controller = require(path)
moduleHolder.push(controller)
}
}
Then use your moduleHolder with dynamically loaded controllers:
然后将您的 moduleHolder 与动态加载的控制器一起使用:
loadModules(DIR)
for (const controller of moduleHolder) {
controller(app, db)
}
回答by FlyingZipper
This is not exactly what you asked for but, with this method I can Iterate throught componentsListin my other files and use function such as componentsList.map(...)which I find pretty usefull !
这不完全是您所要求的,但是,通过这种方法,我可以componentsList在我的其他文件中迭代并使用componentsList.map(...)我认为非常有用的函数!
import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';
import StepFour from './StepFour';
import StepFive from './StepFive';
import StepSix from './StepSix';
import StepSeven from './StepSeven';
import StepEight from './StepEight';
const componentsList= () => [
{ component: StepOne(), key: 'step1' },
{ component: StepTwo(), key: 'step2' },
{ component: StepThree(), key: 'step3' },
{ component: StepFour(), key: 'step4' },
{ component: StepFive(), key: 'step5' },
{ component: StepSix(), key: 'step6' },
{ component: StepSeven(), key: 'step7' },
{ component: StepEight(), key: 'step8' }
];
export default componentsList;

