Category Archives: JavaScript

Enumify: better enums for JavaScript

By Axel Rauschmayer

In this blog post, I present enumify, a library for implementing enums in JavaScript. The approach it takes is inspired by Java’s enums.

Enum patterns

The following is a naive enum pattern for JavaScript:

    const Color = {
        RED: 0,
        GREEN: 1,
        BLUE: 2,
    }

This implementation has several problems:

  1. Logging: If you log an enum value such as Color.RED, you don’t see its name.
  2. Type safety: Enum values are not unique, they can be mixed up with other values.
  3. Membership check: You can’t easily check whether a given value is an element of Color.

We can fix problem #1 by using strings instead of numbers as enum values:

    const Color = {
        RED: 'RED',
        GREEN: 'GREEN',
        BLUE: 'BLUE',
    }

We additionally get type safety if we use symbols as enum values:

    const Color = {
        RED: Symbol('RED'),
        GREEN: Symbol('GREEN'),
        BLUE: Symbol('BLUE'),
    }
    console.log(String(Color.RED));
        // Symbol(RED)

One problem with symbols is that you need to convert them to strings explicitly, you can’t coerce them (e.g. via + or inside template literals):

    console.log('Color: '+Color.RED)
        // TypeError: Cannot convert a Symbol value to a string

We still don’t have a simple membership test. Using a custom class for enums gives us that. Additionally, everything becomes more customizable:

    class Color {
        constructor(name) {
            this.name = name;
        }
        toString() {
            return `Color.${this.name}`;
        }
    }
    Color.RED = new Color('RED');
    Color.GREEN = new Color('GREEN');
    Color.BLUE = new Color('BLUE');
    
    console.log(Color.RED); // Color.RED
    
    // Membership test:
    console.log(Color.GREEN instanceof Color); // true

However, this solution is slightly verbose. Let’s use a library to fix that.

The library enumify

The library enumify lets you turn classes into enums. It is available on GitHub and npm. This is how you would implement the running example via it:

    class Color extends Enum {}
    Color.initEnum(['RED', 'GREEN', 'BLUE']);
    
    console.log(Color.RED); // Color.RED
    console.log(Color.GREEN instanceof Color); // true

The enum is set up via initEnum(), a static method that Color inherits from Enum.

The library “closes” the class Color: After Color.initEnum(), you can’t create any new instances:

    > new Color()
    Error: Enum classes can't be instantiated

Properties of enum classes

enumValues

Enums get a static property enumValues, which contains an Array with all enum values:

    for (const c of Color.enumValues) {
        console.log(c);
    }
    // Output:
    // Color.RED
    // Color.GREEN
    // Color.BLUE

The values are listed in the order in which they were added to the enum class. As explained later, you can also call initEnum() with an object (vs. an Array). Even then, enumValues has the expected structure, because objects record the order in which properties are added to them.

enumValueOf()

The inherited tool method enumValueOf() maps names to values:

    > Color.enumValueOf('RED') === Color.RED
    true

This method is useful for parsing enum values (e.g. if you want to retrieve them from JSON data).

Properties of enum values

Enumify adds two properties to every enum value:

  • name: the name of the enum value.

        > Color.BLUE.name
        'BLUE'
    
  • ordinal: the position of the enum value within the Array enumValues.

        > Color.BLUE.ordinal
        2
    

Advanced features

Custom properties for enum values

initEnum() also accepts an object as its parameter. That enables you to add properties to enum values.

    class TicTacToeColor extends Enum {}
    
    // Alas, data properties don't work, because the enum
    // values (TicTacToeColor.X etc.) don't exist when
    // the object literals are evaluated.
    TicTacToeColor.initEnum({
        O: {
            get inverse() { return TicTacToeColor.X },
        },
        X: {
            get inverse() { return TicTacToeColor.O },
        },
    });
    
    console.log(TicTacToeColor.O.inverse); // TicTacToeColor.X

Another use case for this feature is defining commands for a user interface:

    class Command extends Enum {}
    Command.initEnum({
        CLEAR: {
            description: 'Clear all entries',
            run() { /* ··· */ },
        },
        ADD_NEW: {
            description: 'Add new',
            run() { /* ··· */ },
        },
    });
    console.log('Available commands:');
    for (let cmd of Command.enumValues) {
        console.log(cmd.description);
    }
    // Output:
    // Available commands:
    // Clear all entries
    // Add new

The instance-specific method run() executes the command. enumValues enables us to list all available commands.

Custom prototype methods

If you want all enum values to have the same method, you simply add it to the enum class:

    class Weekday extends Enum {
        isBusinessDay() {
            switch (this) {
                case Weekday.SATURDAY:
                case Weekday.SUNDAY:
                    return false;
                default:
                    return true;
            }
        }
    }
    Weekday.initEnum([
        'MONDAY', 'TUESDAY', 'WEDNESDAY',
        'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']);
    
    console.log(Weekday.SATURDAY.isBusinessDay()); // false
    console.log(Weekday.MONDAY.isBusinessDay()); // true

State machines via enums

Enums help with implementing state machines. This is an example:

    class Result extends Enum {}
    Result.initEnum(['ACCEPTED', 'REJECTED']);
    
    class State extends Enum {}
    State.initEnum({
        START: {
            enter(iter) {
                const {value,done} = iter.next();
                if (done) {
                    return Result.REJECTED;
                }
                switch (value) {
                    case 'A':
                        return State.A_SEQUENCE;
                    default:
                        return Result.REJECTED;
                }
            }
        },
        A_SEQUENCE: ···,
        B_SEQUENCE: ···,
        ACCEPT: {
            enter(iter) {
                return Result.ACCEPTED;
            }
        },
    });
    function runStateMachine(str) {
        let iter = str[Symbol.iterator]();
        let state = State.START;
        while (true) {
            state = state.enter(iter);
            switch (state) {
                case Result.ACCEPTED:
                    return true;
                case Result.REJECTED:
                    return false;
            }
        }
    }
    
    runStateMachine('AABBB'); // true
    runStateMachine('AA'); // false
    runStateMachine('AABBC'); // false

Enums in TypeScript

TypeScript has built-in support for enums:

    enum Color {
        RED, GREEN, BLUE
    }

This is how the enum is implemented:

    var Color;
    (function (Color) {
        Color[Color["RED"] = 0] = "RED";
        Color[Color["GREEN"] = 1] = "GREEN";
        Color[Color["BLUE"] = 2] = "BLUE";
    })(Color || (Color = {}));

This code makes the following assignments:

    Color["RED"] = 0;
    Color["GREEN"] = 1;
    Color["BLUE"] = 2;
    
    Color[0] = "RED";
    Color[1] = "GREEN";
    Color[2] = "BLUE";

TypeScript’s enums have all the disadvantages mentioned for the first enum example earlier: No names for logging, no type safety and no membership tests. You can’t customize these enums, either.

Source:: 2ality

Think You Know ES6? Prove it!

By Danny Markov

ES6-quiz

Your favorite web scripting language just got even better! The 2015 edition of ECMAScript comes with a ton of cool new techniques and programming concepts, much anticipated by the JavaScript community. Most of the new features are already available out of the box with modern browsers and Node.js, and are expected to receive wide support soon.

We’ve prepared a fun quiz which you can take to see how much you know about ES6 (aka ES2015), and maybe learn a few new things as well!

(See this quiz on Tutorialzine.com)

Source:: Tutorialzine.com

classes-inner-names

By Axel Rauschmayer

This blog post explains that classes have lexical inner names, just like named function expressions.

The inner names of function expressions

You may know that function expressions have lexical inner names:

    const fac = function me(n) {
        if (n > 0) {
            // Use inner name `me` to
            // refer to the function
            return n * me(n-1);
        } else {
            return 1;
        }
    };
    console.log(fac(3)); // 6

The name me of the named function expression becomes a lexically bound variable that is unaffected by which variable currently holds the function.

The inner names of classes

Interestingly, ES6 classes also have lexical inner names that you can use in methods (constructor methods and regular methods):

    class C {
        constructor() {
            // Use inner name C to refer to class
            console.log(`constructor: ${C.prop}`);
        }
        logProp() {
            // Use inner name C to refer to class
            console.log(`logProp: ${C.prop}`);
        }
    }
    C.prop = 'Hi!';
    
    const D = C;
    C = null;
    
    // C is not a class, anymore:
    new C().logProp();
        // TypeError: C is not a function
    
    // But inside the class, the identifier C
    // still works
    new D().logProp();
        // constructor: Hi!
        // logProp: Hi!

(In the ES6 spec the inner name is set up by the dynamic semantics of ClassDefinitionEvaluation.)

Acknowledgement: Thanks to Michael Ficarra for pointing out that classes have inner names.

Source:: 2ality

Running locally installed npm executables

By Axel Rauschmayer

One nice npm feature is that you can install packages with executables locally. This blog post explains how to run locally installed executables.

Running executables from a nearby node_modules

(An aside, on the topic of packages versus modules: npm packages may or may not contain Node.js modules.)

If you require a module, Node.js looks for it by going through all node_modules/ directories in ancestor directories (./node_modules/, ../node_modules/, ../../node_modules/, etc.). The first appropriate module that is found is used.

Whenever you are somewhere in the file system, npm root tells you where it would install packages if you used npm install. That directory node_modules/ may or may not exist, already; in the following example, directory /tmp/ is empty.

    $ cd /tmp/
    $ npm root
    /tmp/node_modules

When executables are installed via npm packages, npm links to them:

  • In local installs, they are linked to from a node_modules/.bin/ directory.
  • In global installs, they are linked to from a global bin/ directory (e.g. /usr/local/bin).

The command npm bin lets you find out where the closest executables are:

    $ npm bin
    /tmp/node_modules/.bin

If your shell is bash then you can define the following command for running executables from that directory:

    function npm-do { (PATH=$(npm bin):$PATH; eval $@;) }

Let’s try out that shell command: We install package figlet-cli that comes with an executable. npm puts multiple packages into the closest node_modules/ and links to the executable figlet from node_modules/.bin/:

    $ npm install figlet-cli
    $ ls -1 /tmp/node_modules/
    figlet
    figlet-cli
    minimist
    optimist
    wordwrap
    $ ls -1 /tmp/node_modules/.bin
    figlet

If we run figlet as a normal shell command, it fails, because we haven’t installed the package (and thus the executable) globally. However, npm-do allows us to run figlet.

    $ figlet hi
    -bash: figlet: command not found
    $ npm-do figlet hi
      _     _
     | |__ (_)
     | '_ | |
     | | | | |
     |_| |_|_|

Inside an npm package

I’m using the repo npm-bin-demo to demonstrate running executables from inside an npm package. This repo is installed as follows (feel free to read on without doing that):

    git clone https://github.com/rauschma/npm-bin-demo.git
    cd npm-bin-demo/
    npm install

That package has the following package.json:

    {
      "bin": {
        "hello": "./hello.js"
      },
      "scripts": {
        "fig": "figlet",
        "hello": "./hello.js"
      },
      "dependencies": {
        "figlet-cli": "^0.1.0"
      }
    }
  • bin: lists the executables provided by this package. It only matters if this package is installed via npm and then affects the node_modules/ of an ancestor directory.

  • scripts: defines commands that you can execute via npm run if the current package.json is the one that is closest to your current working directory. Note that we can use figlet as if it were a globally installed shell command. That’s because npm adds local .bin/ directories to the shell path before it executes scripts.

  • dependencies: lists packages that are installed by npm install, into npm-bin-demo/node_modules/. As you can see, we have installed figlet-cli.

Let’s examine our surroundings (remember that we are still inside the directory npm-bin-demo/):

    $ npm root
    /tmp/npm-bin-demo/node_modules
    $ ls -1 node_modules/
    figlet
    figlet-cli
    minimist
    optimist
    wordwrap
    
    $ npm bin
    /tmp/npm-bin-demo/node_modules/.bin
    $ ls -1 node_modules/.bin/
    figlet

As expected, there is no shell command figlet, but we can run figlet via npm-do:

    $ figlet hi
    -bash: figlet: command not found
    $ npm-do figlet hi
      _     _
     | |__ (_)
     | '_ | |
     | | | | |
     |_| |_|_|

We can also execute figlet via npm run:

    $ npm run fig hi
    
    > @ fig /Users/rauschma/tmp/npm-bin-demo
    > figlet "hi"
    
      _     _
     | |__ (_)
     | '_ | |
     | | | | |
     |_| |_|_|

As explained previously, the entries in bin have no effect inside a package, which is why we can’t run hello via npm-do:

    $ npm-do hello
    -bash: hello: command not found

We can, however, run the script whose name is hello:

    $ npm run hello
    
    > @ hello /tmp/npm-bin-demo
    > ./hello.js
    
    Hello everyone!

Further reading

For more information on the topic of local npm installs, consult Sect. “npm and local installs” in “Setting up ES6”.

Source:: 2ality

private-data-classes

By Axel Rauschmayer

This blog post explains four approaches for managing private data for ES6 classes:

  1. Keeping private data in the environment of a class constructor
  2. Marking private properties via a naming convention (e.g. a prefixed underscore)
  3. Keeping private data in WeakMaps
  4. Using symbols as keys for private properties

Approaches #1 and #2 were already common in ES5, for constructors. Approaches #3 and #4 are new in ES6. Let’s implement the same example four times, via each of the approaches.

Keeping private data in the environment of a class constructor

Our running example is a class Countdown that invokes a callback action once a counter (whose initial value is counter) reaches zero. The two parameters action and counter should be stored as private data.

In the first implementation, we store action and counter in the environment of the class constructor. An environment is the internal data structure, in which a JavaScript engine stores the parameters and local variables that come into existence whenever a new scope is entered (e.g. via a function call or a constructor call). This is the code:

    class Countdown {
        constructor(counter, action) {
            Object.assign(this, {
                dec() {
                    if (counter < 1) return;
                    counter--;
                    if (counter === 0) {
                        action();
                    }
                }
            });
        }
    }

Using Countdown looks like this:

    > let c = new Countdown(2, () => console.log('DONE'));
    > c.dec();
    > c.dec();
    DONE

Pro:

  • The private data is completely safe
  • The names of private properties won’t clash with the names of other private properties (of superclasses or subclasses).

Cons:

  • The code becomes less elegant, because you need to add all methods to the instance, inside the constructor (at least those methods that need access to the private data).
  • Due to the instance methods, the code wastes memory. If the methods were prototype methods, they would be shared.

More information on this technique: Sect. “Private Data in the Environment of a Constructor (Crockford Privacy Pattern)” in “Speaking JavaScript”.

Marking private properties via a naming convention

The following code keeps private data in properties whose names a marked via a prefixed underscore:

    class Countdown {
        constructor(counter, action) {
            this._counter = counter;
            this._action = action;
        }
        dec() {
            if (this._counter < 1) return;
            this._counter--;
            if (this._counter === 0) {
                this._action();
            }
        }
    }

Pros:

  • Code looks nice.
  • We can use prototype methods.

Cons:

  • Not safe, only a guideline for client code.
  • The names of private properties can clash.

Keeping private data in WeakMaps

There is a neat technique involving WeakMaps that combines the advantage of the first approach (being able to use prototype methods) with the advantage of the second approach (complete safety). That technique is demonstrated in the following code: it uses the WeakMaps _counter and _action to store private data.

    let _counter = new WeakMap();
    let _action = new WeakMap();
    class Countdown {
        constructor(counter, action) {
            _counter.set(this, counter);
            _action.set(this, action);
        }
        dec() {
            let counter = _counter.get(this);
            if (counter < 1) return;
            counter--;
            _counter.set(this, counter);
            if (counter === 0) {
                _action.get(this)();
            }
        }
    }

Each of the two WeakMaps _counter and _action maps objects to their private data. Due to how WeakMaps work that won’t prevent objects from being garbage-collected. As long as you keep the WeakMaps hidden from the outside world, the private data is safe. If you want to be even safer, you can store WeakMap.prototype.get and WeakMap.prototype.set in temporary variables and invoke those (instead of the methods, dynamically). Then our code wouldn’t be affected if malicious code replaced those methods with ones that snoop on our private data. However, we are only protected against code that runs after our code. There is nothing we can do if it runs before ours.

Pros:

  • We can use prototype methods.
  • Safer than a naming convention for property keys.
  • The names of private properties can’t clash.

Con:

  • Code is not as elegant as a naming convention.

Using symbols as keys for private properties

Another storage location for private data are properties whose keys are symbols:

    const _counter = Symbol('counter');
    const _action = Symbol('action');
    
    class Countdown {
        constructor(counter, action) {
            this[_counter] = counter;
            this[_action] = action;
        }
        dec() {
            if (this[_counter] < 1) return;
            this[_counter]--;
            if (this[_counter] === 0) {
                this[_action]();
            }
        }
    }

Each symbol is unique, which is why a symbol-valued property key will never clash with any other property key. Additionally, symbols are somewhat hidden from the outside world, but not completely:

    let c = new Countdown(2, () => console.log('DONE'));
    
    console.log(Object.keys(c));
        // []
    console.log(Reflect.ownKeys(c));
        // [ Symbol(counter), Symbol(action) ]

Pros:

  • We can use prototype methods.
  • The names of private properties can’t clash.

Cons:

  • Code is not as elegant as a naming convention.
  • Not safe: you can list all property keys (including symbols!) of an object via Reflect.ownKeys().

Further reading

  • Sect. “Keeping Data Private” in “Speaking JavaScript” (covers ES5 techniques)
  • Chap. “Classes” in “Exploring ES6”
  • Chap. “Symbols” in “Exploring ES6”

Source:: 2ality

Looking back on 2015: six exciting web technologies

By Axel Rauschmayer

In 2015, there was an amazing amount of innovation related to the web platform. The following sections describe six technologies that I find exciting:

  • Electron
  • React Native
  • Progressive web apps
  • Visual studio code
  • Rollup
  • Web Assembly

This blog post is a loose follow-up to “Web platform: five technologies to look forward to in 2014”, which I wrote in early 2014.

Electron

Electron (by GitHub) lets you build cross-platform desktop apps with web technologies. Its features include:

  • Automatic updates
  • Crash reporting
  • Windows installers
  • Debugging and profiling
  • Native menus and notifications

Electron was initially created for GitHub’s editor Atom and is now used by various companies, including Microsoft (Visual Studio Code, see below), Slack and Docker.

Architecturally, Electron contains both a Node.js runtime and a minimal embedded Chromium browser. Electron apps run in several processes: A main process runs the main script specified by the app’s package.json file. To display a user interface, that script can open windows. Each of those windows runs in a separate process (a so-called renderer process), just like a tab in a web browser.

React Native

With React Native, you can build native apps for iOS and Android via React. The virtual DOM is still there and you still use JSX to create it, but the actual UI is built with native components such as UITabBar on iOS and Drawer on Android. You lay out those native components via Flexbox.

On one hand that means that each of the following platforms has a slightly different UI layer now: the web, iOS, Android. On the other hand, you’ll be able to reuse much of your code, while having a native experience on each platform.

Usually I’m skeptical of solutions that try to transplant a language that is native on one platform to another one. But a few months ago, an iOS developer evaluated React Native and stated:

I may never write an iOS app in Objective-C or Swift again.

This is remarkable if you consider that he had to learn both JavaScript and React before he could be productive with React Native.

Progressive web apps

There are areas, where native apps have caught up with the web (deep linking, indexing). Progressive web apps are not really a technology, but rather an umbrella term for characteristics of modern web apps. These mean that web apps are catching up with native apps in some areas and moving ahead of them in others:

  • Progressive enhancement: The app runs in as many environments as possible. If it needs a service, it should use whatever is available and degrade gracefully if nothing is there.

  • Responsive user interface: The app adapts to various input methods (touch, speech, etc.) and output methods (different screen sizes, vibration, audio, braille displays, etc.).

  • Connectivity-independence: The app works well offline and with intermittent or low-bandwith connectivity.

  • App-like UI: The app adopts UI elements of native platforms, including a fast-loading user interface (which can be achieved by caching important assets via service workers).

  • Continuous updates (“freshness”): The service worker API defines a process for automatically updating apps to new versions.

  • Secure communication: The app is served and communicates via HTTPS, to prevent snooping and attacks.

  • App discovery: Meta-data such as W3C web app manfests enables search engines to find web apps.

  • Push interaction (“re-engagement”): Features such as push notifications actively keep users up-to-date.

  • Natively installable: On some platforms, you can install a web app so that it feels like a native app (icon on home screen, separate entry in app switcher, browser chrome optional). All without going through a native app store.

  • Linkability: Easily share apps via URLs and run them without installation.

Further reading:

Visual Studio Code

Visual Studio Code is a JavaScript code editor for whom the goal is to exist in the space between full IDEs and text editors. And, in my opinion, it succeeds nicely. A plus is that it’s written in JavaScript and based on Electron. In 2015, VSC became open source and gained extensions (an API for extending it via plugins).

Rollup

Rollup is a module bundler that only includes exports in its output that are actually used (via a technique that is called tree-shaking). It depends on the static structure of ES6 modules for its work.

Further reading:

Web Assembly

Web Assembly is a binary format for a static formal language (derived from asm.js) that can be fed into JavaScript engines (that support it) to create fast executables. The formal language is higher-level than bytecode and therefore easier to evolve. The output lives inside the universe of JavaScript and therefore integrates well with it. Given how fast asm.js is, C++ compiled to Web Assembly will run roughly 70% as fast as when you compile it to native code.

Web Assembly will probably eventually get support for JavaScript OOP. At that point, it will truly be a universal virtual machine for the web.

Further reading:

Source:: 2ality

My new book: “Setting up ES6”

By Axel Rauschmayer

My latest book is called “Setting up ES6”. It covers the following topics:

  • A cheat sheet for deploying ECMAScript 6
  • Example setups (skeleton projects that you can download from GitHub):
    • ES6 in browsers via webpack and Babel
    • ES6 in Node.js via Babel (compiled dynamically or statically)
  • How to configure Babel 6, including a clear explanation of how it interacts with CommonJS modules

Setting up ES6” was conceived as a companion to my other book, “Exploring ES6”:

  • Exploring ES6” is supposed to remain relevant for a longer time, so that a print edition makes sense (which I still intend to publish, hopefully by mid-2016).
  • Setting up ES6” will age more quickly. It mainly documents my attempts to understand how Babel 6 works. In a way, you could call it “Setting up Babel 6”. But it has a slightly broader scope, especially the first chapter on deploying ES6.

Happy reading – the contents of “Setting up ES6” are free to read online. If you like the book then you can support my work by buying the offline version (PDF, EPUB, MOBI).

Source:: 2ality

The future of bundling JavaScript modules

By Axel Rauschmayer

This blog post examines how the bundling of modules is affected by two future developments: HTTP/2 and native modules.

Why we bundle modules

Bundling modules means combining several files with modules into a single file. That is done for three reasons:

  1. Less files need to be retrieved in order to load all modules.
  2. Compressing the bundled file is slightly more efficient than compressing separate files.
  3. During bundling, unused exports can be removed, potentially resulting in significant space savings.

JavaScript modules

With ECMAScript 6, JavaScript finally got built-in modules (I’m calling them JavaScript modules for the remainder of this blog post). However, that feature is currently in a strange position:

On one hand, ES6 fully standardized their syntax and much of their semantics. They have become a popular format for writing modules and their static structure enables the automatic omission of unused exports (also known as “tree-shaking” in the JavaScript world).

On the other hand, standardizing how to load JavaScript modules is ongoing and no JavaScript engine supports them natively, yet. That means that, at the moment, the only way of using JavaScript modules is by compiling them to a non-native format. Popular solutions are: browserify, webpack, jspm and Rollup.

Future developments and bundling

Let’s look at two future developments and how they affect the bundling of JavaScript modules.

Future development: HTTP/2

HTTP/2 is slowly being rolled out. It mainly affects reason #2 for bundling: With HTTP/1, you need one connection per file you are requesting. With HTTP/2, you can retrieve multiple files per connection, which means that there are no performance gains if you download multiple files instead of a single one. That enables smaller, more incremental updates: With bundling, you always need to download the complete bundle. Without bundling, you only need to download the parts that have changed (while the other parts are often still in the browser cache).

However, reasons #2 and #3 for bundling are not negated by HTTP/2. Therefore, mixed approaches may be adopted in the future, to optimize for both incremental updates and minimal total download size.

Future development: native JavaScript modules

Once engines support native JavaScript modules, will that affect bundling? Even AMD modules – which run natively in browsers – have a custom bundle format (along with a minimal loader). Will native JS modules be different? It looks like they will. Rollup lets you bundle multiple JS modules into a single JS module.

Take, for example, these two JS modules:

    // lib.js
    export function foo() {}
    export function bar() {}
    
    // main.js
    import {foo} from './lib.js';
    console.log(foo());

Rollup can bundle these two JS modules into the following single JS module (not the eliminated unused export bar):

    function foo() {}
    
    console.log(foo());

Rollup’s site has a nice interactive playground where you can try it out. It wasn’t a given that that would work – quoting Rollup’s creator Rich Harris:

When I started writing Rollup, it was an experiment that I wasn’t certain would succeed.

The way imports are handled by JS modules helps with bundling: they are not copies of exports, they are read-only views on them.

Further reading

  • Building for HTTP/2” by Rebecca Murphey (explains how best practices change – often radically – with this new version of HTTP)
  • Chap. “Modules” in “Exploring ES6” (explains how ES6 modules work)
  • Babel and CommonJS modules” (explains how Babel ensures that transpiled ES6 modules interoperate properly with CommonJS modules)

Source:: 2ality

Tree-shaking with webpack 2 and Babel 6

By Axel Rauschmayer

Rich Harris’ module bundler Rollup pioneered a new feature in JavaScript world: tree-shaking, excluding unused exports from bundles. Rollup depends on the static structure of ES6 modules (imports and exports can’t be changed at runtime) to detect which exports are unused.

Tree-shaking for webpack is currently in beta. This blog post explains how it works. The project we are going to examine is on GitHub: tree-shaking-demo

How webpack 2 eliminates unused exports

webpack 2, a new version that is in beta, eliminates unused exports in two steps:

  • First, all ES6 module files are combined into a single bundle file. In that file, exports that were not imported anywhere are not exported, anymore.

  • Second, the bundle is minified, while eliminating dead code. Therefore, entities that are neither exported nor used inside their modules do not appear in the minified bundle. Without the first step, dead code elimination would never remove exports (registering an export keeps it alive).

Unused exports can only be reliably detected at build time if the module system has a static structure. Therefore, webpack 2 can parse and understand all of ES6 and only tree-shakes if it detects an ES6 module. However, only imports and exports are transpiled to ES5. If you want all of the bundle to be in ES5, you need a transpiler for the remaining parts of ES6. In this blog post, we’ll use Babel 6.

Input: ES6 code

The demo project has two ES6 modules.

helpers.js with helper functions:

    // helpers.js
    export function foo() {
        return 'foo';
    }
    export function bar() {
        return 'bar';
    }

main.js, the entry point of the web application:

    // main.js
    import 'babel-polyfill';
    import {foo} from './helpers';
    
    let elem = document.getElementById('output');
    elem.innerHTML = `Output: ${foo()}`;

Note that the export bar of module helpers is not used anywhere in this project.

Output without tree-shaking

The canonical choice for Babel 6 is to use the preset es2015:

    {
        presets: ['es2015'],
    }

However, that preset includes the plugin transform-es2015-modules-commonjs, which means that Babel will output CommonJS modules and webpack won’t be able to tree-shake:

    function(module, exports) {
    
        'use strict';
    
        Object.defineProperty(exports, "__esModule", {
            value: true
        });
        exports.foo = foo;
        exports.bar = bar;
        function foo() {
            return 'foo';
        }
        function bar() {
            return 'bar';
        }
    
    }

You can see that bar is part of the exports, which prevents it being recognized as dead code by minification.

Output with tree-shaking

What we want is Babel’s es2015, but without the plugin transform-es2015-modules-commonjs. At the moment, the only way to get that is by mentioning all of the preset’s plugins in your configuration data, except for the one we want to exclude. The preset’s source is on GitHub, so it’s basically a copy/paste task:

    {
        plugins: [
            'transform-es2015-template-literals',
            'transform-es2015-literals',
            'transform-es2015-function-name',
            'transform-es2015-arrow-functions',
            'transform-es2015-block-scoped-functions',
            'transform-es2015-classes',
            'transform-es2015-object-super',
            'transform-es2015-shorthand-properties',
            'transform-es2015-computed-properties',
            'transform-es2015-for-of',
            'transform-es2015-sticky-regex',
            'transform-es2015-unicode-regex',
            'check-es2015-constants',
            'transform-es2015-spread',
            'transform-es2015-parameters',
            'transform-es2015-destructuring',
            'transform-es2015-block-scoping',
            'transform-es2015-typeof-symbol',
            ['transform-regenerator', { async: false, asyncGenerators: false }],
        ],
    }

If we build the project now, module helpers looks like this inside the bundle:

    function(module, exports, __webpack_require__) {
    
        /* harmony export */ exports["foo"] = foo;
        /* unused harmony export bar */;
    
        function foo() {
            return 'foo';
        }
        function bar() {
            return 'bar';
        }
    }

Only foo is an export now, but bar is still there. After minification, helpers looks like this (I’ve added line breaks and whitespace to make the code easier to read):

    function (t, n, r) {
        function e() {
            return "foo"
        }
    
        n.foo = e
    }

Et voilà – no more function bar!

Further reading

Source:: 2ality

Why is (0,obj.prop)() not a method call?

By Axel Rauschmayer

This blog post explores references, a mechanism used by the spec to explain the difference between the following two expressions:

    obj.prop()
    (0, obj.prop)()

Method calls versus function calls

Consider the following object:

    var obj = {
        getThis: function () {
            "use strict";
            return this;
        },
    };

If you call obj.getThis, you have a method call (this points to the object in which the method is stored):

    > obj.getThis() === obj
    true

If you store obj.getThis in a variable and then call it, you are making a function call:

    > var func = obj.getThis;
    > func()
    undefined

The effect is the same if you use the comma operator. Quick recap: the comma operator works like this:

    (expr1, expr2) === expr2

That is, both expressions are evaluated, the result of the whole expression is expr2.

If you apply the comma operator to obj.getThis before calling it, you are also making a function call:

    > (0,obj.getThis)()
    undefined

What the first operand is doesn’t matter at all, here, I use 0, because its short. I’d expect many JavaScript engines to optimize and eliminate the evaluation of the first operand.

However, only using parentheses does not change anything:

    > (obj.getThis)() === obj
    true

So what is going on? The answer has to do with references.

References, a data structure of the ECMAScript spec

References are a data structure that is used internally by the ECMAScript language specification. A reference has three components:

  1. Base value: is either undefined, a primitive value, an object or an environment record. undefined means that a variable name could not be resolved. Accessed via GetBase(V) (given a reference V).
  2. Referenced name: is a string or a symbol. Accessed via GetReferencedName(V) (given a reference V).
  3. Strict reference: flag indicating whether or not the reference was created in strict mode. Accessed via IsStrictReference(V) (given a reference V).

Examples of JavaScript expressions that produce references:

  • Property reference: Evaluating obj.prop in strict mode produces the reference (obj, 'prop', true).
  • Identifier reference: Evaluating foo in strict mode produces the reference (env, 'foo', true). env is the environment record where the variable foo is stored.

The flag for strict mode is necessary, because some operations cause an exception in strict mode, but fail silently in sloppy mode. For example: setting an unresolved variable in sloppy mode creates a global variable, setting it in strict mode throws a ReferenceError.

These are two operations (of several) for references:

  • GetValue(V) if V is a value, the result is V. If V is a reference, the result is the value pointed to by the reference. This conversion from reference to referenced value is called dereferencing.
  • PutValue (V, W) writes the value W to the reference V.
  • GetThisValue(V) is only called if V is a property reference. For normal references, it returns the base value. For references created via super, it returns the additional component thisValue that they have ((which is needed for super property references)[http://exploringjs.com/es6/ch_classes.html#super-properties]).

References in the example

We are now ready to understand the examples we looked at earlier.

The following expression produces a reference:

    obj.getThis

If you function-call this reference V then this is set to GetThisValue(V).

If you wrap obj.getThis in parentheses, nothing changes, parentheses only syntactically group things, but the don’t influence how something is evaluated. That is, the result of the following expression is still a reference:

    (obj.getThis)

If, however, you assign the reference returned by obj.getThis to a variable, the reference is dereferenced:

    var func = obj.getThis;

In other words: what is stored in func is a function, not a reference. In the language spec, assignment operators use GetValue() to turn references into values.

The comma operator also dereferences its operands. Consider this expression:

    (0, obj.getThis)

The comma operator`) to ensure that the result of each operand is dereferenced if it is a reference.

References and bind()

References only being temporary is also the reason why you need to use bind if you want to turn a method into a callback (first line):

    var log = console.log.bind(console);
    log('hello');

If you simply did:

    var log = console.log;

Then the receiver (this) would get lost, because console.log is dereferenced before it is stored in log.

Why does the ECMAScript language specification use references?

JavaScript engines, which are implementations of the ECMAScript language specification, don’t actually use references. That means that they are a device that helps with writing the spec. To see why, consider that they represent storage locations. Then consider that all of the following operations work with storage locations:

  • Reading a value:

        x
        obj.prop
        super.prop
        obj["prop"]
    
  • Calling a function or a method:

        x()
        obj.prop()
        super.prop()
        obj["prop"]()
    
  • Assigning a value:

        x = 123
        obj.prop = 123
        super.prop = 123
        obj["prop"] = 123
    
  • Compound assignment operators. For example, the addition assignment operator (+=):

        x += 5
        obj.prop += 5
        super.prop += 5
        obj["prop"] += 5
    
  • typeof:

        typeof x
        typeof obj.prop
        typeof super.prop
        typeof obj["prop"]
    
  • delete:

        delete x
        delete obj.prop
        delete super.prop
        delete obj["prop"]
    

Because each storage location is represented by the same construct, a reference, the specification only needs to describe a single version of each operation instead of several versions (e.g.: delete for a variable, delete for a property with a fixed key, delete for a property with a dynamically computed key, etc.).

Conclusion

You don’t actually see references when you use JavaScript. But there are languages (e.g. Common Lisp) where references are first class values. That enables intriguing applications. You can, for example, implement functions that perform an assignment for you.

Source:: 2ality