-
Notifications
You must be signed in to change notification settings - Fork 47.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Work with compile-to-JS languages (like CoffeeScript) #47
Comments
@edc what do you think of this?
This works out of the box (and is what JSX actually compiles down to). I fear a solution that parses strings because of performance implications, having to include a parser in the core (which is more bytes down the wire) and that it becomes easier to introduce XSS vulnerabilities. |
Well, that's not really better, it's just writing the JSX transform yourself. Which sucks (otherwise we wouldn't have JSX at all). And if we ever decide to change the output of the transform things are going to fail weirdly. What @edc is proposing is nice in that since it's just JS, things like coffeescript can parse it and not choke. What we could maybe do is have the JSX transform step look for this |
I like @zpao's proposal. The |
Ah, now I get what you meant by |
Another way to support at least CoffeeScript could be to make the component constructor a little more lenient. I've been playing a little with this, and my favorite syntax so far is something like this:
That is:
And, since CoffeeScript is a bit weird, combine multiple "props" objects into one. (CoffeeScript turns that last line into:
). It may not be HTML, but it is quite readable IMHO. |
@holmsand you may want to check out what coffeekup does: coffeekup.org You can pass arrays as children today. We try to avoid them for single-child nodes so we can save an array allocation. I bet we could build a jsx-coffee package that wraps up all the ReactNativeComponents in React.DOM to expose this interface pretty easily. What do you think about that approach? |
@petehunt I'm not that fond of coffeekup (eval evilness, and whatnot). About arrays of children: I just found it confusing a couple of times that multiple children just disappeared without any warning... And the CoffeeScript gets a little bit prettier without the []s. Anyway, wrapping is exactly what I did when playing with React. I ended up with something like the code below (with some auto-autoBinding thrown in). But it sure would be nice to have a common, human-usable API for us preprocessor-challenged users... Reactor = @Reactor or= {}
isProps = (val) ->
typeof val is 'object' and not
(React.isValidComponent(val) or Array.isArray(val))
copyObject = (from, to) ->
for own key, val of from
to[key] = val
to
wrapComponent = (compFn) ->
(children...) ->
# Coffeescript breaks objects into more than one with this syntax:
# L.input type: 'button', onClick: @onClick,
# value: 'Click this button'
# So combine second object with first.
# Also allow props to be omitted, and class instead of className.
props = null
while isProps children[0]
props = copyObject children.shift(), props or {}
if props and 'class' of props
props.className = props['class']
delete props['class']
if children.length
children = children[0] if children.length is 1
compFn props, children
else
compFn props
Reactor.DOM = {}
for own key, val of React.DOM
Reactor.DOM[key] = wrapComponent val
Reactor.createClass = (comp) ->
newc = {}
# autoBind all handlers starting with 'on' or 'handle'
for own key, val of comp
if key.match /^(on|handle)/
val = React.autoBind val
newc[key] = val
wrapComponent React.createClass newc |
One of the common use case of JSX is to embed complex Javascript code within the XML like <ul>
{this.props.children.map(function(child) {
return <li>{child}</li>;
})}
</ul> How would you write that in Coffeescript with your suggested method? Would the code inside of the {} be written in Javascript? Wouldn't that be weird to mix coffeescript and Javascript? |
I still prefer JSX since it is HTML. To quote the React's own document:
IMHO, DSL based on CoffeeScript can easily become a mess because of the mixture of optional parenthesis/braces and significant whitespace. For instance, if you forget a trailing comma and instead of
you have
it will continue to compile, but the semantic is totally different. |
I think the following can be made to work: <form onSubmit={this.handleSubmit.bind(this)}>
<input type="text" ref="textInput" />
<button>Add</button>
</form> (form onSubmit: @handleSubmit,
(input type: 'Text', ref: 'textInput'),
(button 'Add')
) I think the best course of action is to make a CoffeeScript dedicated wrapper that has a nicer syntax than the constructor we have now. |
With {} (form {onSubmit: @handleSubmit},
(input {type: 'Text', ref: 'textInput'}),
(button {}, 'Add')
) With {} and []: {} means attributes, [] means children (form {onSubmit: @handleSubmit}, [
(input {type: 'Text', ref: 'textInput'}),
(button ['Add'])
]) Where the general form is (name {attributes}, [children]). Only children is optinal |
@vjeux It would be really nice to treat CoffeeScript as a first-class citizen and have CSX in addition to JSX 😃. We might even be able to get rid of |
If you feel like making JSX work on CoffeeScript, that would be awesome :) I don't think that anyone is working on it right now. About class extension, we could totally do that. We didn't do it because there's no class support on raw Javascript. |
@vjeux cool. Will try to put something together. Off topic, but are you guys attending any meetup to get more traction? |
@edc Of course it would be nice to have a preprocessor for CoffeeScript as well - as you say there are some downsides to using a DSL. But there are upsides as well, since the preprocessor is essentially creating an entirely new, and somewhat unfamiliar, language, with gotchas of its own. |
@edc Yes! Nothing on the books yet but if you have suggestions on particular meetups let me know. |
The CoffeeScript grammar appears to be fairly well-defined and extensible. So it might be even easier to write a transformer for XML literals in CoffeeScript than it was to implement JSX using Esprima. |
I'm not sure if we can ever make it work but this is valid CoffeeScript :p _<script>_
_ _<ul>_
_ _<div id="vjeux" /_>_
_ _<_/ul>_
_<_/script>_ If you ignore the _ this is also XML :p |
The following could be made to work but doesn't really look like XML anymore and I prefer the version with () {} [] that I talked about earlier
|
I just realized the following works fine:
So I guess you could close the issue. :) |
I'd like to see this issue open. The above solution looks great but defeats the purpose of coffeescript by making a potentially big chunk of code javascript. Plus, it kills the syntax highlighting, which really makes a designer's life hard. And if I'm not mistaken, the whole point of jsx is to write HTML-like code in a js file isn't it? (Disclaimer: I'm still checking out react and am by no mean fluent in it. Please point out any false assumption I'm making) The downside of this is that just like many solutions proposed here, this looks clean at the expense of regular javascript. I have some neat solutions in mind but, another time. Second, just like lots of the newcomers, I'm still a bit uncomfortable at the idea of writing my markup, especially markup that needs compiling, in my js files. It's mostly a mental barrier. I have an idea for the best of both worlds but now that I'm writing, I think I need a bit more reflection on this. I'll open a separate issue once I get more acquainted with this library. |
So if you wanted, you can just use It's the integration of JSX into coffeescript that's hard. coffeescript probably chokes on As to your last point, I'll reiterate that you don't have to use JSX. You can write the |
@chenglou how about something like this? http://jsfiddle.net/hdrV3/1/ Just a thin wrapper around React.DOM to make it more DSLy in CoffeeScript. |
Yeah. |
This conversation may interest you: https://groups.google.com/d/msg/reactjs/dpGem2Yr6do/8VuGYEAzqTcJ |
@chenglou Just to add another datapoint: It turns out that the idea of @edc works quite well in practice, at least for me (i.e. escaping JSX in Coffeescript, and then compiling the resulting .js file using React's compiler). I've just rewritten something like 1500 lines of code using that method, and so far it's been an absolute pleasure. I.e. using code like this Dropdown = React.createClass
render: ->
@transferPropsTo `
<div class="btn-group">
<button tabIndex='-1' type='button' class="btn dropdown-toggle"
data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{this.props.children}
</ul>
</div>` I actually like the 'look' of JSX in Coffeescript better than in JS, since the escaping clearly demarks what is JSX and what is not. |
Shameless but pretty relevant plug: some of the syntax ideas being discussed here are actually close to something I've been working on called reactive.coffee, an embedded DSL for building reactive UIs (in a scalable manner). |
I just want to quickly add that if you're using GitHub's Atom, it (kind of) highlights syntax within backticks. |
Ok, I don't think we are going to extend the transformer in ways that have been discussed, so I'm just going to close this out. People have found solutions that are working for them in different languages. |
I just found https://github.com/jsdf/coffee-react-transform which appears to be a JSX transformer for CoffeeScript. I haven't tried it but it looks promising -- if anyone here tries it out, it would be great if you could report back with your results. |
I just converted a small project to use CJSX. Worked perfectly as far as I can tell and looks very nice. See https://github.com/KyleAMathews/community-mapping-tools/blob/master/react_components/sorted_addresses.coffee or https://github.com/KyleAMathews/community-mapping-tools/blob/master/react_components/header.coffee |
I'm working on CJSX quickstart. Has a Gulpfile to build coffeescript/sass as well as integration with Jest. WIP but coming along. |
* Minor clean up of EventTooltip.js * Fix root cause of #47 and improve tooltip styling Tooltips would go offscreen because of the way `top` is defined. This commit fixes that root cause by changing CanvasPage to position fixed so that tooltips will be positioned relative to the DOM rather than the CanvasPage div. Undoes some of the changes made in #78 as this commit fixes the root cause of the bug. * Disable component name truncation Although this was Brian's recommendation (see #67), I don't think component names will be very long because the source code for those will be really annoying. * Set mouse location on every interaction to fix #87 * Introduce 768-char component name length limit Covers the unlikely edge case that a component name is unreasonably long.
* Minor clean up of EventTooltip.js * Fix root cause of #47 and improve tooltip styling Tooltips would go offscreen because of the way `top` is defined. This commit fixes that root cause by changing CanvasPage to position fixed so that tooltips will be positioned relative to the DOM rather than the CanvasPage div. Undoes some of the changes made in #78 as this commit fixes the root cause of the bug. * Disable component name truncation Although this was Brian's recommendation (see #67), I don't think component names will be very long because the source code for those will be really annoying. * Set mouse location on every interaction to fix #87 * Introduce 768-char component name length limit Covers the unlikely edge case that a component name is unreasonably long.
JSX is nice, but those using compile-to-JS language have to change the transpiler to connect to the JSX compiler. Is there any chance of adding alternative DOM syntax to JSX so it does not break every compile-to-JS language? Something
gettext
-style would be nice. So in addition to:it would be nice to support
The text was updated successfully, but these errors were encountered: