Runtime transform · Babel


#1

Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals. (This plugin is recommended in a library/tool)


This is a companion discussion topic for the original entry at https://babeljs.io/docs/plugins/transform-runtime/

#2

I don’t understand this code at the end:

var Person = function Person() {
  (0, _classCallCheck3.default)(this, Person);
};

In particular how does (0, _classCallCheck3.default) become a callable function? Is something missing there?


#3

@mark0978 That is the comma operator. It executes each expression in order, and evaluates to the last element. I have often wondered why it is necessary in the transpiled code as well. @hzoo why is this necessary?


#4

Wow, would not have thought the transpiler would issue 0, as an expression since it does nothing in this case. Seems like you could save about 5 characters (and make the code more readable), but maybe that is the job of uglify.


#5

Asked @ljharb the same question, here is the answer:

it ensures the default function isn’t called with _classCallCheck3 as its receiver (this value).
it’s a trick, a shortcut for const func = _classCallCheck3.default; func(this, Person);


#6

I recently got bit by this quirk, where calling:

var foo = MyClass.staticMethod;
# Reference to `this` inside `staticMathod` was
# undefined, causing an error.
foo();

wasn’t the same as:

var bar = MyClass;
# this did what I wanted
bar.staticMethod();

which was totally unexpected for me.

Do you know why ES does things this way? Shouldn’t foo and bar.staticMethod be a reference to the same thing?


#7

The this keyword in ES function refers to the object that invokes the function, e.g. bar.staticMethod() that’s object bar invoking function staticMethod. This language feature is quite commonly seen in many languages, especially object oriented ones – Java has the exactly same keyword, Python has self (though it’s made explicit at method definition).

To answer your question, foo and bar.staticMethod IS referring the same thing, it’s just the this keyword inside the function refers to different things. If you want your foo and bar.staticMethod to behave the same, you should make it pure function in the first place to ensure that.


#8

In addition to what @hackape already said: I don’t know of any programming language where calling a static method would tolerate this being referenced. It’s not a quirk, it’s just OO programming.

In the second example you are not calling a static method but an object method, which is akin to saying "tell bar to do staticMethod", and inside staticMethod, this will refer to bar for this call. In the first example, you say something like "tell the template for all MyClass objects to do staticMethod". What would this refer to given that? There may at that point in the code not even be a MyClass object.


#9

It’s important to note that this approach actually does affect globals, even though it’s described here as “automatically polyfilling your code without polluting globals”. Transpiled code can break other JS code running on the same page because of modifications to globals. See this issue, for example.


#10

Can anyone shed some light on whether or not the babel-polyfill is needed when using this? Would that be duplicating code? From the explanation, it sounds like I can drop the polyfill and let the webpack & babel reference the runtime instead.


#11

@alexsasharegan that seems to be correct yes, the polyfill allows you to use the new ES5 methods on instances.

I wonder, would it be possible for babel to just detect references to names of new methods and only include polyfills for all the names it finds? E.g. if I type somewhere foo.startsWith(...), the polyfill for startsWith would be included, even if foo is not a string at all.

That way, it would only include polyfills for things you might actually be using.