How I Made a Personal Blog with Vue & Gridsome
| 7 min read
Update 2024: I’ve updated my site a lot since writing this. I switched to using Next.js a few years ago, and this year I’ve moved to Astro.
I always used a CMS like WordPress or Ghost to host my sites.
But I decided that I should make something ‘from scratch’ for a change. So I set out to build a personal blog — and I had to create all the features that I wanted “manually”.
This is how I did it.
Getting started
The first part was to decide which tools I’d use for the job.
I was already familiar with Vue from a previous project.
But I had heard great things about React as well…
Then I tried React. Didn’t take long for me to return to Vue.
It’s just so enjoyable to use. So that’s what I settled on.
I wanted it to be fast, and I had heard of this thing called static sites.
They were supposedly really fast. And of course, I wanted my site to be fast.
Why are static sites fast?
The content that you serve to the user is already generated.
That means no waiting for database queries. No waiting for template engines. The content is just sent straight to the user.
There are many other benefits. You can read about them here. I’ll talk about one of them a bit later; they’re easy to host.
Installing everything
I had most of the prerequisites before starting this project because of previous projects. But let’s take it from scratch.
You’ll need Node.js. Just install it from their site. I’m currently using version 12.14.1.
Alright. Now, Gridsome:
npm install --global @gridsome/cli
At this point, I created a new repository with the gridsome create PROJECTNAME
command.
I recommend that you just read the docs to get started. That’s what I did.
Which Node Modules to use?
I went through a lot of issues and steps to figure out which Node modules to install. I’ll spare you the story and instead just tell you what I use, and why.
- FontAwesome icons — I use these as social icons.
@gridsome/plugin-google-analytics
(link) — Google Analytics because I want to track how many people come and go.@gridsome/plugin-sitemap
(link) — For SEO. You make a sitemap and use the Google Search Console to let Google know which sites are on your page. It makes it easier for Google to ‘index you’, which makes it easier for people to find you. Win-win.@gridsome/remark-prismjs
(link) — For code highlighting.@gridsome/source-filesystem
(link) — My posts are written in markdown. This lets the website ‘detect’ those post files and feeds it into GraphQL. Using that, I don’t have to make a new page from scratch each time I want to post something. There are other sources that you can use, but I found this one to be the simplest to get started with.@gridsome/transformer-remark
(link) — This is there so the markdown can be translated into HTML.gridsome-plugin-netlify-cms
(link[now DecapCMS) — I use this to make it easier to manage all the markdown files for my posts.netlify-cms
(link) — See above
gridsome-remark-katex
(link) — I wanted to be able to write math equations on my website that aren’t ugly:compared to e = mc^2. gridsome-plugin-tailwindcss
(link) — I styled my website with Tailwind. It’s a bit more ‘manual’ compared to frameworks like Bootstrap. But I like it.
And for good measure, here is my package.json
dependencies:
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-brands-svg-icons": "5.13.0",
"@fortawesome/vue-fontawesome": "0.1.10",
"@gridsome/plugin-google-analytics": "0.1.1",
"@gridsome/plugin-sitemap": "0.3.0",
"@gridsome/remark-prismjs": "0.3.0",
"@gridsome/source-filesystem": "0.6.2",
"@gridsome/transformer-remark": "0.6.0",
"gridsome": "^0.7.0",
"gridsome-plugin-netlify-cms": "1.0.9",
"gridsome-remark-katex": "0.1.1",
"netlify-cms": "2.10.50",
"remark-html": "11.0.2",
"remark-html-katex": "2.0.1",
"remark-math": "2.0.1"
},
"devDependencies": {
"gridsome-plugin-tailwindcss": "2.2.48"
}
Setting up a blog
Setting up the source & transformer
It took a few steps to get this right.
When you want to share articles, you have to tell the @gridsome/source-filesystem
(link) plugin where to look.
Just follow the instructions to set it up on the plugin page. I’ll wait.
Now we’ll want to set some settings for remark. You can copy mine. Just put this into your module.exports
in the gridsome.config.js
file.
transformers: {
remark: {
externalLinksTarget: '_blank', // External links are opened in a new tab
plugins: [
'@gridsome/remark-prismjs', // Code highlighing
'remark-math', // Math
'remark-html-katex', // Math
'remark-html', // Math
]
}
},
These plugins also need themes. I ended up using the xonokai theme for code highlighting. Browse Prism themes here.
This is what I put in my main.js
file:
head.link.push({
rel: "stylesheet",
href: "https://cdn.jsdelivr.net/npm/[email protected]/themes/prism-xonokai.css",
});
head.link.push({
rel: "stylesheet",
href: "https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css",
});
Posting posts
This is the part where we tell the Netlify CMS where to look for posts. And where to put posts.
I followed the instructions on the gridsome-plugin-netlify-cms
(link) page. And then the Netlify CMS guide in the Gridsome Docs.
Now that we can use the CMS, it’s time to post something.
But wait…
Where will we display our posts?
Displaying posts
There are two things to do.
Currently, the source-filesystem
settings in gridsome.config.js
look something like this:
{
use: '@gridsome/source-filesystem',
options: {
typeName: 'Post',
path: './content/posts/**/*.md',
}
},
We also set a template for the Post type. It looks something like this:
templates: {
Post: '/blog/:title',
}
So the first thing we should do is set up a template.
This is done by making a .vue
file in the templates
folder. The Gridsome Docs has a great introduction to making these.
This is what I ended up with. Just ignore the NewsletterForm
component — that came later.
<template>
<Layout>
<div class="post-title">
<g-link to="/blog" class="font-medium">← Go Back</g-link>
<h1 class="text-4xl">{{$page.post.title}}</h1>
<p class="post-date">{{$page.post.date}} | {{$page.post.timeToRead}} min read</p>
</div>
<hr class="m-4">
<div class="post-content">
<p v-html="$page.post.content" />
</div>
<NewsletterForm class="mt-16" />
</Layout>
</template>
<page-query>
query Post ($path: String!) {
post: post (path: $path) {
id
title
content
date (format: "D MMMM YYYY")
timeToRead
}
}
</page-query>
<script>
import NewsletterForm from '../components/NewsletterForm';
export default {
metaInfo() {
return {
title: this.$page.post.title
};
},
components: {
NewsletterForm,
},
};
</script>
And now, where do we display those posts? I made a Blog.vue
page in the pages
folder. It looks like this:
<template>
<Layout>
<div class="post-list">
<div v-for="(edge, index) in $page.allPost.edges" :key="index" class="p-4 hover:shadow-xs rounded-lg">
<g-link :to="edge.node.path" class="noUnderlineOnHover" style="text-decoration:none;">
<h1 class="text-3xl font-normal" v-html="edge.node.title" />
<p class="text-lg font-normal noUnderlineOnHover">{{edge.node.date}} | {{edge.node.timeToRead}} min read</p>
<hr class="mt-2 mb-2 line ml-16 mr-16" />
<p class="text-lg font-normal italic noUnderlineOnHover" v-html="edge.node.description" />
</g-link>
</div>
</div>
</Layout>
</template>
<script>
export default {
metaInfo: {
title: "Blog"
}
};
</script>
<style>
h1 {
@apply leading-none;
@apply mb-2;
@apply mt-2;
}
.noUnderlineOnHover:hover {
text-decoration: none;
}
</style>
<page-query>
query {
allPost(order: DESC) {
totalCount
edges {
node {
id
title
timeToRead
description
date (format: "D MMMM YYYY")
path
}
}
}
}
</page-query>
Especially pay attention to the v-for
loop. This is I display all of my posts on the page. Way better than making a div
for each post, right?
Making it pretty
At this point, I set up a simple homepage in the index.vue
file. I created a basic navbar and linked to the blog page.
Creating the navbar took a lot of googling. I wanted it to be just right. Mobile friendly and all. That’s all I can encourage you to do, as well.
I made the navbar a component. I put that into my Default.vue
layout. Now it’s on every page — not just the homepage.
The basic layout of my site is very simple.
- Navbar
- Content
- Footer (which currently doesn’t have anything in it)
You can get pretty far with styling your site to your preferences. That’s what I did.
Going live
Man. I wanted to do everything. I wanted to host my site in a Docker container connected to other apps using Apache. Make it scalable. Set up the server myself using Digital Ocean.
But it’s a static site. That’s way overkill. At least for me.
So I ended up going for Netlify. Which is free.
You simply host your site in a repository, and then Netlify will automatically deploy it every time you post something or make an update.
Gridsome has a guide for Deploying to Netlify. And Netlify will help you along when you sign up.
Conclusion
This is all there really is to it. This is how I built the foundation for my personal website. I learned a lot from building it.
I’ve even built upon it since then; added components and new post types. Played with GraphQL. And so much more.
I encourage you to learn on your own. Be curious. If you have an idea, try to implement it.
It’s great to build something that you can be proud of. Something you use.
So if you haven’t already, go ahead and get started. Build your own website.
Liked this post? Join the newsletter.
Get notified whenever I post something new.