Learn how to build a blog with Nuxt and Markdown
Integrate Markdown to manage form. Because implementing SSR on your own can be really tedious, Nuxt.js gives you full support out of the box and will. /nuxt/844cb81.js has the real markdown content! I think it's will be bad in SEO. I think it's will be bad in SEO. So I want a solution that can directly generate html that contains origin markdown content. Jun 04, 2020 Parsing Markdown Front Matter on Nuxt.js Extracting front matter from markdown posts using the frontmatter-markdown-loader package on Nuxt.js with ease. April 9, 2020 - 20 min read.
- Writing Your Blog Posts
- Creating the Blog Pages
Since writing this post, @nuxt/content has been released which makes it much easier to handle Markdown content with Nuxt. It also features hot reload in development and handles Vue components in Markdown!
I recently redesigned my website to showcase my projects and facilitate writing my new blog, which you’re reading right now! I wanted my new website to be performant, look good and be accessible to everyone. However, I also wanted my experience to be good — I wanted to be able to easily write new blog posts and for it to just work, without writing code for each new page I wanted to add to my website.
The Nuxt Big Thing #
At the moment, JAMstack seems to be all the rage, with an increasing number of websites being pre-rendered and served by a CDN. Building websites in this manner brings brilliant performance at a cheap cost; this website is hosted for free on Netlify, I just pay around $10 a year for my domain.
I decided to make my new website using Nuxt, a static site generator (amongst other things) which is built upon Vue. Nuxt has allowed me to build a performant website, with a great developer experience as well as user experience.
In this series of blog posts, I’m going to detail how I use Markdown for the content of my website, how I created a responsive, lazy image component, a dark theme and more.
Why Markdown? #
In my opinion, Markdown is a fantastic middle ground between writing markup (for example, HTML) and writing normal text. It allows you to express everything you might need in a blog post, like italics, emphasis,
inline code and images with a very concise syntax.
Loading Markdown Files #
In order to load Markdown files into Nuxt, we need to use a webpack loader. A webpack loader simply preprocesses a file, of a given type, to allow us to include it into our application. Conveniently,
frontmatter-markdown-loader does exactly what we want: it compiles our Markdown into HTML and then gives it to us as a Vue render function, including the front matter attributes from the top of the Markdown file. All we need to do is to tell webpack to use
frontmatter-markdown-loader whenever it sees a Markdown file, which we can do in
markdown-it to compile the Markdown. If you wish, you can pass your own options to
markdown-it or override the Markdown compilation completely with your Markdown compiler of choice, see the documentation on how to do this.
A Markdown Component #
Now we have told webpack how to load Markdown files, we need some way to show them to the user! Let’s create a Markdown component, I’ve just called mine
Markdown.vue for ease, within your
If you’re new to Vue, you might be surprised to see that our Markdown component doesn’t have a
<template> at the top. Instead of this, we have a
render function on the component which is used to render the HTML — behind the scenes, Vue converts all templates into render functions anyway. The render function takes a single argument, which is used to create elements. It’s convention to name this parameter
h, but it can be thought of as
Our Markdown component has a single required prop, a
markdown object, which contains the render functions exposed by
frontmatter-markdown-loader. These functions are actually passed as strings, so when the component is created we turn these back into functions by using
new Function(). Note I’ve added two comments for ESLint above these lines, as it’s considered bad practice to create functions in this way, but this is a valid case.
In our component’s render function, we simply call the template render function which we assigned when the component was created, or create an empty div if the template render function doesn’t exist. That’s pretty much it, add some styles to your Markdown component and you’re good to go!
Writing Your Blog Posts #
Now it’s time to write your first blog post and let Nuxt know that you’ve written one. Create a new directory in the root of your project called
contents and then create a Markdown file in there called
my-first-blog-post.md. At the start of the Markdown file, we’re going to write some front matter, which is just some extra information about our blog post, such as the date and title. Front matter is always placed at the top of the file and is denoted by the
--- three dashes. You can also put Vue components in your Markdown files, because we’re using Vue render functions, to give your blog posts special powers!
contents directory, we’re also going to create an
Nuxt Configuration #
We need to change the configuration of Nuxt slightly, to let it know about our blog posts. This is because the pages for our blog posts will be generated dynamically, i.e. we’re not manually creating a page for each of them. In
nuxt.config.js, we’re going to import the routes for our blog posts at the top, and then pass them to
generate.routes. This ensures that Nuxt will generate these pages when we run
Creating the Blog Pages #
Finally, we need to actually create the pages for our blog. Let’s create a new directory in the
pages directory called
blog and in this we’ll create two pages:
index.vue to list the blog posts and
_post.vue for the individual blog posts. Note that any dynamic page must be prefixed by an underscore.
Listing Your Blog Posts #
index.vue, we’re going to use
asyncData to load the blog posts before the component is created. We’ll map over the
postSlugs array which we exported earlier, importing each blog post; this will use
frontmatter-markdown-loader which we also set up earlier. In this page, we only need the attributes of each blog post so we’ll return just the attributes and then sort the posts depending on their date.
Showing an Individual Blog Post #
The last thing we need to do is create the page for the individual blog posts, the content itself! In a dynamic route such as
_post.vue, the route parameters are passed into the context of
asyncData: we can access the slug of our post (
params.post. If you named your dynamic route
_slug.vue instead, then you would access the route as
When we have the slug of the blog post, we’re going to import the corresponding Markdown file, again which will be loaded using
frontmatter-markdown-loader. Note that if the user has requested a blog post which doesn’t exist, for example
/blog/non-existent-blog-post, this would try to load
contents/non-existent-blog-post.md which would error. We need to catch this error and instead render the error page by calling
error() with the status code and error message.
The template of our blog post displays the title and the date from the attributes of the Markdown file, then uses our Markdown component to render the body of the blog post!
Nuxt Js Markdown
Wrapping Up #
That’s everything! When you’ve finished all of these steps, you’ll be able to write blog posts in Markdown and see them appear in your
/blog page. Clicking on a blog post will take you to
/blog/name-of-blog-post, where you’ll see your blog post compiled from the Markdown using Vue’s render functions.
Feel free to contact me if you have any queries or feedback and keep an eye out for my next blog post!