Quickly build a performant Landing page with Nuxt
Tags: a11y, tutorial, webdev, nuxt
Published: 2020-07-15 06:48:36

I've been building [Mylo](https://www.mylo.fit) (a more intelligent workout assistant) but contrary to popular advice, I started building the app and completely ignored making a landing page. I should have taken that advice 😔

There are all the usual reasons like letting you build hype and gather email addresses, but the biggest impact I've noticed is how 'real' it makes the project. It's no longer an idea in your head but a landmark that others can see giving them the chance to understand you.

Determined to make a landing page, I decided to learn Nuxt, let me share what I learned to help you make your own page and get amazing scores in Lighthouse.

## Setup

Setting up your nuxt project is pretty straightforward, as per nuxt's getting started guide, run this command:

```
$ npx create-nuxt-app <project-name>
```

When you go through the setup cli make sure to select 'static' as the target, it's a brand new option in Nuxt that will let you generate a fully static version of your site. This will make it load much faster, and you can benefit from free hosting on most CDNs, like Netlify.

Add the generate command to your package.json:
```jsonc
{
    // ...
    "scripts": {
        // ...
        "generate": "nuxt build && nuxt export",
    }
    // ...
}
```

```
$ cd <project-name>
$ npm run dev
```

After that you're pretty much dealing with standard Vue. I won't go into all the details of Nuxt because you won't need most of them for a simple landing page like this one, but here is a brief primer of what you do need:

### Directory structure

Unlike Vue, which essentially dumps you in the desert with nothing but a `src` folder, Nuxt leaves you by the oasis 🌴
You're given a few folders to help you get started, here are the ones you will definitely need:

* assets - static assets that you want Nuxt to bundle/transform for you (images, SVG, CSS)
* components - your usual components like buttons, modals, forms, etc.
* layouts - these are also components but they handle full page elements like a header, footer, sidebar, etc.
* pages - each file/folder here will get mapped to a URL of your site
    * index.vue -> yoursite.com/
    * about.vue -> yoursite.com/about
    * blog/welcome.vue -> yoursite.com/blog/welcome

Generally a landing page is rather light in interactivity so you might find yourself writing very little JS, and might not use the other Nuxt features like `asyncData`.

If you want to check out the code behind Mylo's homepage, I've open-sourced it here: [Github - MyloWebsite](https://github.com/MaxMonteil/MyloWebsite)

## Improving Lighthouse

Making the site itself is only the first step though, we need to make sure performance is great, a slow site doesn't make for a great first impression of your product or service.

So first, go ahead and run a Lighthouse audit to get an idea of where things stand.

Before optimizing 😰
![Lighthouse scores before optimization (performance 13, accessibility 79, best practices 100, SEO 100)](https://dev-to-uploads.s3.amazonaws.com/i/8ilngopl6sacuio5q2ku.jpg)

These scores aren't all that great, the performance one is downright horrible. But here's where a few changes get me 😎
![Lighthouse scores after optimization (performance 91, accessibility 100, best practices 93, SEO 100)](https://dev-to-uploads.s3.amazonaws.com/i/rrhcnfhexxmuhn78w2kd.jpg)

### Performance

The biggest issue I was running into were caused by SVGs.

When it comes to icons I generally prefer to use SVGs over images, they often result in smaller file sizes, can be modified with CSS, and can be resized without any loss of quality.

Now there are many ways to embed them into your site depending on what you need. I needed to be able to modify their color with CSS so I inlined them.

```html
<template functional>
  <svg
    xmlns="http://www.w3.org/2000/svg"
    :width="props.size"
    :height="props.size"
    viewBox="0 0 16 16"
    :aria-labelledby="props.labelledby"
    role="presentation"
  >
    <title lang="en">logo icon</title>
    ...
  </svg>
</template>
```

This works great for simpler SVGs like the logo. But when I inlined a more complex one (multiple times) it made the DOM huge, filling it with giant SVG tags that the browser had to parse through, giving me that performance score of 13.

The solution then was to embed them in an `<img />` tag. This way you avoid adding thousands of DOM elements while still benefiting from caching, but you lose the ability to color them with CSS...

```html
<img :src="require('~/assets/images/sports_icons.svg')" />
```

#### Or do you?

Turns out there are a couple of ways to change the color of an SVG even if embedded this way. They involve using combinations of CSS filters to get the color you want.

You can find more information on how to do that in this  post:
[CSS Tricks - Change SVG fill on hover](https://css-tricks.com/the-many-ways-to-change-an-svg-fill-on-hover-and-when-to-use-them/)

But these filters aren't very intuitive to combine into the color you want, luckily I found this codepen which can convert a HEX value into the matching set of CSS filters:
[Generate filters for a hex](https://codepen.io/sosuke/pen/Pjoqqp)

```html
<img
    :src="require('~/assets/images/sports_icons.svg')"
    class="fill-green"
/>
```

```css
.fill-green {
  filter: invert(91%) sepia(10%) saturate(1436%) hue-rotate(90deg) brightness(94%) contrast(93%);
}
```

### Accessibility - color contrast

Another issue I had was poor color contrast.
In most design tools you start off by creating a nice color palette which you then tweak to get proper contrast.

What if you could do things the other way around? That's what [Leonardo Color](https://leonardocolor.io/) does. You set your base color(s) and from there generate additional colors that achieve the contrast ratios you need to pass the [WCAG's criteria](https://webaim.org/articles/contrast/).

And here is another tool you can use to check contrast between colors: [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)

## Conclusion

Making a landing page really is a good first step, it seemed like such a daunting task to me but ended up being much easier to create than my actual project.

Turns out I was just scared of how concrete it would make Mylo feel, because now the whole world can see and criticize it, but in the end, what better way is there to improve?

Let me know what you thought of this post and if you check out [Mylo](https://www.mylo.fit) I'd love to hear your feedback!😁


## P.S. Here's one more tip

Making the landing page is cool and all but you're likely going to need a way to contact those who sign up, and it looks more professional to have an email address on at a custom domain.

> `contact@<your-project>.com`

Some hosting services offer emails but I use Netlify which doesn't offer this and getting such an address is usually a paid service but I found this guide to set you up for free!

[How to setup a custom email address for free](https://marvintan.com/posts/free-custom-email-address/)