@dinos I was speaking theoretically. But this strengthens the point of having files with single default exports, because then the set of files that are ever imported become the “tree-shaking” mechanism without need for actual tree-shaking analysis. So, with default exports/imports we can easily know if some file will be included in a bundle or not. That is more difficult to determine with files containing lots of named exports (in theory). So, if the compiler (in theory) is more simple and just includes whole files without dead-code-elimination, then having single default exports in every file is the method of choice to use for eliminating unused code in the compiled result (although that does mean more work splitting things into files compared to just naming exports in a single file). If you have a compiler (theoretical or not) that can perform sophisticated tree shaking, then bunching named exports together may not be a problem, but at least we know it won’t be a problem if we stick to single default exports.
Example: Suppose we have utilities.js that has tons of named exports. We can import like this:
import {one, two, three} from `./utilities`
The compiler would need to perform dead-code-elimination to drop unused code from utilities.js.
Now, suppose instead of named exports we put each export into separate files: utilities/one.js
, utilities/two.js
, utilities/three.js
, etc. We can import like this:
import one from `./utilities/one`
import two from `./utilities/two`
import three from `./utilities/three`
That was more work to split the exports into separate files, and more verbose to import, but now the bundler only needs to include files that are ever imported, without needing to perform tree-shaking/dead-code-elimination, under the assumption that anything you ever import will be used.
It all depends on the use case too. For app code, use whichever is easier since you’re probably using 100% of your app code. But, when writing a library (like lodash, for example) make it easy to import specific things so that dead-code-elimination is implicit simply due to the end user importing only what’s needed. Library authors don’t know if the end user’s bundler will support dead-code-elimination, so using well-defined single default exports eliminates the need for the dead-code-elimination.