ES6 module -> UMD and SystemJS

1,561 views
Skip to first unread message

hyper...@gmail.com

unread,
Sep 7, 2015, 9:57:08 AM9/7/15
to SystemJS
Hello group,

What is the current best practice for creating a module in ES6 that is compatible with npm, browser/bower (script src="" tag), and JSPM/SystemJS? Thought is to use babel to transpile the ES6 to UMD for npm and bower then add a `jspm.main` property in package.json to point to the ES6 module.

However as discussed in detail in this issue https://github.com/systemjs/systemjs/issues/304 there is a difference in the way babel handles default exports and the way SystemJS works. Since adding `export var __useDefault = true;` breaks babel to UMD and without it means something ugly like `require('myMod').default` in SystemJS how can one write a ES6 module that is cross universal... with the same API in each.

I think my choices are:

a) Give up on ES6 and just write CJS, wrap it in UMD.
b) Have SystemJS/JSPM point to the same generated UMD file as node/browser.
c) Write a shim for SystemJS that looks something like this: `module.exports = require('path/to/es6file.js').default`.

Any thoughts? Thank you.

P.S. Sorry for asking the same question I posed on gitter, my time zone makes the chat rooms difficult.

Guy Bedford

unread,
Sep 8, 2015, 12:30:41 PM9/8/15
to hyper...@gmail.com, SystemJS
The best workflows I'd suggest today for writing ES6 and publishing for the widest possible audience is to build your ES6 into CommonJS as separate files using Babel, or to build your ES6 into a single file using a SFX bundle with SystemJS builder.

--
You received this message because you are subscribed to the Google Groups "SystemJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to systemjs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jayson Harshbarger

unread,
Sep 9, 2015, 8:59:04 AM9/9/15
to SystemJS, hyper...@gmail.com
Thank you Guy.  I guess for now I'll point everything to the generated UMD.

Jayson Harshbarger

unread,
Sep 21, 2015, 2:16:08 AM9/21/15
to SystemJS, hyper...@gmail.com
Hello again Guy,

As I mention before I to leave out __useDefault in my ES6 source because that breaks the default export when building using babel.  So what I have done is I created an "index.jspm.js" file that looks like this:

```
export * from './src/index';
export {default} from './src/index';
export var __useDefault = true;
```

Perhaps there could be a way to do this on install with JSPM by specifying jspm.useDefault in package.json?

Thanks again,

Guy Bedford

unread,
Sep 24, 2015, 5:11:20 PM9/24/15
to Jayson Harshbarger, SystemJS
Hi Jayson,

As mentioned on Gitter, __useDefault is a private internal property and not designed to be used this way.

In future, when we update to the new spec System.import will never actually give the `default` value as the browser loader will never do this or support this flag. It was necessary to start in SystemJS though as all CommonJS modules would have given just a `default` object otherwise.

If you're looking to provide a nice index file, perhaps just do something like -

module.exports = require('./src/index');

Which would achieve the same effect.

Jayson Harshbarger

unread,
Sep 24, 2015, 11:05:16 PM9/24/15
to SystemJS
Hello Guy,

I'm sorry to beat this to death, I know you are busy, but I am still struggling with this.  Your comment and example above make me think perhaps I am misunderstanding something or not making my use case clear.  Let me try one more time.

Let's say I have an ES6 module in mytool.es6.js that exports a single class using `export default class MyTool {}`.  I can use this module directly in any system that supports ES6 imports using `import MyTool from 'mytool.es6.js'`.

I need to make my tool available to node and bower users. For this, I can use babel to transile into `mytool.umd.js`.  Now node users can `var MyTool = require('mytool')` while bower users have MyTool as a global.

I can setup package.json and bower.json to use `mytool.umd.js` as the main entry point for most users and set jspm: main to 'mytool.es6.js' for JSPM users.

Everything works fine until a SystemJS user, either directly or through a dependency, calls `var MyTool = require('mytool')`.  In this case, the user will get `{ default: MyTool }` instead of the MyTool constructor.

My choices to prevent this seam to be:

a) Use `mytool.umd.js` as the main entry point for everyone, even developers working only in ES6 modules.
b) Add a shim like I suggested before, using the unsupported `__useDefault`:

export {default} from './src/mytool.es6.js';
export var __useDefault = true;

c) Use a CJS shim (like your example but exporting default):

module.exports = require('./src/mytool.es6.js').default;

The third option means mixing CJS in the middle of what could be ES6 all the way down.  I've been reading every github issue I can find on interOp but most discussions relate to importing CJS modules in ES6, not the reverse.  You mention System.import but that is not my reason for using __useDefault.

Thank you once again.

Jayson

Guy Bedford

unread,
Sep 25, 2015, 9:47:22 AM9/25/15
to Jayson Harshbarger, SystemJS
Yes, exactly. ES6 will always look like that when imported into CommonJS - that is how the interop works. (a) or (c) is the way to go here.

--
Reply all
Reply to author
Forward
0 new messages