Babel 6 – useless by default
fourlightyears.blogspot.com
fourlightyears.blogspot.com
Babel < 6 was trying to be everything for everyone and that wasn't working out. Everyone wanted to get their pet feature in. And we came under fire for making it easy for people to use experimental features.
That said, there is probably room to create a es2015-cli or something like it that provides a default experience, but that's orthogonal to this discussion.
Finally, the point you raise about Babel just disappearing into the stack is also misinformed. Transpiling should always be a technical decision to be made. For example, you should know that a for-of statement will transpile to include a bunch of runtime checks that would be slow in hot code etc.
I use TS exclusively, and that is unrelated to working with it professionally on a daily basis. It is a thorough pleasure.
On the other hand, I don't feel that it's reasonable to assume that setting up a build system will be trivial. Jumping into ES6 isn't and shouldn't be a trivial decision, transpilation is a complex process with edge cases. That doesn't mean it should be a pain in the ass, and I don't want it to be, but it doesn't mean it will be instantaneous and easy. Users have totally different build targets (different Node versions, different browsers, some need IE8 support, some don't). Different systems need different levels of polyfilling and differing output syntax.
Enabling everything by default is one option here, but that encourages people to not consider how things actually work, which is rarely a good idea. It also assumes that adding complexity around knowing what to _disable_ is actually better, which I'm not convinced it is.
There's no magical "ES6"-level of browsers which support all features of Promises, though[1]. Some products support IE11, some don't. Some only support the latest versions of Chrome and Firefox. Additionally, more people are using features not even in spec[2], known as "strawman proposals", some which are quite popular in real-life code examples[3]
Because of the moving targets on what Babel is transpiling from and to, they went for a "you decide" approach which promotes no particular level of "modern javascript" or "compiled javascript".
It's unfortunate they don't have `npm install --save-dev babel babel-preset-es2015` and "write `{"presets":"es2015"}` to a new .babelrc file" smack-bang at the top of the homepage though. The "handbook" links to a page of links, the "setup" page asks more questions than it answers. With modern Babel, no matter what build system, the above 2 steps are the same, and the 3rd is "add babel to your build system, or `npm install -g babel` and run that"
[1] https://kangax.github.io/compat-table/es6/ [2] https://babeljs.algolia.com/docs/usage/experimental/ [3] https://github.com/reactjs/redux/issues/226
Not even the need to understand what presets are, choose the presets, install the presets, diagnose the problems with the presets etc. Just make it work out of the box.
On top of that it was only going to get worse as people were throwing proposals around left and right and we never were quite sure what a "sane default" was. We were never sure how to keep people on track with rapidly changing proposals.
The move to a completely configured Babel, meant a move from implicit behavior to explicit behavior. People are forced to tell Babel what they want out of it.
Configuration means explicitness, explicitness means safety.
Hopefully the message that is coming through here is that configuring Babel is extremely hard and time consuming and error prone and is a massive, massive headache.
I am still right now trying to work out why async and await do not work after spending all day on it.
Probably for Babel experts configuration is easy and quick but for those who are not specialists in it forcing users down a configuration path is deeply, excruciatingly painful.
Or they (or you) could make a configurator (they already have a build-tool focused one, but they need one kind of like what jQuery has) on the website, where you can select your target browser version(s), and what features you want enabled. Bam. Magic! Here's a JSON file, put it into your project root.
Async/await, I'd just go with TypeScript and then transpile the ES6 to ES5 with Babel.
See: https://github.com/andrenarchy/jspm-typescript-es6-boilerpla...
I think this would be a great first step towards making startup for new users less painful. Or maybe making an onboarding process similar to `npm init`, where the user is walked through a series of questions about what they need for their project and the initial .babelrc is generated automatically.
npm install --save-dev babel-cli babel-preset-es2015
echo '{ "presets": ["es2015"] }' > .babelrc
echo "console.log(`1 + 1 = ${1 + 1}`);" > index.js
./node_modules/.bin/babel-node index.js.
I would link to http://babeljs.io/docs/usage/cli/ since users wouldn't get what babel-node vs babel is.
The init cli is certainly something we should do; I mentioned this in a comment below.(issue is https://phabricator.babeljs.io/T6956)
The author of the post doesn't seem to understand that many of the transforms supported by Babel touch on proposals that are actually at various stages of being experimental or unstable, which actively should not be enabled by default for the sanity of users who don't know better.
Opting a novice user by default into a language feature that might well change is not a good thing! Otherwise we end up with something dumb like the legacy decorator transform, where people unknowing code against proposals that are liable to change under them.
Babel-5-stage-0-ese is not ES.next!
The idea that users should be protected from themselves isn't an effective one and is at the heart of the idea that Babel should do less and more should be configured in.
Nothing terrible will happen if a user uses a feature that is experimental or unstable. They might get to use it successfully however if it comes preconfigured. I can just update my code when the spec stablises.
>> the sanity of users
The sanity of users is broken by the myriad problems with Babel configuration.
Proposals are constantly changing, and keeping a monolithic Babel on track with them without breaking things for users all the time is a difficult problem.
The configuration is more than just configuration, it's explicitness. It's telling Babel exactly what you want out of it. That way you never have to worry about changing behavior until you want to make the migration.
The situation is more nuanced than you are recognizing.
Appropriate protection is a warning in the docs "this code might change when the spec is finalised".
Inappropriate protection is hiding those features away behind difficult-to-configure barriers making it only possible for experts to configure their systems to run it.
I hate to say it, but you really don't know what you are talking about.
Please refrain from getting personal in arguments on HN, even though it's frustrating when someone doesn't know what they're talking about.
This comment would be great with just the first paragraph.
I'd actually take the opposite position here: people should typically not have to consider how the tools they use work, until they need to go beyond the basics.
If all I want is "the latest javascript", I should be able to get it without pondering the genius of a library's creators.
Simplification, preconfiguration, removing of the need to configure. If these were major project goals then the developers could be reminded of them every time they implement something. If a developer implements some new feature that requires (yet more) configuration then other project developers can remind them "hey was there any way you could have done this without config, or built the config in?".
I do think the kitchen sink should be included by default, even for experimental stuff. Optimisation and minimisation should be the expert case. Maybe the kitchen sink costs are size of executable or performance of compiled code but I'd gladly pay that price for something that actually instantly works without always expecting to descend into configuration hell.
Consider async/await. Why not include it fully configured out of the box? Right now I am sitting here wasting my Easter public holiday trying to get async/await to work - it still does not.
"ERROR in ./app/components/Kernel/KernelFiles.jsx Module build failed: SyntaxError: C:/Users/andrewstuart/devel/desktop/app/components/Kernel/KernelFiles.jsx: Unexpected token (253:17)"
async/await are a great idea and developers will want to use them. Who cares if the standard is not yet ratified, why does that mean I should live with the cost of trying (unsuccessfully) to configure it? Why didn't the developers do it?
>> I don't feel that it's reasonable to assume that setting up a build system will be trivial.
Absolutely correct, and that's the precise reason why projects like Babel should do their utmost to make it as trivial as it possibly can be.
>> Enabling everything by default is one option here, but that encourages people to not consider how things actually work
This isn't a good enough reason to force me to do configuration.
I really want to defer the need to know how things work as far as possible into the future unless I really need to know it now. It's not that I want to be ignorant, but right now I am focusing all my learning effort on programming my application, and how the language works, and how the libraries work. Do I really need to be forced to understand how Babel works too? I'd prefer not to unless that learning directly gets me some outcome.
>> It also assumes that adding complexity around knowing what to _disable_ is actually better, which I'm not convinced it is.
Yes but better to invert the formula so that configuration is a process for experts to disable functionality in order to optimise rather than forcing beginners to enable.
Also, don't you Babel developers find you have to spend time constantly diagnosing configuration problems and errors?
A common theme in the counter-argument is that developers should be aiming to get Babel to some "ideal state" which is neither zero-config or full-config.
I'm not ES/Babel expert, but I think that's a reasonable point.
HOWEVER, I strongly feel that it is easier to get to this "ideal state" if you start with a most-uses-cases config. It's always easier to optimise from something that works, instead of trying to optimise from a broken state in the way that Babel now ships.
There's a very good reason that Babel doesn't, and we should actually be fairly grateful that the Babel team have made the considered decision not to include such things.
First off, neither async/await nor decorators are actually part of ES2015. They're both TC39 proposals, at various stages of completion: https://github.com/tc39/ecma262. Very justifiably, neither Babel 5 nor Babel 6 transpiled those out-of-the-box by default; for novice programmers, using language features that are unstable proposals that have not finalized is quite dangerous – what are you going to do if those proposals change, as the decorators proposal actually has changed?
More specifically, there are meaningful issues with both of those transforms if used without further thought. Babel's stock transpilation of async/await brings in an entire runtime component in the form of the Regenerator runtime, and additionally requires that Promises exist in the JavaScript environment, which requires polyfills in the general case.
For decorators, the proposal itself is still in flux. The current version of the proposal (https://github.com/wycats/javascript-decorators/blob/master/...) is actually quite different from the old proposal, which was the one that was implemented in Babel 5. Additionally, the current proposal isn't even fully nailed down yet. Certainly one should not expect Babel to implement a language feature for which there isn't even yet a stable proposal!
This isn't to say that Babel 6 is perfect, but the specific counterexamples the author of this post brings up are extremely weak, and if anything demonstrate very good choices on the part of the maintainers of Babel.
I'd just update my code to meet the spec. Likely it would take vastly less time than the hours needed to fail in configuring Babel. The documentation can just say "this feature isn't finalised, it might change." That's enough. The code does not need to be disabled just because the spec isn't final.
>> quite dangerous
It's not really dangerous. No-one is going to die. It's emotive words like dangerous that lead Babel developers to think "we'd better hide that functionality behind hard-to-configure barriers so people don't cut themselves on the dangerous code".
We don't want Babel's configuration to be difficult, we just want people to explicitly tell us what they want.
If you have suggestions on how to make the configuration easier I'm happy to hear it. But turning stuff on by default it a terrible terrible decision that hurts the community.
I have been satisfied so far.
I'm now going to attempt to switch to TypeScript. I wonder how deep this new rabbit hole will be.....
The magic may be in Typescript helping you figure out which runtime polyfills to configure, maybe even spit out something resembling a .babelrc for your Typescript project.
There's definitely discussions on this topic in the GitHub Issues, though I haven't perused them recently so I can't tell you right now if there is any progress.
And it works out of the box with zero configuration
I'm barely using any TypeScriot features. I just wanted a simpler build system.
This is the reason I wrote the post and I'd really like to get back to actually programming.
npm i -D babel-cli babel-preset-es2015 babel-preset-stage-0 babel-plugin-transform-runtime
echo "export default async function requireFromTwitter (id) {}" > index.js
echo '{ "presets": ["es2015","stage-0"], "plugins": ["transform-runtime"] }' > .babelrc
./node_modules/.bin/babel-node index.js
What I like about your solution here is that is proves installation correctness in an absolutely minimalist way.
If you made one of these for every Babel plugin then life would be a whole lot easier for people trying to work out if they have correctly configured the plugin.
Assuming of course your solutions are in a highly visible place that is obviously current and up to date.
FYI: in reference to https://twitter.com/rauchg/status/712799807073419264
Your title is a little inflammatory: "a lesson in how NOT to design software.".
Re: Javascript tooling. Yes is it painful. But Babel is designed exactly as it should be, and the solution to fix your problem is a library that wraps around it.
Post: http://robotlolita.me/2016/01/09/no-i-dont-want-to-configure...
Discussion: https://news.ycombinator.com/item?id=10878623