Did you know that you can write JSX in python code?
Yes, I am not kidding! It is actually possible today!
You may have found jinja templates ugly and absolutely nightmare for templating in django or flask. If that's so, you are really going to enjoy this quick tutorial.
In this article, I am going to show you an interesting approach to component driven frontend development in python using a new library which is called pyjsx
.
So, let's get started!
Set up the Virtual Environment
First things first. Let's quickly set up a venv
to install the required library.
python3 -m venv .venv
and activate it -
In Linux/MacOS -
source .venv/bin/activate # for POSIX Shells
In Windows -
./.venv/Scripts/activate.bat REM for windows cmd
./.venv/Scripts/activate.ps1 # for powershell
Install the Library
.venv/bin/pip3 install python-jsx # (for POSIX Shells)
.\.venv\Scripts\pip3.exe install python-jsx # (for windows)
If you use mypy then set up the ini file (mypy.ini
) for accurate type checking.
[mypy]
plugins = pyjsx.mypy
Now we are ready to dive in.
Note: I am not going to install flask or quart or hypercorn or any other dedicated backend framework or http server library, for this simple pyjsx demonstration.
We will use the
http.server
module from the standard library of python for setting up the web server.
Let's Write some Python JSX (PYJSX)
Just exactly how you write functional components and pass props to them in React you do it the same way in pyjsx.
for example, you would write a header component this way -
# coding: jsx
from pyjsx import jsx, JSX
def Header(style, children) -> JSX:
return <h1 style={style}>{children}</h1>
The most important things here to know and be careful about are -
- The comment
# coding: jsx
is REQUIRED. It is not a plain regular comment but a directive that tells Python to let our library parse the file first. - The components can't be defined in a regular python file. You are only allowed to import the components in a python file, from the parsed files that contain the component definition(s). This component filename must end with
.px
file extension. - The import
from pyjsx import jsx
is vital becausePyJSX
transpiles JSX intojsx(...)
calls so it must be in scope.
Let's define some components
Make sure you put the file extension as .px
NOT .py
.
The <Header/>
component -
# coding: jsx
from pyjsx import jsx, JSX
def Header(style, children) -> JSX:
return <h1 style={style}>{children}</h1>
The <Main/>
component -
# coding: jsx
from pyjsx import jsx, JSX
def Main(children) -> JSX:
return <main>{children}</main>
And here is the <App/>
component.
# coding: jsx
from pyjsx import jsx, JSX
from main import Main
from header import Header
def App() -> JSX:
return (
<div>
<Header style={{"color": "darkgreen"}}>Hello from PYJSX!</Header>
<Main>
<p style={{"color": "crimson"}}>This was rendered with PyJSX!</p>
</Main>
</div>
)
Now, Here comes the part of server. We will set up a pretty simple http server to serve the <App/>
component on GET
request.
Hey, hey, hey, before writing a runnable file, remember this -
❗❗ To run a file containing
JSX
, thejsx
codec must be registered first in the runtime, which can only be done withfrom pyjsx import auto_setup
.
⚠️ This must occur before importingpx
files or any other file containing JSX.
Setting Up the server
Import modules -
from http.server import BaseHTTPRequestHandler, HTTPServer
from pyjsx import auto_setup # MUST import this before importing JSX
from app import App
Define constants -
HOST = '127.0.0.1'
PORT = 8080
Define the HTTP request handler class to setup server
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
# Send response headers
self.send_header('Content-type', 'text/html')
self.end_headers()
# using fstring to convert the JSX into string
response = f"{App()}"
# convert the string data into bytes before sending over network
self.wfile.write(response.encode())
def log_message(self, format, *args):
return # Suppress default logging for clean output
def run_server():
server = HTTPServer((HOST, PORT), MyHandler)
print(f"Serving HTTP on {HOST}:{PORT} ...")
try:
server.serve_forever()
except KeyboardInterrupt:
print("\nShutting down the server.")
server.server_close()
Now let's run the server to see it in action (I mean browser).
Look, our server works perfectly fine, and the pyjsx code is beautifully rendered in the DOM!
Wrapping it up
You must be delighted to know that pyjsx also supports fragment components <></>
and nested expressions like -
<div>
{[<p>Row: {i}</p> for i in range(10)]}
</div>
already.
So, we see that pyjsx has a lot of potential.
It is a new library, and I think it is not ready for production yet. But it is completely open source with Apache Licence, so with valuable community contributions we can make development of this library progress rapidly and see it as a huge leap forward towards declarative web ui development in python.
What do you think, want to give it a go?
Check it out in GitHub and explore more examples to build something awesome with it!
PyJSX - Write JSX directly in Python
from pyjsx import jsx, JSX
def Header(style, children) -> JSX:
return <h1 style={style}>{children}</h1>
def Main(children) -> JSX:
return <main>{children}</main>
def App() -> JSX:
return (
<div>
<Header style={{"color": "red"}}>Hello, world!</Header>
<Main>
<p>This was rendered with PyJSX!</p>
</Main>
</div>
)
Installation
Get it via pip:
pip install python-jsx
Minimal example (using the coding
directive)
Tip
There are more examples available in the examples folder.
There are two supported ways to seamlessly integrate JSX into your codebase One…
Conclusion
I would really appreciate your feedback on this tutorial. How would you rate it? How can I improve it?
If you found this project or tutorial helpful, please consider sharing some love to the article. It will encourage me to create more content like this.
If you found this POST helpful, if this blog added some value to your time and energy, please support by sharing it with your developer friends.
Follow me for more quality tech content. 👇🏽👇🏽👇🏽
Feel free to connect with me at - Twitter, LinkedIn or GitHub :)
Happy Coding 🧑🏽💻👩🏽💻! Have a nice day ahead! 🚀
Top comments (19)
Insightful
Thanks for letting me know. Now build something cool with it
Cool thanks for sharing
You're welcome 🤗. Glad you found it useful 😁.
Insightful
Now build something cool with it
That’s seriously cool ..
Yupp! It is a game changer!
Wow its so cool
But is it better than Jinja2 ?
That can be setup easily with fastapi or flask
Well actually Jinja really serves its purpose greatly. That being said, it is a templating engine for python.
Jinja is generally static, (HTML rendered before delivery). While JSX is dynamic and is loved by devs mostly for its component-based reusability, nesting and the ability of easily passing props for dynamic behavior.
The best way is to use the best of both worlds.
As in the end, we are converting PyJSX into strings currently for rendering as html, we will be able to use them directly in flask routes. What we can do is break our whole UI into reusable components and then serve them as html when sending via response in flask routes.
A Quick Example for you if my explanation above was messy (sorry 🥲😅😅🥲) -
PyJSX with Flask
With PyJSX, you define your components in Python files (often with a .px extension, though not strictly required for simple cases if transpiled correctly). The output of a PyJSX component is of JSX type which can be formatted in fstrings, which Flask can directly return.
First, define a PyJSX component. You would typically save this in a file, for example,
component.px
-Then, in your Flask application (
app.py
), you would import and use these components:See it works perfectly fine -
such a great blog. keep it up
Glad you found it interesting!
Interesting..
Thanks now try it out and let me how it goes
Why, do you hate python?
No, I am even fine with people breaking established industry standards, I get it, it is fun. I just don't like it when people take the joke too seriously and actually start using these in production. Look what happened to React. They invent a new "solution" to the mess they helped create every year, and each solution requires two new inventions.
If you hold your ear from the other side so often that your arms get entangled, you should just let go.
Wow. insightful!
And the HeadWind HTML is super awesome man!! Lol!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.