DEV Community

Cover image for Avoid using default exports

Avoid using default exports

Phuoc Nguyen on January 10, 2024

As you may already know, there are two different ways to share functions in JavaScript: default exports and named exports. Default exports are used...
Collapse
 
brense profile image
Rense Bakker

Actually IDEs should not have any problem finding your default exports aslong as they are not anonymous functions or objects. If you use recommended eslint rules, it will tell you not to export anonymous functions and objects.

// Editor has no idea what to do
export default function(){}

// Editor will be able to auto import doSomething 
export default function doSomething(){}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
chema profile image
José María CL

Yeah but that's a "if you setup that stuff correctly" 😕

Using named exports doesn't depend on ideal circumstances

Collapse
 
brense profile image
Rense Bakker

This works in vscode without any additional configuration and I'm pretty confident it works in most other editors as well, if they understand named exports they also understand default exports as long as your default exports are not anonymous functions.

Collapse
 
aminnairi profile image
Amin • Edited

There is a clear difference between function expression and function declaration and they both serve a purpose.

This can't be a viable solution since imposing function declaration would mean losing the benefits of arrow functions that grab the outer context instead of creating a context. This can be destructive for some project relying on this mecanism.

Also, you can't use that reliably on scalar data types that uses default exports, it simply fails short on your text editor and its completion system (which comes most of the time from the language server). TypeScript/JavaScript language servers do not work well on default exporting scalar data types. So using a default export is very much problematic for a lot of things.

Instead, named exports are harmless in the sense that you can either named export a function expression as well as a function declaration, it does not impose on your team a way of doing things, plus the benefits mentioned above in this article. And it provides the best completions and auto-import capabilities from your language server when used in your text editor (and many editor benefit from that such as Emacs, Neovim, IntelliJ, VSCode, etc...).

Collapse
 
brense profile image
Rense Bakker

You can do this with arrow functions as well:

// Editor has no idea what to do and you should never do this.
export default () => {}

// Editor has no problem auto importing non-anonymous arrow function
const someArrowFunction = () => {}
export default someArrowFunction
Enter fullscreen mode Exit fullscreen mode
Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Default exports can be confusing in complex modules. Developers may not know which export is the default or even be aware of its existence. This can cause delays as engineers must spend more time looking at documentation or even the source code to find the functions they need.

I've read this paragraph several times now and I still think it makes no sense whatsoever. Can you explain what you mean by this?

If you decide to rename a named export in a module, for example, changing the name of the add function to sum, most IDEs can automatically update all usages. This makes the refactoring process much easier.
However, with default exports, this isn't possible.

Again, this doesn't make any sense to me whatsoever; what is the problem here? Default exports have no name, so what would you want to happen here?

As we discussed earlier, when a module provides named exports, we can easily select a specific function from the module by using a shortcut provided by the IDE. This feature not only saves time, but also helps the IDE suggest and auto-import the necessary functions as we type.

This one makes more sense, but it's not really an argument against default imports. As long as your default export is also available as a named export (which is probably a good idea regardless), this still works 100%.

Default exports can be imported using any name you choose. This can lead to inconsistencies when multiple engineers are working on the same codebase and using different import names.

Again, this is a good reason to also have a named export for your default export, but it doesn't speak against having a default export in any way.

Setting that aside, regardless of consistency or not, if I look at a source file and see import add from "sum" I will probably scratch my head multiple times and tell whomever wrote that to fix it (or just not interact with the project if it's OSS)

Conclusion

Just provide named alternatives for your default export and everyone will be happy. We can have both.

Collapse
 
wakywayne profile image
wakywayne • Edited

Isn't that a bit repetitive though? Regarding both default and named exporting.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

it's three keywords per file, I don't think that's the kind of thing to seriously be worried about.

Collapse
 
butalin profile image
Anass Boutaline

This could be a discussion rather than a judgement, this way you're misleading others, named export or default export each export type has a purpose, some times you need to export a single function from a file to serve specific purpose, as you can use named export when you wants to group multiple functions in a single file etc

Collapse
 
htho profile image
Hauke T.

You had me at "Refactoring" - very true.

Collapse
 
seandinan profile image
Sean Dinan • Edited

Yep, spot on. Especially the Inconsistent Codebases section.

In the rare instances where a named export does need to be renamed, it can always be done with as:

import { Provider as RollbarProvider, ErrorBoundary } from '@rollbar/react';
Enter fullscreen mode Exit fullscreen mode
Collapse
 
wakywayne profile image
wakywayne

I'd say what the OP is suggesting is probably the safer bet, but this really is only an issue in really big code bases with lots of people working on it. Also in frameworks like React that have strict file naming conventions as long as you follow those conventions, you should just use the previous standards not make up your own. Another situation where default exports are better is when you are making a npm package, in this use case it only makes things worse for the user if they have to remember the name of the export.

Collapse
 
ekdikeo profile image
Eric B

Most of these aren't real problems, and many people use default exports just fine.

Collapse
 
gibbitz profile image
Paul Fox

I have worked on code bases with default exports where casing and typos have caused discoverability issues.

import Buton from 'Button'
Enter fullscreen mode Exit fullscreen mode

If it can break "find in files" that's a good enough reason for me to not use it. IDEs make our lives easier in a lot of ways, but at the end of the day an IDE is just a tool. If you need it to understand your code, there's a problem. Anything that makes the code easier to understand without tooling is best practice in my book.

Default exports are not needed. Exporting a single named function from a module is completely unrestricted. If you need to rename a module, use the as directive.

import { module as betterNamedModule } from 'module';
Enter fullscreen mode Exit fullscreen mode

Then grepping the codebase will at least see the import reference. You won't even need it if you take your time namig things and refactor when things become so similar that their names overlap. So why use default exports?

Collapse
 
drewkilleen profile image
Drew Killeen

Good thoughts, I like that you're challenging convention and asking us to think through things rather than just following the norms.

In my opinion, all of what you're saying is true when a file has multiple exports. I do find it confusing to have a default export mixed with named exports. But typically when a default export is used, I only see a single export from that file. I haven't run into any problems with that, especially since the file, function, and import almost always share the same name.

But at the same time, I also see no argument against using only named exports, so maybe you're on to something.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

The IDE has no issues finding default exports while typing. It is a matter of providing proper information. Someone already said that if you export a nameless something, then that's a problem, but if you export something with a name, that name shows up in autocomplete.

Furthermore, NPM packages should provide proper d.ts files. Using my vite-plugin-single-spa package as example, you just install, then open vite.config.ts and you start typing "import vitep". At this point you should see autocomplete showing you the right option (vitePluginSingleSpa).

Collapse
 
jpilson profile image
Joao Sumbo (J.P) • Edited

To me , it seems like this articles seems like a personal issue l.
I use Vue , and Typescript , on top of that I apply OOP , which means there are a lot Class files that it makes sense that one File holds 1 default class and maybe some types. I use default export often an I have never any of the problems you mentioned my IDE (Webstorm, intelij) knows exactly where are they. On top of that I use the default export in conjunction with "named export" andy IDE k ow exactly how to import them . import A, {b}.

Collapse
 
jackmellis profile image
Jack

This is the developer-equivalence of first world problems.

IDEs have no problem discovering default exports in my experience. And I frequently rename default exports and vscode is smart enough to rename imports automatically.

I also have absolutely no issue with somebody deciding to only use named exports in their codebases, go for it. But here we're dressing personal preference as best practice which is incorrect.

Collapse
 
shawn_p profile image
Shawn P • Edited

The reason we have so many different tools at our disposal is so that we can use the best tool for a given context, and contexts vary greatly in this field. It is disappointing to see so much of these “never use X conventional method ever again” articles and videos which usually fail to sufficiently acknowledge the optimal use cases for the thing they are bashing on and seem aimed at being provocative and generating clicks more than offering genuine educational content. This article starts by acknowledging the correct use cases but then proceeds to suggest never using them ever again.

Default exports are absolutely the right choice when there’s only one thing to be exported, and there are plenty of architectural nuances from project-to-project that could warrant their use in other contexts. This point-blank statement of “default exports are bad and you shouldn’t use them” comes across as biased and imho could be potentially misleading to beginners.

Collapse
 
matveit profile image
Матвей Т

A thing I tend to do, when I am working on a module where it makes sense to have multiple exports, but also one main default export is this:

export function add(x: number, y: number): number {
    return x + y;
}
export default add;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dtasev profile image
Dimitar

If you're getting confused by exports then I'd recommend investing a few minutes in getting a free IDE.

As a newcommer to the JS env from cpp/python I don't really see the need of default exports. Everyone else has managed without them.

Collapse
 
aloisseckar profile image
Alois Sečkár

Good summary.

I especially dont like when I am forced to mix named and default imports from 3rd party libraries. (yes, I know I can make a custom reexport somewhere in codebase).

Collapse
 
chema profile image
José María CL

Totally agree. However, I want to read different point of views in the comments below 🤭

Collapse
 
aralroca profile image
Aral Roca

I would say it depends on the project, usually the default exports compilers minify them much better, especially for libraries and frameworks.

Collapse
 
kotapi profile image
Pranay Kothapalli

This is not a problem at all, at best this post is about preferences. It doesn't speak about numerous pitfalls of using names exports and it's performance

Collapse
 
clockelliptic profile image
Software Engineer • Edited

This grossly overlooks and disregards the cases when and reasons why you should use default exports.

Collapse
 
ekeboetuk profile image
коричневатый

Nice one Nguyen, for me as an amateur level developer I find this absolutely sensible 👍