facebook/create-react-app

Easily Add an Babel Plugin

birdwell opened this issue · 18 comments

Note from maintainers

For people coming to this thread later—if you use MobX or a similar library, you don’t need decorators. They are just syntax sugar in this case.
Learn more: #214 (comment), #411 (comment).
Here is why we don’t include them: #411 (comment).

The setup is excellent. I need to add the babel plugin ""transform-decorators-legacy"" because a library I'm using has decorators. Yet, I do not want to eject for one simple babel plugin. Is there a way to add a babel plugin without ejecting?

@birdwell No, and that is by design. If you need to deviate from the standard babel configuration, you will need to eject. Thanks!

need to add the babel plugin ""transform-decorators-legacy"" because a library I'm using has decorators.

This sounds a but confused. If a library uses decorators internally, presumably it is transpiled to ES5 on build so this shouldn’t be an issue.

If a library tells you to use decorators, most likely there is an alternative way of using it without them. For example people commonly say MobX “needs” decorators but it couldn’t be further from truth: you can use plain functions instead.

If you can clarify which library you meant, I can point you to an example of using it without the decorator syntax.

Hey Dan, this the library. Thanks a ton. Great work to all of you guys on this project. You are right there is probably an easy way to get around using them. @gaearon

Basically putting a decorator @foo before the definition of X is the same as saying X = foo(X) after X is defined. It's like one more line of code to do things without decorators.

So there's two decorators in that react-redux-firebase example. One is connect in react-redux. http://redux.js.org/docs/basics/UsageWithReact.html has some examples of using it with no decorator.

To convert the firebase decorator, look at one of their examples like https://github.com/tiberiuc/redux-react-firebase/blob/master/example/App.js -

@firebase()
class TodoItem extends Component {
  // Lots of stuff here
}

Instead of that you could just do

class TodoItem extends Component {
  // Lots of stuff here
}
TodoItem = firebase()(TodoItem)

Hopefully that helps!

Adding to what @lacker says, I believe that applying HOCs as functions instead of decorators should not be a way to do it, but the preferred way, for three reasons:

  1. It's standardised and one less dependency
  2. It uses the same syntax for functional and class components
  3. It allows exporting the unwrapped component for testing

Where point three is the most important one because when testing you usually want to test your component, not the HOC.

// Todo.js

export class Todo extends Component {
  // ...
}

// Defining an enhance function is down to personal preference, but I find using it in
// combination with a compose function to be a lot cleaner when using multiple HOCs
const enhance = compose( // compose can be imported from redux or recompose
  firebase(),
  /* more HOCs */
);

export default enhance(Todo);
// Todo.test.js

import EnhancedTodo, { Todo } from 'Todo.js';

// EnhancedTodo is the component wrapped by any HOCs
// Todo is the bare component

Another nice thing that’s nice to know: you can chain decorators applied as functions with any functional composition helper. Redux provides compose, you can find the same function in Lodash as flowRight:

import { compose } from 'redux'

class MyThing extends Component {
  // ...
}

// compose multiple "decorators"
const enhance = compose(
  connect(mapStateToProps),
  injectLocale(),
  firebase()
)

// export wrapped component
export default enhance(MyThing)

@gaearon @alexanderchr @lacker Thank you guys so much! Learned a bunch from those three comments. Plus, now I don't have to eject. 😄 👍

Update: Got my project working with above methods and no ejecting! Thank you again!

As create-react-app is probably more for people starting out, my vote would be to add the decorators to the basic kit. Makes it easy to follow existing tutorials, without having to insert a different syntax and to get it working. For example this great tutorial on MobX us strewn with decorators. https://www.youtube.com/watch?v=nYvNqKrl69s. I'm having to go through and alter code and for a newbie it just makes getting it working a bit more painful...

BTW- Thanks for all you guys do. I LOVE create-react-app.

Our position is simple: we add transforms that are either stable enough (like async/await) or heavily used by Facebook (like class properties). Only that lets us be confident in suggesting them, because if something changes in the standard, we’ll write and release a codemod to migrate away from them.

Since we don’t currently use decorators, we don’t take it upon ourselves to provide a migration path if the standard becomes incompatible. Additionally decorators aren’t even officially supported by Babel (-legacy is there for a reason). And when they are configured slightly incorrectly people blame React.

So no, we won’t provide support for them until they either become a part of the language, or we start using them internally at Facebook. Sorry! Bring it up with the tutorial authors because MobX absolutely does not require decorators.

Another argument against adding the -legacy transform is that any decorator written against it is - as it stands - incompatible with the current decorators proposal. There's multiple breaking changes between the stage-0 proposal (implemented by the -legacy transform) and the current stage-2 proposal. So if you use one of the -legacy-style decorators in your code, you run the risk of locking yourself out of future versions of babel or at least making the upgrade a lot more painful.

Thanks Dan,

The frontend JS ecosystem has many permutations and it really slows down learning and gettingstuffdone for JSnewbies like me. The reason I like React/Redux so much is that the community is so active and supportive. Cheers!

Decorators would be a very nice addition to have and frankly do you really think they will not be included in JS in the future? Angular uses them heavily, Typescript uses them, Mobx uses them.

@arisAlexis I’m afraid you missed my comment where I described exactly why we don’t include them in this tool. Whether I think they will become a part of JS or not is irrelevant here.

For people coming to this thread later—if you use MobX or a similar library, you don’t need decorators. They are just syntax sugar in this case.

Learn more: #214 (comment), #411 (comment).
Here is why we don’t include them: #411 (comment).

For anyone reading this in the future, I would like to point out that the decorators spec has changed significantly. I'm really glad we made the decision to not support them at early stage, so users who didn't eject don't need to change their code.

I don't recommend anyone to rely on the legacy decorator transform (that is not part of CRA). See this thread for more info: https://twitter.com/dan_abramov/status/897491076537356288.

Bable implemented decorator plugin: https://babeljs.io/docs/en/babel-plugin-proposal-decorators, is that stable enough? #214 (comment). Thanks!!!

@gaearon Sorry to bother you, no one replys for a long time.

i guess it won't be added until it is finalized. @maicss