Let's Build a HTML and CSS Landing Page with Parcel
Tags: html, javascript, parcel, sass
Published: 2021-08-06 13:47:53

---
title: Let's Build a HTML and CSS Landing Page with Parcel
published: true
description: An intro tutorial to Parcel by building and deploying a static website with HTML, SASS and JavaScript for free. Includes starter templates.
tags: html, javascript, parcel, sass
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6unpi6qrohqmv29wrq54.png
canonical_url: https://aileenrae.co.uk/blog/lets-build-a-landing-page-with-parcel
---
Ever wanted to dive straight into building a simple HTML page without having to faff around with build configuration?

Sure, there are amazing online tools like [Codepen](https://codepen.io/), but I'm talking something you can run locally with hot reloading, something you can easily build and deploy with minimum setup.

I wanted just that, and that's when I learned about [Parcel.js](https://parceljs.org/). The "blazing fast, zero configuration web application bundler".

![Parcel landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6unpi6qrohqmv29wrq54.png)

Unlike [Webpack](https://webpack.js.org/), a bundler which offers maximal configurability, Parcel prefers a **minimal config approach**. It handles most imports out-of-the box, with no need to manually install plugins.

If that sounds good and you want some free project templates to start from already, I've got you covered. 😉 They're at the bottom of this article. Curious to learn more? Let's build a landing page together to see how it works.

- [Let's build a landing page](#lets-build-a-landing-page)
  * [Hello World page](#hello-world-page)
  * [Add SASS styles](#add-sass-styles)
  * [Separating HTML into partials with posthtml-include](#separating-html-into-partials-with-posthtmlinclude)
  * [I want to use TypeScript!](#i-want-to-use-typescript)
  * [Installing extra dependencies & finishing the landing page](#installing-extra-dependencies-amp-finishing-the-landing-page)
  * [Cross-Browser Support](#crossbrowser-support)
  * [Deploying our landing page](#deploying-our-landing-page)
- [Some downsides](#some-downsides)
- [Takeaways](#takeaways)
- [One-click deploy starter templates](#oneclick-deploy-starter-templates)

## Let's build a landing page

We're going to build and deploy [this landing page designed by Codewell](https://www.codewell.cc/challenges/608d9565747bad001532bd64).

![Landing page design by Codewell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f03x6tgwh0mht38p9ph9.png)

We'll be using [SASS](https://sass-lang.com/) and [posthtml](https://posthtml.org/#/), which can be used with Parcel with minimal configuration. Finally we're using [Netlify](https://www.netlify.com/) to deploy our landing page for free.

### Hello World page

First, we'll get a simple "hello world" up and running with Parcel. You'll need the [npm CLI](https://docs.npmjs.com/cli) installed for this.

1. Create a directory to host the project and make it your current directory.
    ```bash
    $ mkdir commune-waitlist-page
    $ cd commune-waitlist-page
    ```

2. Run `npm init` and follow the prompts (defaults are fine).

3. Open the directory in your favourite code editor. You should have a `package.json` file. Remove the `"main": "index.js",` line, since Parcel will not need it.

4. Next let's add our main HTML and JS files. Create a `src` directory and create two files named `index.html` and `index.js`, with the following content:
    `index.html`:
    ```html
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Commune Waitlist Page</title>
      </head>
      <body>
        <h1>Commune</h1>
        <script type="module" src="./index.js"></script>
      </body>
    </html>
```

    `index.js`:
    ```js
console.log("Hello world! 👋");
    ```

    Your directory should now look something like this:
    ![Project directory structure. A "src" directory contains "index.html" and "index.js", plus a "package.json" file in the root directory/](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8nbz3yganhfdizcuh3z.png)

5. Finally, let's add Parcel! Run 
    ```bash
    $ npm install -D parcel@next
    ```
    
    to save Parcel v2 as a dev dependency. Then add the following to the "scripts" property in `package.json`:
    ```json
    "start": "parcel serve ./src/index.html",
    "build": "parcel build ./src/index.html"
    ```

6. Run `npm start` and open http://localhost:1234 in your browser to see your Hello World app running locally!

![Screenshot of Hello World app running in Firefox browser.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x0u7uce4tbgzcgbq5ffk.png)

Unlike other bundlers, Parcel uses an HTML file as its entry point, as you can see in the `parcel serve` and `parcel build` commands we added to `package.json`. Parcel detects any JavaScript or CSS dependencies directly from the entry HTML file then bundles it appropriately.

### Add SASS styles

Being able to use SASS for my stylesheet is one of my biggest motivations for using a bundler for a simple frontend app like this. Parcel makes adding SASS a breeze.

1. In the `src` directory, create a file called `styles.scss`. For the sake of this demo, I am using it to create two SASS variables and set them as the `color` and `background-color` of the page:

    ```scss
    // styles.scss
    $background-color: #F6F9FE;
    $color: #353252;

    body {
        background-color: $background-color;
        color: $color;
    }
    ```

2. Add the following line to your `index.html` file:

    ```html
    <link rel="stylesheet" href="./styles.scss" />
    ```
    <p></p>
    then switch back to the browser to see your style changes.

That's it! ✨ No plugins to install, no config files to add, nothing. SASS just _works_.

![Screenshot of Hello World app running in Firefox browser, now with some added styles.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/my9gkwh9oilfucn34i6j.png)

Behind the scenes - as soon as you hit "save" on `index.html` - Parcel read the file and saw it referenced a `.scss` file. It then went and installed the appropriate SASS plugin for you and rebuilt for hot reload. In fact, if you inspect your `package.json` file you'll see Parcel has added the `@parcel/transformer-sass` plugin to your dev dependencies for you.

### Separating HTML into partials with posthtml-include

Our `index.html` file is small at the moment, but it's going to get pretty long as we build the landing page. It becomes tedious scrolling up and down a long HTML file to make edits.

One way to avoid that is to split our HTML into separate partial `.html` files. Parcel offers a plugin for [posthtml](https://v2.parceljs.org/languages/html/#posthtml), which lets us do this. It requires a small config file.

Let's try this by adding a partial for the navigation bar on the landing page.

1. At the root of your project directory (where `package.json` lives), create a new file called `.posthtmlrc` containing the following:

    ```json
    {
        "plugins": {
            "posthtml-include": {
                "root": "./src"
            }
        }
    }
    ```

2. In the `src` directory, create a new directory called `partials`. In `partials`, create a new file called `nav.html` with the following content:

    ```html
    <nav>
      <ul>
        <li><a href="#">Features</a></li>
        <li><a href="#">Affiliates</a></li>
        <li><a href="#">Pricing</a></li>
        <li><a href="#">Communities</a></li>
        <li><a href="#">Join Waitlist</a></li>
      </ul>
    </nav>

    ```

3. Then, replace the `<h1>Commune</h1>` line in `index.html` with the following:

    ```html
    <header>
      <h1>Commune</h1>
      <include src="partials/nav.html"></include>
    </header>
    ```

4. If npm throws an `EPERM` error, cancel the process with <kbd>Ctrl</kbd>+<kbd>C</kbd> and run `npm start` again.

Once again, that's it! ✨ If you inspect your `package.json` file you will see that Parcel has installed the necessary package for you: `posthtml-include` in this instance.

![Screenshot of Hello World app running in Firefox browser with navigation links added.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/orcpyhe54eaunrjyu9ec.png)

### I want to use TypeScript!

I'm not on the TypeScript train yet, but I hear you! Parcel has you covered. Here's a contrived example to prove it.

1. First, let's rename our `index.js` file to `index.ts` and update the reference in `index.html` accordingly. You may need to restart the app.

2. It works! But let's add some TypeScript-specific code to convince ourselves. Replace the contents of `index.ts` with:
    ```ts
    function consoleLogWithEmoji(message: string, emoji: string): void {
        console.log(message + " " + emoji);
    }

    consoleLogWithEmoji("Hello world!", "👋");
    ```

Easy-peasy! Unfortunately though, Parcel doesn't perform TypeScript type checking out-the-box. Further TypeScript details are outwith the scope of this article, but you can learn [how to configure type-checking in the Parcel documentation](https://v2.parceljs.org/languages/typescript/#type-checking).

### Installing extra dependencies & finishing the landing page

I won't waste your time walking through every piece of HTML and CSS I added to build the landing page. If you'd like to see the changes I made you can see the [diff on GitHub here](https://github.com/aileen-r/commune-waitlist-page/pull/1).

With Parcel we can install npm packages just like we can with other bundlers. As a finishing touch, I'm going to add some light animation using the [animate on scroll](https://michalsnik.github.io/aos/) library.

To use animate on scroll, run 

```bash
npm install aos --save
```

in the project root directory. Next we add

```js
import AOS from 'aos';
import 'aos/dist/aos.css';

AOS.init();
```

to our`index.js` file. You can also add additional configuration options to the `AOS.init()` call. See the [AOS docs](https://github.com/michalsnik/aos/tree/v2) for details.

Now we can add `data-aos="animation_name"` to any element you want to animate in. I added `data-aos="fade"` to the page wrapper div, then some other fade in animations after a short delay.

![Landing page animated with Animate on scroll library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdw9q3060yy9oqk8xf76.gif)

It's done! 🎉 One last thing before we can build for production...

### Cross-Browser Support

Before we deploy our app, let's add some basic cross-browser support. Parcel doesn't transpile any code out-of-the-box, but we can add support for some older browsers with [browserslist](https://parceljs.org/getting-started/webapp/#declaring-browser-targets).

Simply add

```json
"browserslist": [
    "defaults"
]
```

to `package.json` to configure browserslist's recommended cross-browser support. You can check out the [browserslist repo](https://github.com/browserslist/browserslist) for more configuration options.

Now let's get this thing deployed!

### Deploying our landing page

We're going to use [Netlify](https://www.netlify.com/) to deploy our landing page. I love using Netlify to host my frontend projects because it connects directly to [GitHub](https://github.com/), it's super quick and easy to set up, and it's free!

If you're not already using GitHub to host your code there's [a guide for pushing your code to a GitHub repository here](https://docs.github.com/en/github/importing-your-projects-to-github/importing-source-code-to-github/adding-an-existing-project-to-github-using-the-command-line).

To deploy the code from GitHub to Netlify:

1. Login or sign-up to [Netlify](https://app.netlify.com).

2. On the overview page, click "New site from Git".
    ![Netlify overview page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qv0l108699yudnvu2v1y.png)

3. Choose "GitHub" as your Git provider. There is also the option to choose GitLab or BitBucket.
    ![Connect Netlify to GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4tbrhf30q25tmm1xktkl.png)

4. On the next page of the wizard, select the GitHub repository for your project.

5. All the default site settings are correct for us, but let's quickly break the build settings down:  
    - **Base directory** - This is the directory where you run npm commands like `npm start` and `npm run build`. For us, this is the root directory so this should be blank.
    - **Build command** - The command for creating a production build. This is `npm run build`, which we added to `package.json` back when we first built a Hello World page.
    <pre>"build": "parcel build ./src/index.html"</pre>
    - **Publish directoy** - This is the name of the directory that is outputted from `npm run build`. For us this is `dist`, which is the default from Parcel.
    ![Netlify build settings for a Parcel app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eq2gancx7g2kt0ubns7t.png)
    
6. Click "Deploy site".

7. Netlify will create a randomly generated URL for you like _elegant-elion-c301a1.netlify.app_. You can edit this by clicking "Site settings" then "Change site name".

8. Once the last production deploy has a green "Published" badge next to it, your website is live! It will re-deploy any time you push code changes to the default branch of your GitHub repository.
    ![Commune waitlist page deployed to Netlify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f07om5qlgqgvv89vbo53.png)

And it's done! My landing page now lives at https://commune-waitlist-page-aileen-r.netlify.app/ 🚀 

## Some downsides

My overall experience of using Parcel was a happy one, since I could get up and running super quickly. That being said I did hit a couple of snags along the way.

Hot reload sometimes fails to recompile and you have to manually kill the app then rerun `npm start`. I noticed this when:
1. Saving a SASS file with a syntax error, like a missing semi-colon. Fixing the error and re-saving doesn't force a recompile like I would expect. This is obviously only an issue when using SASS.
2. Making an edit to an HTML file. About 50% of the time it would throw an `EPERM` permissions error since it was trying to rename a file that was currently in-use by the running process (`npm start`). It's possible this error only occurs when using posthtml-include, but I haven't investigated further.
    ![EPERM error after editing an HTML file.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6r4kj98877f5pn5yn134.png)

While this is a bit of a nuisance, the app startup time is quick so it never interrupted my flow.

Another hurdle I ran into was cross-browser support. While everything worked smoothly for semi-modern browsers, Internet Explorer 11 support was a different issue. First there is [an issue running dev server in IE11](https://github.com/parcel-bundler/parcel/issues/2364), and you have to manually install polyfills yourself. I chose to ignore IE11 support since [Microsoft is finally retiring the browser in 2022](https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/). If you need to continue to support IE...well, may the force be with you.

It's worth noting that I've been using v2 of Parcel, which at the time of writing is still at its first release candidate build.

## Takeaways

Parcel is great for small projects. I've specifically found it to be perfect for setting up [technical test solutions](https://github.com/aileen-r/group-array-elements-interview-question) while job hunting as it makes it easy to add Jest for unit testing without using a JS framework starter kit like Create React App.

If I found myself needing more configurability, I would probably still pick Webpack first.

One thing Parcel offers which I didn't try is using it for [React](https://v2.parceljs.org/recipes/react/) or [VueJS](https://v2.parceljs.org/languages/vue/) apps. Personally I think the starter projects generated by [Create React App](https://create-react-app.dev/) and [Vue CLI](https://cli.vuejs.org/guide/creating-a-project.html) are easy enough to get started with, so I don't see a need to try and use Parcel. If anyone has used Parcel for React or Vue I'd love to hear your experience with it in the comments.

## One-click deploy starter templates

If reading a tutorial isn't your thing and you want to dive headfirst into code, I've prepared some starter templates for you. Each has a "deploy to Netlify" button which creates your own copy of the repository and deploys it to Netlify for free with one click!

- [HTML, CSS, and JavaScript starter template with Parcel](https://github.com/aileen-r/parcel-html-css-js-starter-template)
- [HTML, SASS, and JavaScript starter template with Parcel](https://github.com/aileen-r/parcel-html-sass-js-starter-template)

If you find any of the templates useful please let me know. Thanks for reading!