Using ParcelJS Bundler for Building ReactJS Application

There are some choices if you need a web application bundler. One of them is ParcelJS, which is relatively new. Described as blazing fast, zero configuration web application bundler, Parcel can be an alternative if you want to build application quickly.

If you use Webpack, you need to create configuration first before running the build process. It gives you flexibility to define loaders, plugins, etc. However, if you don't like to setup configuration, using Parcel is more appropriate because it uses zero configuration. In addition, the build process is usually much faster.

Features

Below are some features of ParcelJS:

    • Super-fast bundle times: Parcel uses multiple worker processes and supports multi-core compilation. With the helpf of filesystem cache, the rebuild process is really fast
    • Bundle all your assets: It has built-in support for JS, CSS, HTML, file assets, and more .
    • Automatic transforms: Using Babel, PostCSS, and PostHTML, the code will be automaticaly transformed, including minified.
    • Zero config code splitting: With dynamic import() syntax, output bundles are splited, so that it will only load what's need on initial load.
    • Hot module replacement: While you're developing and making changes to the code, it automatically performs rebuild and updates the modules on the browser.
    • Error logging: When an error occurs, it will print the highlighted code that causes the error - that's really useful to find a mistake.

Dependencies

Below are the dependencies required for this project. Add them to package.json and run npm install.

  "dependencies": {
      "express": "~4.16.3"
    },
    "devDependencies": {
      "babel-preset-env": "~7.0.0-beta.3",
      "babel-preset-react": "~6.24.1",
      "node-sass": "~4.9.3",
      "parcel-bundler": "~1.9.7",
      "react": "~16.4.2",
      "react-dom": "~16.4.2"
    },

Developing Application

Parcel requires an entry point where it starts to build, usually an HTML or a JS file. In this tutorial, we're going to use an HTML file as the entry point.

src/index.html

  <!DOCTYPE html>
  <html>
  <head>
    <title>React starter app 4</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">
  </head>
  <body>
  <header>
    <nav class="navbar" role="navigation" aria-label="main navigation">
      <div class="navbar-brand">
        <a class="navbar-item" href="https://www.woolha.com">
          Woolha.com
        </a>
      </div>
    </nav>
  </header>
  <div id="app"></div>
  <script src="./index.js"></script>
  </body>
  </html>

The HTML file above loads a JavaScript file <script src="./index.js"></script>. Parcel knows it and it will build the JavaScript file as well. Here's the JavaSript file.

src/index.js

  import React from "react";
  import ReactDOM from "react-dom";
  
  import './scss/app.scss';
  import MainComponent from './components/Main'
  
  const App = document.getElementById("app");
  
  ReactDOM.render(, App);

Just like other application bundler, it will go through each dependencies and include them in the output. The JavaScript file renders a ReactJS component MainComponent and also imports a scss file for CSS styling.

src/scss/app.scss

  body {
    background-color: #efefef;
    text-align: center;
    height: 100vh;

    .navbar {
      background: #009696;
      color: #ffffff;
      height: 30px;

      a {
        color: #ffffff;
      }
    }

    #app {
      margin-top: 50px;
      font-size: 20px;

      input {
        -webkit-appearance: none;
        height: 30px;
        background-color:#FFF;
        color:#666;
        font-weight:bold;
        border: solid #666 1px;
        font-size: 14px;
        padding: 10px;
        margin: 20px;
      }
    }
  }

In this tutorial, we're going to create a very simple React application which renders a text input field and prints the value on the input field (entered by user) as a text.

src/components/Main.jsx

  import React, { Component } from 'react';
  import ParcelLogo from '../img/parcel-logo.png';
  
  class MainComponent extends Component {
    constructor() {
      super();
  
      this.state = {
        text: '',
      };
  
      this.submit = this.submit.bind(this);
  
      if (module.hot) {
        module.hot.dispose(function () {
          // Module is about to be replaced
          console.log('Replacing ...');
        });
  
        module.hot.accept(function () {
          // Module or one of dependencies was just updated
          console.log('Successfully updated');
          this.setState({ text: '' })
        });
      }
    }
  
    submit(e) {
      this.setState({ text: e.target.value });
    }
  
    render() {
      return (
        <div>
          <img src={ParcelLogo} />
          <div className="form-group">
            <input
              className="form-control"
              height="100px"
              id="name"
              name="name"
              onChange={this.submit}
              value={this.state.text}
            />
          </div>
          <h1>Hello6 {this.state.text}</h1>
        </div>
      );
    }
  }
  
  export default MainComponent;

 

As examplifed above, it's possible to import not only code, but also static files such as images.

import ParcelLogo from '../img/parcel-logo.png';

The file must be exist of course, otherwise the build will be failed.

As mentioned above, one of the ParcelJS features is hot module replaement and it's enabled by default. So, if you change the code, you can also add what should your app do when module is about to be replaced, and when module or one of dependencies was just updated. Inside the constructor, add the following:

src/components/Main.jsx

  if (module.hot) {
  module.hot.dispose(function () {
    // Module is about to be replaced
    console.log('Replacing ...');
  });

  module.hot.accept(function () {
    // Module or one of dependencies was just updated
      console.log('Successfully updated');
      this.setState({ text: '' });
    });
  }

The code above will make the text state set to empty string every time the module updated. Hot swapping only works if safe write is disabled. Some IDEs enable safe write by default.

Now, let's use Parcel to bundle our application. As we use src/index.html as the entry point, run parcel build src/index.html. Wait a couple of seconds and it will start a server at port 1234. Open http://localhost:1234 on a web browser, you should be able to see the application running. Using view source or inspect element feature, you'll see that the CSS file is automatically injected to the HTML.

ReactJs ParcelJs Screenshot

If you want to make sure hot replacement is working, just modify the code and Parcel would build it automatically and also refresh the application running on the browser.

To make it easy the next time you need to run it, add the following to your package.json.

package.json

  "scripts": {
      "build-run": "parcel src/index.html"
    }

Now you can use npm run build-run to run Parcel to build your code and running a server for debugging.

Build Only

Running Parcel with the above command is useful for debugging while developing application. However, if you only need to only build the code without running it on a port, you have to use a slightly different command by adding build before the entry point.

Let's assume we render the HTML file from back-end using any template engine, which is the most likely case in production. But, to make it simple, in this tutorial, we only serve a static HTML file from the back-end using ExpressJS' sendFile.

app.js

  const express = require('express');
  
  const fs = require('fs');
  const http = require('http');
  const path = require('path');
  
  const app = express();
  
  app.get('/', (req, res) => {
    res.writeHead(200, {"Content-Type": "text/html"});
  
    fs.createReadStream(path.resolve(__dirname, 'src/index.html'))
      .pipe(res);
  
  });

  // Parcel generates file on dist directory
  app.use('/', express.static(path.join(__dirname, 'dist')));
  
  http.createServer(app).listen(3333, function(){
   console.log("Server started at port 3333");
  });

However, because we serve a static HTML file, the CSS file will not be included automatically. Therefore, we need to slightly modify the HTML file to include the CSS file generated by the bundler. The name of the CSS file is the same as the entry point file name, of course with different extension. Add this line to the <head> section of src/index.html.

  <link rel="stylesheet" href="/index.css"></head>

Then, modify the scripts section of package.json.

package.json

  "scripts": {
    "build": "parcel build src/index.js",
    "build-run": "parcel src/index.html"
  }

Now we have two commands available. To build application, run npm run build. Wait until the build finish and you'll see some files generated on dist directory. Then, start the Express server by running node app.js

By default, the output will be on dist directory. For custom output directory, you can add --out-dir custom_dir_name flag.

That's all about how to use ParcelJS bundler to build React application. You can download the code on Github.