Have you ever tried describing Meteor
without mentioning JavaScript?
The JavaScript App Platform
Meteor is a complete open source platform
for building web and mobile apps
in pure JavaScript
What are we talking aboutwhen we talk
about JavaScript?
The language that runs in web
browsers, the one that hasn't changed
all that much since the early 2000s?
The language that puts the “JS”in Node.JS?
But which version of Node?
How much of the standard library actually works according to
the specification?
Which specification
are we talking about?
Can you run the same code
in a web browser?
What kind of module system
does Meteor support?
What is the deal with Fibers?
These questions have answers!
The most valuable property of any programming language:
Everyone can agree precisely what will happen when a computer
runs a program written in that language.
“JavaScript” conveys much of the necessary information
Though “JavaScript” may be a little
vague, a vast audience of programmers
still know it by that name, so
that's why we keep calling it that.
But programming languages can
change, and JavaScript is changing
faster than ever!
ECMAScript 2015
A big departure from sequential numbering (ECMAScript 4, 5,
6), since it signals an intention to
release a new standard every year.
Now easier than ever to propose new language
features, build consensus around
those
proposals, and get them
implemented.
RegExp.escape revived on
es-discuss
last month, presented in this week's TC39 meeting.
Multiple levels of implementation:
transpilers
(Traceur,
Babel)
native support in Node
native support in (some) browsers
native support everywhere
Our commitment:
The ecmascript package will provide any and all
language features that can be faithfully compiled to code that
runs natively in all JavaScript engines.
Two kinds of progress:
Meteor provides simulated support for features not yet
implemented natively in all JavaScript engines.
Native support catches up to the simulation.
Code you write in the first stage should not have to be
rewritten when the second stage arrives.
The code behind the meteor command-line tool has
been using ECMAScript 2015 features for some time now.
And it's great.
How great?
function JsFile() {
InputFile.apply(this, arguments);
}
JsFile.prototype = Object.create(InputFile.prototype);
JsFile.prototype.constructor = JsFile;
JsFile.prototype.addJavaScript = function (options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
};
exports.JsFile = JsFile;
How great?
function JsFile() {
InputFile.apply(this, arguments);
}
Meteor._inherits(JsFile, InputFile);
JsFile.prototype.addJavaScript = function (options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
};
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
constructor() {
InputFile.apply(this, arguments);
}
}
JsFile.prototype.addJavaScript = function (options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
};
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
constructor() {
super(...arguments);
}
}
JsFile.prototype.addJavaScript = function (options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
};
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
constructor() {
super(...arguments);
}
addJavaScript(options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
}
}
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
addJavaScript(options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
}
}
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
addJavaScript(options) {
this._minifiedFiles.push({
data: options.data,
sourceMap: options.sourceMap,
path: options.path
});
}
}
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
addJavaScript({ data, sourceMap, path }) {
this._minifiedFiles.push({
data: data,
sourceMap: sourceMap,
path: path
});
}
}
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
addJavaScript({ data, sourceMap, path }) {
this._minifiedFiles.push({
data,
sourceMap,
path,
});
}
}
exports.JsFile = JsFile;
How great?
class JsFile extends InputFile {
addJavaScript({ data, sourceMap, path }) {
this._minifiedFiles.push({ data, sourceMap, path });
}
}
exports.JsFile = JsFile;
How great?
export class JsFile extends InputFile {
addJavaScript({ data, sourceMap, path }) {
this._minifiedFiles.push({ data, sourceMap, path });
}
}
How great?
export class JsFile extends InputFile {
addJavaScript({ data, sourceMap = null, path }) {
this._minifiedFiles.push({ data, sourceMap, path });
}
}
We're pretty addicted.
And we want you to have the same development experience.
How?
meteor add ecmascript
Just a package that can be added to any
app or api.used by any
package, and it will be
installed by default for all new apps and packages.
With many thanks to
Babel
So what dialect of JavaScript does Meteor implement?
The latest one: ECMAScript
2015+
Whatever we can faithfully transpile.
Whatever will one day be implemented natively.
Whatever helps you write Meteor apps.
Example: for-of
loops
let sum = 0;
for (let x of arrayOfNumbers) {
sum += x;
}
gets transpiled to
var sum = 0;
var _iter = arrayOfNumbers[Symbol.iterator](), _result;
while (! (_result = _iter.next()).done) {
var x = _result.value;
sum += x;
}
Symbol.iterator is a special kind of unique
property name that cannot be simulated faithfully.
Example: for-of loops
var sum = 0;
var _iter = arrayOfNumbers[Symbol.iterator](), _result;
while (! (_result = _iter.next()).done) {
var x = _result.value;
sum += x;
}
assumes a minimal Symbol implementation:
if (typeof Symbol === "undefined") {
Symbol = function Symbol() {};
}
Example: for-of loops
var sum = 0;
var _iter = arrayOfNumbers[Symbol.iterator](), _result;
while (! (_result = _iter.next()).done) {
var x = _result.value;
sum += x;
}
assumes a minimal Symbol implementation:
if (typeof Symbol === "undefined") {
Symbol = function Symbol() {};
}
if (! Symbol.iterator) {
Symbol.iterator = "@@iterator";
}
Example: for-of loops
var sum = 0;
var _iter = arrayOfNumbers[Symbol.iterator](), _result;
while (! (_result = _iter.next()).done) {
var x = _result.value;
sum += x;
}
assumes a minimal Symbol implementation:
if (typeof Symbol === "undefined") {
Symbol = function Symbol() {}; // Fake!
}
if (! Symbol.iterator) {
Symbol.iterator = "@@iterator"; // Fake!
}
Since the original for-of loop works
today in translation, and it will continue
to work natively once it no longer needs to be
translated,
for-of loops meet our criteria for
inclusion in the ecmascript
package,
while Symbols do not.
Example: Array.prototype
Array methods
like .forEach, .map,
and .reduce are now available in almost
every JavaScript engine, except
Internet Explorer 8 and earlier.
We use a popular polyfill library called
es5-shim
to implement these methods, but
there is no way to make them non-enumerable
in IE8.
Example: Array.prototype
If you ever use a for-in loop to
iterate over an array in IE8, you'll get all those method
names, too!
let sparseArray = [];
sparseArray[0] = "a";
sparseArray[2] = "c";
for (let index in sparseArray) {
console.log(index); // Should log 0 and 2.
}
Normally you would be out of luck, but
Meteor can actually fix this for you.
Example: Array.prototype
If you ever use a for-in loop to
iterate over an array in IE8, you'll get all those method
names, too!
let sparseArray = [];
sparseArray[0] = "a";
sparseArray[2] = "c";
for (let index in runtime.sanitizeForInObject(sparseArray)) {
console.log(index); // Should log 0 and 2.
}
Normally you would be out of luck, but Meteor can actually fix
this for you.
Example: Array.prototype
If you ever use a for-in loop to
iterate over an array in IE8, you'll get all those method
names, too!
let sparseArray = [];
sparseArray[0] = "a";
sparseArray[2] = "c";
for (let index in runtime.sanitizeForInObject(sparseArray)) {
console.log(index); // Should log 0 and 2.
}
In most browsers, the sanitizeForInObject helper
function simply returns its argument.
Example: Array.prototype
If you ever use a for-in loop to
iterate over an array in IE8, you'll get all those method
names, too!
let sparseArray = [];
sparseArray[0] = "a";
sparseArray[2] = "c";
for (let index in runtime.sanitizeForInObject(sparseArray)) {
console.log(index); // Should log 0 and 2.
}
In IE8, when the argument is an
array, it returns a new object
containing only the enumerable keys.
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Promise.prototype.then = function then(onResolved, onRejected) {
};
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Promise.prototype.then = function then(onResolved, onRejected) {
var Promise = this.constructor;
};
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Promise.prototype.then = function then(onResolved, onRejected) {
var Promise = this.constructor;
if (typeof Promise.Fiber === "function") {
}
};
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Promise.prototype.then = function then(onResolved, onRejected) {
var Promise = this.constructor;
if (typeof Promise.Fiber === "function") {
return es6PromiseThen.call(
this,
wrapCallback(onResolved, Promise),
wrapCallback(onRejected, Promise)
);
}
};
Example: Promise.Fiber
// Replace Promise.prototype.then with a wrapper that ensures the
// onResolved and onRejected callbacks always run in a Fiber.
var es6PromiseThen = Promise.prototype.then;
Promise.prototype.then = function then(onResolved, onRejected) {
var Promise = this.constructor;
if (typeof Promise.Fiber === "function") {
return es6PromiseThen.call(
this,
wrapCallback(onResolved, Promise),
wrapCallback(onRejected, Promise)
);
}
return es6PromiseThen.call(this, onResolved, onRejected);
};
Good Promise tutorials:
HTML5Rocks,
2ality
Example: Promise.Fiber
function wrapCallback(callback, Promise) {
var fiber = Promise.Fiber.current;
var dynamics = fiber && fiber._meteorDynamics;
return callback && function (arg) {
return fiberPool.run({
callback: callback,
args: [arg], // Avoid dealing with arguments objects.
dynamics: dynamics
}, Promise);
};
}
Fibers are recycled using a
pool,
so a new Fiber does not have to be created
every time a Promise callback fires.
Example: Promise.Fiber
function wrapCallback(callback, Promise) {
var fiber = Promise.Fiber.current;
var dynamics = fiber && fiber._meteorDynamics;
return callback && function (arg) {
return fiberPool.run({
callback: callback,
args: [arg], // Avoid dealing with arguments objects.
dynamics: dynamics
}, Promise);
};
}
Even better,
Fiber._meteorDynamics is
saved and restored when the callback
runs, so you never have to
call Meteor.bindEnvironment with
Promises!
We believe...
You shouldn't have to wait for universal native support before
using the latest ECMAScript features.
Nor should you to have to wonder when it's safe to transition
from simulated to native support.
Nor should it be your job to find the best way to integrate
libraries like es5-shim with tools like Babel.
Meteor can be the place where these solutions accumulate
Because Meteor provides a complete platform out of the
box, including compilation, packaging,
and delivery of scripts, libraries, source maps, and other
assets, we are in an ideal
position to make the transition to ECMAScript 2015+ as
seamless as possible.
That, more than
anything, is why I left my job
at Facebook
Facebook has these posters up everywhere that say things like
“FOCUS ON IMPACT,” so
that's what I did.
I believe Meteor has the best chance of
providing the best experience
for developing apps with the latest version of
JavaScript.
And there are a whole lot more of you than there are engineers
at Facebook.
Meteor += ECMAScript
Ben Newman
30 July 2015
{ github,
twitter,
instagram,
facebook
}.com/benjamn