Please be patient with me, this is my first post :)
Who would like to see native/vanilla JSX support in JavaScript? I feel like this would be very beneficial to the JS community. First, here are some examples.
element.appendChild(
<button onClick={()=> {
console.log('lasers on!');
}}>
Activate Lasers
</button>
);
Also imagine the possibilities with SSR simply in express:
app.get('/version', (req, res) => {
res.send(
<div>
{process.version.node}
</div>
);
});
The way this would work is that a JSX fragment is it's own type which can be imported/exported from different files and represented as functions with a return value like (but not) react components.
In the first example, the JSX would be serialized into a HTMLElement or string (for .innerHTML), and when using document.appendChild, all the event listeners like onClick would be added to the corresponding element.
In the second example (Node.js runtime), the jsx would be converted to a string. Since this is SSR (server-side rendering) there obviously would be no event listeners or dom element. Instead, the JSX would be converted to a string that is then simply passed to the res.send()
function. Obviously, things like <!doctype HTML>
would also be passed as a string. This would require no change from the express.js framework.
I was thinking about cross-compatibility between Node.js and the browser or other runtimes, and I thought to make this a vanilla JS feature instead of browser or Node api so it could be used everywhere.
I did not mention the main reason I think this is a good idea, so I will note them out below:
1) Setting/changing HTML
If you have used React, Vue, Svelte, Ember, Qwik, Angular, Preact, Solid, or something similar, you may have noticed that the development process is way easier for complex applications. But this comes with a downside, like JavaScript support and large components that are downloaded in the browser. It's the norm currently to load a third party software from NPM to write any type of app these days. Almost every web app these days uses some type of framework. While React is good for building complex apps, I feel like native JSX would set a middle ground between simple apps with forms or basic interactivity and advanced apps like Discord or Asana.
The big issues these days with building interactive vanilla JS apps and SPA's is making interactive UIs. Here are some approaches:
element.innerHTML = `<button id="magic">Make some magic!</button>`
document.getElementById('magic').addEventListener('click', () => {
console.log('magic');
});
First of all, using innerHTML could be unsafe and code gets really messy when put inside template literals. Also, linters cannot format the HTML inside of this. The separate event listener is also not very declarative nor easy to read.
function magic(){
console.log('magic');
}
element.innerHTML = `<button onclick="magic()" id="magic">Make some magic!</button>`
Sure, this is more declarative but can also get very messy.
const element = document.createElement('div');
const button = document.createElement('button');
const buttonText = document.createTextNode('Make some magic!');
button.appendChild(buttonText);
button.setAttribute('id', 'magic');
element.appendChild(button);
document.body.appendChild(element);
button.addEventListener('click', () => {
console.log('magic');
});
Another way of doing it is using document.createElement
which is a lot cleaner but is also very tedious and not declarative at all. Imagine a whole codebase with these types of nested elements. Now, look at the example above and ask yourself which - which one is the best?
Nested components
It's no lie that nested components are way easier to use and are one of the most popular reasons to switch to React over vanilla JS for a good reason. It is clearly way simpler to create functions like this instead of writing all your code inside html or strings within the JavaScript:
const Greeting = (props) => {
return (
<div>
<h1>Hello, {props.name}!</h1>
</div>
);
};
const MainComponent = (props) => {
return (
<div>
<h1>Main Component</h1>
<Greeting name={props.name} />
</div>
);
};
document.body.appendChild(<MainComponent />)
This example has no react, and does not need any types of external libraries. Making changes would also be very simple.
document.addEventListener('keypress', () => {
console.log('Key pressed:', event.key);
document.querySelector("name").replaceChild(<Greeting id="" />)
});
3) Security
This is very simple. XSS can be prevented by either using .innerText but this does not work for innerHTML. You could sanitize the HTML string using regex or .replace()
, but it adds extra steps that should instead be baked into JS.
const Greeting = (props) => {
return (
<div>
<h1>Hello, {untrustedAjaxResponse.name}!</h1>
</div>
);
};
4) Server-side rendering
We got tools like Astro and Next.js which are obviously more advanced, but what if you could just eliminate all those steps and render JSX in Node.js or deno, simply using JavaScript? This would eliminate SSR frameworks to some extent and also static site builders
ejs, moustache, and handlebars were also made to solve this, but it was very messy and not built in to the JS ecosystem. They are not type-safe and hard to debug and format.
Deno fresh is actually a great implementation of this, but would obviously require seperate .jsx
files.
Another benefit is that if it was built into JavaScript it would most likely be way faster than the above alternatives.