ElianCodes

← Back to blog

Setting up Nuxt with Pug and Stylus

Nuxt is really cool all by itself but can even be cooler when combined with another templating engine. In this example I’ll use Pug and Stylus to fiddle around.

Installing Nuxt

Ofcourse, the basic requirement of this whole setup is Nuxt. I’ve been using Nuxt for a couple months and it really has become part of my go-to tech-stack. I love all the possibilities that Nuxt has to offer. You can install so many extra modules and make them do your work, which is really useful. I’ve already written some blogposts about some Nuxt modules, so I won’t go to deep on them in this article, but I will show the basics of installing and using Nuxt by itself.

If you’re looking to understand the basics of Stylus, Pug, Vue or Nuxt itself, this probably won’t be something for you, but you’re always welcome to read 😉

First of all, let’s install the basic Nuxt boilerplate

npx create-nuxt-app your-awesome-website

It will ask you some stuff like what modules you want, what UI framework you need ect. Choose freely, but it’s easier to go with just the basics here.

Now that Nuxt is installed, you should be able to run yarn dev or npm run dev to start the dev-server. From this point on I’ll use Yarn since it’s my personal preference, but feel free to use whatever you like most.

Adding Pug to the config

Installing Pug onto Nuxt

To start using Pug as a templating engine in Nuxt, we firstly have to install the language processor itself, to do this, we’ll use two packages, one as the language and one as the loader so that Nuxt knows how to handle and compile the templates.

yarn add -D pug pug-plain-loader

There’s also another package called vue-pug-loader which focusses more on maintaining the Pug syntax with Vue variables ‘more about that on the NPM package README). You can choose whatever you like.

Using a Pug layout

If you have been using pug for a while, you’ll know that Pug in itself is a templating engine and doesn’t really need Nuxt to prove it’s worth. Well, you’re right. In Pug you can use the include or extends element to extend a layout or include another template. (more info about this is on their own documentation) This does also work in Nuxt if you like working that way, but I’m more of a Nuxt layout user, so I wrote the part below for the people looking to use a combination of both Vue and Nuxt.

Using a combination of Pug and Vue for components and Layouts

Nuxt has a default folder called layouts/ in which it let’s you define and create your own layouts using the <nuxt /> element to show where page content should go. This works exactly the same in Pug:

<template lang="pug">
  div header //- your header could be here main nuxt //- Nuxt will place the
  page content here footer //- here comes your footer content
</template>

<script>
  export default {
    name: "default-layout",
  };
</script>

Using dynamic assets in Pug

One of the things I struggled with in my first experience with using a combination of Pug, Vue and Nuxt was using dynamic assets.

Static assets are as simple as HTML where you include the relative path in the src attribute in your <img/> element. That’s ofcourse if you place them in the static folder in your Nuxt configuration.

Here’s how to use a dynamic asset:

<template lang="pug">
  ul li(v-for="icon in icons" :key="icon")
  img(:src="require(`~/assets/img/icons/${icon}`)")
</template>

<script>
  export default {
    name: "using-dynamic-assets",
    data() {
      return {
        icons: ["first.svg", "second.png"],
      };
    },
  };
</script>

Using Vue variables in Pug

Like you’ve seen in the example above, it’s possible to use things like v-if, v-for and other Vue specific functions. It’s also possible to use variables or props in our pug templates, just like you normally would:

<template lang="pug">
  div article.main-content h2 {{ title }} p {{ description }}
</template>

<script>
  export default {
      name: 'using-vue-variables',
      props [
          'title', 'description'
      ]
  }
</script>

Using components with props

to actually make the component above work, we would still need something like this:

<template lang="pug">
  div UsingVueVariables( v-for="block in blocks" :key="block.title"
  :title="block.title" :description="block.description" )
</template>

<script>
  import UsingVueVariables from "~/components/using-vue-variables.vue";
  export default {
    name: "using-components-with-props",
    components: {
      UsingVueVariables,
    },
    data() {
      return {
        blocks: [
          { title: "hello", description: "world" },
          { title: "from", description: "ElianCodes" },
        ],
      };
    },
  };
</script>

Works like magic!

Adding Stylus

Installing Stylus onto Nuxt

Since the codebase from the project I was porting to Nuxt was already using Stylus, I didn’t want to change it to Sass or similar, so I took it as a challenge to get it working with Nuxt. Seemed harder then it actually is.

yarn add -D stylus stylus-loader

Note: bear in mind that Nuxt >= v2.9 still uses Webpack 4 and not 5, so you’ll probably need to downgrade your stylus-loader package to a Webpack 4 compatible version (v4.3.3)

Stylus in a styled component

A lot of people tend to use single-file components in Vue, I don’t blame them since it’s the easiest way to start off a new project. Here’s how to create a new styled component using Stylus as stylesheet:

<template>
  <main>
    <h1>A simple styled component</h1>
    <p>Using Vue, Nuxt and Stylus</p>
  </main>
</template>

<script>
  export default {
    name: "using-stylus",
  };
</script>

<style lang="styl" scoped>
  h1
      color green
  p
      color blue
</style>

Stylus as a global stylesheet

Sometimes, a styles component library can be quite a handful, somtimes I prefer to just have a global stylesheet which imports all other Stylesheets, luckily for us, Nuxt let’s you do this with quite an ease:

export default {
  css: [{ src: "~/assets/styls/styles.styl", lang: "styl" }],
};

Now Nuxt knows that it has to include the file in the buildfolder and will include those styles on every page!

Using external files as templates

One of the coolest and easiest things to do when you’re rebuilding a website that already used Pug in the passed or when you want to keep a specific structure, is to use external Pug files as templates into your Vue components. This is made really easy by adding it as an external template (same can be done for stylesheets BTW):

<template lang="pug" src="~/components/folder/component.pug" />

<script>
export default {
  name: 'external-pug-template'
}
</script>

<style lang="styl" src='~/assets/styl/stylesheet.styl'>

Written by Elian Van Cutsem

← Back to blog
  • Elians Astro Startkit

    Elians Astro Startkit

    I just published the setup I use for my personal projects. You can read more about it in this blogpost.

  • So, I'm leaving vBridge

    So, I'm leaving vBridge

    After spending a couple of years at vBridge Cloud, I'm leaving the company. I've worked at vBridge eversince I graduated. Now, It's time for a new adventure! I'm joining the DX-team at Astro full-time!

  • Becoming an Astro maintainer

    Becoming an Astro maintainer

    Since a week, I'm an Astro maintainer, in this post, I describe the process and my start in open source. I also give some insight in what I'm planning to work on.

  • 🍱 Brutal: A theme for Astro

    🍱 Brutal: A theme for Astro

    Brutal is a minimal neobrutalist theme for Astro. It's based on Neobrutalist Web Design, a movement that aims to create websites with a minimalistic and functional design. It has some integrations like Image Optimization, RSS, Sitemap, ready to get your SEO done right.

  • 🎤 Am I an international public speaker now?

    🎤 Am I an international public speaker now?

    A few weeks ago, I gave my first international keynote talk at JSWorld in Amsterdam. In this blogpost, I wanted to share some insights about the conference and my talk.

  • ✨ Building Blog tag index pages in Astro

    ✨ Building Blog tag index pages in Astro

    I wanted to add blog tag collection pages to my website. This way, people could filter on tags I used in my blog posts. Here is a guide on how I implemented it.