David Bashford

A web dev blog from a Washington DC based Dad, UI architect, web developer, and creator of Mimosa.

    

ember.js, es6 modules, and some unfortunate transpiler behavior

It's Ember's Fault

In January my team at Berico started doing a lot of work with Ember. We'll probably have a good dozen folks writing Ember apps in the near future. Ember has a steep learning curve, but the higher up that curve we get, the happier we are with the decision. There is just a tremendous amount of power there.

As recent Ember adopters, we've kept a close eye on the Ember community. Among other things that community has adopted is the es6 module syntax. Commits like this are frequent as the Ember codebase itself gets an es6 module overhaul. Not ones to buck a trend, at least not yet, we've adopted that syntax in our apps as well.

How to es6 module?

Lets cover a little ground on the es6 syntax.

This code exports some simple named values.

// file: hello_world.js
var hello = "hello";  
var world = "world";  
export { hello, world };  

And this code imports those same values.

import { hello, world } from "hello_world";  
console.log( hello, world );  // hello world  

You can also export values without naming them using the default keyword.

// file: hello_world.js
var hello = "world"  
export default hello;  

And then import it giving it whatever name you wish.

import abc from "hello_world";  
console.log( abc );  // world  

If you want to import a file that doesn't export anything, perhaps it just runs code that attaches to window, you would write import "foo".

Awesome, lets use that now!


Fail.

It'll be quite some time before all the browsers we have to support will natively support this syntax. Years.

And that's it.

I'll totally blog about it in 2017.

Thanks for coming!

Srsly?

Nahhh. This problem, like all in life, can be transpiled away.

es6-module-transpiler

Square's es6-module-transpiler was made to convert -- or transpile -- code using es6 module syntax into code you can actually use. The transpiler will take in your code and compile it into either AMD or CommonJS. Lets look at some of the above code transpiled to AMD.

These two blocks of code...

// file: hello_world.js
var hello = "hello";  
var world = "world";  
export { hello, world };  
import { hello, world } from "hello_world";  
console.log( hello, world );  // hello world  

...get transpiled into these:

define(  
  ["exports"],
  function(__exports__) {
    "use strict";
    // file: hello_world.js
    var hello = "hello";
    var world = "world";
    __exports__.hello = hello;
    __exports__.world = world;
  });
define(  
  ["hello_world"],
  function(__dependency1__) {
    "use strict";
    var hello = __dependency1__.hello;
    var world = __dependency1__.world;
    console.log( hello, world );  // hello world
  });

This should resemble the sort of AMD code you might write.

Perform this transformation on your es6 module code before you load it in the browser and your require.js/AMD application will work perfectly.

How can I use it?

All the build tools have plugins for the es6-module-transpiler. Grunt. Gulp. Brunch. Mimosa.

But... we have a problem

Starting with version 0.3.0 (its at 0.3.6 as of this writing) the es6-module-transpiler broke AMD apps.

import Ember from 'ember';  
var App = Ember.Application.create({});  
export default App;  

This simple bit of code gets transpiled into this:

1 define(  
2   ["ember","exports"],  
3   function(__dependency1__, __exports__) {  
4     "use strict";  
5     var Ember = __dependency1__["default"];  
6     var App = Ember.Application.create({});  
7     __exports__["default"] = App;  
8   });  

Line 5 above is the problem. Ember is set to __dependency1__["default"], which would work great if Ember had a default property, but it doesn't (or at least it hasn't). Almost every other vendor library will have this same problem.

The transpiler expects, by way of its output, that all other modules that have default exports will attach that export to the default property. In fact, you can see the transpiler doing this on line 7. __exports__["default"] = App attaches App to the default property of __exports__ such that files importing this file can access it via that property.

Will they fix it?

It's looking like they won't. Sad face.

Edit: So I failed to notice that the compatFix option was available and mentioned in that issue. I had built a amd-shim module for Mimosa not knowing the ability to fix the issue was there as a hidden option.

Saved!

Lets hope that option isn't removed as some in that thread suggested should happen.

Play with it!

Check out the es6-module-transpiler and Ember in brzpegasus' example Ember app.

comments powered by Disqus