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
Official Docs
It contains a lot of info on how to get started, config your site, use themes, work with markdown and so on.Article on creating a Custom VuePress theme
Excellent article by my colleague Jen Looper how to create a custom theme.How to create a Custom component
This excellent article from Raymond really made it click for me how to author a custom component
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:
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
Create a directory
Next step is to create a directory and place yourself in it:
mkdir my-blog
cd my-blog
Create some blog content
Next step is to create a README.md
file like so:
# My blog
Welcome to my blog
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 -->
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/)
lets also add:
[Home](/)
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
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
}
}
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
---
another example is:
title: Blogging Like a Hacker
lang: en-US
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>
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" />
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:
Create a directory and articles, let's create a directory for our articles and let's call it
pages
next createtypescript.md
andvuex.md
Add frontmatter, let's give them each a front matter that includes title, language, publishing data, and list of keywords
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
---
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;
});
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>
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:
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
---
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/'
}
]
}
}
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)
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
That sounds really great Michael. Thanks for sharing your story :)
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. 👌🏽
[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
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
Cheers Chris, appreciate the quick reply...
Dave
HOLD MY BEER 🍺
The World's Simplest "Static Site Generator"
David Wickes ・ Oct 19 '18 ・ 3 min read
interesting :)
Thanks Chris!
:)
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.
Thanks Ben. Yea VuePress is by far the easiest I've tried and adding custom components is also easy
Thank you for the article! 🙌 Good writing.
Appreciate that Gaute, thanks :)