DEV Community

Cover image for Create YOUR next static blog in Vuepress and Vue
Chris Noring for ITNEXT

Posted on • Edited on • Originally published at softchris.github.io

Create YOUR next static blog in Vuepress and Vue

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

The idea with this series is to have a look at how you can build your own blog using one of the known static site generators.

TLDR; Yes this article is a bit long but well worth a read as it manages to tell you how to not only get started with your own homepage but also how to build custom components and use the default theme. Also if you never used a static site generator before, this is VERY easy to get started with.

Building your own blog can be a very ambitious project where you spend time coding or integrating and tweaking different components that you absolutely must have or something dead simple, where you just focus on writing the article.

Blogs are usually static sites and people often don't want to write their blog posts in HTML but prefer to write them in something else like Markdown or just plain text. For that reason, static site generator tools exist that caters to beginners as well as the most advanced user possible.

I'm definitely one of those people, Markdown FTW and the less I need to deal with my blog the better :)

This is part of a series of articles in which we look at different static site generators. In this article, we will focus on VuePress, a static site generator from the Vue team themselves.

We will cover the following:

  • Install and Set up. This part is pretty important that it's smooth and easy
  • Hello world Creating that first page is an important part of the experience, let's see how fast we can be up and running.
  • Static pages for CV, About and other pages
  • Creating blog posts We look at different static site generators with the intention of being able to use it as a blog engine so we need to understand how we should name those files, how we work with frontmatter, tags, slugs and other things
  • Customize the looks, colors, layout etc. We might be happy with a theme we are given but sometimes we want to be able to tweak the looks. Or even better is there a great default theme we could be using HINT
  • Create custom controls like a list-page of articles. It's a quite common thing to want to list all the articles your blog consist or maybe a tag cloud. The point is we either want to use these kinds of articles or be able to create them ourselves if they aren't available.

 Resources

There are some great links you should have a look at if you really want to get into using Vuepress

 Install & Set up

First of all, we need Node.js installed on our system so go and install that first if you don't have it:

https://nodejs.org/en/download/

To install the Vuepress CLI we will need to do so on a global level, note below how we use the global flag for yarn or -g for NPM install.

yarn global add vuepress # OR npm install -g vuepress
Enter fullscreen mode Exit fullscreen mode

Create a directory
Next step is to create a directory and place yourself in it:

mkdir my-blog
cd my-blog
Enter fullscreen mode Exit fullscreen mode

Create some blog content

Next step is to create a README.md file like so:

# My blog

Welcome to my blog
Enter fullscreen mode Exit fullscreen mode

Build and Run our blog

Next step is to type vuepress dev in the terminal:

That did a whole slew of things. Adding a theme, applying plugins and ended up serving our page at http://localhost:8080

There we have it. Our first page.

THAT WAS FAST.

There is no denying that getting started was ridiculously easy.

However, a good static site generator should be able to do a few tricks so let's move on.

Creating static pages

We've already seen how our README.md file was turned into our default page but a blog most likely needs a couple of supporting pages like an about page or an article list page and so on and a menu would be nice.

Supporting pages

Let's create some supporting pages about.md and cv.md so our project now looks like this:

  • README.md, our default page
  • cv.md, a page containing our CV
  • about.md, a page containing more details about us

Our vuepress CLI command is already running in the background so when we created the above files with their content, it recompiled and we can now reach these pages at their filename, so http://localhost:8080/about.html and also http://localhost:8080/about. The latter is rewritten to the HTML version.

Just a quick reminder of our file structure so far:

Navigation

What about navigation then, how can I navigate between pages? Well lets look at an excerpt we found in the offical docs:

[Home](/) <!-- Sends the user to the root README.md -->
[foo](/foo/) <!-- Sends the user to index.html of directory foo -->
[foo heading anchor](/foo/#heading) <!-- Anchors user to a heading in the foo README file -->
[foo - one](/foo/one.html) <!-- You can append .html -->
[foo - two](/foo/two.md) <!-- Or you can append .md -->
Enter fullscreen mode Exit fullscreen mode

Ok, that means that we can link to the home page, to a landing page under a directory, to a specific anchor on a page and we can either type the .md or .html file ending.

Impressive let's try it out

Change README.md to say:

# My blog

Welcome to my blog

- [About](/about/)
- [CV](/cv/)
Enter fullscreen mode Exit fullscreen mode

lets also add:

[Home](/)
Enter fullscreen mode Exit fullscreen mode

to the bottom of about.md and cv.md. Now we have a fully working navigation system between our starting page and our two other pages.

Make it ready for production

So far we have been using vuepress dev to host the blog in the browser, but how do we actually make it ready for production, you know have it generate HTML, CSS and all those other bits? Cause if we look at our file structure right now it's just markdown files. The answer is a simple one, we type:

vuepress build
Enter fullscreen mode Exit fullscreen mode

Running said command will give you the following result

As indicated this will create a .vuepress directory and a dist directory under it

Above we can see that each of our markdown files has turned into HTML files. We have also gotten a assets subdirectory that contains, JavaScript, CSS, and images.

Almost too easy right?

 Blogging with Markdown

The main reason for us to start evaluating static site generators is finding something that supports our blogging effort. Let's try to list what features we want and things we need to tag each article with:

  • Topic tags, a way to give the page proper tags. It's important for a reader that they can easily see the content of an article.
  • Title, a descriptive title is key in having people select to read our article
  • Date, a date when it was written, it's important that we can assign a date to an article so we easily can see when we wrote it but also group/sort it by datee
  • Code highlight, this is a must. Reading long lines of source code is unbearable without highlight.

Write an article

Ok then, lets create a directory pages and start creating an article article.md. Let's add a few paragraphs and add som code like we are used to, now render it with vuepress dev:

Ok, that looks pretty good we got good looking rendering of the article text as some nice highlight of the code. But wait there is more. We can actually indicate specific rows like so:

WHAT...

I know right, so useful when you want to highlight new additions to the code. So how did we do this?

Normally we start a code portion with three ` backticks and then we add js for example to indicate the language, in this case, JavaScript. If we add something to this {}, we can indicate rows we want to highlight. To accomplish the above we typed js{3,4} after the backticks, to say that we wanted row 3 and 4 highlighted extra.

One more thing about code rendering is that we can enable line numbers by creating a file config.js under the directory .vuepress and set the lineNumbers property like so:

module.exports = {
  markdown: {
    lineNumbers: true
  }
}
Enter fullscreen mode Exit fullscreen mode

Frontmatter

This is the part of the article that goes at the top. We can use this to set things like:

  • title
  • path
  • keywords
  • publishing date
  • meta information

In Vuepress, we define this header, the frontmatter as YAML. It can look like this:

---
property: value
objectproperty: 
  prop: value
  prop2: value
---
Enter fullscreen mode Exit fullscreen mode

another example is:

title: Blogging Like a Hacker
lang: en-US
Enter fullscreen mode Exit fullscreen mode

So when does all of this matter?

First thing you need to know is that the underlying engine to this is Vue and Vue reads in all the different pages as objects and the front matter will be read in as an object.

If we then fill the front matter with interesting information like a title, keywords, publishing data and so on it will be very easy to create different components that can easily showcase your blog info like a list of articles, ordered by date or why not a tag cloud of the most used tags?

Ok, yea that sounds neat but how do I do that?

Read on and you will find out in the next section.

Custom controls

It should be said that there isn't many ready to use controls. However, given how easy it is to create those you don't really need them. Below we will show one simple component, so you get the hang of it and one little more advanced one.

Ok, we just introduced the concept of frontmatter a piece of YAML at the top of each article but how do we actually do something useful with it? The answer is we create custom controls.

Ok you said that already, but how?

Remember how I said everything is Vue.js? No? Well, it is. This means that if we create a directory components under the .vuepress directory, that was created when we ran vue build we can create Vue components that we can use everywhere on the site.

Really? I know how to create Vue components but how do I use them?

Let's start with creating a component About.vue

and give the file the following content:

// About.vue

<template>
  <div class="box">
    <h2>{{title}}</h2>
    {{message}}<button @click="click">Hi</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: 'about page'
    }
  },
  methods: {
    click() {
      alert('hi')
    }
  },
  props: ['title']
}
</script>
<style scoped>
 .box {
   padding: 20px;
   margin: 2px;
   box-shadow: 0 0 10px black;
 }
</style>
Enter fullscreen mode Exit fullscreen mode

The above looks like a quite ordinary Vue.js component that has a data property message, an input parameter title and a method click.

So you're saying I can use this in page?

Correct, just add it like so in about.md:

# About

<About title="about me" />
Enter fullscreen mode Exit fullscreen mode

Wait, so you are mixing markdown and HTML elements?

Yup, that just works. The result looks like this:

As you can see above this renders nicely and even the javascript part works as well when we click the button we get our alert window.

A list control

Ok then, we have created our first custom control which is really cool how easy that was but we haven't shown its real value, namely - how we can interact with the front matter.

What we will do is to create a list-control. A control that takes all the articles we have written and is able to present those in a list format. Let's do the following:

  1. Create a directory and articles, let's create a directory for our articles and let's call it pages next create typescript.md and vuex.md

  2. Add frontmatter, let's give them each a front matter that includes title, language, publishing data, and list of keywords

  3. Create a list component, let's create a list component that will be able to iterate over these articles, grab out the data it needs and format it nicely

Create a directory and articles
It should look like the below

Add frontmatter
We said before this is YAML so let's try to include all the needed info we mentioned like so:

---
title: My first article on TypeScript
lang: en-US
published: 2019-09-19
meta:
  keywords:
    - TypeScript
    - JavaScript
    - Tutorial
  description:
    content: Article on TypeScript
---
Enter fullscreen mode Exit fullscreen mode

Above is an example of one of the articles front matter, the one called typescript.md. Obviously, the articles title, publishing date, keywords and description would be different for another article. We can pretty much decide how we want to structure the above, as long as it is valid YAML.

Create a list component

There is one thing making all this possible. Vue components placed in the components directory have access to a site object like so this.$site. That site object has property pages which is a list containing all the pages you have so this.$site.pages.

That's awesome news, but we need to filter it a little because we only want pages in the pages directory. We can easily get that through the following code:

return this.$site.pages
  .filter(p => {
    return p.path.indexOf('/pages/') >= 0;
});
Enter fullscreen mode Exit fullscreen mode

Now is where our front matter comes in. Everything we define in a frontmatter of our page is being parsed as an object so when we loop through each page we have access to page.frontmatter. Therefore we can easily access our keywords with page.frontmatter.meta.keywords for example.

This means we can keep building out our list component to look like so:

// List.vue

<template>
  <div>
    <div class="article" v-for="page in files">
      <a v-bind:href="page.path">{{page.title}}</a>
      <div class="keywords">
        <span class="keyword" v-for="key in page.frontmatter.meta.keywords">{{key}}</span>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  computed: {
    files() {
      return this.$site.pages
        .filter(p => { 
          return p.path.indexOf('/pages/') >= 0;
        });
    }
  }
}
</script>
<style scoped>
  .article {
    margin-bottom: 20px;
    border-left: solid 5px #3eaf7c;
    padding: 20px;
  }
  .keywords {
    margin-top: 10px;
  }
  .keyword {
    padding: 5px;
    border-radius: 7px;
    font-size: small;
    background: #3eaf7c;
    margin-right: 5px;
    color: white;
    font-weight: 500;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Putting it in use it will render like so:

Now we can definitely improve the above by making sure when we click a keyword we end up with a list of articles matching that keyword and well, the sky is the limit. I will leave that exercise up to you. You should have been given enough information to know how to continue.

 Default theme

Theming itself is a big topic so I will leave custom theming for a future article. What I will describe is how you can use the current default theme and help make your site a little better looking.

It contains quite a lot of functionality, the full list of features is here:

https://vuepress.vuejs.org/default-theme-config/

One thing we can change is our homepage README.md. We can completely change it by adding frontmatter like so:

---
home: true
heroImage: ./logo.png
actionText: Get Started →
actionLink: /articles/
features:
- title: Blog
  details: This is a blog consisting of articles on various tech topics
- title: CV
  details: This is my CV
- title: About
  details: This tells you everything about who I am as a person
footer: MIT Licensed | Copyright © 2018-present Evan You
---
Enter fullscreen mode Exit fullscreen mode

This will give us a hero part of the page, a prominent piece of information followed by three columns features underneath. The above YAML will render like so:

NOTE, we haven't discussed how we manage assets and you might be wondering how it knew how to resolve heroImage that pointed to ./logo.png. We actually created a directory public under .vuepress and that's where we put our image.

I thought I would mention one more thing on our default theme and that is the menu functionality. We need to create a file config.js under .vuepress directory and make sure we set the property themeConfig like so:

module.exports = {
  themeConfig: {
    nav: [{
        text: 'Home',
        link: '/'
      },
      {
        text: 'About',
        link: '/about/'
      },
      {
        text: 'CV',
        link: '/cv/'
      },
      {
        text: 'Blog',
        link: '/articles/'
      },
      {
        text: 'Public Speaking',
        link: '/speaking/'
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Summary

That was all folks. :)

We went all the way from installing a CLI to learning some useful commands like vuepress dev to work with it. Furthermore, we also learned about vuepress build that would render the finished static files.

One of the really cool things we showed was how easy it was to create custom controls and finally, we showed how much functionality is already there when you used the default theme.

As a personal note, this is seriously the simplest static site generator I've ever used. Can't wait for this to be even better from its already very good level. TRY IT!

Top comments (14)

Collapse
 
michaelbrooks profile image
Michael Brooks

I actually did this myself last week because I had errors on my WordPress blog caused by a theme update. I tried restoring to a previous version, but nothing fixed it so I got fed up and went with VuePress.

It's really good, my blog is picking up the latest 20 posts, but I still have a lot to do in order to improve it like pagination and some meta-information.

I'm hosting it with Netlify which is incredible and using NetlifyCMS in order to add/edit new articles and it's working so well.

Speed has also been so much better, my WP site was rated in the 20s which is poor, but now my blog is around 66 on mobile and 98 on desktop, still room for improvement though.

Check it out here michaelbrooks.co.uk

Collapse
 
softchris profile image
Chris Noring

That sounds really great Michael. Thanks for sharing your story :)

Collapse
 
hoodlumz profile image
David Elstob

Nice article, Chris. Thanks.

Gone down the Vue route myself, as it seems easiest to learn out of the big JS frameworks, but with Gridsome.

Netlify is cool, too, especially the automatic build and deploy, and the approachable CMS. Plus the easiest forms ever.

However, when I added my own domain name it slowed down by 0.5 seconds due to redirecting. Possibly my fault? So I moved it to my new Hostinger Account where I got 4 years business hosting for £200.

I’ve had to sacrifice the automatic deployment, but instead I’m able to link up to Cloudflare and use my personal recipe for 0.2 seconds TTFB and 100/100 on PageSpeed Insights.

I followed an Andre Madarang tutorial to include Tailwind with Gridsome, but self-hosted Google fonts to save another 0.5 seconds. (First time I’ve actually saved time self-hosting fonts).

Full site loads in under a second... not bad for shared hosting.

davidelstob.com

Will be following this guide next. 👌🏽

Collapse
 
daveit profile image
Dave Porter • Edited

[UPDATE] Apologies, it suddenly started working - maybe the server needed restarting?

I got a bit lost when you got to About.md (after creating About.vue)
There was already an about.md
Do I create a new About.md (capital A) in a different place ?
Adding the content to the existing about.md displays just the word About ?
Do you have a github repository for this ?
TIA, Dave

Collapse
 
softchris profile image
Chris Noring

I've changed in the article. It should only be about.md. Sorry for the confusion. Here's a repo github.com/softchris/vuepress-demo

Collapse
 
daveit profile image
Dave Porter

Cheers Chris, appreciate the quick reply...
Dave

Collapse
 
gypsydave5 profile image
David Wickes

As a personal note, this is seriously the simplest static site generator I've ever used.

HOLD MY BEER 🍺

Collapse
 
softchris profile image
Chris Noring

interesting :)

Collapse
 
carlillo profile image
Carlos Caballero

Thanks Chris!

Collapse
 
softchris profile image
Chris Noring

:)

Collapse
 
bennadel profile image
Ben Nadel

Great write-up, thank you. I first tried Jekyll and was running in to all kinds of problems just getting hello-world to work. Comparatively, VuePress seems like a world easier.

Collapse
 
softchris profile image
Chris Noring

Thanks Ben. Yea VuePress is by far the easiest I've tried and adding custom components is also easy

Collapse
 
gautemeekolsen profile image
Gaute Meek Olsen

Thank you for the article! 🙌 Good writing.

Collapse
 
softchris profile image
Chris Noring

Appreciate that Gaute, thanks :)