Create a static blog with Markdown + Nuxt

create a static blog with markdown and nuxt

Introduction:

If you're someone who has wanted a static blog without having to setup and use a CMS(Content Management System) or external service to get your content, then you were in the same boat that I was in until I found this process. In this article I'm going to summarize and break down the steps I took to create this site and how I configured Nuxt to generate a static site that serves dynamic markdown content.

Getting started:

So first things first, we need to initialize our Nuxt project. You can run either of the following:

  • yarn:
    yarn create nuxt-app <my-static-blog>
  • npx:
    npx create-nuxt-app <my-static-blog>

Running either of those will take you through the Nuxt scaffolding CLI and will give you options to choose how you want your Nuxt application setup. This is the setup I'll be using:

creating a markdown blog with nuxt

Next we want to install:
@nuxtjs/markdownit - A markdown parser which will convert your markdown into html, and allow for use in your Vue components.

  • yarn: yarn add @nuxtjs/markdownit
  • npm: npm i @nuxtjs/markdownit

Configuration:

Once you have that installed, go into your nuxt.config.js file and add the newly installed package to your modules property array like so:

nuxt.config.js

  ...
  /*
  ** Nuxt.js modules
  */
  modules: [
    '@nuxtjs/pwa',
    ['@nuxtjs/markdownit', { linkify: true }]
  ],
  ...

After you've done this, the next thing you want to do is get your project directory set up to look something like this:

nuxt static blog directory setup

  • static/articles/... - Where we will store our markdown files.
  • pages/article/_slug.vue - Component to dynamically render markdown content associated with it's own route.

_slug.vue

  <template>
   <div class="article-container">
     <!-- eslint-disable-next-line vue/no-v-html -->
     <div v-html="content.default" />
   </div>
  </template>

  <script>
  export default {
   async asyncData({ params }) {
     const article = await import(`~/static/articles/${params.slug}.md`)
     return {
         content: article
       }
     }
  }
  </script>

Here we get to make use of Nuxt's asyncData function, which is only available for components in your pages directory.

asyncData is processed on the server side to make the data available before your page component is initiated, it receives context as it's first argument, which is used to fetch your components data.

Inside asyncData we are going to use await to import the files from our static/articles/... directory, that holds our markdown files, and render it in the component using Vue's v-html directive to render our HTML, if we were to use double mustache syntax it would interpret the data as plain text.

After that, go back to your config file and add this:

nuxt.config.js

  // Require Node's file system module:
  const fs = require('fs');

  // Array that will contain your route objects:
  const routesArray = [];

  // Read files in the ./static/articles directory:
  const files = fs.readdirSync('./static/articles');

  // Array of routes to be generated by Nuxt:
  const createRoutesArray = () => {
    files.forEach((file) => {

      let name = file.substr(0, file.lastIndex0f('.'));
      let route = '/article/' +  name;

      routesArray.push(route);
    })
  }

  // Function to be called later in our generate property:
  const getSlugs = (article, index) => {
    let slug = article.substr(0, article.lastIndexOf('.'))
    return `/article/${slug}`
  }

   export default {
     ...
   }

There is a little bit going on here, so let's summarize it. We are reading the markdown files in the articles directory and then creating an array contained with each file. getSlugs is a function that just returns a url slug, which we will end up calling below in our routes function:

nuxt.config.js

  /*
  ** Generate static routes:
  */
  generate: {
    routes: function() {
      return articles.map(getSlugs)
    }
  },
  /* Build configuration */

Add the generate property to your config file above your build configuration and inside will be a function that will return an array of dynamic routes for Nuxt to generate based on the names of your markdown files.

/* Example:
** ./static/articles/nuxt_md_blog.md => yoursite.com/article/nuxt_md_blog
*/

Once all this is done, go to your terminal and run either of the following below to test that your routes were created locally.

  • yarn: yarn dev
  • npm: npm run dev

visit: localhost:3000/article/<markdown_file>

To spin up your static deployment bundle run:

  • yarn: yarn generate && yarn start
  • npm: npm run generate && npm run start

Conclusion:

That's it, you should now have a static blog site up and running, the only thing left for you to do is style your page and optionally highlight your markdown syntax.

For markdown hightlighting I've seen people use: highlight.js
For this site(elijahkotyluk.com/article/nuxt_md_blog), I used SCSS :)

If you have any feedback, feel free to reach out:
email: elijah@elijahkotyluk.com twitter: @elijahdavidk