ES6 in Production

ES6 in Production

Everybody is talking about ES6, but is anyone out there using it in production? Mango recently started adopting ES6 features that make our front-end code easier to write and maintain.

In this talk, I will explain why we decided to use ES6, how we started to use it in production (using npm, browserify and babel) and I'll explain what problems we found along the way and how we solved them.

Links:
https://getmango.com
https://getmango.com/blog/writing-es6-modules-with-6to5/
http://kangax.github.io/compat-table/
https://github.com/zloirock/core-js
https://github.com/mango/emitter
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts
http://benmccormick.org/2015/04/07/es6-classes-and-backbone-js/

F8a70e01eddbadc5e4f9876ff34494fa?s=128

Guille Paz

April 25, 2015
Tweet

Transcript

  1. ES6 in Production JSConf Uruguay 2015

  2. - Made in Buenos Aires, Argentina - Front-end Developer -

    Working at Mango @pazguille (twitter / github) Guille Paz
  3. #ES6inProd Your feedback is welcome!

  4. ES6

  5. Hi! https://getmango.com

  6. Why?

  7. Why?

  8. Future Why?

  9. Why? Code

  10. Why? • Write expressive code

  11. Why? • Write expressive code • Easier to understand

  12. Why? • Write expressive code • Easier to understand •

    Standardizes commons practices
  13. Why? ES6 Modules

  14. define('Slideout', // Deps ['inherit', 'Emitter'], // Slideout function(inherit, Emitter) {

    function Slideout(options) { … } // Export return Slideout; }); Why? AMD
  15. // Deps var inherit = require('inherit'); var Emitter = require('emitter');

    // Slideout function Slideout(options) { … } // Export module.exports = Slideout; Why? CommonJS
  16. Why? ES6 Modules // Deps import inherit from 'inherit'; import

    Emitter from 'emitter'; // Slideout function Slideout(options) { … } // Export export default Slideout;
  17. Why? Classes

  18. None
  19. // Slideout function Slideout(options) { … } // Inherit from

    Emitter inherit(Slideout, Emitter); // Extend prototype Slideout.prototype.open = function() { … }; Why? Classes
  20. // Slideout class Slideout extends Emitter { constructor(options={}) { …

    } open() { … } } Why? Classes
  21. // Deps var inherit = require('inherit'); var Emitter = require('emitter');

    // Slideout function Slideout(options) { … } // Inherit from Emitter inherit(Slideout, Emitter); // Extend prototype Slideout.prototype.open = function() { … }; // Export module.exports = Slideout; Why?
  22. // Deps var inherit = require('inherit'); var Emitter = require('emitter');

    // Slideout function Slideout(options) { … } // Inherit from Emitter inherit(Slideout, Emitter); // Extend prototype Slideout.prototype.open = function() { … }; // Export module.exports = Slideout; Why? // Deps import Emitter from 'emitter'; // Slideout class Slideout extends Emitter { constructor(options={}) { … } open() { … } } // Export export default Slideout;
  23. Why? Classes arrow = > functions Module Syntax let/const Rest

    Parameters Templates Strings Default Parameters
  24. getmango.com/blog https://getmango.com/blog/writing-es6-modules-with-6to5/

  25. How?

  26. Transpilers How?

  27. How? ES6 ES5

  28. How?

  29. How?

  30. Build Process How?

  31. How?

  32. browserify({'entries': opts.entries, 'debug': true}) .plugin('factor-bundle', {'outputs': opts.bundles}) .on('error', function(err) {

    … }) .bundle() .pipe(fs.createWriteStream(opts.output)); How?
  33. How? Babelify

  34. browserify({'entries': opts.entries, 'debug': true}) .plugin('factor-bundle', {'outputs': opts.bundles}) .transform('babelify') .on('error', function(err)

    { … }) .bundle() .pipe(fs.createWriteStream(opts.output)); How?
  35. Browser How?

  36. How? http://kangax.github.io/compat-table/es5/ ES5

  37. Polyfills How?

  38. How? http://kangax.github.io/compat-table/es6/ ES6

  39. core-js How? https://github.com/zloirock/core-js

  40. How? es5.js (IE < 9) Custom build https://github.com/zloirock/core-js

  41. How? es5.js (IE < 9) es6.js (all) Custom build https://github.com/zloirock/core-js

  42. index.html How? … <!--[if lt IE 9]> <script src="/js/es5.js"></script> <![endif]-->

    <script src="/js/es6.js"></script> <script src="/js/build.js"></script> </body>
  43. None
  44. None
  45. Issues

  46. Issues Context

  47. ~110 modules Issues

  48. Issues

  49. ES5 / ES6 Issues

  50. Dependencies Issues

  51. Issues ├─ src ├─ boot.js └─ bus.js ├─ package.json ├─

    test └─ node_modules ├─ slideout └─ emitter Dashboard ES6 ES6
  52. Issues bus.js // Deps import Emitter from 'emitter'; // bus

    const bus = new Emitter(); // Export export default bus;
  53. Issues

  54. … exports['default'] = bus; module.exports = exports['default']; },{'emitter':2}],2:[function(require,module,exports){ class Emitter

    { on(event, listener) { … Issues output.js
  55. None
  56. Issues Dashboard ├─ src ├─ boot.js └─ bus.js ├─ package.json

    ├─ test └─ node_modules ├─ slideout └─ emitter Babelify
  57. Issues Dashboard ├─ src ├─ boot.js └─ bus.js ├─ package.json

    ├─ test └─ node_modules ├─ slideout └─ emitter Babelify
  58. Issues Dashboard ├─ src ├─ boot.js └─ bus.js ├─ package.json

    ├─ test └─ node_modules ├─ slideout └─ emitter Babelify
  59. global : true Issues

  60. browserify({'entries': opts.entries, 'debug': true}) .plugin('factor-bundle', {'outputs': opts.bundles}) .transform('babelify') .on('error', function(err)

    { … }) .bundle() .pipe(fs.createWriteStream(opts.output)); Issues
  61. browserify({'entries': opts.entries, 'debug': true}) .plugin('factor-bundle', {'outputs': opts.bundles}) .transform('babelify', {'global': true})

    .on('error', function(err) { … }) .bundle() .pipe(fs.createWriteStream(opts.output)); Issues
  62. … exports['default'] = bus; module.exports = exports['default']; },{'emitter':2}],2:[function(require,module,exports){ var Emitter

    = (function () { function Emitter() { … Issues output.js
  63. package.json Issues

  64. … "browserify": { "transform": ["babelify"] }, … Issues Emitter.js -

    package.json
  65. … "browserify": { "transform": ["babelify"] }, "dependencies": { "babelify": "6.0.2"

    }, … Issues Emitter.js - package.json
  66. Issues

  67. Writing ES6 Issues

  68. Publishing ES5 Issues

  69. Issues Module ├─ src └─ index.js ├─ package.json └─ test

  70. Issues Module ├─ src └─ index.js ├─ package.json └─ test

    ES6
  71. Issues Module ES5 ├─ src └─ index.js ├─ package.json └─

    test ├─ dist └─ index.js
  72. … "main": "dist/index.js", … Issues package.json

  73. Issues Compile Task (npm, grunt, gulp, broccoli)

  74. … "main": "dist/index.js", "script": { "compile": "babel src --out-dir dist"

    }, … Issues Compile Task
  75. Issues npm run compile

  76. … "main": "dist/index.js", "script": { "compile": "babel src --out-dir dist",

    "prepublish": "npm run compile" }, … Issues Prepublish Task
  77. mango/emitter Issues https://github.com/mango/emitter

  78. Inheritance Issues

  79. 'use strict'; var extend = require('extend'); // Inherits prototype properties

    module.exports = function inherit(child, parent) { extend(child.prototype, parent.prototype); return parent.prototype; }; Issues inherit.js - ES5
  80. Issues Emitter.js - ES6 class Emitter { constructor(options={}) { …

    } on() { … } emit() { … } … } export default Emitter;
  81. // Deps var inherit = require('inherit'); var Emitter = require('emitter');

    // Slideout function Slideout(options) { … } // Inherit from Emitter inherit(Slideout, Emitter); // Extend prototype Slideout.prototype.open = function() { … }; // Export module.export = Slideout; Issues Slideout.js - ES5
  82. // Deps var inherit = require('inherit'); var Emitter = require('emitter');

    // Slideout function Slideout(options) { … } // Inherit from Emitter inherit(Slideout, Emitter); // Extend prototype Slideout.prototype.open = function() { … }; // Export module.export = Slideout; Issues Slideout.js - ES5
  83. console.log(Slideout.prototype); // { open: function } Issues Slideout.js - ES5

  84. console.log(Emitter.prototype); // { } Issues Emitter.js - ES6

  85. Issues http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

  86. Issues

  87. class Emitter { … on() { … } … }

    Issues Emitter.js - ES6
  88. class Emitter { … on() { … } … }

    Issues Emitter.js - ES5 function Emitter() {} Object.defineProperties(Emitter.prototype, { 'on': { 'writable': true, 'configurable': true, 'enumerable': false, 'value': function on() {} } });
  89. class Emitter { … on() { … } … }

    Issues Emitter.js - ES5 function Emitter() {} Object.defineProperties(Emitter.prototype, { 'on': { 'writable': true, 'configurable': true, 'enumerable': false, 'value': function on() {} } });
  90. Loose Mode (babel) Issues

  91. Issues es6.classes

  92. browserify({'entries': opts.entries, 'debug': true}) .plugin('factor-bundle', {'outputs': opts.bundles}) .transform('babelify', {'global': true,

    'loose': ['es6.classes']}) .on('error', function(err) { … }) .bundle() .pipe(fs.createWriteStream(opts.output)); Issues Build Process
  93. class Emitter { … on() { … } … }

    Issues Emitter.js - ES5 var Emitter = (function () { function Emitter() { … } Emitter.prototype.on = function on() {}; … return Emitter; })();
  94. console.log(Slideout.prototype); // { open: function, on: function } Issues Slideout.js

    - ES5
  95. Object.create Issues

  96. 'use strict'; var extend = require('extend'); // Inherits prototype properties.

    module.exports = function inherit(child, parent) { extend(child.prototype, parent.prototype); return parent.prototype; }; Issues inherit.js - ES5
  97. 'use strict'; // Inherits prototype properties. module.exports = function inherit(child,

    parent) { child.prototype = Object.create(parent.prototype); return parent.prototype; }; Issues inherit.js - ES5
  98. super() - this Issues

  99. class Slideout extends Emitter { constructor(options={}) { this._padding = options.padding;

    … } } Issues Slideout.js - ES6
  100. Line 12: 'this' is not allowed before super() Issues

  101. class Slideout extends Emitter { constructor(options={}) { this._padding = options.padding;

    … } } Issues Slideout.js - ES6
  102. class Slideout extends Emitter { constructor(options={}) { super(options); this._padding =

    options.padding; … } } Issues Slideout.js - ES6
  103. Issues https://twitter.com/jashkenas/status/585458831993528320

  104. Issues http://benmccormick.org/2015/04/07/es6-classes-and-backbone-js/

  105. import & hoisting Issues

  106. import _ from 'i18n'; import translations from 'translations.json'; _.add(translations); import

    login from './login'; … Issues Login View - ES6
  107. import _ from 'i18n'; import translations from 'translations.json'; _.add(translations); import

    login from './login'; … Issues Login View - ES6
  108. Issues

  109. Issues Login View - ES5 var _import = require('i18n'); var

    _import2 = _interopRequireWildcard(_import); var _translations = require('translations.json'); var _translations2 = _interopRequireWildcard(_translations); var _login = require('./login'); var __login2 = _interopRequireWildcard(__login); _import2['default'].add(_translations2['default']);
  110. var _import = require('i18n'); var _import2 = _interopRequireWildcard(_import); var _translations

    = require('translations.json'); var _translations2 = _interopRequireWildcard(_translations); var _login = require('./login'); var __login2 = _interopRequireWildcard(__login); _import2['default'].add(_translations2['default']); Issues Login View - ES5
  111. Issues

  112. Babel 4.1.7 Issues

  113. Takeaway

  114. • Transpile to ES5 (Babel) Takeaway

  115. • Transpile to ES5 (Babel) • Use ES5/ES6 polyfills (core-js)

    Takeaway
  116. • Transpile to ES5 (Babel) • Use ES5/ES6 polyfills (core-js)

    • Babelify: opts.global or package.json Takeaway
  117. Takeaway • Transpile to ES5 (Babel) • Use ES5/ES6 polyfills

    (core-js) • Babelify: opts.global or package.json • Write ES6, publish ES5 (compile task)
  118. • Transpile to ES5 (Babel) • Use ES5/ES6 polyfills (core-js)

    • Babelify: opts.global or package.json • Write ES6, publish ES5 (compile task) • Babel - loose mode (es6.classes, es6.modules, … ) Takeaway
  119. Thank you! <3