facebook / jsx

The JSX specification is a XML-like syntax extension to ECMAScript.
http://facebook.github.io/jsx/
1.96k stars 133 forks source link

AssignmentExpression in JSXAttributeName #21

Open NekR opened 9 years ago

NekR commented 9 years ago

It would be good to have ability to evaluate attribute name. For example:

<Component {attr}="value" />

Might be transpiled to:

Component({
  [attr]: "value"
});

Yes, this is es6 output because JSX spec extends es6 specs. Transpilers/targets which do not support es6, but only es5 might choose to not support this feature. But for others it might be useful.

Also, E4X support this feature and for me, it's reasonable to have it.

RReverser commented 9 years ago

Technically, this is currently supported via JSX spread like

<Component {...{[attr]: "value"}} />

but I totally agree that having short syntax for separate properties would be a great addition.

NekR commented 9 years ago

Just made little PR #22 for the case that all will agree with this feature.

@RReverser can you review it?

sebmarkbage commented 9 years ago

In general, I'm a little skeptical to adding more stuff until we can get more people involved in this spec. E.g. the people writing library alternatives to React, so that React isn't the only consumer of this spec. Also, more implementors such as TypeScript.

To make it more palatable to them it's important that the spec starts off as a minimal-viable-product. Other than that I think that this is probably a solid proposal.

NekR commented 9 years ago

@sebmarkbage Here I believe now is another consumer of JSX :-)

RReverser commented 9 years ago

@NekR I'm not sure I see benefits of inventing own babel-plugin-jsx over setting jsxPragma in Babel to own runtime.

NekR commented 9 years ago

@RReverser that is explained in blog-post, but in short, Babel emits React-specific calls even with changed pragma (traspiling there also is called React, not jsx, btw). Inlined output also is not very helpful since it's still React-specific and making another framework on top of that would be a hack. For example deku guys had same the thoughts about it.

JSX-IR just allows independent output which can be consumed by deku, Incremental DOM, whatever, etc. "Give it five minutes", if you can, please.

NekR commented 9 years ago

@RReverser See https://github.com/facebook/jsx/issues/29#issuecomment-76677259 and next comment. /cc @sebmck

RReverser commented 9 years ago

Well, it's not really that specific and easy to write runtime that would just covert those calls into your own builders (instead of writing completely another transpiler plugin).

NekR commented 9 years ago

@RReverser well, what is a problem with separate compiler plugin? Also, why then react team is about to optimize their output and use inline object instead of functions calls? I believe there is performance value too.

Why all should stick to React infrastructure? I do not see benefits of using function calls at all, and especially React specific. Expect of that it's already implemented.

RReverser commented 9 years ago

@NekR I just don't see where is "stick to React infrastructure". Function calls are the sanest way of constructing, optimizing and modifying objects, and they're not React-specific at all, as soon as you can pass own runtime via jsxPragma. Of course, there is not much problems with separate compiler plugin, but that means that you stick with own support for JSX, and if/when JSX is extended with new node types, you have to maintain and add support for those new node types on your own instead of relying on central implementation.

sebmck commented 9 years ago

Function calls are good because they allow you to validate the input at runtime and produce useful stack traces.

NekR commented 9 years ago

@RReverser Why is Babel central implementation and why then have the spec at all? Imagine Brendan Eich and Mozilla are saying -- why v8, let's stick to one central implementation, because otherwise you will need to maintain your own implementation. Isn't it sounds ridiculous?

trueadm commented 9 years ago

@RReverser Whilst function calls might conform to sanity when in the development stages they don't when at production stages. In the case of virtual DOM object construction they're simply constructor calls where the end output remains largely the same. Given this is being actioned by a transpiler rather than a human, it makes sense to optimise where possible. It's faster at a run-time level to pass back an object than it is to call repeated createElement functions – in fact, you're likely to see "Not optimized: Optimized too many times" from the V8 JIT compiler.

NekR commented 9 years ago

@sebmck it will be handled by the functions anyway, but just later. Stack traces point sounds fair, but there is always are trade-off between usability and performance. Function calls probably can be used in development mode, but it introduces so much complexity. With objects literals you do not need to have anything in views/templates/components scope since it's just object without direct dependencies.

RReverser commented 9 years ago

@trueadm Nothing stops you from writing a function that returns cached value, and in fact you'll get direct inlining in any modern JIT including V8, just as you do with compile-time inlining.

sebmck commented 9 years ago

@NekR Yep, that's why there's facebook/react#3228.

NekR commented 9 years ago

@RReverser so say then so to Facebook React and ask them to stop doing optimizations here facebook/react#3228 @sebmck I know. Why then we are talking about problems with object literals?

sebmck commented 9 years ago

@NekR

Why then we are talking about problems with object literals?

Because you proposing using object literals always rather than as an optional production optimisation.

trueadm commented 9 years ago

@RReverser Whilst they make best-efforts to inline at JIT level, there's no guarantee at all – especially when you're manipulating function arguments. Clearly, as pointed out above, there is already work going into this though – so I'm happy there :)

NekR commented 9 years ago

@sebmck it wasn't proposed to React, I believe. JSX-IR has its own use cases which might not be good for React or some other framework. Using string templates also has their own problems and disadvantages, but there absolutely are cases for them and people are using them.

There are many vdom/jsx/whatever frameworks in a wild which are sticking to object literals too.

Anyway, development environment for JSX-IR might my patched/adopted and there might be a flag to transpiler to insert special debug function calls or mark object by some special way. But for production it still will object literals as they were introduced. In my mind, debug tools and goodies are made after as a optimizations for development workflow.

The idea was just to show how JSX and its output might be used universally. And speaking about creation of dedicated plugin--I assume it would be hard to incline you and Babel community to develop additional feature to JSX output which is not used by the React, since you are already providing feedback such as "why create plugin" even when that plugin is not related to React at all.

RReverser commented 9 years ago

so say then so to Facebook React and ask them to stop doing optimizations here facebook/react#3228

Those optimizations are in separate optional transformer and it doesn't impact you at all. Moreover, since they're not specific, you can use them for own runtime without need for reinventing same optimization techniques!

RReverser commented 9 years ago

I assume it would be hard to incline you and Babel community to develop additional feature to JSX output which is not used by the React, since you are already providing feedback such as "why create plugin" even when that plugin is not related to React at all

In fact, it's you who mentions React repeatedly in this thread, while we're trying to convince you that JSX implementation in Babel is not React-specific.

NekR commented 9 years ago

In fact, it's you who mentions React repeatedly in this thread, while we're trying to convince you that JSX implementation in Babel is not React-specific.

It's and people are just adoption their implementation to React compatible output.

Those optimizations are in separate optional transformer and it doesn't impact you at all. Moreover, since they're not specific, you can use them for own runtime without need for reinventing same optimization techniques!

Do you think Babel will allow me to put children on the same level as props are instead of containing children in props?

children in props is React's design artifact and I for example do not want it, so I do not use React specific output.

In fact, it's you who mentions React repeatedly in this thread

Sure, because you are by some reason imposing to me React's compatible JS output. How I cannot mention it?

RReverser commented 9 years ago

children in props is React's design artifact and I for example do not want it, so I do not use React specific output.

This is happening only in optimizer plugin, JSX transformation itself is React-agnostic (as I already told above). If you need different optimizer output, just fork it or write your own, but why replacing entire JSX transformation for the sake of one small module's behavior?

Sure, because you are by some reason imposing to me React's compatible JS output. How I cannot mention it?

Because personally I use JSX for custom stuff totally unrelated to React and without any dependency on it, so I'm just trying to understand what problem you're trying to solve.

NekR commented 9 years ago

I am not saying there is dependency of React, I am saying that React's JSX output became de-facto standard. There is many React's artifacts in current Babel's JSX output, but solve please this one particular problem with existing Babel JSX transpiler:

Translate this

/** @jsx X */

<div>
  <Test />
</div>

Into this

/** @jsx X */

"use strict";

X(
  "div",
  null,
  X("Test", null)
);

This is happening only in optimizer plugin, JSX transformation itself is React-agnostic (as I already told above). If you need different optimizer output, just fork it or write your own, but why replacing entire JSX transformation for the sake of one small module's behavior?

Are you kidding here? So you are saying forking Babel would be better than just writing a plugin? If I will want and optimized output of React's JSX I will write another plugin again, instead of just forking Babel. This is why plugins exists at all.

treshugart commented 7 years ago

@sebmarkbage just seeing this now. We support JSX in Skate and would love to see something like this. We have a lot of heuristics around how we should be setting props: is it an attribute, property or event listener? We'd like to be able to change that and let the user specify by an identifier, or something, how they intend it to be set. For example:

<div @aria-labelledby={this.id} />

Would be pretty nice. While it might not fit JSX to be able to literally do that, doing something like proposed at the beginning of this issue would help with that:

<div ['@aria-labelledby']={this.id} />
amiller-gh commented 7 years ago

Hey all, coming over here from #42, where I accidentally proposed this exact language feature! There seems to be general consensus that this feature has value, and I'd love to see it move forward. @sebmarkbage, are there still concerns about engaging more people in this spec process two years after your original comment, and what is the plan for JSX 2.0? (sorry, new to the conversation)

Questions I have after reading this proposal:

1) There needs to be clarification around AssignmentExpressions in attributes and namespaces. Ex: Would the following be valid? I would assume no.

let namespace = 'my-namespace';
let attrName = 'my-attr';
<div [namespace]:[attrName]="value" />;

2) Member expressions are allowed in tag names, and – at least in React's implementation – these are resolved to a value for element creation. Ex:

let obj = { 
  tagName: 'span' 
};
<obj.tagName />;

The above proposal essentially does exactly this for attributes. Do we want to allow member expressions in attribute names for consistency with tag names and a cleaner API? And if so, how does that play with namespaced attributes? AssignmentExpressions may still be used for expressions that can't be expressed only with dot notation. Ex:

let attrs = {
  '@escape-me': 'value',
  name: 'value',
  namespace: 'my-namespace'
};
let name = 'attribute-name';
let namespace = 'my-namespace';
<span 
     attrs.name="foo"
     [attrs['@escape-me']]="biz" 
     [name]="baz"
     attrs.namespace:attrs.name="bar" // Is this valid?
     [namespace]:attrs.name="bar" // Or this?
/>;

3) Similarly, do we want to allow AssignmentExpressions in tag names for the same reason?

let tagName = {
  '@escape-me': 'span'
};
<[tagName['@escape-me']] />;

Side note: while looking into this language feature, I found an inconsistency between the JSX spec and Babylon's implementation that more work on this issue may help resolve.

The JSX parser in Babylon currently allows tag names and namespaced tag names with member expressions:

<test:foo.bar></test:foo.bar>

However, this is wrong according to the current JSX spec, where JSXNamespacedNames do not allow member expressions, only identifiers:

JSXElementName :
- JSXIdentifier
- JSXNamespacedName
- JSXMemberExpression

JSXAttributeName :
- JSXIdentifier
- JSXNamespacedName

JSXIdentifier :
- IdentifierStart
- JSXIdentifier IdentifierPart
- JSXIdentifier NO WHITESPACE OR COMMENT `-`

JSXNamespacedName :
- JSXIdentifier `:` JSXIdentifier

JSXMemberExpression :
- JSXIdentifier `.` JSXIdentifier
- JSXMemberExpression `.` JSXIdentifier

This grammar allows tag names like these:

<foo:bar></foo:bar>
<foo.bar></foo.bar>

But does not allow for namespaced member expression tags like the Babylon parser currently does:

<test:foo.bar></test:foo.bar>
jackromo888 commented 1 year ago

``https://metadata.ens.domains/assets/doc_output.json