Using Parcel v2 and Transcrypt to create web applications with Python
Tags: python, react, webdev, parcel
Published: 2022-03-07 19:26:27

When the [*React to Python*](https://pyreact.com) book was published, Parcel version 2 was just about to go into Beta.  Because of that, it was still a bit too volatile to include in the book.  But now that it is officially released, I thought I'd give those of you using Parcel as part of the toolchain I outlined in the book, a guide to using the newer version of Parcel.

There are definitely some new features available in the latest version of Parcel that makes switching to it worthwhile.  To start with, the Parcel development server now supports server proxies, so you don't have to use an external proxy server to serve up your back-end REST services during the development process.  On top of that, the tree shaking algorithm is much more efficient at eliminating unused code from the generated JavaScript bundle, making the deployment bundle smaller.  Oh, and the builds are faster too!  Running a production build on the project in Part III of the _React to Python_ book resulted in a JavaScript bundle that was 30% smaller, and it took 15% less time to build.

The general steps to modify an application to move from using the original version of Parcel to Parcel v2 are covered in the [Parcel v2 documentation](https://parceljs.org/getting-started/migration/).  Here, we'll go through the migration requirements in a little more detail from the perspective of a Python web application that utilizes the [Transcrypt](https://www.transcrypt.org) Python-to-JavaScript transpiler.

## Installation
The name of the NPM library for [Parcel v2](https://www.npmjs.com/package/parcel) has changed from `parcel-bundler` to `parcel`.  So to install the Parcel v2 JavaScript library, use the following to install it as a development dependency:  
$ `npm install parcel --save-dev`  

A new recently released [Parcel plugin for Transcrypt](https://www.npmjs.com/package/parcel-transformer-transcrypt) that works with Parcel v2 can be installed with:  
$ `npm install parcel-transformer-transcrypt --save-dev`
  
## Configuration
For Parcel to know about the Transcrypt plugin, we need to add a _.parcelrc_ file in the same folder that the _package.json_ file resides in:  

Listing 1: [*.parcelrc*](https://github.com/JennaSys/rtp_demo/blob/parcel-v2/.parcelrc)
```json
{
  "extends": ["@parcel/config-default"],
  "transformers": {
    "*.py": ["parcel-transformer-transcrypt"]
  }
}
```
This file tells Parcel that anytime it has a file with a `.py` extension, that it should pass the file on to the Transcrypt plugin for processing.

The Parcel CLI parameters have changed slightly compared to the previous version.  So upgrading an existing project to Parcel v2 may require you to update your NPM scripts in the _package.json_ file.

Most notably, the `--log-level` parameter now uses keywords instead of numbers, and the keyword for the output folder has changed from `--out-dir` to `--dist-dir`.   New scripts may look something more like this:
```json
  "scripts": {
    "start": "NODE_ENV=development parcel --log-level info src/index.html --dist-dir dist/dev --port 8080",
    "build": "NODE_ENV=production parcel build --log-level info src/index.html --no-source-maps --dist-dir dist/prod --no-cache"
  }
```

If you are using the Node.js `require()` function in your source code to load static resources like images, you may also need to let Parcel know where to find those resource files at bundling time. If the path to the transpiled JavaScript files are no longer located relative to the source file folder after building, add an `"alias"` entry to _package.json_:
```json
  "alias": {
    "./static/**": "./src/static/$1"
  }
  ```
This entry will tell Parcel that for any files that are supposed to be in a `static/` folder in the current directory, to look for them in the `src/static/` folder instead (relative to the root project folder).


## Plugin Options
The new Parcel plugin for Transcrypt works pretty much just like the one for the original version of Parcel, with a few additions.  The key new features include:
- A configurable output folder (when using Transcrypt 3.9)
- The Parcel file watch works on  _all_  transpiled Python files in development mode and not just the entry point
- It checks to make sure that the Python version matches the version of Transcrypt being used
- It doesn’t need patching before using it :-)

Like the previous version, it has a default configuration that can be overridden with an entry in the _package.json_ file for a project:
```json
  "parcel-transformer-transcrypt": {
    "transcryptVersion": "3.9",
    "watchAllFiles": true,
    "command": "python -m transcrypt",
    "arguments": [
      "--nomin",
      "--map",
      "--verbose"
    ]
  }
```
The above configuration shows the default values that the Parcel Transcrypt plugin uses.  The `"transcryptVersion"`, `"watchAllFiles"`, `"command"`, and `"arguments"` keys are all optional.  Default values are used for any keys that are not supplied.

If the `watchAllFiles` key is missing or set to `true`, all Python files that Transcrypt processes will be added to Parcel’s file watch.  If this key is set to `false`, only the initial entry point file will be watched. 

Transcrypt normally puts the files it generates in a folder called `__target__`, which is created in the same folder as the source files you are processing.  This behavior may not be desirable if you prefer to keep your source code tree free of generated files.  

By default, if you are using Transcrypt 3.9, the Parcel transformer will instead put Transcrypt's generated files in a folder named `.build` that is created in the project's root folder (where the _package.json_ file resides and where you run `npm` commands from).   You can override the location of this build folder by adding an argument to the above configuration as shown here:
```json
    "arguments": [
      "--nomin",
      "--map",
      "--verbose",
      "--outdir src/__target__"  
    ]
```
The output folder you specify in the arguments should be relative to the project's root folder.  

_Note that the `--outdir` directive is not valid for Transcrypt version 3.7 and is ignored in that case._

Building a [Python React demo application](https://github.com/JennaSys/rtp_demo/tree/parcel-v2) with Parcel v2 and the new Python plugin yields the following console output:
![Screenshot of parcel-transformer-transcrypt processing files](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/indmpoidaqsbgy3yik2n.png)



## Proxy Server
One of the new features of Parcel v2 is the ability of its development server to act as a proxy for back-end data services like a REST API.  So now, instead of having to roll your own proxy server with `Express.js` and the `http-proxy-middleware` packages, you can configure Parcel to provide the same capability with no additional plugins required.

To do so does require creating a simple _.proxyrc_ JSON configuration file:

Listing 2: *.proxyrc*
```json
{
  "/api": {
    "target": "http://localhost:8000/",
    "pathRewrite": {
      "^/api": ""
    }
  }
}
```
This configuration would forward any requests having a URL starting with `/api` to a backend server listening on port 8000, stripping off the `/api` prefix in the process. For example, a request to `http://localhost:1234/api/getusers` would be proxied to `http://localhost:8000/getusers`


## Additional Details
The new version of Parcel does not automatically treat `<script>` tags as modules, so you must now explicitly specify them as such in order for imports to work correctly in a web browser. You can accomplish this by including a `type="module"` attribute in the `<script>` tag that loads the application entry point in the _index.html_ file as shown below:   

Listing 3: [*index.html*](https://github.com/JennaSys/rtp_demo/blob/parcel-v2/.parcelrc)
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <script type="module" src="app.py"></script>
        <title>React to Python</title>
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>
```

Most of the changes that need to be made when upgrading from Parcel v1 to Parcel v2 happen in the _package.json_ file.  In addition to what was mentioned above, you may have a line like this in your _package.json_ file that was added by default when you ran `npm init`:  
`“main”: “index.js”`  
While that key was previously ignored in the older version of Parcel, the new version of Parcel will try and treat your web application as a library if it finds it there.  To keep Parcel v2 from complaining, that line will need to be removed.


## tl;dr
In summary, here are the basic changes needed when moving from Parcel v1 to Parcel v2 for Python web applications:
- Add  `type="module"`  to entry point script tag in  _index.html_
- Add  _.parcelrc_  file to let Parcel know how to process `.py` files
- Update  _package.json_:
  - Remove key entry for `"main": "index.js"` if it exists
  - Update NPM scripts with new Parcel CLI parameters
  - Add `"alias"` key for relative static imports if necessary
  - Update `"devDependencies"`:
      - _Change_ `parcel-bundler` to `parcel`
      - _Change_ `parcel-plugin-transcrypt` to  `parcel-transformer-transcrypt`
      - _Change_ `parcel-plugin-bundle-visualiser` to  `@parcel/reporter-bundle-analyzer`
      - _Remove_  `express`
      - _Remove_  `http-proxy-middleware`
- If using a proxy server:
  - Add a _.proxyrc_ file with the backend server configuration
  - Delete  _dev-server.js_  and use  `npm start`  instead of  `npm run dev` for development


## Conclusion
One of the admittedly annoying pain points of using the toolchain I outlined in the _React to Python_ book, was the fact that the Transcrypt plugin for Parcel was broken.  And because the plugin was not being actively maintained, it had to be patched after installing it. With Parcel v2 and the new Transcrypt plugin developed for it, this is no longer the case. Developing web applications with Python is now even more seamless and productive than it was before.


## Resources
- Source Code:
    https://github.com/JennaSys/rtp_demo/tree/parcel-v2  

- Parcel Website:
    https://parceljs.org/  
    
- Parcel v2 Migration Documentation:
    https://parceljs.org/getting-started/migration/    
    
- Parcel Plugin for Transcrypt:
    https://www.npmjs.com/package/parcel-transformer-transcrypt  
  
- Creating React Applications with Python tutorial:
    https://leanpub.com/rtptutorial  
  
- React to Python Book:
    https://pyreact.com  

- Transcrypt Site:
    https://www.transcrypt.org