# VuePress Tutorial 15 - Blog Plugin

By: Jay the Code Monkey
Posted: Sep 21, 2022 Updated: Apr 18, 2023

# What We're Doing

It's now time to install and begin the process of configuring @vuepress/plugin-blog (opens new window). We're going to start by describing the main features provided by the plugin. Then we'll go over the installation and usage. After going over the installation and usage, we'll describe the concepts and implementation of document classification, permalinks, and directory classification.

If you're interested you can check out the blog plugin code here (opens new window). You can also check out the @vuepress/theme-blog (opens new window) if you're interested in learning more about it. We won't be discussing the blog theme in detail since we're using the default theme (opens new window).

Make sure you start the local development server which should be running at http://localhost:8080/ (opens new window) to see the changes we'll be making to the site. If the changes aren't appearing after you save them, then try restarting your local development server.

You can view all of the code in this tutorial by going to the tutorial-15 branch of the code-monkeys-blog-tutorials (opens new window) repository.

# Features

The blog plugin provides the following main features:

We'll be discussing pagination and the Client API in more detail in future tutorials.

# Installation

We're now ready to discuss the installation of the plugin.

# Using the Tutorials Repo

If you're following along with the tutorials, then when you switch to the tutorial-15 branch you can run the following command to install the package instead of running the installation command:

This will ensure you have the same version used in the blog since the command uses the version specified in the yarn.lock file during the installation.

# Using the Installation Command

To install the blog plugin in your own project you can run the following command:

Installing the Same Blog Plugin Version

If you want to ensure you're installing the same version being used in the tutorials and blog, then run yarn upgrade @vuepress/plugin-blog@1.9.4.

# Updated package.json File

After installing the plugin, the package.json file should look something like this:

# Automatically Installed Plugins

When installing the blog plugin you may have noticed the following plugins also get installed:

These plugins provide features that are common to blogs, so they're included in the installation of the blog plugin. Including these plugins in the installation of the blog plugin saves you the time of searching for plugins that provide these common features as well as from having to separately install each plugin.

The plugins will only be used though if you enable them in the config.js file.

They can also be installed as standalone plugins, so you don't need to use the blog plugin to use them for your site.

We'll be discussing these plugins in more detail in future tutorials.

# Usage

To use the blog plugin we need to add the following to the config.js file which should now look something like this:

# Document Classification

The blog plugin provides a document classifier which is a set of functions that handles the classifications of pages with the same characteristics.

These characteristics for pages in a blog may consist of:

  • Pages in the same directory, e.g., a _posts directory.
  • Pages containing the same frontmatter key, e.g., tag: js which signifies those pages contain content related to js, i.e., JavaScript.

Another common requirement is the ability to group all pages as well as pages with specific tags for pagination.

Before discussing directory classification, we're going to first define what a permalink is as well as discuss how they're built and configured. This will give us a better understanding of how the blog plugin uses permalinks to build customizable links for blog posts which is preferable to using the default way of creating links.

A permalink is a URL that is intended to remain unchanged for a long time. This leads to links that are less susceptible to link rot (opens new window) which is when a link ceases to point to its originally targeted web page due to the page being relocated to a new address or becoming permanently unavailable.

VuePress v1 (opens new window) provided support for creating customizable links by introducing the ability to build permalinks.

# Template Variables

We're able to build permalinks by using the following template variables:

Variable Description
:year Published year of post (4-digit)
:month Published month of post (2-digit)
:i_month Published month of post (without leading zeros)
:day Published day of post (2-digit)
:i_day Published day of post (without leading zeros)
:slug Slugified file path (without extension)
:regular Permalink generated by VuePress by default.

# Default Configuration

The default configuration for permalinks is /:regular.

The :regular template variable will first check if the Markdown files in the documents directory which in our case is the docs directory are index files, i.e., README.md or index.md.

  • If they're index files, they get converted to URLs without extensions that are based on the file hierarchy.
  • If they're not index files, they get converted to URLs with html extensions that are based on the file hierarchy.

Let's look at some examples to make this clearer where the file paths are relative to the documents directory which again in our case is the docs directory:

Relative Path Page Routing
/README.md /
/foo/README.md /foo/
/foo.md /foo.html
/foo/bar.md /foo/bar.html

Using Vue Files

Files with a vue extension follow the same conventions described for Markdown files above, e.g., /README.vue gets converted to /.

You can take a look at fileToPath.ts (opens new window) to see the code that handles converting files to paths.

# Global Configuration

To globally change the default configuration for permalinks for your site you can add the permalink property to the config.js file.

We can build a permalink to use in the config.js file by using the template variables.

For example we can use the template variables to build the following permalink: /:year/:month/:day/:slug.

We can then set this as the value for the permalink property in the config.js file:

Using the Default Configuration

We'll be leaving the permalink property with the default value of /:regular, and we'll use the configuration provided by the blog plugin to customize the permalinks for each blog post.

# Local Configuration

It's also possible to set a permalink locally for a single page which overrides any globally set configuration.

This is done be setting the permalink property in the frontmatter of the Markdown file:

This will set the permalink property to be /using-a-local-permalink instead of following the global configuration.

Now that we have an understanding of document classification and permalinks, let's move onto the directory classifier which handles classifying pages placed in the same directory.

# Directory Classification

First we need to create a directory that will contain all of the pages we want to classify. To do this we'll create a _posts directory inside of the docs directory. The docs directory for your site should now look something like this:

. ├── docs │ ├── .vuepress │ ├── _posts │ ├── icons │ └── README.md

Next, we'll create the following example pages in the _posts directory:

  • 2020-07-03-example-page-1.md
  • 2021-11-16-example-page-2.md
  • 2022-05-08-example-page-3.md

The _posts directory for your site should now look like this:

. ├── _posts │ ├── 2020-07-03-example-page-1.md │ ├── 2021-11-16-example-page-2.md │ └── 2022-05-08-example-page-3.md

By default VuePress (opens new window) will create the following page URLs since it uses the /:regular template variable described above when building the links:

  • /_posts/2020-07-03-example-page-1.html
  • /_posts/2021-11-16-example-page-2.html
  • /_posts/2022-05-08-example-page-3.html

You should now be able to navigate to these pages in the browser:

The default behavior is fine for creating the main pages on the site, but having the ability to build customizable links for blog posts is preferable.

After using the configuration provided by the blog plugin to build customized permalinks, the page URLs will look like this:

  • /2020/07/03/example-page-1/
  • /2021/11/16/example-page-2/
  • /2022/05/08/example-page-3/

To build these customizable links we're going to start setting up the directory classifier configuration in the config.js file.

# directories

First, we'll add the directories property which is used to create the directory classifier.

The expected type is a DirectoryClassifier[], and the default value is [].

Here's the updated config.js file:

# id

Next, we'll add the id property which sets a unique id for the current classifier. We'll use a value of posts.

The expected type is a string, and the default value is undefined.

Here's the updated config.js file:

# dirname

Now, we'll add the dirname property which is used to identify the directory we want to classify. This is the _posts directory we created earlier.

The expected type is a string, and the default value is undefined.

Here's the updated config.js file:

After setting the dirname property, the page URLs get set to the customized permalinks mentioned above:

The customized permalinks are actually built using properties we haven't discussed yet. The blog plugin sets default values that don't need to be explicitly set in the config.js file. We'll be discussing these other properties and their default values below.

The previously provided links still work because they get converted to the customized permalinks when navigating to those pages.

Unknown Custom Element

When navigating to the links if you inspect the browser then go to the Console, you'll see the following error: Unknown custom element: <Post>.

This error is occurring because the plugin is looking for a Post layout component in the layouts directory which we haven't created yet.

Before creating a Post layout component to fix this error, we're going to first add the path property.

# path

The path property specifies the entry page, also known as the list page for the current classifier. This page will be used to display your posts as a paginated list.

The expected type is a string, and the default value is /${id}/ where ${id} is the value of the id property we previously set.

This means you don't need to explicitly set the path property if you're going to be using the same value as the id property. We'll be using a value of /posts/ for the path property, so we don't need to explicitly set the property. However, we're going to explicitly set the property because it allows us to have a quick reference to the property and its value.

Here's the updated config.js file:

You can navigate to the entry page by using the following link:

Notice this link has the value of the path property in it, i.e., /posts/. This is the same link we set in the navbar dropdown menu for All Posts, so you can click on that link to navigate to the entry page which will eventually be a paginated list of all of the posts.

Currently, when navigating to that link the Layout component provided by the default theme (opens new window) is displayed. The blog plugin will fallback to using the Layout component if it's unable to find an IndexPost layout component in the layouts directory.

This means we can create an IndexPost layout component that specifically handles the layout of the paginated list of all of the posts instead of using the Layout component.

# Creating the IndexPost Layout

To create the IndexPost layout component we're going to add an IndexPost.vue file inside of the layouts directory. The layouts directory for your site should now look something like this:

. ├── layouts │ ├── GlobalLayout.vue │ └── IndexPost.vue

We're going to begin the development of the IndexPost layout component by adding template, script, and style tags:

We'll continue developing the IndexPost layout component in a future tutorial.

# layout

We're now ready to add the layout property which is used to specify which layout to use for the entry page.

The expected type is a string, and the default value is 'IndexPost' || 'Layout'.

From the default value we can see why the entry page originally defaulted to using the Layout component before we created the IndexPost layout component. Since the blog plugin looks for the IndexPost layout component by default, we don't need to explicitly set the property. However, we're going to explicitly set it because this gives us a quick reference to the property and its value.

It's also possible to use a custom value for the layout property, e.g., you could use a value of MyIndexPost which you would have to explicitly set in the config.js file. Then you would have to create a MyIndexPost.vue file inside of the layouts directory.

Here's the updated config.js file:

We're now going to fix the Unknown Custom Element error we got after adding the dirname property. To fix this error we need to create the previously mentioned Post layout component.

# Creating the Post Layout

The Post layout component is used to handle the layout for individual post pages.

To create the Post layout component we're going to add a Post.vue file inside of the layouts directory. The layouts directory for your site should now look something like this:

. ├── layouts │ ├── GlobalLayout.vue │ ├── IndexPost.vue │ └── Post.vue

We're going to begin the development of the Post layout component by adding template, script, and style tags:

We'll continue developing the Post layout component in a future tutorial.

# itemLayout

We're now ready to add the itemLayout property which is used to specify which layout to use for individual post pages.

The expected type is a string, and the default value is 'Post'.

From the default value we can see why the blog plugin looks for a Post layout component. Since the blog plugin looks for the Post layout component by default, we don't need to explicitly set the property. However, we're going to explicitly set it because this once again gives us a quick reference to the property and its value.

It's also possible to use a custom value for the itemLayout property, e.g., you could use a value of MyPost which you would have to explicitly set in the config.js file. Then you would have to create a MyPost.vue file inside of the layouts directory.

Here's the updated config.js file:

We're now ready to add the itemPermalink property which is used to build customized permalinks for each blog post.

The expected type is a string, and the default value is '/:year/:month/:day/:slug'.

From the default value we can see how the blog plugin built the customized permalinks after only setting the dirname property. Since the blog plugin uses the value we currently want, we don't need to explicitly set the property. However, just like the other properties we're going to explicitly set it because this gives us a quick reference to the property and its value.

Here's the updated config.js file:

# Summary of URLs and Layouts

Here's a table that summarizes the relationship between the page URLs the blog plugin builds using customized permalinks and the layout components.

URLs Layouts
/posts/ IndexPost (falls back to Layout)
/2020/07/03/example-page-1/ Post
/2021/11/16/example-page-2/ Post
/2022/05/08/example-page-3/ Post

# Next Steps

In the next tutorial we'll be discussing the configuration for the pagination property as well as how to access the pagination data in the layout components by using the Client API.

Made by & for Code Monkeys 🐵