Using Elm and Parcel for zero configuration web asset management


At some point our frontend had ~200 lines of Webpack configuration and it was going to grow by at least another 200 lines for a simple change of having two top-level html outptus. My mind went “what happened to convention over configuration in the frontend sphere”? I discovered Parcel.

In this short post I’ll show you how to get started with Parcel and Elm to achieve zero configuration for managing your assets.

With very little configuration you get:

  • live Elm reloading
  • ~100ms rebuilds with a warm cache (measured using ~1500 loc)
  • --debug when using a server (this change hasn’t been released yet)
  • --optimize when using a build
  • importing an asset (from node_modules or relatively) just does the right thing
  • bundling and minification of assets

Bootstrapping

Using yarn or npm (btw, pnpm is currently the most sane Node package manager):

mkdir parcel-elm-demo && cd parcel-elm-demo
yarn add parcel-bundler elm
yarn run elm init

We’ll create a minimal Elm program to start with in src/Main.elm:

import Html exposing (..)

main = text "Hello world"

Next we create a top-level asset that Parcel will build, index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
  </head>
  <body>
    <div id="main"></div>
    <script src="./index.js"></script>
  </body>
</html>

Note how we’re including src as relative path to a JavaScript file. The general idea in Parcel is that you import files of any asset type, and Parcel will know how to process and bundle it.

The gist of glueing Elm and Parcel together is in index.js:

import { Elm } from './src/Main.elm'

Elm.Main.init({
  node: document.getElementById('main'),
});

At the import Parcel will detect that it’s an Elm asset, so it will use Elm to compile it and then exports the Elm Javascript object as we use it to initialize Elm in the DOM.

Running Parcel

There are two main operations in Parcel. First, you have a development mode via live-reloading server:

$ yarn run parcel index.html
yarn run v1.9.4
$ /home/ielectric/dev/parcel-demo/node_modules/.bin/parcel index.html
Server running at http://localhost:1234
✨  Built in 456ms.

Open http://localhost:1234 and modify src/Main.elm. You should see on the terminal

✨  Built in 123ms.

and your page will be refreshed automatically.

To produce a final bundle for production, you use parcel with a command, build:

$ yarn run parcel build index.html
yarn run v1.9.4
$ /home/ielectric/dev/parcel-demo/node_modules/.bin/parcel build index.html
✨  Built in 2.07s.

dist/parcel-demo.bc110dbc.js     7.93 KB    1.55s
dist/parcel-demo.4f74f229.map      373 B      3ms
dist/index.html                    288 B    442ms
Done in 2.87s.

Your minified, bundled Elm project is now ready to be deployed.

Parcel isn’t perfect (yet!)

There are a few issues still around.

That’s it. Last but not least, we’re building next-generation CI and binary caching services, take a look at Hercules CI and Cachix.