306

I am currently using ES6 in an React app via webpack/babel. I am using index files to gather all components of a module and export them. Unfortunately, that looks like this:

import Comp1_ from './Comp1.jsx';
import Comp2_ from './Comp2.jsx';
import Comp3_ from './Comp3.jsx';

export const Comp1 = Comp1_;
export const Comp2 = Comp2_;
export const Comp3 = Comp3_;

So I can nicely import it from other places like this:

import { Comp1, Comp2, Comp3 } from './components';

Obviously that isn't a very nice solution, so I was wondering, if there was any other way. I don't seem to able to export the imported component directly.

sergioviniciuss
  • 4,596
  • 3
  • 36
  • 50
MoeSattler
  • 6,684
  • 6
  • 24
  • 44
  • Possible duplicate of [import modules from files in directory](http://stackoverflow.com/questions/29722270/import-modules-from-files-in-directory) – Inanc Gumus Feb 20 '17 at 18:21

8 Answers8

550

You can easily re-export the default import:

export {default as Comp1} from './Comp1.jsx';
export {default as Comp2} from './Comp2.jsx';
export {default as Comp3} from './Comp3.jsx';

There also is a proposal for ES7 ES8 that will let you write export Comp1 from '…';.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 2
    See also similar patterns [here](http://stackoverflow.com/a/32230064/1048572) and [here](http://stackoverflow.com/q/29722270/1048572) – Bergi Dec 03 '15 at 17:47
  • 6
    In addition to the ES8 proposal, you can use code generation to maintain index files. Have a look at https://github.com/gajus/create-index and https://github.com/ryardley/indexr. – Gajus Aug 14 '16 at 22:48
  • @Bergi So these 3 lines do both the import and export? Or is this just exporting but you no longer need to fiddle with the Comp1_ name etc.? – musicformellons Sep 24 '16 at 11:21
  • @musicformellons They directly export from the referenced module, yes. – Bergi Sep 24 '16 at 12:46
  • @Bergi I've used this quite heavily in a codebase with 275 modules at the moment. Could it be that this is actually quite problematic because it will create a whole lot of circular references given that components also compose other components? I'm wondering if I should revert from this technique completely. Do you by chance know a good workaround? Btw. I've not only used this for components, but also utility classes, etc. – amann Oct 14 '16 at 14:07
  • 2
    @amann A circular reference of itself is not bad, but *can* lead to problems depending on what the module does. Regardless, I think you should only use this pattern in the index file of your library to export all components, and if you have inter-module dependencies you should import them directly instead of importing the part from the large one. With that, no circular references are introduced by this pattern. – Bergi Oct 14 '16 at 17:11
  • @Bergi thanks for the quick response! You're right, that could help indeed. I'll investigate a bit more. Recently I've encountered a problem where a higher order component with `import {withLoadedData} from 'utils/HOC';` failed to execute, because the function wasn't defined in the moment it should execute in file it is imported into (these are a bit more problematic because that code runs immediately, whereas a imported React component only executes in render for example). I'll try to resolve the circular dependencies between the lib modules and see if that helps. Thanks again! – amann Oct 17 '16 at 08:00
  • @Bergi can you do a default export in a similar fashion? I've got `export default from './AppBar';` however I get `Module build failed: SyntaxError: Unexpected token, expected ; (3:20)` when web pack tries to build – Tyler Dec 29 '16 at 17:32
  • @Tyler [yes you can](http://stackoverflow.com/a/32230064/1048572), what you tried is [not yet](https://github.com/leebyron/ecmascript-export-default-from) supported – Bergi Dec 29 '16 at 19:27
  • Is tree shaking with this approach still possible? – David Spiess Jul 03 '17 at 09:26
  • @DavidSpiess yes, all it requires are individual exports. – Bergi Jul 03 '17 at 12:53
  • @Bergi Is there a way to export all default components in a dir as named exports by filename with a single line? Like `export default from "./*"`? A syntax like this should re-export default `Comp1`, `Comp2` and `Comp3` exports as named exports for consumer code when these components are loaded from this file. The purpose is to automatically export the default exports of new files added to the directory to be available as named exports in the client code... Is it possibile? – tonix Apr 13 '20 at 08:12
  • @tonix Not with EcmaScript itself, no, but there are tools for your build chain that can automatically generate these files or hook in the module resolution to provide a "virtual" module with these exports. – Bergi Apr 13 '20 at 12:29
  • Could you advise please which tools are they and where I can find them? Thank you! – tonix Apr 13 '20 at 13:45
  • @tonix No, it depends on your toolchain (i.e. what is already in place) and what exact solution you are looking for. Just search for the name of your bundling tool and the term "index module". – Bergi Apr 13 '20 at 17:05
  • Using both Webpack and Rollup, will google around, thanks! – tonix Apr 13 '20 at 19:53
  • Is it possible to also export the named exports from the same file in one line? Or does that require two `export` statements? – Henry Woody Oct 07 '20 at 01:00
  • @HenryWoody No, `export * from '…';` requires a second export declaration. – Bergi Oct 07 '20 at 07:32
  • @DavidSpiess This technique is very powerful and expressive, however it can disable tree shaking if the modules are in turn importing other libraries. In that case you should disable sideEffects, see https://github.com/vercel/next.js/issues/12557#issuecomment-1318932358 – Giorgio Tempesta Feb 01 '23 at 15:53
86

Also, bear in mind that if you need to export multiple functions at once, like actions you can use

export * from './XThingActions';
G. M.
  • 1,835
  • 14
  • 12
  • 23
    Yes. Unforunately this _only_ takes named exports, i.e. it does not include the default export. – ArneHugo Dec 15 '16 at 08:37
  • get's me a (pretty misleading... took me a moment) `SyntaxError: Unexpected reserved word`, @Bergi's accepted answer does work. – Frank N Aug 05 '17 at 10:17
  • You can also name your default export to get around that issue. And your actions shouldn't really have a default export so this solution works well. – Barry Michael Doyle Mar 19 '18 at 08:27
  • 5
    best practice is to not use default exports in javascript, unnecessary extra syntax. @G.M. has the best answer on this thread for modern javascript. – mibbit Aug 09 '18 at 00:11
  • re only taking named exports, you can do this: `import defaultExport from './myComponent';` `export default defaultExport;` `export * from './myComponent';` – Howard Jul 28 '23 at 17:00
51

default export

// Default export (recommended)
export {default} from './module' 

// Default export with alias
export {default as d1} from './module' 

all export

// In >ES7, it could be
export * from './module'

// In >ES7, with alias
export * as d1 from './module'

function name export

// export by function names
export { funcName1, funcName2, …} from './module'

// export by aliases
export { funcName1 as f1, funcName2 as f2, …} from './module'

destructured object export

// export destructured object
export const { myVar, myFunction } = myObjectWithEverything

// export destructured object, with renaming
export const { v1: myVar, f1: myFunction } = myBigObject

with array

// it works with array as well
export const [ funcName1, funcName2 ] = myBigArray

More infos: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

pirs
  • 2,410
  • 2
  • 18
  • 25
  • 2
    2 points for {default}! Had no idea something nice like this existed. – ankush981 Oct 14 '21 at 14:19
  • 1
    If you have an `export myFile` in a file, then a `const myFile = require('/myfile')` in other file, you could `console.log('myFile')` to see that `import` add an overlayer in the object and you will see argument `default` as well in your imported object. – pirs Oct 16 '21 at 07:03
49

Too late but I want to share the way that I resolve it.

Having model file which has two named export:

export { Schema, Model };

and having controller file which has the default export:

export default Controller;

I exposed in the index file in this way:

import { Schema, Model } from './model';
import Controller from './controller';

export { Schema, Model, Controller };

and assuming that I want import all of them:

import { Schema, Model, Controller } from '../../path/';
Javier Aguila
  • 574
  • 4
  • 5
12

Folder structure:

components|
          |_Comp.js
          |_AnotherComp.js
          |_YetAnotherComp.js
          |_index.js

in Comp.js file.. and do similar to other components:

export {Comp}

from index.js

export {Comp} from './Comp';
export {AnotherComp} from './AnotherComp';
export {YetAnotherComp} from './YetAnotherComp';

now you can import anywhere

import {Comp, AnotherComp, YetAnotherComp} from './components'
Rezan Moh
  • 336
  • 2
  • 7
3

I've been searching for years how to export modules as both, named exports, and default exports in modular JavaScript. After tons of experimenting, the solution I found is quite simple and efficient.

// index.js
export { default as Client } from "./client/Client.js";
export { default as Events } from "./utils/Events.js";

// Or export named exports
export { Client } from "./client/Client.js";
export { Events } from "./utils/Events.js";

export * as default from "./index.js";

This would allow each exported module to be imported in two ways:

// script.js
import { Client } from "index.js";
new Client();

import module from "index.js";
new module.Client();

// You could also do this if you prefer to do so:
const { Client } = module;

You can mess around with this to have it suit your needs, but it works for me. Hope it helps!

Calculamatrise
  • 364
  • 3
  • 6
1

What worked for me was adding the type keyword:

export type { Comp1, Comp2 } from './somewhere';
wilbo
  • 71
  • 1
  • 2
0

Install @babel/plugin-proposal-export-default-from via:

yarn add -D @babel/plugin-proposal-export-default-from

In your .babelrc.json or any of the Configuration File Types

module.exports = {
  //...
  plugins: [
     '@babel/plugin-proposal-export-default-from'
  ]
  //...
}

Now you can export directly from a file-path:

export Foo from './components/Foo'
export Bar from './components/Bar'

Good Luck...

Sasha Kondrashov
  • 4,038
  • 1
  • 18
  • 29
Aakash
  • 21,375
  • 7
  • 100
  • 81
  • 1
    How to do it for Create-React-App without ejecting? – Negin Basiri May 28 '20 at 05:27
  • Thank you for the answer. I think this is a little scoped for some specific project, but in other ones such as react-react-app or nextjs doesn't seem to work properly – Jhonatan Mar 23 '22 at 12:09