Python excels in server-side applications, while JS dominates client-side web development. So, both are vital for development.
And that’s the problem we’re tackling today—running Python code in your JavaScript application. I guess the first question is whether you can run Python code in JS.
The answer is yes. It is possible to run Python code in a JavaScript application (ideally Nose.js) with the help of some tools and libraries available for Python and JS. However, it is impossible to compile Python code natively within JavaScript code because there is no Python compiler.
There are four methods to run your Py code in JS. Obviously, each method has its own use cases and pros and cons, but if I were developing an application, I’d try to stick to one of the first three methods.
Here’s a cheatsheet I made so you can decide which method you would prefer:
Ps…you can download the cheatsheet here.
Method | Pros | Cons | Use cases |
---|---|---|---|
Transpilers | Direct translation of Py code to JS, easy to integrate into existing JavaScript projects. | Limited by the transpiler’s ability to interpret Python code correctly; may not support all Python libraries. | Ideal for integrating small pieces of Python logic into a JavaScript app without heavy dependencies. |
Python with Node.js | Leverages Node.js’s capabilities to run Python scripts, allows powerful server-side processing. | Requires managing two different runtime environments. | Ideal for apps that require extensive server-side processing and Node.js’s event-driven architecture. |
AJAX Requests | Easy implementation, leverages existing web technologies, and keeps computation on the server, preserving client performance. | Dependent on network latency and potential security vulnerabilities with exposed APIs. | Suitable for applications where the client needs to interact with Python code running on a server. |
WebAssembly | Runs at near-native speed, securely sandboxed within the browser, and supports complex computational tasks. | Complex setup, may not support all Python libraries, learning curve for WebAssembly tools. | Recommended for applications requiring intensive computation. |
Method 1: Using a Transpiler
A transpiler, or source-to-source compiler, is a type of compiler that reads the source code written in one programming language and produces the equivalent code in another language. Pretty neat, right?
How do Transpilers work?
Transpilers work by parsing the source code into a data structure known as an Abstract Syntax Tree (AST), which represents the code’s syntactic structure in a tree format. The transpiler then transforms this AST of the source language (Python) into the AST of the target language (JavaScript), which is converted into runnable JavaScript code.
I have mostly used three transpilers in my development: Brython, Transcript and Skulpt. Let me give you a quick look at each of them.
Brython
Brython (Browser Python) implements Python 3 for client-side web programming via a JavaScript engine.
To get started with Brython, follow these steps:
1. Include Brython: You can include Brython in your HTML by linking to the Brython script hosted on a CDN. The brython() function then initialises Brython after the page is loaded.
<!DOCTYPE html> <html> <head> <script src="<https://cdn.jsdelivr.net/npm/[email protected]/brython.min.js>"></script> </head> <body onload="brython()"> <!-- Brython code will go here --> </body> </html>
2. Create a Python Script in HTML: Use the <script> tag with type=”text/python” to write Python code:
<script type="text/python"> def say_hello(): print("Hello from Python!") say_hello() </script>
3. View in Browser: When you load this HTML file in a browser, Brython will run the Python code, executing the say_hello function.
Skulpt
Skulpt is a unique open-source Python-to-JavaScript compiler that implements Python in the browser by compiling Python code into JavaScript at runtime. This approach lets us use Python’s syntax and powerful libraries directly within the web apps.
Include Skulpt in Your HTML: Skulpt can be loaded into your HTML using a script tag that points to the Skulpt files hosted on a CDN:
<!DOCTYPE html> <html> <head> <script src="<https://cdn.jsdelivr.net/npm/[email protected]/skulpt.min.js>" type="text/javascript"></script> <script src="<https://cdn.jsdelivr.net/npm/[email protected]/skulpt-stdlib.min.js>" type="text/javascript"></script> </head> <body> <textarea id="pythonCode" cols="40" rows="10">print("Hello, Python in the browser!")</textarea><br> <button onclick="runPython()">Run Python</button> <pre id="output"></pre> <script> function runPython() { Sk.configure({ output: function(text) { document.getElementById('output').textContent += text; }, read: function(x) { if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined) throw "File not found: '" + x + "'"; return Sk.builtinFiles["files"][x]; } }); var prog = document.getElementById('pythonCode').value; Sk.misceval.asyncToPromise(function() { return Sk.importMainWithBody("<stdin>", false, prog, true); }).then(function(mod) { console.log('Program execution completed successfully'); }).catch(function(err) { document.getElementById('output').textContent = err.toString(); }); } </script> </body> </html>
Note: The skulpt.min.js file is the main Skulpt engine, and skulpt-stdlib.min.js includes the standard Python library adapted for Skulpt.
JavaScript Execution Logic:
The JavaScript function runPython() sets up Skulpt’s configuration to handle output and file reads, executes the Python code from the text area. The output of the Python code is displayed in the <pre> tag under the button.
Transcrypt
Transcrypt is a Python-to-JavaScript compiler that lets you write Python code and transpile it into highly optimised JavaScript.
What does that mean, you ask? With Transcrypt, you can retain most of Python’s core syntax and advanced features like multiple inheritance and operator overloading, all within a JavaScript environment.
1. Install Transcrypt: Open your terminal or command prompt and run the following command:’
pip install transcrypt
2. Prepare Your Project Directory: Create a new directory for your project if you haven’t already, and navigate into it:
mkdir my_transcrypt_project cd my_transcrypt_project
3. Create a Python Script: In your project directory, create a new file named example.py and add the following Python code:
def greet(name): print(f"Hello, {name}!") greet("World")
4. Transpile Python to JavaScript: Run Transcrypt to convert your Python code into JavaScript:
transcrypt -b -n example.py
The -b option tells Transcrypt to run a build, and -n prevents it from adding line numbers to the output, making the JavaScript code cleaner.
5. Include the Transpiled JavaScript in an HTML File: Create an HTML file in the same directory named index.html and include the generated JavaScript file:
<!DOCTYPE html> <html> <head> <title>Transcrypt Example</title> </head> <body> <script src="__target__/example.js"></script> </body> </html>
The JavaScript file generated by Transcrypt is located in the target directory created during the transpilation process.
6. Run Your Web Page: Open index.html in a web browser to see the output. The Python function greet is executed as JavaScript, displaying “Hello, World!” in the browser’s JavaScript console.
Method 2: Using Python with Node.js
Python can be integrated with Node.js through child processes, a core feature in Node.js that allows it to run system commands within a Node.js environment.
For the purposes of this guide, I’ll assume you already have Node.js and Python installed on the system (or server).
1. Set up Node.js application: Create a new directory for your project and initialise a new Node.js application:
mkdir node_python_example cd node_python_example npm init -y # Initialises a new Node.js project with a default package.json
2. Create a Python Script: In the project directory, create a Python script named compute.py that performs a simple task, such as calculating the factorial of a number:
import sys def factorial(n): if n == 0: return 1 else: return n * factorial(n-1) if __name__ == '__main__': num = int(sys.argv[1]) # Takes number from command line argument print(factorial(num)) sys.stdout.flush()
The sys.stdout.flush() forces the Python program to flush out the output buffer, ensuring that all outputs are sent back to the Node.js process without delay.
3. Write a Node.js Script to Call Python: In the same directory, create a server.js file that will spawn the Python script as a child process:
const express = require('express'); const { spawn } = require('child_process'); const app = express(); const port = 3000;
4. Define a Function to Run Python Scripts: Implement a function runPythonScript that uses Node.js’s child_process.spawn to invoke the Python script. This function takes the script path, arguments, and a callback function to handle the output or errors.
function runPythonScript(scriptPath, args, callback) { const pythonProcess = spawn('python', [scriptPath].concat(args)); let data = ''; pythonProcess.stdout.on('data', (chunk) => { data += chunk.toString(); // Collect data from Python script }); pythonProcess.stderr.on('data', (error) => { console.error(`stderr: ${error}`); }); pythonProcess.on('close', (code) => { if (code !== 0) { console.log(`Python script exited with code ${code}`); callback(`Error: Script exited with code ${code}`, null); } else { console.log('Python script executed successfully'); callback(null, data); } }); }
5. Create a Route to Handle Requests: Set up a route in your Express application that users can access to run the Python script.
app.get('/factorial/:number', (req, res) => { const number = req.params.number; runPythonScript('compute.py', [number], (err, result) => { if (err) { res.status(500).send(err); } else { res.send(`Factorial of ${number} is ${result}`); } }); });
The route captures a number from the URL parameter, calls the Python script, and sends the result back to the client.
6. Run Your Node.js Application: Start your Node.js application by running:
node server.js
7. Access the Application: Open a web browser and navigate to http://localhost:3000/factorial/5 to see the output of the Python script calculated and displayed by the Node.js server.
Method 3: AJAX requests
AJAX (Asynchronous JavaScript and XML) is a technique for creating fast and dynamic web pages. It allows us to update web pages asynchronously by exchanging small amounts of data with the server behind the scenes.
Essentially, you can update parts of a web page without reloading the whole page by making AJAZ requests to the server and receiving data back.
How to run Python code in JavaScript using AJAX requests?
To handle AJAX requests, a server capable of processing these requests is required. We’ll use Flask – it’s a Python micro-framework suitable for small to medium-sized web applications.
Here’s the link to Flask documentation if you want to learn more.
1. Install Flask: First, ensure Python and pip are installed on your system, then install Flask using pip:
pip install Flask
2. Create a Flask App: Set up a basic Flask application that will handle requests from your JavaScript client. The following Flask application provides an endpoint /calculate that calculates the factorial of a number.
from flask import Flask, jsonify, request app = Flask(__name__) @app.route('/calculate', methods=['GET']) def calculate(): # Example function: Calculate factorial number = request.args.get('number', default=1, type=int) result = factorial(number) return jsonify({'result': result}) def factorial(n): if n == 0: return 1 else: return n * factorial(n-1) if __name__ == '__main__': app.run(debug=True, port=5000)
3. HTML Setup: Create an HTML interface for input and interaction.
<!DOCTYPE html> <html> <head><title>Compute Factorial</title></head> <body> <input id="numberInput" type="number" placeholder="Enter a number"> <button onclick="getFactorial()">Calculate</button> <p id="result"></p> <script src="script.js"></script> </body> </html>
4. JavaScript for AJAX Request: Write JavaScript to handle the user input and send an AJAX request to the Flask API.
function getFactorial() { var number = document.getElementById('numberInput').value; fetch(`http://localhost:5000/calculate?number=${number}`) .then(response => response.json()) .then(data => { document.getElementById('result').innerHTML = `Factorial: ${data.result}`; }) .catch(error => console.error('Error:', error)); }
This JavaScript code uses the fetch API to send a GET request to the Flask server, retrieves the factorial calculation, and displays it on the page.
Method 4: Utilising WebAssembly
WebAssembly (often abbreviated as Wasm) is a binary instruction format for a stack-based virtual machine. Wasm enables code to run in the web browser at near-native speed, making it an excellent choice for high-performance applications running complex algorithms in a client browser.
How to compile Python Code to WebAssembly and run it in a browser?
To compile Python code to WebAssembly, we typically use a toolchain like Emscripten, which can compile Python to WebAssembly. Let’s get started:
1. Install Emscripten: Cloning the Emscripten repository using git and follow the installation instructions on their official site.
git clone <https://github.com/emscripten-core/emsdk.git> cd emsdk ./emsdk install latest ./emsdk activate latest source ./emsdk_env.sh
2. Prepare Your Python Code: Ensure your code is compatible with the limitations of the Python interpreter you plan to use in WebAssembly. I’ll use a simple Python script that calculates factorials for this example.
def factorial(n): if n == 0: return 1 else: return n * factorial(n-1) print(factorial(5))
3. Compile Python Code to WebAssembly: Next, convert this Python script into a form that can be compiled into WebAssembly. To do so, we’ll convert Python into a lower-level language like C or C++ that can be compiled in Emscripten. I’ll be using a tool called Cython for that.
cython --embed -o factorial.c factorial.py emcc factorial.c -o factorial.html -s WASM=1
4. Run in a Web Browser: The emcc command will generate several files, including ‘factorial.wasm,‘ ‘factorial.js,‘ and ‘factorial.html.‘ You can open factorial.html in your web browser to see the result of the Python code executed via WebAssembly.
5. HTML Setup: Create an HTML file with an input field and a button to trigger the calculation.
<!DOCTYPE html> <html> <head><title>Factorial Calculator</title></head> <body> <input id="number" type="number" placeholder="Enter a number..."> <button onclick="calculateFactorial()">Calculate Factorial</button> <div id="result"></div> <script src="factorial.js"></script> </body> </html>
6. JavaScript Integration: Modify the factorial.js generated by Emscripten to handle the button click and display results.
function calculateFactorial() { var num = document.getElementById('number').value; var result = Module.ccall('factorial', 'number', ['number'], [num]); document.getElementById('result').innerHTML = 'Factorial: ' + result; }
Using Pyodide with WebAssembly
Pyodide is an open-source project that brings the extensive Python scientific stack to the web. It lets you run Python code in a browser’s JavaScript environment using WebAssembly.
It comes with over 75 packages from the Python scientific and data analysis ecosystem, all precompiled to WebAssembly. Pyodide’s beauty lies in its seamless integration with web applications, enabling the direct use of libraries like NumPy, Pandas, Matplotlib, and more in the browser.
The setup is the same as how we just did with WebAssembly. Here’s the Pyodide documentation if you wish to try.
Should you run Python code in JavaScript? – Limitations
Now that’s the REAL question. Given how versatile coding is, you and I both knew there were going to be several ways to successfully compile a Python code within JavaScript.
However, is that something you should be doing in the first place? From what I can see there are four major limitations to this approach.
Performance Overhead: While tools like WebAssembly and Pyodide aim to run Python code at near-native speed, they still can’t match the performance of JavaScript running natively in browsers. This is particularly noticeable in highly interactive or real-time applications.
Complexity in Maintenance: Integrating Python code into JavaScript projects adds an additional layer of complexity. Novice developers might not be able to handle that maintenance. And advanced developers might not wanna take unnecessary load.
Compatibility and Dependency Issues: Some Python libraries may not be fully compatible or available in the JavaScript environment, severely limiting the functionality.
Security Concerns: Running server-side Python code exposed via APIs can lead to security vulnerabilities if not properly managed, such as exposure to injection attacks or unauthorised access.