Giter Club home page Giter Club logo

Comments (21)

edemaine avatar edemaine commented on May 26, 2024 2

I agree 100% (also a Solid fan here!). We had some discussions about this in the Discord, and I was planning to take a stab at implementing it (as Daniel doesn't use JSX himself).

I think the right way to do this is to support both syntaxes, via a parser flag in the first line (the existing "civet ..." directive). That way we can still offer CoffeeScript compatibility. For example:

  • "civet coffeeCompat" - closing tags, not indentation based
  • "civet coffeeCompat indentJSX" - CoffeeScript but with indentation JSX
  • "civet closeJSX" - Civet as it is now, requiring closing tags
  • default - indentation JSX

@STRd6 I haven't looked at how JSX is handled, but I assume there's significant support in the lexer. Will it be feasible to support both modes?

from civet.

STRd6 avatar STRd6 commented on May 26, 2024 1

@lorefnon I'm definitely open to exploring it. I don't use JSX too much myself but I do see the value in Civet providing a much more concise, mostly compatible JSX that improves the common cases and supports best practices (i18n). Worst case we can add a directive like "civet jsxCompat" for people migrating from existing JSX codebases.

<div> "hi" if i > 2
---
<div>{i > 2?"hi": void 0}</div>

So far seems like it would be 👍

from civet.

lorefnon avatar lorefnon commented on May 26, 2024 1

Yes, I wasn't suggesting adopting all parts of imba template syntax. It is very feature rich, has evolved over quite a long time, and some of it (eg. scoped css, slots etc.) are closely tied to their implementation and will not translate well to arbitrary jsx providers.

I was primarily highlighting the expression support because needing to wrap code in { } looks a bit weird in an indented language which otherwise doesn't use braces as block delimiter.

from civet.

lorefnon avatar lorefnon commented on May 26, 2024 1

Just to add to the above, unlike React where jsx always transforms to a plain function call, frameworks like solid, qwik have different and more involved compile time support for jsx - if we don't support jsx, to be able to consume these libraries in a civet we will have to do one of the following:

  1. Use a less performant or less type-safe representation
  2. Expose a custom dsl that emulates these transformations and keeps track of updates

But if we support jsx, civet can just rely on whatever jsx specific tooling these libraries maintain

from civet.

edemaine avatar edemaine commented on May 26, 2024 1

Since optional closing tags is a superset of explicit closing tags then it could make a very compatible default that people could opt into by usage.

I don't think this is right, because entering JSX normally (in CoffeeScript) means "ignore all indentation until we re-enter code mode via {". In testing #25, I finally found an example where this actually matters:

return
  <div>
foo bar
  </div>

In CoffeeScript, this is a <div> element with some text. If we allow <div> to become <div/> automatically when it has nothing intended inside it, then we end up turning foo bar into the function call foo(bar) instead of treating it like text.

So I think a toggle may be useful, for backward compatibility. But hopefully this kind of use is pretty rare (text is normally intended within the tag) so we can have indentation JSX on by default.

from civet.

STRd6 avatar STRd6 commented on May 26, 2024 1

It might also be worth exploring optional braces for attributes:

<For each=cats()>
  (cat, i) =>
    <li>
      <a target="_blank" href=`https://www.youtube.com/watch?v=${cat.id}`>
        `${i() + 1}: ${cat.name}`

from civet.

lorefnon avatar lorefnon commented on May 26, 2024 1

@STRd6 @edemaine Are we still open to a language level flag to skip braces for embedded code (basically #20 (comment)) ?

from civet.

STRd6 avatar STRd6 commented on May 26, 2024

It should be possible to support both, and it may even be possible to support optional closing tags by default. With the caching implemented in the parser there is much less cost to distant lookaheads. Since optional closing tags is a superset of explicit closing tags then it could make a very compatible default that people could opt into by usage. Perhaps the only necessary directive would be "civet closeJSX" to opt into mandatory explicit JSX closing.

@edemaine take a look at the NestedBlockStatements rule for an example of how the parser currently handles nesting. You can add a production to JSXElement that uses nesting and inserts a synthetic closing tag (similar to how it checks for mismatched tags). Let me know if you have any other questions, thanks!

from civet.

lorefnon avatar lorefnon commented on May 26, 2024

So the indentation based syntax in imba has a few more nuances other than optional closing tag. I am not suggesting we adopt them all, but one thing of interest is that because strings need to be explicitly quoted, we can avoid the need to wrap expressions in braces as in JSX.

This enables us to write code like:

<div.tiles> for tile,i in game.tiles
	<Tile data=game nr=i @click=game.place(i)> tile

which is more succinct compared to:

<div.tiles>{for tile,i in game.tiles
	<Tile data={game} nr={i} @click={game.place(i)}> {tile}}

from civet.

STRd6 avatar STRd6 commented on May 26, 2024

@lorefnon I agree about removing (or optional) braces for attribute values but for element content non-braced characters would collide with text children.

from civet.

lorefnon avatar lorefnon commented on May 26, 2024

Yes, unless text children in indented jsx mode have to be always quoted eg.

<div>"Foo"

Text content within jsx is increasingly uncommon in most apps that support i18n

from civet.

edemaine avatar edemaine commented on May 26, 2024

It'd be helpful to pull apart the various features of imba to see what makes sense here.

Indentation instead of explicitly closing tags

I think we all agree this is good, especially if we can also still support closing tags.

.className

I'm a big fan of Pug so I like the idea of div.foo as shorthand for <div class="foo">. However, I don't think it's a good idea in JSX context, because <div.foo> already has a meaning. For example, Motion One for Solid uses <Motion.div> to dereference the div property of the Motion object.

Maybe <div .foo> could work? But this looks less like a CSS selector...

Children are JS expressions, not text

I'm a little more hesitant on this one, as it makes the notation not feel like HTML anymore. JSX has such clear semantics that braces mean JS content, whether they're in attributes or children. JSX also has the nice feature that you can copy/paste HTML and you're generally good (especially with Solid).

On the other hand, I can see preferring this. Maybe it makes sense to offer both options via a civet flag?

Also, I don't think I understand how imba actually treats children. They're not just JS expressions. There's also the css thing (it's clearly not a function), and multiple tag children can be "returned" without having to wrap in <>...</> as you do in React or Solid. I'm not sure how this would be achieved in Civet. An option for implicitly wrapping multiple consecutive tags into a fragment would be really convenient (can't tell you how many times I've forgotten to do this in CoffeeScript).

from civet.

HerringtonDarkholme avatar HerringtonDarkholme commented on May 26, 2024

Do we really need JSX in Civet? Civet is expressive enough for markup I think.
Previously we also have https://github.com/mauricemach/coffeekup

from civet.

edemaine avatar edemaine commented on May 26, 2024

Do we really need JSX in Civet?

Yes. There are many frameworks that work much better with JSX. Big examples are React (the most popular front-end framework), Preact, and Solid. JSX is also used in many other smaller projects, for example my own SVG Tiler (JSX is simply the best way to express programmatic SVG).

Omitting JSX would be limiting Civet to a much smaller audience. JSX is also a key feature of CoffeeScript, so it makes sense for compatibility as well.

from civet.

edemaine avatar edemaine commented on May 26, 2024

Actually, the </div> in that example forces it to parse correctly... I was testing wrong. So maybe there isn't actually a bad case?

from civet.

edemaine avatar edemaine commented on May 26, 2024

Indentation-based JSX is now live in 0.4.28! (Currently, co-existing with explicitly closed tags.)

Examples (from solidjs.com):

https://playground.solidjs.com/

function Counter()
  [count, setCount] := createSignal 1
  increment := -> setCount count() + 1
  <button type="button" onClick={increment}>
    {count()}

https://www.solidjs.com/tutorial/introduction_jsx

return
  <>
    <div>
      Hello {name}!
    {svg}

https://www.solidjs.com/tutorial/flow_for

<For each={cats()}>{(cat, i) =>
  <li>
    <a target="_blank" href={`https://www.youtube.com/watch?v=${cat.id}`}>
      {i() + 1}: {cat.name}
}

With the other imba suggestions I could see supporting (with a compiler flag):

<For each={cats()}>
  (cat, i) =>
    <li>
      <a target="_blank" href={`https://www.youtube.com/watch?v=${cat.id}`}>
        `${i() + 1}: ${cat.name}`

Maybe I'll try that next.

from civet.

lorefnon avatar lorefnon commented on May 26, 2024

Great! Thanks a lot for working on this.

from civet.

edemaine avatar edemaine commented on May 26, 2024

For those tracking this GitHub issue:

It might also be worth exploring optional braces for attributes:

Now supported in Civet v0.5.0! Any attribute values with no "unwrapped" whitespace should now work without braces. For example: cats()?.names[i] or (=> console.log 'hello world').

Also added is computed property names like [propName()]=propValue(). (This compiles to {...{[propName()]: propValue()}}.)

And previously added is the shorthand {foo} for foo={foo}. This works more generally with any braced object literal, including getters and setters.

from civet.

STRd6 avatar STRd6 commented on May 26, 2024

Resolved in: #25

from civet.

STRd6 avatar STRd6 commented on May 26, 2024

@lorefnon I'm open to it, at least as an optional flag. It might make sense to open a new issue about only that.

from civet.

edemaine avatar edemaine commented on May 26, 2024

I also plan to work on it, but I'm doing lower-hanging JSX fruit first. 🙂

from civet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.