Parcel: an Easier Build Process

Webpack is the incumbent in build and task-runner terms. It supplanted Gulp shortly after that tool replaced Grunt in turn. Though that whole period of rapid churn was a dark time, things have definitely stabilised. Webpack has become the default. It’s the core of CLI build systems for React, Vue, and Angular. It’s the assumed build process.

Anything challenging this as an option needs to provide a significant point of difference, and a significant benefit.

Thankfully, Parcel does.

The real key difference is a zero config development experience.

If you’ve ever worked extensively with Webpack you’re aware that “zero config” certainly would not apply. Tools like Create-React-App isolate users from too much config, but they do so by presetting an absolute buttload of config to meet the needs of the tool.

Working with Webpack configs directly is not a pleasant experience. In fact, it’s the punishment for stealing in some countries.

Parcel does away with all of this config and replaces it with… nothing. It’s just gone.

The best way to demonstrate how this works is a simple example.

We’ll start off by installing the one thing we need — Parcel itself.

npm i -g parcel-bundler

That done we’ll make a little project directory in whatever location we make little project directories in. I prefer to do this stuff in the terminal but obviously that’s up to you.

mkdir parcel-test
cd parcel-test
touch index.html
touch index.js
code .

When that is all done we’ll have a few empty files in a directory and the project open in Visual Studio Code and ready to go. Obviously if you don’t use VS Code, do whatever is appropriate for your editor.

We want some basic markup in our index.html file, so just dump this code in there.

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

If you go back to your terminal and run parcel index.html you’ll see that it spins up and gives you a url to look at: by default this is http://localhost:1234. Admittedly there’s not much to look at now. Add a console.log or some nonsense to your index.js file and you’ll see it auto-reloads in the browser and everything works as expected.

Obviously this is trivial, just serving, so let’s make it do a bit of work. Make another file called project.js and add this trivial JS class.

export default class Project {
constructor(name) { = name;

Then you can change the index.js file to the following.

import Project from './project';const projectObject = new Project("My Project Name");

If you go back to the browser you’ll see that the console has logged out My Project Name as you’d expect. This shows two things. First, it’s being transpiled. Our javascript class is working directly in the browser. That’s not 100% certain though. In fact huge amounts of even fancy ES6+ just don’t really need to be transpiled. I believe a class can run natively in most browsers now. But what wouldn’t work is the import. So we can tell that this is being properly compiled and bundled. Which is great, there’s been no need to any config or setup and we have a working (if simple) JavaScript app.

So the next step is obviously some styling, but we won’t just do it in easy mode, let’s use SASS.

Make index.scss however floats your boat and once your boat is floating let’s dump some scss into it.

$blue: #0000A0;body {
background-color: $blue;

Again this is pretty trivial scss. The goal here is to demonstrate that the builder is transpiling it correctly, not showing all the raw power and fury of SCSS syntax.

Once you add import './index.scss'; to your index.js file and save it you should find it refreshes and the background will now be dark blue.

This worked for me with no problems, first time, zero install. But this isn’t what the documentation says so your mileage may vary. According to the documentation you need to first install an scss compiler npm i -D sass. I don’t recall ever doing that but maybe I have a global compiler installed. A quick check of all of my global dependencies - npm list -g --depth 0 if you’re interested - shows no such thing. It just works. If you have a look at the package.json file (which note we never made) you’ll see that has sass in there, and correctly added it as a devDependency. Cool.

This isn’t the end of Parcel’s box of tricks. Among other tools, Parcel will parse and compile TypeScript, Elm, Less, Stylus, Coffeescript (lol), Pug, and a bunch of other types of files.

Impressively, this even includes frameworks.

If you add an App.vue file you can put in just the following code.

<div>Built using {{bundler}}</div>
module.exports = {
data: () => ({bundler: "Parcel"})

Then you’ll need to replace your index.js code with something that bootstraps all of that.

import Vue from 'vue';
import App from './App.vue';
new Vue(App).$mount('#app');

And don’t forget to add <div id="app"></div> to somewhere in your index.html file as well.

You should see from that a working Vue app. No loader, no config, no setup, no install. Out of the box working.

Not just Vue either. React will do the same thing. As soon as Parcel sees some JSX it will get busy installing React and React DOM so it can handle that as well.

As well as development, Parcel can also be used to build with a simple command line. It even has intuitive and easy support for code splitting.

So what about downsides?

Ok, it’s important to judge any technology on an honest assessment of strengths and weaknesses. No library is going to be perfect, and I certainly have run into a few issues with Parcel.

Take these with a grain of salt, though. I’ve been using Parcel for about a year now. Many of these issues may have been resolved in the meantime. I know at least one of them was being worked on, and I can see at a glance that at another one is fixed. I’ll highlight those, though.

First of all, although you can make a React or Vue app work with Parcel, you potentially miss out on some functionality from using their idiomatic CLI setup. Though create-react-app is pretty short on useful features, it still creates a relatively comprehensive dev environment. The Vue-CLI is also relatively trivial compared to Angular or Ember’s workflows, but still offers some functionality that a Parcel user might miss.

Another issue Parcel is likely to have is a lack of community. If things do go wrong you likely won’t find 700+ answers on StackOverflow.

One major problem I had was with React versions. A major bug was occurring in my code in relation to the Context api. It was clearly there, but didn’t work. It turned out that Parcel had installed a very specific version of React that only partially implemented Context. And because it didn’t put the version in package.json it was not obvious. I should note that more recent versions of Parcel seem to install everything to package.json so there is a lot more visibility.

Another issue I ran across was with Drizzle, a blockchain library for (primarily) React. I simply couldn’t get it working. The reference install worked fine but mine didn’t. Eventually, after several days, I was able to trace it down to Parcel’s bundler having a different timing sequence than Webpack, meaning some function calls were not available. I was never able to resolve this issue and simply opted not to use Drizzle instead. This won’t always be an option.

Another issue that came up a lot was with React. Parcel would try and auto-reload the React app on changes, and would instead crash. This was essentially some sort of infinite loop that would exceed a stack. This issue is fixed now, but a quick look at Parcel’s issue board (actually I was just looking for the exact error) shows there are still some problems with HMR with Parcel.

There were other times where Parcel just… didn’t rebuild. It got stuck. One thing I will say for it is that its build system is actually pretty comprehensible. Files are built in memory and dumped into a /dist directory. Deleting that /dist directory is perfectly safe and occasionally useful. Deleting both this directory and /.cache solved about 99% of issues I encountered, except as listed above.

You’ll notice when I was talking about transpiling earlier I made it very clear that you didn’t need to install babel, didn’t need a .babelrc file, didn’t need to mess around with babel plugins, etc? Well, that’s only true up to a point. If you start using wild features you may quickly find they’re not supported. Rest/Spread syntax worked perfectly fine, but class properties and decorators gave me build errors. This isn’t to say you can’t enable these features. In fact, the series I linked to for all of the above was written entirely using Parcel projects as testbeds.

There were other little issues that cropped up from time to time. A sub-dependency changed version and broke builds. The no-sourcemaps flag stopped working for a bit. But these were minor issues fixed within a day or two.

When And When Not To Parcel

There is a time and place for all technology, and there are some pretty solid guidelines to when Parcel is likely to be a good call.

If you’re using an existing framework like React or Vue, skip it and just use the idiomatic Webpack-based command-line scaffolding tools. While I do run some flagship production apps as Parcel builds there is sometimes friction. There are benefits to the road more travelled.

On the other hand, if you’re making apps that don’t have frameworks, or spinning up mockups to demo, create spikes, or test a technology, Parcel is a great option.

Its rapid ramp up to a mature dev environment, sass, Typescript, or ES6, is hard to beat.

There is a Parcel 2 in development. It will be interesting to see what that involves. But for now you should give Parcel a serious look. If just to escape the tyranny of Webpack configs.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Matt Burgess

Matt Burgess


Senior Web Developer based in Bangkok, Thailand. Javascript, Web and Blockchain Developer.