Error with ES6 and JSX

810 views
Skip to first unread message

Ken Carpenter

unread,
May 26, 2014, 12:02:01 PM5/26/14
to mimo...@googlegroups.com
I'm trying to use ES6 code along with React JSX's embedded HTML.

/** @jsx React.DOM */

function foo({x,y,z}) =>
{
  var str = "x=" + x + " y=" + y + " z=" + z;
  console.log(str);
  return <div>{str}</div>;
}

foo({x:1, y:2, z:3});

I get a compile error on the "=>", which makes me think that ES6->ES5 compilation step isn't happening.

Essentially what needs to happen is:
  • Process ES6 JSX file to an ES6 JavaScript file
  • Compile ES6 JavaScript file to an ES5 JavaScript file
  • Process ES5 JavaScript file (I guess this is just moving it to the public folder)
The mimosa-react module seems to use the compile step (although there is no register step), while regenerate is registered with afterCompile, so it seems that this should work.

Any idea what I'm doing wrong?

Further info:

The following are the modules I have in my mimosa-config.coffee:

  modules: [
    'copy',
    'server',
    'jshint',
    'csslint',
    'require',
    'minify-js',
    'minify-css',
    'live-reload',
    'server-reload',
    'bower',
    'iced-coffeescript',
    'coffeelint',
    'sass',
    'dust',
    'web-package',
    'combine',
    'regenerator',
    'react'
  ],

I've tried using mimosa-traceur and mimosa-regenerator, but neither one worked.

If I change the code to the following (no ES6 code), the JSX conversion works and I see the React.DOM.div() call in the public output.

/** @jsx React.DOM */

function bar(x,y,z)
{
  var str = "x=" + x + " y=" + y + " z=" + z;
  console.log(str);
  return <div>{str}</div>;
};

bar(1, 2, 3);

GMail

unread,
May 26, 2014, 12:21:34 PM5/26/14
to mimo...@googlegroups.com
Not at a computer to play with this right now, but...

Does the react compiler choke on es6?

The regenerator compiler just manages generators. Not sure if it'll manage the syntax switch.  Probably need traceur for that.

But both of those are compilers so will overwrite each other's output.

Need to get with the authors of the traceur modules to see what might be doable.

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

Ken Carpenter

unread,
May 26, 2014, 12:31:23 PM5/26/14
to mimo...@googlegroups.com
The output is the following:

    16:29:07 - ERROR - File assets/javascripts/traceur-test.jsx failed compile. Reason: Error: Parse Error: Line 3: Unexpected token =>

Since it is referring to the .jsx file I would guess that it's react choking on the unexpected token, but not 100% sure about that.


Ken

GMail

unread,
May 26, 2014, 12:36:37 PM5/26/14
to mimo...@googlegroups.com
If you remove the other compilers guessing you'll get the same result?  I think it is also likely react.

Sent from my iPhone

dbashford

unread,
May 26, 2014, 2:05:34 PM5/26/14
to mimo...@googlegroups.com
Rushing to get ready for a flight down to JSConf, but the thought occurred to me that this may not be possible, even outisde of Mimosa.

Lets say we need to run traceur first.  Well, fairly sure traceur will choke on something like this: https://github.com/dbashford/MimosaReactBackboneTodoList/blob/master/assets/javascripts/app/todo-footer.jsx#L16-L24  I can't see it being able to successfully parse that.

Lets say we need to run JSX first.  I can see the JSX compiler not being able to parse ES6.  There is a single option, "harmony", that can be passed into the compiler.  Not sure what that may do though, https://github.com/facebook/react/commit/5106b793f76f2ba226420e5e5078d35796487d39

Ken Carpenter

unread,
May 26, 2014, 2:18:18 PM5/26/14
to mimo...@googlegroups.com
Just saw that harmony option too.  Apparently it runs jstransform which performs ES6 -> ES5 transformations on the AST that React parses.


I'll try it out later today.


Ken

GMail

unread,
May 26, 2014, 2:28:21 PM5/26/14
to mimo...@googlegroups.com
In which case traceur is unnecessary?

Happy to take a PR that adds an 'options' object with harmony set to false by default.  Might be a day or two before I can hack into that myself.

Sent from my iPhone

Ken Carpenter

unread,
May 26, 2014, 3:00:47 PM5/26/14
to mimo...@googlegroups.com
If the jstransform code handles all the ES6 code, then yes, Traceur would be unnecessary.

Regarding the PR, I'll see if I can work out how/where to add that.  I've been in "user" mode so far, not "developer" mode with Mimosa and not really sure I've groked the mental model of how Mimosa puts all the pieces together.

FYI, I tried creating a new project from the react-backbone skeleton and just added the following to app.jsx just before var "BackboneMixin = {":

  let x = 10;
  let {x,y,z} = {x:1, y:2, z:3};

  let foo = () =>
  {
    console.log("foo!");
  };

Even though jshint/lint complained about the ES6 code and told me to set esnext, it still passed all the ES6 code through properly into the public app.js.

I added the following to my config file and the lint warnings are gone now:

  jshint:
    rules:
      esnext: true

But I still get this error:

  11:55:52 - ERROR - mimosa-require: unable to parse public/javascripts/app/app.js { [Error: Line 14: Unexpected token {] index: 759, lineNumber: 14, column: 7 }
  11:55:52 - Success - Wrote file public/javascripts/app/app.js

Also, as a side note, I think the automatic insertion of the /** @jsx React.DOM */ line is throwing off the line number in the error reported above.  The actual code is on line 13 in the app.jsx file.


Ken

Ken Carpenter

unread,
May 26, 2014, 3:03:37 PM5/26/14
to mimo...@googlegroups.com
Regarding the line numbers,  technically it's correct because it reported the error against the public/javascripts/app.js file.  I was looking for the error in the .jsx file though.


Ken

dbashford

unread,
May 26, 2014, 4:20:20 PM5/26/14
to mimo...@googlegroups.com
I've pushed what should be the update to mimosa-react, https://github.com/dbashford/mimosa-react, to capture options.  Because of the limitations of the airport wifi, I can't get it tested properly.  But you should be able to clone the repo and do a "mimosa mod:install" from inside the repo to install the module into mimosa.

Ken Carpenter

unread,
May 26, 2014, 5:14:56 PM5/26/14
to mimo...@googlegroups.com
Thanks!  I actually worked through it myself too and got it working. My changes are almost identical to yours, except I didn't add the option type checking part. :-)

I tried my version and it does help, in that jstransform does "some" ES6 transformation (e.g., arrow functions), but it doesn't support everything (e.g., destructuring doesn't work).

A Traceur solution still seems to be necessary to get full ES6 functionality unfortunately, or perhaps additional transforms on the jstransform side, but I have no idea when/if those are coming.

Alternatively, I see that browserify can run other modules to transform things like es6ify and grunt-react (https://www.npmjs.org/package/grunt-react).  That feels like adding an unnecessary layer of complexity though.


Ken

Ken Carpenter

unread,
May 26, 2014, 5:36:34 PM5/26/14
to mimo...@googlegroups.com
After adding "traceur" back into the modules list, I get errors that include the < character from the pre-transformed .jsx file, so it seems Traceur is being passed the untransformed source code, not the transformed app.js file.

Is there a way to specify a dependency between react jsx and traceur so that it traceur receives the output from the react jsx transformation?

The biggest problem I have understanding Mimosa right now is know what is going to transform what, in what order.

Ken Carpenter

unread,
May 26, 2014, 8:58:30 PM5/26/14
to mimo...@googlegroups.com
You'd want to run lint with the esnext flag turned on in there too after jsx runs, but before traceur converts the code to old school JS.

I know it was running lint already, but I'm not sure at what step it ran it.

dbashford

unread,
May 28, 2014, 8:23:20 AM5/28/14
to mimo...@googlegroups.com
Sorry for taking another day to get to you on this.

Mimosa's workflows are like a car assembly line. 

https://github.com/dbashford/mimosa/blob/master/src/util/workflow.coffee#L19-L30

For each workflow, modules line up to perform a task for a certain step.  The object in the code I linked above is keyed by workflow name with the arrays being the steps.  The steps are executed in order, with Mimosa passing information (like a file that is being processed) from step to step.  Each module can modify or transform data when it is called such that downstream modules see the modified data.

https://github.com/CraigCav/mimosa-traceur/blob/master/src/index.js#L75

traceur runs "afterCompile".

https://github.com/dbashford/mimosa-react/blob/master/src/index.js#L28

react is a javascript compiler, which gets special treatment from mimosa.  It runs during the "compile" step.  Don't have to understand how mimosa lines up modules to know that afterCompile is after compile. ;)

So what should be happening is..

1.  in the compile step, mimosa-react transforms options.files[].inputFileText to options.files[].outputFileText.
2. in the afterCompile step mimosa-traceur transforms options.files[].outputFileText to a new options.files[].outputFileText.  Essentially rewriting it.

This would meant hat react would need to be able to handle es6 syntax.  By the time react has compiled it, the code is valid, so the traceur compiler should be able to handle it ok.

https://github.com/dbashford/mimosa-jshint/blob/master/src/index.js#L121

jshint also runs "afterCompile".  When two modules register for the same step, the order in the modules array wins.  So, if you have traceur running BEFORE jshint, jshint would be running on the compiled JS code and you likely would not need the esnext flag.  If you have traceur running AFTER jshint, then jshint would need to understand esnext.

IMPORTANT!

I noticed this just before hitting POST on the message. Bug in traceur code: https://github.com/CraigCav/mimosa-traceur/issues/5 If you make the change I suggest in that issue, this MAY work out.

Ken Carpenter

unread,
May 28, 2014, 12:27:07 PM5/28/14
to mimo...@googlegroups.com
First, thanks for the explanation.  I pretty much got the overall concept already, but when you have several things transforming your code along the way, I was a bit confused in which order certain things occur. The comment about order in the modules list giving precedence helps clear that up a fair bit though.

Second, with the above suggested changes, it is more or less working for me now.

My mimosa-config.coffee looks like this now:

exports.config = {
  modules: [
    'copy',
    'server',
    'csslint',
    'require',
    'minify-js',
    'minify-css',
    'live-reload',
    'server-reload',
    'react',
    'jshint',
    'bower',
    'sass',
    'dust',
    'web-package',
    'combine',
    'traceur'
  ],
  react:
    options:
      harmony: true
  jshint:
    rules:
      esnext: true
}

To summarize how this got to a working state:
The caveat is that not all ES6 syntax works:

For example, destructuring like this works:

function foo({x,y,z})
{
  var str = " + x" + x + " y=" + y + " z=" + z;
  return (<div>{str}</div>);
}

and an arrow function like this works:

var bar = (x, y, z) =>
{
  var str = " + x" + x + " y=" + y + " z=" + z;
  return (<div>{str}</div>);
};

But an arrow function with destructuring like this doesn't work:

var baz = ({x,y,z}) =>
{
  var str = " + x" + x + " y=" + y + " z=" + z;
  return (<div>{str}</div>);
}; 

React complains:

...failed compile. Reason: Error: Parse Error: Line 30: Unexpected token =>


It's much, much closer though!  I'll look into the React parsing issue with them.


Ken

Ken Carpenter

unread,
May 28, 2014, 4:52:44 PM5/28/14
to mimo...@googlegroups.com
So I found a workaround for now in case anyone else is facing this:

The bar function works in es6fiddle.com and in React JSX.

let bar = (params) =>
{
  let {x, y, z} = params;
  console.log("x=" + x + " y=" + y + " z=" + z);
}

bar({x:1, y:2, z:3});

The baz function works in es6fiddle.com, but not in React JSX.

let baz = ({x, y, z}) =>
{
  console.log("x=" + x + " y=" + y + " z=" + z);
}

baz({x:4, y:5, z:6});



Ken

Ken Carpenter

unread,
May 28, 2014, 6:43:27 PM5/28/14
to mimo...@googlegroups.com
Quick update:

I checked on the React Google Group and Ben Alpert figures it's an Esprima harmony parsing issue.

I've submitted a defect to Esprima here:


On Wednesday, May 28, 2014 9:27:07 AM UTC-7, Ken Carpenter wrote:

Ken Carpenter

unread,
May 29, 2014, 9:37:08 PM5/29/14
to mimo...@googlegroups.com
I keep replying to my own post!

I just submitted a Pull Request to mimosa-tracer that adds support for the --experimental flag and fixes the other issue mentioned above.

    https://github.com/CraigCav/mimosa-traceur/pull/6


Ken

dbashford

unread,
May 29, 2014, 10:00:09 PM5/29/14
to mimo...@googlegroups.com
Awesome!

I've just flagged you as an OK poster here.  Google was thinking you were spamming which is why you kept having messages disappear.  They were piling up in a spam bucket and Google only lets me know they end up there once a day.

I realized I hadn't published mimosa-react since making the changes at the airport.  That is pub'd now.

Ken Carpenter

unread,
May 29, 2014, 11:29:37 PM5/29/14
to mimo...@googlegroups.com
Ooooooooooohhhhhhhh!  Makes sense now.


Ken
Reply all
Reply to author
Forward
0 new messages