Your screen is too narrow. Try landscape orientation?

Default Export was a Mistake

4 min read
Featured Image

EcmaScript has been evolving, with new features and best practices constantly emerging. One such feature is the ability to import and export modules. The former is the more popular choice of the two options available: default export and named export. However, named exports are the right choice in most cases.

Let's begin with a comparison

Since we only have two choices here, let's give export default a name of A and export a name of B, and when combined, let's call it C.

Exports

Developers tend to use export default when exporting a module more often. I've been an eyewitness to this in many projects where I had a chance to work with a team.

A. Can have a single default export
B. Can have multiple named exports
C. Can have A + B combined

I recommend using C for libraries transitioning to a major release. Assuming they used option A in the past, and now they want to switch to option B, without introducing breaking change (yet). Additionally, if you are working on a library that needs to support browser use outside of modules, you should use option A for an entry targeting browser use and option B for the modules.

// A
export default function lib() {}
 
// B
export function lib() {}
export function utils() {}
 
// C
export default function lib() {}
export function utils() {}

Imports

There are some differences with imports, but using default alone or combined with named exports will become the worst decision you could've ever made.

A. Can have a single default import
B. Can have multiple named imports
C. Can have A + B combined

// A
import iCanBeAnything from './lib'
 
// B
import { lib, utils } from './lib'
 
// C
import iCanBeWhatYouWantMeToBe, { utils } from './lib'

Just look at that! I'll explain this further below, but please, only go for A or C.

Debugging

When working on medium to large project codebases, debugging simplicity should be a high priority. If you use default exports more often, you will waste too much time debugging and mind-mapping which module you imported and from where it is coming.

A. Will quickly become a pain to debug
B. Will be easy to debug

As default export has no name (obviously), one can import it and give it any name they desire. To be consistent, you must remember how you named each default import. Imagine working with a team; everyone will call that import differently. It will be a nightmare to debug and keep track of it.

IDE intelli-sense

Developer's best friend is IDE. They help us with many various tasks. The two most important ones for this article's explanation are auto-import and symbol renaming.

A. Will not work with auto-import, nor symbol rename (as default is practically unnamed)
B. Will work with auto-import and symbol renaming

You will often need to import a module when working on a project. Aside, when refactoring, you will usually reach out for symbol renaming. If you are using default exports, you will be unable to use these features.

Lazy loading

Lazy loading is a technique that allows you to load a module only when it is needed. It is a great technique when you have a large codebase and want to keep the initial bundle size small.

A. Will require similar approach as B, but be less readable
B. Will be simple to work with and readable

// A
const { default: lib } = await import('./lib')
 
// B
const { lib } = await import('./lib')

Tree shaking

Tree shaking is a technique that allows you to remove unused code from your bundle. It will automatically take care of everything so that your final bundle becomes smaller. When using default exports, it is challenging to achieve tree-shaking as the objects can be large and complex.

A. Impossible to tree-shake
B. Easy to tree-shake

// A
export default {
  foo: 'foo',
  bar: 'bar',
}
 
// B
export const foo = 'foo'
export const bar = 'bar'

Conclusion

While I did recommend using named exports, I do not want to discourage you from using default exports where it makes sense. Some frameworks and libraries use default exports, so you will have to use them. However, if you are starting a new project, I recommend using named exports. It will make your life easier and your codebase more readable and easier to maintain.

jsesmmodulesexports