DEV Community

LuisPa
LuisPa

Posted on • Edited on

How to add Barrels in TypeScript (or JavaScript)

Hi!

This is a short post about how to create a useful import/export strategy on Typescript. Now, this is not an exclusive Typescript feature, but in this example, we will apply this to the TS environment.

The goal of this is to make the code more readable and maintainable once it gets it bigger and bigger.

A barrel's a way to put together all the same type or the same usage files in the same place, and then, use a unique file to import them and then export them at the same time.

Example

This is the scenario. We have 3 interfaces in our project interfaces folder and an index.ts file imported them on the root of the project

index.ts
interfaces/
  bear.interface.ts
  pig.interface.ts
  man.interface.ts
Enter fullscreen mode Exit fullscreen mode
// index.ts
import { Bear } from './interfaces/bear.interface';
import { Pig } from './interfaces/pig.interface';
import { Man } from './interfaces/man.interface';
Enter fullscreen mode Exit fullscreen mode

The only thing that it's common between these 3 files it's that all 3 contains interfaces.

As you can see, we have 3 import statements. This is a common and normal approach.

Using barrels.

This is the scenario when the barrels come on the scene. We can modify just a little bit out of the structure and we will have a more readable way to do the imports. You must follow these 3 steps.

  1. Adding a barrel file.

Add an index to the interfaces folder.

index.ts
interfaces/
  bear.interface
  pig.interface
  man.interface
  index.ts   <--- Barrel file
Enter fullscreen mode Exit fullscreen mode
  1. Import all the interfaces and then export them in the same file.
// ./interfaces/index.ts
export * from './bear.interface';
export * from './man.interface';
export * from './pig.interface';
Enter fullscreen mode Exit fullscreen mode
  1. Update your imports statements on the root of the project index file.
// **BEFORE** 
// index.ts
import { Bear } from './interfaces/bear.interface';
import { Pig } from './interfaces/pig.interface';
import { Man } from './interfaces/man.interface';

// **NOW** 
// index.ts
import { Bear, Pig, Man } from './interfaces';
Enter fullscreen mode Exit fullscreen mode

Wrap up

This barrel approach doesn't resolve a huge problem, but ovoid the quantity of readability of the code when de codebase gets bigger.

You can establish barrels on JS and TS as well.

And that's all for today.

Happy coding!

Top comments (14)

Collapse
 
macsikora profile image
Pragmatic Maciej

You should also add - don't do that ;)

Collapse
 
fjones profile image
FJones • Edited

Sorta. Don't do that... with a blanket export.

Having an index barrel with all available exports can be very useful for readability and makes it easier to move/rename the implementation files. (Think __init__.py indexes in python.) It also allows for implicit private exports which can be more easily respected by a module consumer.

That said, export * from 'foo' introduces magic that may in fact produce more opaque code instead. Prefer explicitly exporting the relevant symbols as an actual index.

Collapse
 
boywithsilverwings profile image
Agney Menon

I do believe the barrel pattern is useful in some cases. Like say, an API interface, so you can call the APIs with something like api.user.get, so user gets autocomplete on the APIs can narrow down from there. But putting interfaces/components there in the same name can get confusing real quick. With editors like VS Code that support automatic imports, all users would see two imports for this and then might end up picking the wrong one making the barrels kinda useless.

Collapse
 
luispa profile image
Info Comment hidden by post author - thread only accessible via permalink
LuisPa

Hi! What did you mean?

Collapse
 
macsikora profile image
Pragmatic Maciej

Tell me why I should maintain one + file for every directory and what is an issue to import file directly? And who puts one interface per file?

Thread Thread
 
adam_cyclones profile image
Adam Crockett 🌀

Probably more prevalent in declarative styles of codebase? I would see one or more varients in one file. But not just one interface.

Collapse
 
spock123 profile image
Lars Rye Jeppesen

Webpack has issues tree shaking this.

Collapse
 
javiasilis profile image
Jose

I've unfortunately learned the hard way at this. I love barreling and it does clean up your code considerably... But it harms all of the bundlers ability to tree shake (even when you have all the output for ES2017 or newer).

I'm currently undergoing a massive refactor in which I'm stripping all the barrels.

Collapse
 
bryanprimus profile image
Bryan Primus Lumbantobing

what did you do instead. I'm planning to do the same removing the barrel. but i couldn't find the right way.

My file importing so many components that I ended up have more than 50 lines only importing components

Thread Thread
 
javiasilis profile image
Jose • Edited

To be honest, me neither. What I ended up doing was only barreling those files that I know they were going to be used together, and manually removing each of the other ones... Yes, I spent many many hours in the refactor... But it was worth it.

Plus I used type aliases (works both on Babel and TypeScript) to better index my applications.

Collapse
 
krvajalmiguel profile image
Miguel Carvajal • Edited

Hi, thanks for the post. I just want to add that this can have a direct impact in bundle size. This is the case with webpack (for example) if you dont have tree-shaking properly configured. It is recomendable to import the file you need directly as others pointed out already.

Collapse
 
matthiasccri profile image
Matthias

I'd advise against barrels.

Unless your code is marked as "sideEffects": false, using the barrel module will import all of the import tree.

This is fine for small isolated groups of modules, but in a larger codebase, a single import can instantly broaden the "import tree". This slows down builds, mostly.

So, for large and complex codebases, don't even think about using barrels (unless of course you have sideEffects: false enabled).

Collapse
 
rgails profile image
Ryan Gails • Edited

Great article! Barrels are cool and all until you get an import order issue in a big application and then they're not so cool.

Collapse
 
zenventzi profile image
Zen Ventzi

Could you give an example of what that looks like?

Some comments have been hidden by the post's author - find out more