The next point is regarding IDE's. Honestly, I don't understand the obsession with designing a language around tooltips in an IDE. I personally use vim and once I know a code base I rarely need to look stuff up. If your code and internal APIs are that complicated where you can't remember basic function signatures, its time to refactor and simplify so you can fit all that stuff in your memory without the need for hints.
To the point about refactoring: I really doubt named imports are going to save you much time here at all. How much time do you spend figuring out the import/exports from a file vs. refactoring what the actual code is doing? Unless you're talking about some kind of formal AST automation (which could benefit from being more explicit)?
The next comment is about tree shaking. Better known as "dead code elimination" and its been in uglifiyjs and closure compiler for 10 years but somehow the webpack folks thought tree shaking sounded cooler, even though they don't even implement it and just shell out to uglifer. My argument here is that if your code is so messy and is in need of good shake (no pun intended, well...err), you have big problems. I cringe when I see people trying to layer on tools to paper over technical debt. You should actually go through the source and remove what isn't needed or used anymore.
Projects have dependencies from teams with various skill levels and external dependencies over most of which you have little or no control. For this and many others reasons "refactoring to simplify" often isn't an option. Similarly, tree shaking doesn't just apply to the code from your project. Also, what about the time when you first start on a project? Or maybe you're only working on a project for a short time? Wouldn't it be nice if the experience was good regardless?
The author makes a good suggestion for consideration. Anytime we find a principle which is likely to lead to an overall improvement at scale it's worth considering, especially when it comes without much if any a downside. I'm not necessarily agreeing that this is the case here, but just don't think your comments add much.
The correct and pragmatic course of action to address problems in code quality is to address them by refactoring, one file at a time. If you want to see the effects of explicit imports, go ahead and look at any large java code base. What ends up happening is fragmentation and enormous and tediously huge import declarations at the top of every file. Again, it's better to address the real problem and not the symptom of poor code quality.
How much code do you work with, out of curiosity? At my work, we have about 500,000 lines of code, and while I'm usually working on a specific part of that, modifying and interfacing with other parts of the code is common. And, of course, for new people and people switching teams, all code is unfamiliar. IMO, expecting people to "just know the code" is really unreasonable; working with code you're not familiar with is very common in software engineering, and our tools and practices should take that into consideration.
Must be nice to work on stuff you're familiar with for years, day in and day out. That's not the use-case.
My problem with this article is the advice is far too broad "ban all default exports" without being considerate of how others code.
For example, I prefer to keep my modules small, with only one export. I may export helper or unwrapped versions of higher order components for easier testing, but generally I want my modules small and single purpose.
Default exports are helpful constructs. Disagree with this article overall.
import MyThing from "../../components/editors/MyThing";
import {MyThing} from "../../components/editors/MyThing";
But if it's named, you don't need to stop what you're doing, scroll to the top of the file, type out the import statement by hand, and look over at your code tree and figure out the path to the module you want.You just type MyT Ctrl-Space and let intellij do all that for you, not even having to move out of the function you're writing.
export default function MyComponent(props) { }; export default class C extends React.Component { ... }Both tools are useful; both are necessary; most modules should have a single default export.
Maybe a nitpick, but given that most other programming languages don't distinguish named vs default, it's probably not necessary. You can do all your programming where every module is something (like in Java) or where every module only has things (like in Python), but there's certainly value in being able to express one or the other in the same language. The downside is that the named/default distinction adds language complexity and learning curve, makes tooling support a little harder, and makes things like CommonJS interop more of a pain.
Not sure that how other languages do things really plays a part in how JS does things?
I think his point is that having them available is necessary, because they both have strong use cases.
import {x,y,z} from 'module'
^ this is an abomination from 'module' import {x,y,z}
would be nicer import {x,y,z} from 'module'
Yoda from Star Wars might agree with your preference since he speaks backwards English.All kidding aside, I'd love to hear your logic about why you think the backwards version is better.
etc.
export default { foo: 2 };
export const foo = 3;
// other file
import { foo } from './file'
console.log(foo);
Presumably last one wins or, if the other way around, a reassignment of const error?
Both default and named exports can be rebound to new symbols locally. But that has no effect on how statically analyzable the code is.
“It can’t be auto refactored” just isn’t true. If it’s true for your particular tool, file a bug.
People are using a cargo cult understanding of how code analysis works. It’s not just grepping for a string.
It's clear for me that in this case you could talk only on refactoring like "rename all default imports to:" This is different than simply renaming a symbol and I don't know IDE that supports this operation.
If your IDE doesn't support rename-references that's your IDE's deficiency - not default exports.
import * as mymodule from './mymodule'
Namely, treat the whole module as one thing, and give it a name. It would be great if you could do that without specifying the name manually, e.g. like "import mymodule" in Python.The other times, I do:
import SingleClass from './singleclass'
# or
import {SingleClass} from './singleclass'
Its rather rare that I want a handfull of single things from a module - either one or all (all can mean "one object that has everything" or "all functions and constants in one wrapper", depending on how stuff is exported). The only time I need the `import {a,b,c} from './utils'` syntax is usually with a grab-bag util function module.You get used to it, but I sometimes wish things were more like Python.
There is no reason to import what you don't need. This is why wildcard imports are generally frowned upon in most development teams. (I say most, thats unqualified, of course, but from my experience, its always been a part of the code standards)
Your code is much more readable and clear when you are explicit about what you are importing.
Default exports were introduced because often a module wants to export a single value or piece of functionality. In such cases, in module systems where all exports are named, the author of the module and its consumer have to coordinate on some convention to indicate "this is the thing". For example, some languages choose the same as the file name (with fun casing consequences or conversions). Some choose a particular name like "t" (I've heard one of the MLs does this). Some don't have a convention at all and you have to consult the documentation for each import.
When designing JS modules, we decided to bake in a single somewhat-privileged export name for these cases, "default", which gets nice syntax on both the export and import sides to help encourage ecosystem standardization and coordination.
You can choose to deviate from it, in favor of your own convention. (It seems like the author prefers some kind of filename-converted-to-camelCase for their projects.) But do so being aware you're walking away from the ecosystem affordances and it will be unexpected for your consumers.
Particularly this comment, which agrees that default exports were a mistake: https://github.com/rollup/rollup/issues/1078#issuecomment-26...
> Ecma Script Modules which finally solved the problem of sharing code between files (modules) on a language level. It was a huge step forward
Step forward? We were writing modules just fine in 2010. I don’t know a single project off the top of my head that actually benefits from tree shaking. It has been 5-6 years since modules appeared and there is little to show for it. We could do almost the same with node’s commonjs. You could write code that would run anywhere without pre-processing or transpiling. Every time I see a project where the first three pages of documentation are about setting up Babel and webpack I feel like switching off.
which makes me cry :D
There's no reason a default export cannot have a name.
export default function foo() {...}
With this in place VS Code is able to auto-import the dependency and refactor its name if necessary.I dislike when I use some external module and I have to look up whether the module is the value or not...
Edit: as an additional annoyance, when mixing CommonJS and ES6, the value may be in an element called "default". In some cases. I'm still unsure when.
export default class Foo { }
export const Bar = "";
and then import Foo, { Bar } from "./module"
I would expect if a module has a default export, then it should not have named ones. Why? At least it puts more structure in your code architecture. import function from 'function';
import * as module from 'module';
Why wildcard imports over named imports?Wildcards preserve context. `ReactDOM.render` means more than `render`. Using wildcards avoids collisions - lodash, http, https each have a named export `get` [0]. Wildcards still supports tree shaking! Try it in webpack or rollup - only the named exports that you access will be included in the shooken bundle [1].
[0]: Yeah, I know you can import { get as httpsGet }, but why would I want to?
[1]: Unless you treat the binding as an object. `Object.keys(module)` will break tree-shaking.
None of the points made in the article are even valid.
1) You don't get better DX because you simply cannot use the same symbol name everywhere all the time anyway because names clash.
2) With point 1 gone, point 2 is wiped out as well.
3) This is patently false.
[0] https://github.com/airbnb/javascript#modules--prefer-default...