[javascript] Is it possible to import modules from all files in a directory, using a wildcard?

With ES6, I can import several exports from a file like this:

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?

This question is related to javascript ecmascript-6 es6-modules

The answer is


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:

// 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 /):

$ 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:

// 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:

// 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 destructuring import { Matters, Contacts } from './collections'; in the previous example.

$ 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.js to 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".

If you want a particular file, import thingA from './myLib/thingA'; in your own projects.

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.

Made it this far? See the docs for more details.

Also, yay for Stackoverflow finally supporting three `s as code fence markup.


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).

Usage (currently you'll need to use babel to use the export file):

$ 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()

I was able to take from user atilkan's approach and modify it a bit:

For Typescript users;

require.context('@/folder/with/modules', false, /\.ts$/).keys().forEach((fileName => {
    import('@/folder/with/modules' + fileName).then((mod) => {
            (window as any)[fileName] = mod[fileName];
            const module = new (window as any)[fileName]();

            // use module
});

}));

You can use require as well:

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:

  loadModules(DIR) 
  for (const controller of moduleHolder) {
    controller(app, db)
  }

Just an other approach to @Bergi's answer

// 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';

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

export const example = 'example';
export const anotherExample = 'anotherExample';

./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

import { example, anotherExample } from './modules'

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')
  });
});

if you don't export default in A, B, C but just export {} then it's possible to do so

// things/A.js
export function A() {}

// things/B.js
export function B() {}

// things/C.js
export function C() {}

// foo.js
import * as Foo from ./thing
Foo.A()
Foo.B()
Foo.C()

This is not exactly what you asked for but, with this method I can Iterate throught componentsList in my other files and use function such as componentsList.map(...) which I find pretty usefull !

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;

If you are using webpack. This imports files automatically and exports as api namespace.

So no need to update on every file addition.

import camelCase from "lodash-es";
const requireModule = require.context("./", false, /\.js$/); // 
const api = {};

requireModule.keys().forEach(fileName => {
  if (fileName === "./index.js") return;
  const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ""));
  api[moduleName] = {
    ...requireModule(fileName).default
  };
});

export default api;

For Typescript users;

import { camelCase } from "lodash-es"
const requireModule = require.context("./folderName", false, /\.ts$/)

interface LooseObject {
  [key: string]: any
}

const api: LooseObject = {}

requireModule.keys().forEach(fileName => {
  if (fileName === "./index.ts") return
  const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ""))
  api[moduleName] = {
    ...requireModule(fileName).default,
  }
})

export default api

Just a variation on the theme already provided in the answer, but how about this:

In a Thing,

export default function ThingA () {}

In 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'

The current answers suggest a workaround but it's bugged me why this doesn't exist, so I've created a babel plugin which does this.

Install it using:

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

then add it to your .babelrc with:

{
    "plugins": ["wildcard"]
}

see the repo for detailed install info


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 repo contains further information on what exactly it does, but doing it this way avoids creating index.js files and also happens at compile-time to avoid doing readdirs at runtime.

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.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to ecmascript-6

"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6 where is create-react-app webpack config and files? Can (a== 1 && a ==2 && a==3) ever evaluate to true? How do I fix "Expected to return a value at the end of arrow function" warning? Enums in Javascript with ES6 Home does not contain an export named Home How to scroll to an element? How to update nested state properties in React eslint: error Parsing error: The keyword 'const' is reserved Node.js ES6 classes with require

Examples related to es6-modules

How can I use an ES6 import in Node.js? Using import fs from 'fs' ES6 modules in the browser: Uncaught SyntaxError: Unexpected token import What is difference between Axios and Fetch? How can I alias a default import in JavaScript? `export const` vs. `export default` in ES6 Javascript ES6 export const vs export let Is it possible to import modules from all files in a directory, using a wildcard?