Martim Nascimento
3 min readSep 23, 2017

For some time I was an observer of initiatives in using python in the browser. A long time ago I was a follower of Pyjamas/PyJS project, including watching in real time the leadership war between some of its contributors. Now we have a plethora of projects trying to make this a reality (1, 2, 3, 4, etc) but the workflow, development usability and integration with modern javascript is far from acceptable.

With the new wave of language transpilers for javascript that dream turned to be possible and almost inevitable. Without knowing the scope of each project I always had the impression that BabelJS would be the best place to make that process. But after investigating a little more and have used in some projects I realized that WebPack would be the right way to do that.

Last week I decided to experiment with this idea. I knew that PyJS (old Pyjamas) would not be the best option for the transpilation. After the leadership war the project almost died. Skulpt could be a strong choice if it wasn’t restricted to Python 2. The Transcrypt project seemed to be appropriated since supports Python 3 and the option for fast code generation (at least is what his slogan says) is a must, so I choose it.

(Edited: RapydScript and Brython could also be a good choice. I will try those in the future)

The next step would be implement the webpack loader. For that I have used the webpack documentation as reference (obvious) but also those loaders as example:

To implement a webpack loader we need to implement and export a javascript function that receives the original source code (python) and returns the javascript transpiled code as a string. The loader when installed in the webpack.config.js file will join the webpack transformation chain.

Async

Since we’ll use the node filesystem api to read and write the file we need to use the async webpack loaders api. For that we need just to call the this.async webpack method. This method returns a callback that we need to call when our processing was finished.

The canonical result is listed here (you can see the complete result in the repository)

const cmd = require('node-cmd')
const fs = require('fs');
const path = require('path');
module.exports = function (source) { var callback = this.async(); var entry = this._module.resource; var name = path.basename(entry, ".py"); cmd.get('transcrypt -b -n ' + entry,
function(err, data, stderr) {
if (!err) {
js = fs.readFileSync(
"./__javascript__/" + name + ".js", "utf8")
callback(null, js);
}
else {
console.log("Error: " + err);
}
});
}

Let’s use it!

if someone have interest in helping I published the source code in github and uploaded to npm (py-loader). In the repository there are an example but if you want a quickstart just follow the steps below:

  1. Install transcrypt (you will need pip)
pip install transcrypt

2. Install the package

npm install --save-dev py-loader

3. Add the loader inside your webpack.config.js

function cwd (path) {
return require('path').resolve(__dirname, path)
}
module.exports = {
entry: cwd('main.js'),
output: {
path: cwd('dist'),
filename: 'app.js'
},
module: {
rules: [
{
test: /\.py$/,
loader: 'py-loader'
}
]
}
}

4. Create a python file named hello.py

def hello_world():
print("Hello from python")
print("document {}".format(document))

5. Create a javascript file (main.js) that imports the python file

import Hello from './hello.py'

6. Include the generated file in a html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body onload="hello.hello_world()">
<div id="app"></div>
<script src="app.js"></script>
</body>
</html>

7. Execute the webpack build process

webpack --progress --profile --colors

Open the html in the browser. Voilá! You should see the “Hello from python” message in the browser console.

It also works with webpack-dev-server so you can have the same live-reload experience you have with javascript!

webpack-dev-server --progress --colors --port 8080 --content-base .

The future

There are still many things to do for making our dream to program Python in the browser (seamless) come true. Below I list some:

  1. Verify the possibility in Transcrypt to use an in-memory transpilation instead of saving to a temporary file. This could improve the speed of the process.
  2. Verify the viability in using another javascript libraries (like axios) inside python code.
  3. Experiment with other python/javascript transpilers (RapydScript and brython are in the queue).
Martim Nascimento

Hi, I’m a maker living in Brasil. Interested in programming, music and arts. Feel free to contact me at martim00.wordpress.com