Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modernizing the Sencha class system

Modernizing the Sencha class system

Presentation by Lee Boonstra. Sencha Roadshows 2016

Lee Boonstra

December 09, 2016
Tweet

More Decks by Lee Boonstra

Other Decks in Technology

Transcript

  1. Modernizing the Ext JS Class System
    Lee Boonstra
    @ladysign

    View Slide

  2. Agenda
    • Background
    - Goals for language and tools
    - Transpilers & Source maps
    • Class system content
    - Modules
    - Classes & Mixins
    - Life-cycle
    • The Road Ahead

    View Slide

  3. “ What you know as JavaScript in browsers and
    Node.js is actually a superset of ECMAScript.
    Browsers and Node.js add more functionality
    through additional objects and methods, but the
    core of the language remains as defined in
    ECMAScript.

    View Slide

  4. Terminology
    • JavaScript - the language name
    • ECMAScript - the name of the standard
    • ES2015 / ES6 – Newest version of the ECMAScript standard
    • Transpiler - Transforms ES2015 code to the
    JavaScript that currently supported in our browsers.

    View Slide

  5. History

    View Slide

  6. About Compatibility
    You can find an overview of compatibility, in one of these ECMAScript 2015 compatibility
    tables: http://kangax.github.io/compat-table/es6/
    ES2015 Implementations:
    • V8 (Chrome, Node.js, Opera)
    • JavaScript Core (Webkit, Safari)
    • Chakra (MS Edge)
    • SpiderMonkey (Firefox)
    • Mobile (iOS 9+, Android 4.4+)

    View Slide

  7. Goals for language and tools

    View Slide

  8. Ext.define('MyApp.view.MyGrid ', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.mygrid',
    //configs for a custom grid
    });
    Why Ext JS?
    • Cross platform apps.
    - Support for legacy and modern browsers.
    - All types of devices
    • One framework, to develop complex
    applications fast.
    • Components, components,
    components…

    View Slide

  9. import { define } from '@extjs/kernel';
    import { grid } from '@extjs/modern';
    class MyApp.view.MyGrid extends grid {
    //configs for a custom grid
    }
    export default MyApp.view.MyGrid;
    ES2015 style of code
    The Benefits:
    • ES2015, helps you with developer
    productivity.
    • Can make use of new tools.
    • As a JS developer you can make use of
    the latest standards.
    • Reduces the Ext JS learning curve.

    View Slide

  10. We need a balance between
    Future-proofing vs. Compatibility

    View Slide

  11. Future-proofing
    Balance Between…
    Compatibility
    Ext.define works as before
    Existing code organization is supported
    Ext.require works as before
    callParent must be available
    Ext namespace is globally available
    New class syntax can derive from any class
    Module-based structure
    import and export syntax is supported
    super calls must work (strict mode)
    Ext is scoped to its module

    View Slide

  12. YOU PROMISED ME
    NOT TO REWRITE MY CODE

    View Slide

  13. Sencha will provide an upgrade tool
    to transform an old Ext.define
    code base to the modern
    ES2015 class syntax!

    View Slide

  14. There are Frameworks and Tools everywhere
    JavaScript is here to stay.

    View Slide

  15. ES2015 Score Cards
    Windows 7
    http://kangax.github.io/compat-table/es6/

    View Slide

  16. Tools Enable Language Adoption
    Build Tool Trends
    https://www.google.com/trends/explore?cat=5&q=grunt,gulp,webpack

    View Slide

  17. New Build Tool
    Open tooling platform

    View Slide

  18. Transpilers and Source Maps

    View Slide

  19. Transpilers
    • Transpilers (like Babel) are JavaScript-to-JavaScript compilers
    • Transpilers go beyond “polyfills” by providing missing language syntax!
    • Transpilers are currently the only platforms that accept imports, exports and decorators
    • Transpilers allow us to future-proof our code (unblocking the language adoption curve)
    - No more “I have to develop code for the worst supported browsers”
    • (though, not everything can be fixed by tools)

    View Slide

  20. Source Maps
    • Source Maps enable the debugger to display the original source code…
    - …not the ugly transpiler output!
    • Source Maps have been around since 2012
    - This is great because they are widely supported
    • Source Maps are supported by:
    - Chrome, Firefox, Edge, Safari
    - IE11 (with Windows 8.1 Update)
    See: https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

    View Slide

  21. 21
    HANDED THE MOST DANGEROUS WEAPON
    IN THE GALAXY…
    IMMEDIATELY POINT AT FACE

    View Slide

  22. Trust, But Be Careful with it
    • Transpilers can produce some scary code
    - Only transpile away what your target browser(s) do not support
    - Check what is produced if performance or code size is a concern
    - Especially if you need to support browsers like IE 11… or Safari 9 (or older)
    • Even natively supported idioms can have surprising performance
    - The “for…of” loop construct – awesome syntax! Not-so-great performance
    https://kpdecker.github.io/six-speed/

    View Slide

  23. Trust, But Verify
    ES5: for loop vs. ES2015: for...of loop
    var data = [1, 2, 3];
    var ret = '';
    for (var value of data) {
    ret += value;
    }
    var data = [1, 2, 3];
    var ret = '';
    for (var i = 0; i < data.length; ++i) {
    ret += data[i];
    }

    View Slide

  24. Class System Contents

    View Slide

  25. Namespaces vs Modules

    View Slide

  26. Ext = {};
    Ext.global = window;
    Ext.global.Ext = Ext;
    Ext.define('App.some.Thing', {
    extend: 'App.foo.Bar',
    requires: [ 'Ext.grid.Panel' ],
    ExtJS: Namespaces
    • Namespaces are nested objects
    • Ext.define() defines class & adds to the
    namespace
    • The Loader maps names to URL’s
    • Files are loaded at global scope
    Ext = {
    global: {
    Ext: Ext,
    App: {
    foo: {
    Bar: constructor
    },
    some: {
    Thing: constructor
    }
    }
    },
    grid: {
    Panel: constructor
    }
    }
    Ext.Loader.setPath({
    Ext: '../ext/src',
    App: './app'
    });
    // Ext.grid.Panel
    // => '../ext/src/grid/Panel.js'
    // App.foo.Bar
    // => './app/foo/Bar.js'

    View Slide

  27. var foo = 'bar'; // private, not global
    export var abc = 'abc';
    export default class Bar {
    // ...
    }
    New: ES2015 Modules
    • Modules are files
    • Modules execute in a private scope (not
    global)
    • Modules publish values using export
    • Modules can have one, unnamed “default”
    export value
    • Modules use import to acquire values
    exported by other modules
    • Modules are imported by path or name
    ./path/file.js
    import { abc } from '../path/file';
    import Bar from '../path/file.js';
    import Ext from '@extjs/kernel';
    import { define } from '@extjs/kernel';
    ./other/thing.js

    View Slide

  28. import { button } from '@extjs/modern';
    import { hbox } from '@extjs/modern/layout';
    import { Ext_Button } from '@extjs/modern';
    New: Importing Components
    • Classes are exported in several ways:
    - By xtype
    - By alias family
    - By class name
    • These would be used where strings
    might be used today
    • These exports can be generated by the
    new build tool

    View Slide

  29. Sencha Cmd Understands Namespaces
    The New Build Tool Understands Modules

    View Slide

  30. Classes

    View Slide

  31. Ext.define('App.some.Thing', {
    extend: 'App.foo.Bar',
    requires: [ 'Ext.grid.Panel' ],
    alias: 'thing',
    text: 'Hello',
    constructor: function (config) {
    this.callParent([config]);
    },
    method: function (x) {
    return this.callParent([x]) * 42;
    },
    statics: {
    create: function (cfg) {
    cfg.type = 'thing';
    return this.callParent([cfg]);
    }
    }
    });
    ExtJS: Classes
    Ext.define()
    • Inheritance
    • Requires (directives)
    • Properties
    • Constructors
    • Methods
    • Static methods
    • callParent

    View Slide

  32. import { define } from '@extjs/kernel';
    import { grid } from '@extjs/modern';
    import Bar from 'app/foo';
    @define('App.some.Thing', {
    alias: 'thing',
    text: 'Hello'
    })
    class Thing extends Bar {
    method (x) {
    return super.method(x) * 42;
    }
    static create (cfg) {
    cfg.type = 'thing';
    return super.create(cfg);
    }
    }
    export default Thing;
    New: ES2015 Classes
    import - export - class - @define
    • Inheritance
    • Directives
    • Properties
    • Methods
    • Static methods
    • Super calls (callParent)
    Decorator

    View Slide

  33. function define (className, body) {
    return T => {
    T.define(className, body);
    };
    }
    @define('ShootAble', {
    alias: 'gun',
    shoot: function(){ return 'Pow!' }
    })
    class HanSolo extends Human {
    }
    New: Decorators
    • Decorators are functions that
    manipulate classes (or methods)
    • Decorators can accept arguments…
    - But must return a function to call as if no
    arguments were provided
    • The @decorator syntax is just a
    different way to call these functions
    • Decorators are currently a Stage 2
    proposal (not yet standardized)
    https://github.com/tc39/proposals
    //another way of achieving the same without a decorator:
    define('ShootAble', {
    alias: 'gun',
    shoot: function(){ return 'Pow!' }
    })(HanSolo);

    View Slide

  34. class Foo {
    constructor (x) {
    this.x = 42;
    }
    }
    new Foo(42);
    let obj = {};
    Foo.call(obj, 42);
    ES2015: Restrictions on constructor
    • A constructor can only be called with
    the new operator.
    • Calling a constructor with call() or
    apply() throws a TypeError.

    View Slide

  35. Mixins

    View Slide

  36. Ext.define('Clickable', {
    click: function (e) {
    //click
    }
    });
    Ext.define('MyApp.custom.Component', {
    extend: 'Ext.Component',
    mixins: [ 'Clickable' ],
    });
    Ext.define('MyApp.view.OtherComponent', {
    extend: 'Ext.Component',
    mixins: [ 'Clickable' ],
    click: function (e) {
    this.mixins.clickable.click.call(this);
    }
    });
    ExtJS: Mixins
    • Mixins is multiple inheritance
    • Mixins are classes
    • Methods from the mixin prototype are
    copied to the target class prototype
    • Unless there is already a method
    present
    component.click();

    View Slide

  37. import { Ext, define } from '@extjs/kernel';
    import MyComponent from 'app/view';
    class Clickable extends Ext.Base {
    click (e) {
    //click
    }
    }
    @define({ mixins: [ Clickable ] })
    class OtherComponent extends MyComponent {
    click (e) {
    this.mixins.clickable.click.call(this);
    }
    }
    @define({ extend: [ Clickable ] })
    class OtherComponent extends MyComponent {
    click (e) {
    super.click(e);
    }
    }
    ES2015: Mixins
    • Mixins are classes (extend Ext.Base)
    • Use @define to mix in the mixin(s)
    • Mixins will be able to act more like a true
    base
    - The extend directive accepts mixins
    - Calls to overlapping methods are handled in
    the super call

    View Slide

  38. Common Object Life-cycle

    View Slide

  39. The Life-cycle of Ext.Base
    Creation
    • Instances are created with operator new
    - or Ext.create() or other factory
    • The native constructor is available to ES2015 classes
    - Not recommended in most cases
    • The construct method is available to all classes
    - The new name for the old constructor

    View Slide

  40. The Life-cycle of Ext.Base
    Configuration
    • Use the config directive to define configuration properties
    • Config system calls your apply and update methods
    • Ext.Base construct calls initConfig

    View Slide

  41. The Life-cycle of Ext.Base
    Destruction
    • Cleanup is handled by destroy
    • Sets flags like destroying and destroyed
    • Ignores multiple calls
    • Calls destruct (just once)
    • New: Clears instance properties to avoid memory leaks

    View Slide

  42. import Ext from '@extjs/kernel';
    class Human extends Ext.Base {
    construct (config) {
    super.construct();
    this.talk = function(){ return “Hello!” };
    }
    class HanSolo extends Human {
    construct (config) {
    super.construct(config);
    this.shoot = function() { return “Pow!” };
    }
    @define({ mixins: [ HanSolo ] })
    class Wookie extends Ext.Base {
    construct (config) {
    super.construct();
    this.mixins.hansolo.construct(config);
    this.talk = function() { “Roarrrrr!” };
    }
    }
    new Wookie();
    Life-cycles
    Human
    Ext.Base
    HanSolo
    Wookie

    View Slide

  43. The Road Ahead

    View Slide

  44. The Road Ahead
    Sencha Cmd 6.5
    • Available now (Early Access)!
    • Uses Google Closure Compiler
    • Supports much of the ES2015 syntax (http://kangax.github.io/compat-table/es6/)
    • Provides polyfills as well
    • Transpiling is optional
    • New compressor (replaces YUI) can process native ES2015 code

    View Slide

  45. The Road Ahead
    Ext JS.Next
    • Framework will have changes in Ext.Base
    • New Build Tool and new Sencha Cmd
    • Upgrade tool to convert from projects from Cmd to Build
    • Estimated at 2nd half of 2017

    View Slide

  46. Questions?
    @ladysign

    View Slide

  47. Thank you!
    @ladysign

    View Slide