-
• #2
Wow, that's impressive!
I'm a bit new to this, but how does JSX normally work? Obviously if I paste this into a browser or Node.js, I get
Unexpected token '<'
- so does React rely on transpiling this code before upload? Or does it do some weird parsing/code rewriting thing normally?I'm a bit iffy about building stuff into the interpreter itself that isn't part of the default JS spec - for instance looking at the changes I believe that the line
1 < /a/.exec("Hallo").index
works at the moment but would fail with the new changes.At the end of the day, Espruino really isn't anywhere near React, so I think if people start thinking the layout library behaves like it they will ultimately end up confused/disappointed.
However if we could actually just turn this into a generic XML parser then that could be awesome, and we could build functionality a bit like you're suggesting right in:
const layout= new Layout(`<Vertical> <Label font="20%">JSX</Label> <Button col="blue">Maybe</Label> </Vertical>`);
-
• #3
JSX is usually transpiled by the TypeScript compiler or Babel.
There are multiple issues with my current implementation, I wanted to have a prototype in case it was a definite no.
A thing React does for some reason is when there's only one child, it's not wrapped in an array in the props. My implementation doesn't do this, because it's weird. I don't think it would make sense to implement it because it would require most things to manually wrap the lone child in case it's a child layouting thing (strings are automatically concatenated). I bring this up because TypeScript's JSX support is very flexible, and it almost support using JSX for layout exactly the way I described, except for that quirk.
The issue other than RegEx lexing is the fact that the tag contents (inbetween and ) doesn't allow any characters other than the latin alphabet, this is more tricky than it sounds, as there's no way to tell if a string has had single or double quotes after it has been lexed, and it would require manually adding the delimiter characters, which is not ideal. I think the solution would be to have the lexer have flags for a couple of modes:- Normal - the usual lexing mode
- No tokens - always gives one character at a time, without trying to read strings and stuff. Pretokenised characters might be a problem, but they can just be converted into their string forms (It doesn't matter that pretokenised characters represent multiple characters, since it's going to be appended to a buffer string in any case)
- No regex - this is hacky and less subtle than I personally like, but I don't know of any other way for resolving the issue.
As per having a string and parsing it, there are multiple pitfalls, some of them which are described in the original JSX spec:
- There's no way to verify that the XML is correct before running the code.
- There's no meaningful way of referencing anything which doesn't serialize to a string, eg. there's no way to set a button's callback.
I see why people would be confused as to why JSX is used in a different way versus React, but using Layout requires reading the docs (or examples) beforehand, so if the usecase of JSX can be explained there, I don't think it will be a problem.
- Normal - the usual lexing mode
-
• #4
Thanks! I'd be interested to hear other people's views on this, but personally I don't see a massive difference in readability between these two:
const layoutObj = <Vertical> <Label font="20%">JSX</Label> <Button col="blue">Maybe</Label> </Vertical>; // ... const layout = { type: "v", c:[ { type: "txt", font: "20%", label: "JSX"}, { type: "btn", color: "blue", label:"maybe"} ]}
Because the Bangle is so constrained and the screen is small, you're never going to be able to have a lot of stuff in the Layout, so I really don't see a big benefit in this - and actually having a whole new syntax and parser that isn't JS and isn't quite JSX just for a few lines of code in a few apps seems like massive overkill, especially on Bangle.js 1 where we're starting to have to worry about how big the Espruino binary is so it'll fit in the available flash.
This is undoubtedly cool, but I just think for Bangle.js, it's too much. I guess if you really wanted you could add a plugin to EspruinoTools that detected JSX on the PC, parsed it and rewrote it into a JS object, but I'm conscious that much like the TypeScript support this will probably be something that gets added, used for one app, and then forgotten about.
A built in XML parser though? That would actually be useful for loads of people - especially with the HTTP request support added to
Gadgetbridge
-
• #5
Hi! Сorrect the typo, otherwise people won't understand why it's written that way :)
instead<Button col="blue">Maybe</Label>
<Button col="blue">Maybe</Button>
-
• #6
In fact, I also thought it would be fun if it was possible to use JSX in B.js, but I would also like to have concepts like hooks. In general, I would expect concepts from the React world.
JSX and React are very popular, this is already a certain standard for the web-dev and if the same concepts could be applied to a microcontroller, then it would be fun :) Also, in theory, it would add popularity to the project, new users, because the world of React is huge.
However, there must be a person who will do this: create and maintain JSX React transpiler into the Espruino JS code. As a plugin for Babel or something else.
-
• #7
I work with React at my job, and I really do love that stuff.
I don't know if it's relevant, but Preact is very similar to React, and is only like 3kb (with 0 dependencies).The way React actually works is by transpilation typescript/bable/webpack magic
This
function simplestReactComponent() { return <div>Hello world!</div>; }
Becomes this
function simplestReactComponent() { return React.createElement("div", null, "Hello world!"); }
It wouldn't under any circumstances be part of the interpreter, but I don't know if it's a good investment of time..
-
• #8
I found this tool, it transpiles React live to actual Javascript.
-
• #9
I'm worried that using a normal JS library would cause memory problems - in some other posts, it can be seen that the Bangle.js 1 is struggling with memory in some posts in some cases. I think I have to agree with Gordon that the upper limit for UIs on the Bangle.js is not that high to warrant very complex UI frameworks.
The reason I originally steered away from a master function is because unlike React, where there's one master function for everything (React.createElement
, orjsx
in newer versions) and having it always loaded everywhere is consented, a lot of Espruino apps might never want Layout (or not have it at all), so I don't think the React way of making elements is suitable for Espruino.
The way I did it in the intepreter (and what I think should be done) is without a constructor function: the JSX syntax would be a shorthand function call, basically. Esprima natively supports JSX and is used in EspruinoTools, so it would probably make sense to have it convert<Button col="blue">Maybe</Button>
to
Button({ children: "Maybe", col: "blue" })
, though I could see why part-improvised syntax and grammar might be frowned upon.
I like the Bangle.js Layout library, and I like React. Both are similar, in my opinion. One thing React has which Layout doesn't is JSX: Instead of having to write object literals or function calls, it can be something which looks like HTML or XML.
For example:
instead of
I think it would be cool if the Espruino interpreter supported some form of JSX, since it would make Bangle.js Layout code be easier to read.
I've made a local branch which implements JSX in the interpreter.
I think there can be a problem with JsHint not supporting it and stuff, but maybe it can remedied by updating CodeMirror to use ESLint?