Deploying ECMAScript 6
2ality.com
2ality.com
I've found the JS to be much cleaner and easier to read and I've heard similar statements from the rest of the dev team. I highly recommend it. The best part is you can convert your code 1 file (or "class") at a time and your old JS will still continue to work perfectly.
Feel free to ask me any questions about the process and any potential issues and I can respond with how we dealt with it (if we did).
Did it live side by side with existing code?
Were your watchers efficient or did it slow down over time the more you added?
Looking to do this on a large JS code base soon. Thanks for your input, Josh
"use babel";
at the top of files that should be transpiled but I couldn't find a good "gulp way" to check for that. I also considered using a "filename.es6.js" structure but following file renames in SVN is a bitch and a half (not my only reason) so I didn't want to have to change those all back when es6 was widespread enough to use directly. I settled on running them all though so our "gulp build" takes 30 seconds or so but for our "gulp watch" (which starts off by building everything) I implemented caching so that only changed files had to be re-transpiled before getting concated into our "app.js" file. With this change it takes <1sec to transpile changed JS. Since our JS dev's use "gulp watch" everything works out quite nice so that they can edit a file and reload their browser to see the change immediately (30 sec times would have killed babel in it's crib for us and I assume most other places).For caching we used the gulp-cached [0] plugin. It's important to note that if you plan on concat-ing your files that you are caching then you will also need to use gulp-remember [1] which re-introduces cached files into your file stream after the intensive parts of are done so for example:
var customJSStream = gulp.src('webroot/source/js/**/*.js'))
.pipe(cache('app-custom-js'))
.pipe(babel())
.pipe(remember('app-custom-js'))
...
(NOTE: I've left out stuff from our gulpfile and simplified it for display here)We then combine that stream with 2 others and concat them all together but that's not important for this example. Let me know if you have any other questions!
You can combine it with gulp-if, to isolate those files that need compilation.
Also good luck getting source maps + babel + bower + etc to work under make, I honestly don't believe it's possible or if it is it would be so convoluted that it would be impossible to extend or understand.
Gulp may not be a perfect tool (I don't believe such a tool exists) but it's leaps and bounds above make and a better choice than grunt IMHO.
It would be the same if you suggest Java codebase to switch from maven to make. Yes ... it would be far difficult to do that.
But as the other commenter said, all es5 JS is valid es6 JS...
I suspect they just flipped a switch causing all files to be run through the transpiler, regardless of filename extension or anything. However at the time the switch was flipped, none of those files actually contained any ES6-specific syntax, so the transpiler was mainly just passing code through unchanged, even though it technically is transpiling everything. Now they're simply going through the code and swapping in ES6 syntax here and there. It all works because 6 is a superset of 5.
By using a more functional approach, you can chain promises or streams very effectively[1].
Further than that, it's silly to compare browsers that aren't stable yet.
[1] https://bugzilla.mozilla.org/show_bug.cgi?id=950547 [2] https://bugzilla.mozilla.org/show_bug.cgi?id=1023609
If anyone has any questions, feel free to ping me or stop by our support chat[1].
IE didn't support basically any of ES5 until 2011 with IE 9, and, for example, Safari didn't support bind() until 2012. Strict mode didn't appear until IE 10, Firefox 4, and Chrome 13. Those dates aren't so great even if you ignore that you'd often have to support the earlier versions for a significant amount of time anyway.
What is not so good with TypeScript is that they have a rule of not polyfilling things. So if you want any new ES6 methods for array/string etc. You would need to polyfill them yourself.
See the status here:
http://kangax.github.io/compat-table/es6/
The column below "babel" is what you would get when you program raw ES6 and transpile using Babel. The column below TypeScript is, unfortunately, what we are currently dealing with. Many lacking features.
So far, 1.5 doesn't look like it will bridge this gap substantially.
That may have changed somewhat in the TS 1.5 alpha - they're supporting more features on the ES5 target than they did in 1.4.
But yes, you still can't use ES6 features that TS doesn't know about.
It's true that there's not too many ES6 features implemented yet, but the 1.5 release will bring a lot of new ES6 features, and it's right around the corner.
A little nick pick about TypeScript and I hope that other dislike its influence to ES6/7 too: Microsoft's mastermind behind C# and TypeScript: Anders Hejlsberg was the original author of Turbo Pascal and the chief architect of Delphi. In 1996, Hejlsberg left Borland and joined Microsoft. One of his first achievements was the J++ programming language. Since 2000, he has been the lead architect of the team developing the language C#. In 2012 Hejlsberg announced his new project TypeScript—a superset of JavaScript. I sincerely hope he stays away from ES7 - I don't like his syntax preferences. (ES4/AS3 syntax was already weird as hell, and good that it failed.) ES5/JavaScript 5 was so great and lean - so refreshing coming from C++/Java/C#. TypeScript feels a bit like a Trojan horse that emerges as ES7. As the linked article says "TypeScript: Is basically ECMAScript 6 plus optional type annotations." Or the other way around, they turned the beloved ES5 to Hejlsberg's TypeScript. So don't destroy ES7.
You can use babel or traceur (just comment/uncomment one line), although the default is traceur. Gulp is used for building, packaging, and lint/transpile on save. base-node contains everything to package your application into a minimal Docker container (<10MB compressed + your minified, transpiled code) with io.js. base-angular will give you a module system, LESS transpiling, live-reload (LESS/CSS changes are injected without reload), and a minified, cache-busted output that you can drop into any web server (minimal nginix containerization in the works).
I'm sure the documentation could be better, but the Readme.md has enough to get you started and the code should be very straight-forward.
Since I'm using git, I can set these master repos as the 'upstream' and whenever I make changes to the base project (like, adding containerization support) I can easily push that change out to all my projects and everything gets tracked nicely in the revision graph. The `create.sh` script in base-node will actually do that rewiring for you.
> npm may eventually support two versions of the same module, which would enable you to deliver libraries as both ES5 and ES6 for Node.js, io.js and client-side module systems that are based on npm.
No, please no. Why would I ever want to deliver a library in both modes just for some better / different syntax? Yes ES6 is nicer than ES5 but doubling the modules isn't worth it at all.
I still think a better solution is some sort of byte code so people can use whatever language they want instead of trying to force JavaScript to be the "byte code of the web".
Transpilation is really the only option... And even using a common bytecode, there will still be a compile step which is separate from the source, and requires mapping to be able to associate the bytecode to the source with the same potential for bugs you are complaining about.
Has it really been tried though? I've never seen more than a few half assed attempts without all parties involved. I've love to see them come together to work something like this out; the web as it exists today isn't nearly as snappy or nice as native apps so I feel like something will eventually change here. Whether that's the help of a bytecode implementation or something else I'm not sure.
> And even using a common bytecode, there will still be a compile step which is separate from the source, and requires mapping to be able to associate the bytecode to the source with the same potential for bugs you are complaining about.
Yes there is always potential for compilation to introduce bugs but compiling into a bytecode is vasty different from compiling into JavaScript. JavaScript is a functional language with a lot of quirks; Java bytecode and .Net's MSIL, for comparison, are very raw and fast with as few features as possible. It's significantly better to compile into some form of bytecode for later execution than compiling into another human-readable language.
Also, if you are creating more discrete modules, the transpile time for a given module isn't bad at all. From a given project, I'm just bringing in `mymodule` and don't have to think about it beyond that... using jsparta, I can test against the es6 version for coverage, etc... and with mappings, the merged/minified JS the client sees can still reference the real starting point.
for the most part it's much friendlier when you embrace npm/node workflows with browserify (or webpack). With this in place, you always write/work against your es6-style. I use commonjs module syntax instead of imports, but may change my approach in the future.
You use commonjs with es6? Why?
I can sympathize the initial fear of transpiling. However, it really is much better than you think. Source maps have made big strides in the past year and Babel has excellent support for them.
Besides source maps, Babel does a lot to keep the generated code as similar as possible to the input. There are very few features that require complex transpiling.
Another neat trick I've learned recently is that when you are debugging in a modern browser that does not require certain features to be transpiled, you can simply blacklist them in Babel and debug them natively. Then when you are deploying you can turn transpiling back on for everything and support every browser. (Note: be careful that you don't blacklist features with buggy implementations)
Transpiling is quite nice, and it's very likely that you already do it with something like Uglify or Closure compiler.
> npm may eventually support two versions of the same module, which would enable you to deliver libraries as both ES5 and ES6 for Node.js, io.js and client-side module systems that are based on npm.
This will actually be necessary in the node environment if we are ever to migrate to ES6+ features without causing breaking changes for module users.
ES6 isn't just some nicer syntax/features, it's the future of JavaScript and transpilers are the way we are going to get there.
I understand all that but after being bitten by the CoffeeScript transpiler on multiple occasions and Google's closure once, I try to avoid it at all costs. It adds an additional level of complexity to projects (needing to transpile before testing / debugging) and I just don't want to risk it for such little return, in my opinion.
I'm sympathetic to the cause of getting more people using ES6 and this is a way to do it today but personally I won't use it until ES6 is native in all of my browser and server targets.
> Transpiling is quite nice, and it's very likely that you already do it with something like Uglify or Closure compiler.
I've run into an issue with Closure at a point in the past (essentially the optimization to make everything into one statement breaking Opera; that was almost impossible to figure out but thankfully someone else did). But I do use Uglify; I try to limit it to compression only but it still changes things here and there (at least it appeared to; honestly it's been a while since I've dug into that code).
Minification, especially without all of the features enabled, should be safer than any other type of transpiler considering it has far less to do and many of the changes should be able to do so without consequence. Even still I do re-run all of my unit tests against minified versions of my code. It also makes me uneasy still but seems to be a necessary evil :)
>> npm may eventually support two versions of the same module, which would enable you to deliver libraries as both ES5 and ES6 for Node.js, io.js and client-side module systems that are based on npm. > This will actually be necessary in the node environment if we are ever to migrate to ES6+ features without causing breaking changes for module users.
I'm having a hard time believing this will happen. This adds complexity to every module as they now have to maintain an ES6 and an ES5 version should they actually want to use ES6. Yeah they can transpile but they still have two modules to maintain, track bugs in case there is a difference, etc. This is unrealistic in my opinion and I don't get why it's even necessary; simply make a certain version of node be required if you want to use ES6. If users can't do that they'll have to use an older version.
Moving to native ES6 on node should happen really quickly compared to the browser space. The browser space is going to be painful.
Also seems like the best way to ease into it.