Bundling Your Web App Using Parcel

While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Parcel is an up-and-coming module bundler that’s extremely fast and that supports HTML, CSS, JavaScript, Image and TypeScript assets out of the box without the need for separate plugins. Best of all, no configuration is needed and it’s as simple as pointing it to an entry file and Parcel takes over with bundling, transforming and minimizing assets.

Let’s explore how Parcel is used.


All that’s needed to get started is the parcel-bundler package. Install it globally using npm or Yarn:

$ npm i -g parcel-bundler

# or, using Yarn:
$ yarn global add parcel-bundler


First, initialize a new npm project:

$ npm init

# or, using Yarn
$ yarn init

Next, we’ll demonstrate Parcel’s usage with a very simple demo app that contains a main index.html, two JavaScript files and two CSS files. The app has two buttons that change the page’s background color when clicked.

Here’s the content of our HTML file:

<!DOCTYPE html>
<html lang="en">

  <meta charset="UTF-8">
  <title>Color My World</title>

  <link rel="stylesheet" href="./styles.css">


  <div class="controls">
    <button id="color">Color!</button>
    <button id="premium-color">Premium color!</button>

  <script src="./index.js"></script>


Notice how the paths we use for our styles and script files are relative. This is important for Parcel to work its magic. Other assets like images should also be referenced using relative paths.

Our entry JavaScript file looks like this:

'use strict';

import premiumColors from './premium';
const colorBtn = document.getElementById('color');
const premiumColorBtn = document.getElementById('premium-color');
const availableColors = [
colorBtn.addEventListener('click', () => {
  const randIdx = Math.floor(Math.random() * availableColors.length);
  document.documentElement.style.setProperty('--bg', availableColors[randIdx]);

You’ll notice that we’re using ES6 modules here, but Parcel also understands CommonJS syntax. Our second JavaScript file simply contains a default export with our premium colors:

export default [

Our main CSS file imports another stylesheet with styles for our buttons and defines style rules for the body element and .controls div:

@import './button.css';

body {
  background: var(--bg, paleturquoise);
  height: 100vh;

And finally, our buttons styles are really simple:

button {
  background: peachpuff;
  font-size: 1.3em;
  border: none;
  padding: .4em;
  margin: .3em;
  border-radius: 4px;
  box-shadow: 0 0 10px rgba(0,0,0,0.13);

Parcel also supports SASS, LESS and Stylus out of the box!

With our simple app ready, we can call parcel and point it to the index.html entry file:

$ parcel index.html

Parcel will generate the different bundles in a /dist folder, start a local server at http://localhost:1234/ and start listening for changes.

You can also specify a different output folder using the --out-dir flag:

$ parcel index.html --out-dir public

Parcel also has a watch command to bundle and listen for changes, but without starting a local server:

$ parcel watch index.html

When your app is ready for production, you can bundle a production build using the build command:

$ parcel build index.html

This will turn off Parcel’s Hot Module Replacement and minimize the JavaScript, CSS and HTML assets (using UglifyJS, cssnano and htmlnano).

Babel and PostCSS

On top of bundling, Parcel can, out of the box, perform code transforms using Babel, PostCSS and PostHTML.

All you have to do is add the necessary dependencies and include the respective configuration files at the root of your project, and Parcel will take care of the rest.

For example, if you want to want to use PostCSS’s autoprefixer to automatically add vendor prefixes, first install the package:

$ npm install autoprefixer

# or, using Yarn:
$ yarn add autoprefixer

And then add a .postcssrc file to the root of your project:

  "plugins": {
    "autoprefixer": true

And that’s it! Now this CSS:

.controls {
  display: flex;
  justify-content: center;
  align-content: center;
  align-items: center;
  height: 100%;

Will be transformed to this:

.controls {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -ms-flex-line-pack: center;
      align-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  height: 100%;

You can also specify which browsers to target using Browserlist by adding a .browserslistrc file to your project.


Parcel even supports TypeScript out of the box. Simply add typescript as a dev dependency to your project:

$ npm i typescript --save-dev

# or, using Yarn:
$ yarn add typescript --dev

Then create add a tsconfig.json file to your project. For example:

  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true

Now, your index file can point directly at your TypeScript entry file and you call parcel as you would normally and the TypeScript code will automatically be transpilled to JS code:

<script src="./index.ts"></script>
$ parcel index.html
  • Check out this post of ours for more help on configuring a new TypeScript project.
  • There’s also a third-party TypeScript plugin for Parcel called parcel-plugin-typescript that has type-checking and error reporting available at build time.

📦 Now you should be off to the races with Parcel’s zero configuration ease of use and fast bundle generation! To learn more, refer to the official documentation.

Creative Commons License