$30 off During Our Annual Pro Sale. View Details »

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/

Guille Paz

April 25, 2015
Tweet

More Decks by Guille Paz

Other Decks in Technology

Transcript

  1. ES6 in Production
    JSConf Uruguay 2015

    View Slide

  2. - Made in Buenos Aires, Argentina
    - Front-end Developer
    - Working at Mango
    @pazguille (twitter / github)
    Guille Paz

    View Slide

  3. #ES6inProd
    Your feedback is welcome!

    View Slide

  4. ES6

    View Slide

  5. Hi!
    https://getmango.com

    View Slide

  6. Why?

    View Slide

  7. Why?

    View Slide

  8. Future
    Why?

    View Slide

  9. Why?
    Code

    View Slide

  10. Why?
    ● Write expressive code

    View Slide

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

    View Slide

  12. Why?
    ● Write expressive code
    ● Easier to understand
    ● Standardizes commons practices

    View Slide

  13. Why?
    ES6 Modules

    View Slide

  14. define('Slideout',
    // Deps
    ['inherit', 'Emitter'],
    // Slideout
    function(inherit, Emitter) {
    function Slideout(options) { … }
    // Export
    return Slideout;
    });
    Why?
    AMD

    View Slide

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

    View Slide

  16. Why?
    ES6 Modules
    // Deps
    import inherit from 'inherit';
    import Emitter from 'emitter';
    // Slideout
    function Slideout(options) { … }
    // Export
    export default Slideout;

    View Slide

  17. Why?
    Classes

    View Slide

  18. View Slide

  19. // Slideout
    function Slideout(options) { … }
    // Inherit from Emitter
    inherit(Slideout, Emitter);
    // Extend prototype
    Slideout.prototype.open = function() { … };
    Why?
    Classes

    View Slide

  20. // Slideout
    class Slideout extends Emitter {
    constructor(options={}) { … }
    open() { … }
    }
    Why?
    Classes

    View Slide

  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?

    View Slide

  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;

    View Slide

  23. Why?
    Classes
    arrow = > functions
    Module Syntax
    let/const
    Rest Parameters
    Templates Strings Default Parameters

    View Slide

  24. getmango.com/blog
    https://getmango.com/blog/writing-es6-modules-with-6to5/

    View Slide

  25. How?

    View Slide

  26. Transpilers
    How?

    View Slide

  27. How?
    ES6 ES5

    View Slide

  28. How?

    View Slide

  29. How?

    View Slide

  30. Build Process
    How?

    View Slide

  31. How?

    View Slide

  32. browserify({'entries': opts.entries, 'debug': true})
    .plugin('factor-bundle', {'outputs': opts.bundles})
    .on('error', function(err) { … })
    .bundle()
    .pipe(fs.createWriteStream(opts.output));
    How?

    View Slide

  33. How?
    Babelify

    View Slide

  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?

    View Slide

  35. Browser
    How?

    View Slide

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

    View Slide

  37. Polyfills
    How?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  42. index.html
    How?




    View Slide

  43. View Slide

  44. View Slide

  45. Issues

    View Slide

  46. Issues
    Context

    View Slide

  47. ~110 modules
    Issues

    View Slide

  48. Issues

    View Slide

  49. ES5 / ES6
    Issues

    View Slide

  50. Dependencies
    Issues

    View Slide

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

    View Slide

  52. Issues
    bus.js
    // Deps
    import Emitter from 'emitter';
    // bus
    const bus = new Emitter();
    // Export
    export default bus;

    View Slide

  53. Issues

    View Slide


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

    Issues
    output.js

    View Slide

  55. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  59. global : true
    Issues

    View Slide

  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

    View Slide

  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

    View Slide


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

    Issues
    output.js

    View Slide

  63. package.json
    Issues

    View Slide


  64. "browserify": {
    "transform": ["babelify"]
    },

    Issues
    Emitter.js - package.json

    View Slide


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

    Issues
    Emitter.js - package.json

    View Slide

  66. Issues

    View Slide

  67. Writing ES6
    Issues

    View Slide

  68. Publishing ES5
    Issues

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide


  72. "main": "dist/index.js",

    Issues
    package.json

    View Slide

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

    View Slide


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

    Issues
    Compile Task

    View Slide

  75. Issues
    npm run compile

    View Slide


  76. "main": "dist/index.js",
    "script": {
    "compile": "babel src --out-dir dist",
    "prepublish": "npm run compile"
    },

    Issues
    Prepublish Task

    View Slide

  77. mango/emitter
    Issues
    https://github.com/mango/emitter

    View Slide

  78. Inheritance
    Issues

    View Slide

  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

    View Slide

  80. Issues
    Emitter.js - ES6
    class Emitter {
    constructor(options={}) { … }
    on() { … }
    emit() { … }

    }
    export default Emitter;

    View Slide

  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

    View Slide

  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

    View Slide

  83. console.log(Slideout.prototype);
    // { open: function }
    Issues
    Slideout.js - ES5

    View Slide

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

    View Slide

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

    View Slide

  86. Issues

    View Slide

  87. class Emitter {

    on() { … }

    }
    Issues
    Emitter.js - ES6

    View Slide

  88. class Emitter {

    on() { … }

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

    View Slide

  89. class Emitter {

    on() { … }

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

    View Slide

  90. Loose Mode
    (babel)
    Issues

    View Slide

  91. Issues
    es6.classes

    View Slide

  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

    View Slide

  93. class Emitter {

    on() { … }

    }
    Issues
    Emitter.js - ES5
    var Emitter = (function () {
    function Emitter() { … }
    Emitter.prototype.on = function on() {};

    return Emitter;
    })();

    View Slide

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

    View Slide

  95. Object.create
    Issues

    View Slide

  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

    View Slide

  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

    View Slide

  98. super() - this
    Issues

    View Slide

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

    }
    }
    Issues
    Slideout.js - ES6

    View Slide

  100. Line 12: 'this' is not allowed before super()
    Issues

    View Slide

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

    }
    }
    Issues
    Slideout.js - ES6

    View Slide

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

    }
    }
    Issues
    Slideout.js - ES6

    View Slide

  103. Issues
    https://twitter.com/jashkenas/status/585458831993528320

    View Slide

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

    View Slide

  105. import & hoisting
    Issues

    View Slide

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

    Issues
    Login View - ES6

    View Slide

  107. import _ from 'i18n';
    import translations from 'translations.json';
    _.add(translations);
    import login from './login';

    Issues
    Login View - ES6

    View Slide

  108. Issues

    View Slide

  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']);

    View Slide

  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

    View Slide

  111. Issues

    View Slide

  112. Babel 4.1.7
    Issues

    View Slide

  113. Takeaway

    View Slide

  114. ● Transpile to ES5 (Babel)
    Takeaway

    View Slide

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

    View Slide

  116. ● Transpile to ES5 (Babel)
    ● Use ES5/ES6 polyfills (core-js)
    ● Babelify: opts.global or package.json
    Takeaway

    View Slide

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

    View Slide

  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

    View Slide

  119. Thank you!
    <3

    View Slide