npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

transcrypt-loader

v1.0.2

Published

Code in Python 3. Bundle to Javascript.

Downloads

17

Readme

Code in Python 3. Bundle to Javascript.

Adds a Py3 -> Javascript transpiler to your Wepack build tool chain.

Web scripts are no longer simple Javascript files linked with <script src=...>. Using bundlers like Webpack and Parcel, today's web projects sport languages like TypeScript, CoffeeScript, SCSS, Less, and ES6 Javascript--often mixed together in a single project.

Bundling is the art of collecting all this diversity into bundles that browsers can understand and run efficiently. And while the bundler runs the overall process, it needs plugins (like this one) to transpile everything into plain 'ole Javascript, CSS, and HTML.

This package is exactly that glue: it runs Transcrypt (the .py -> .js transpiler) whenever Wepack finds a .py file, effectively turning Python into Javascript automagically.

Why?

  • Why Python? If you haven't cried "abomination!" yet, it's probably safe to assume that you and I share a love for a certain Monty-Python-inspired language. Perhaps you even share my dislike for that other language we're forced to use. :)
  • Why Transcrypt? It's is the best implementation I've seen to date to get Python into the browser. Of the many approaches taken over the years, transpiling to Javascript seems to be the "right" way. Plus, you get to say cool words like "transpiling". (I'm not the author of transcrypt, if you are wondering.)
  • Why Bundle? Bundling represents today's best practices approach for Javascript development. Bundlers are the backbone of the toolchain, and they create efficient, minified websites that run on any browser.
  • Why Webpack? It's the standard right now.
  • Why transcrypt-loader? To glue it all together. Just don't inhale too much.

Installation

  1. Install Transcrypt. Instructions are at the website. I'd suggest trying out a few examples so you get used to transcrypt before moving on to bundling. Ensure you can create python, compile it, and run within a browser.
  2. Install npm and Wepack. Instructions are at the websites.
  3. Create an empty folder, and initialize npm: npm init. (all commands are done in a console within your project directory)
  4. Install Webpack: npm install webpack webpack-cli --save-dev
  5. Ensure Webpack runs within your project folder: npx webpack --help
  6. Install this plugin: npm install transcrypt-loader --save-dev
  7. Ensure Transcrypt runs within your project folder: python3 -m transcrypt

Tutorial

If you haven't done it yet, install everything (above).

Open a console and change to your project directory (the one with package.json in it). All of the following commands and files are done in that root project folder.

Configuration

Ensure package.json contains the following (your package versions will likely be different):

"devDependencies": {
    "webpack": "^4.28.3",
    "webpack-cli": "^3.1.2",
    "transcrypt-loader": "^1.0.1",
}

Create the Webpack configuration file in your project directory:

webpack.config.json

module.exports = {
    devtool: 'inline-source-map',
    entry: "./main.py",
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.py$/,
                loader: 'transcrypt-loader',
                options: {}
            }
        ]
    }
};
The options (empty in this example) allow you to change the transcrypt command and arguments.

Source Files

Create the following two files:

index.html

<meta charset="utf-8"/>
<html>
<body>
    <h1>My First App</h1>
    <div id="app"></div>
    <script src="dist/main.js"></script>
</body>
</html>

main.py

# get the "app" div and add an ordered list
app = document.getElementById("app")
ol = app.appendChild(document.createElement('ol'))

# add a few names to the list
for name in [ 'Homer', 'Marge', 'Bart', 'Lisa', 'Maggie' ]:
    li = ol.appendChild(document.createElement('li'))
    li.textContent = f'{name} Simpson'

Your linter might be complaining here because transcrypt python isn't quite regular python. In the above code, we can use document because our py -> js runs in the browser (even if the python linter is upset by it). ```

Bundle 'n Serve

Run the bundler:

npx webpack --watch

Webpack bundles everything into the dist/ folder, and then it starts a server daemon. Webpack continues to watch your project for changes, so watch the log messages as you edit and save.

Open your browser, select File | Open, and open index.html.

Boom, baby! Python-style lists, f-strings, and for loops, right in the browser!

If things don't seem to work when you open the web page, be sure to check the browser console for messages.

You can see the JS generated by Transcrypt in the __target__ folder. Webpack uses these files when bundling. These files can also be incredibly useful when transpiling doesn't happen as expected. The generated JS is pretty readable, and a few console.log statements right in the generated stuff is often the ticket.

Getting Fancy

Let's continue the example with a few callbacks:

index.html

<meta charset="utf-8"/>
<html>
<body>
    <h1>My Second App</h1>
    <div>
        <button id="addButton">Add Item</button>
        <button id="removeButton">Remove Item</button>
    </div>
    <div id="app"></div>
    <script src="dist/main.js"></script>
</body>
</html>

main.py

def ready():
    app = document.querySelector("#app")
    ol = app.appendChild(document.createElement('ol'))
    counter = 1

    def addButtonClicked():
        nonlocal counter
        li = ol.appendChild(document.createElement('li'))
        li.textContent = ', '.join([ 'Item {}'.format(i) for i in range(counter, counter+10) ])
        counter += 10
    document.querySelector('#addButton').addEventListener('click', addButtonClicked)

    def removeButtonClicked():
        if ol.lastChild:
            ol.removeChild(ol.lastChild)
    document.querySelector('#removeButton').addEventListener('click', removeButtonClicked)

document.addEventListener("DOMContentLoaded", ready)
  • Event callbacks: ready runs when the page is ready, and the buttons have click events. If you're used to Javascript's nested functions, it can be off-putting to see how callbacks have to be done here. Python just doesn't support anonymous functions, and lambdas are too limited. You'll get used to it, and perhaps you'll even grow to like it. But I do wish Python supported ruby-style, inline functions.
  • nonlocal: Don't hate on me here. It's just an example to highlight differences between Py and JS. The nonlocal statement is not actually needed. While omitting it would break in regular Python, the JS closure it becomes makes it work with or without nonlocal. Just like a good Thanksgiving meal, it all ends up together in the end (as JS in the browser, in this case).
  • List comprehension: Love those things. Waaay better than mapping with embedded functions. SETL ftw! (with comprehensions, anyway)

Imports

Let's add some imports! We'll do both a Python import and a pure JS import. You'll need four files - careful with the extensions!

index.html

<meta charset="utf-8"/>
<html>
<body>
    <h1>My Third App</h1>
    <div>
        <button id="addButton">Add Item</button>
        <button id="removeButton">Remove Item</button>
    </div>
    <div id="app"></div>
    <script src="dist/main.js"></script>
</body>
</html>

main.py

from .counter import Counter
from .remove import removeButtonClicked

def ready():
    app = document.querySelector("#app")
    ol = app.appendChild(document.createElement('ol'))
    counter = Counter()

    def addButtonClicked():
        li = ol.appendChild(document.createElement('li'))
        li.textContent = counter.getNext()
    document.querySelector('#addButton').addEventListener('click', addButtonClicked)

    # removeButtonClicked function is imported at top
    document.querySelector('#removeButton').addEventListener('click', removeButtonClicked)

document.addEventListener("DOMContentLoaded", ready)

counter.py

class Counter(object):
    def __init__(self):
        self.counter = 1

    def getNext(self):
        items = [ 'Item {}'.format(i) for i in range(self.counter, self.counter + 10) ]
        self.counter += 10
        return ', '.join(items)

remove.js

export function removeButtonClicked() {
    let ol = document.querySelector("#app > ol")
    ol.removeChild(ol.lastChild)
}
  • Mixing of Python and Javascript Files: The main python file is able to import other python files AND JS files! It works the other way too.
  • Python Class: The counter variable has become a proper Python class. It's all grown up! Perhaps someday, it could even become a real iterator.
  • ES6 Javascript: The JS file is using ES6 syntax. Webpack will make it backwards-compatible during bundling (thanks Babel!).

Deploy

When you're ready to deploy production code, change the mode in webpack.config.js to "production". Then run:

npx webpack

Webpack will produce minified, efficient, production-ready bundles. Deploy everything in the dist/ folder.

Code in Python, Bundle to Javascript, Deploy, ??, $$$!