Hoe ik een blog heb gemaakt met Vue en Nuxt Content

Koen van Zeijl
September 14, 2020 7 min lezen
Koen van Zeijl

Introductie

Een tijdje geleden begon er een idee in mijn hoofd rond te dwalen, ik wilde namelijk een blog gaan schrijven. Maar heeft dat nog wel zin in 2020? Tegenwoordig schrijft bijna ieder bedrijf wel een blog, welke uit een lopen van unieke vakantieplekjes tot architectuuradvies. Na een tijdje met het idee te hebben gespeeld besloot ik om dit blog te gaan schrijven.

Het doel van mijn blog is om interessante artikelen over verschillende ICT-onderwerpen te schrijven. Er zijn al genoeg blogs die dit doen in het Engels, maar ik hoop dat ik mensen kan helpen die blogs het liefst in het Nederlands lezen.

De stack

Ik ben opzoek gegaan naar een manier om een blogsite op te zetten dat gebruikt maakt van een CMS om gemakkelijk nieuwe artikelen te kunnen plaatsen. Hiervoor heb ik besloten om een JAM stack te gebruiken. JAM staat voor Javascript, API en Markup. Hierbij worden de verschillende HTML-pagina's van tevoren gegenereerd en op de server geplaatst. Ik wilde mijn blogs schrijven in markdown zodat deze - samen met de overige code voor de website - ook in de repository worden bewaard. Hierdoor sla ik eigenlijk de A stap over waardoor ik een JM stack heb. Of is het nu een JMM stack door markdown? Wie weet.

Er zijn een paar redenen waarom ik voor een JAM stack koos:

  • Het is makkelijk en snel om een custom website te maken
  • JAM is een nieuw begrip voor mij waardoor ik nieuwe kennis op kan doen
  • Het kan serverless gehost worden wat zorgt voor minder setup, onderhoud en geld

Het plan en de uitdaging

Dit is wat ik in gedachte had voor mijn blog:

  • Super snelle rendering
  • Geoptimaliseerde SEO
  • Opgezet met NuxtJS
  • Blogs geschreven met markdown
  • Serverless hosten op netlify
  • Comments afhandelen met disqus

In het kort maak ik een blog met nuxt dat wordt gehost op netlify. De belangrijkste uitdaging was om dynamische elementen soepel op de achtergrond te laten werken, zoals tags of categorieën en sommige SEO-specifieke dingen, bijvoorbeeld het maken van een sitemap.

Waarom NuxtJS?

In verschillende projecten maak ik al gebruik van VueJS en het werkt perfect! Ook voor dit blog wilde ik VueJS gebruiken en wanneer je een statische website wilt maken komt NuxtJS al snel boven drijven. Na verder onderzoek te hebben gedaan bleek dat met behulp van nuxt/content blogs in markdown geschreven konden worden. Hiermee had ik één deel van mijn plan volbracht.

Het installatie en configuratie proces

Nuxt installeren

Voordat je een nuxt project kan maken dien je npx te kunnen gebruiken. Npx wordt standaarde geleverd met NPM >5.2.0. Het installeren van NuxtJS met behulp van de CLI is zeer gemakkelijk. Voer het volgende command uit npx create-nuxt-app <project-naam>. Tijdens dit proces kies je je package manager, linting, css framework en test opties naar voorkeur. Vervolgens kies je voor nuxt/content voor de markdown files en Static voor de rendering mode. Klaar!

Je kunt de blog site zien door de volgende commands uit te voeren:

$ cd <project-naam>
$ npm run dev

Je eerste post

Maak een /content/articles/ folder aan waar je blogs in komen te staan. Hieronder staat een voorbeeld blog bestand:

/content/articles/my-first-blog.md
---
title: Een blog opzetten met VueJS en NuxtJS
short: Hoe maak je een SEO geoptimaliseerde static file blog met NuxtJS en markdown bestanden. Samen met een sitemap.xml en tag pages.
image: /images/my-header-image.jpg
tags:
  - code
  - nuxt
  - markdown
---

## My blog title

De gebruikelijke **markdown** content.

Zoals je in het voorbeeld kan zien wordt er voor de header sectie gebruik gemaakt van YAML. In deze header wordt informatie gezet die hergebruikt kan worden op andere pagina's om bijvoorbeeld op de blog overzicht pagina een korte beschrijving te tonen. Voor de tags creër ik dynamische pagina's om alle blogs met hetzelfde onderwerp/tags weer te kunnen geven, het vinden van relevante blogs wordt hierdoor heel makkelijk.

De structuur van de url

Binnen een nuxt project wordt de url automatisch gegenereerd aan de hand van folder en bestand structuur binnen de /pages folder. Ik wilde mijn blogs het liefst in een aparte map hebben voor als ik mijn projecten ook op de site wil plaatsen. Hierom heb ik voor deze structuur gekozen:

koenvanzeijl.nl                     /// Homepagina
koenvanzeijl.nl/blog                /// Bekijk alle posts
koenvanzeijl.nl/blog/my-first-blog  /// Enkel blog
koenvanzeijl.nl/tag/vue             /// Voor alle gerelateerde blogs

Om tot deze url structuur te komen heb ik mijn project als volgt opgesteld. Bestanden die beginnen met _slug pakken alle requesten op in een dergelijke folder waarbij de slug als params.slug aan de file wordt meegegeven:

pages/index.vue             /// Homepagina
pages/blog/index.vue        /// Bekijk alle posts
pages/blog/_slug.vue        /// Enkel blog
pages/tag/_slug.vue         /// Voor alle gerelateerde blogs

Enkel blog bestand

Hieronder staat een versimpeld voorbeeld van een blog-pagina voor pages/_slug.vue. Het haalt de afbeelding, tags en titel op van de markdown meta informatie.

pages/_slug.vue
<template>
  <div>
    <div class="post-head">
      <h1>{{article.title}}</h1>
      <img :src="article.image" v-if="article.image">
      <div>
        <div class="date">{{article.createdAt}}</div>
        <div class="tags">
          <span v-for="tag in article.tags" :key="tag">
            <nuxt-link :to="'/tag/'+tag">\#{{tag}}</nuxt-link>
          </span>
        </div>
      </div>
    </div>
    <nuxt-content :document="article" />
  </div>
</template>
<script>
  export default {
    async asyncData ({ $content, params }) {
      const article = await $content('articles', params.slug).fetch()
      return article
    }
  }
</script>

Na het maken van deze file zul je je eerste blog kunnen zien door naar http://localhost:3000/blog/my-first-blog te navigeren, Tada je eerste blog! Even iets meer uitleg. In de file _slug.vue wordt het blog opgehaald uit de content/articles folder doormiddel van de functie asyncData(). Welk blog er opgehaald moet worden is doorgegeven via de params.slug parameter. Hierna kan article gebruikt worden in de view en kan de header informatie makkelijk opgehaald worden. Wat opvalt is dat ik gebruik maak van article.createdAt terwijl ik deze niet in de header informatie heb geplaatst. Dit is een van één van de eigeschappen die nuxt/content automatisch meegeeft.

Dit zijn de eigeschappen die standaard opgehaald kunnen worden door middel van nuxt/content

  • body: Blogtekst
  • dir: Folder
  • extension: Bestandsextensie (.md in dit voorbeeld)
  • path: Pad naar het blog
  • slug: De blog slug
  • toc: Een array welke de inhoudsopgave bevat
  • createdAt: De aanmaak datum
  • updatedAt: De datum van de laatste update

Blogoverzicht

Om alle blogs te bekijken (/pages/blog/index.vue) wordt de nuxt/content api gebruikt om data op te halen. Hieronder staat weer een voorbeeld.

/pages/blog/index.vue
<template>
  <div>
     <h1>Mijn blog posts:</h1>
     <ul>
        <li v-for="article in articles" :key="article.title">
           <nuxt-link to="#">{{article.title}}</nuxt-link>
        </li>
     </ul>
  </div>
</template>
<script>
  export default {
    async asyncData ({ $content, params }) {
      const articles = await $content('articles', params.slug)
        .only(['title', 'description', 'image', 'slug'])
        .sortBy('createdAt', 'asc')
        .fetch()

      return articles
    }
  }
</script>

De posts kunnen gemakkelijk gesorteerd worden door het gebruik van sortBy() uit de nuxt/content module. Je kunt dit view gemakkelijk uitbreiden door bijvoorbeeld de beschrijving te plaatsten in de v-for loop.

De tags

Het template van de tag pagina is bijna identiek aan de bovenstaande pagina. Het enige verschil is dat de tags worden gefilterd in de asyncData() methode.

/pages/tag/_slug.vue
<script>
export default {
  async asyncData ({ $content, params }) {
    const articles = await $content('articles')
      .where({
        tags: { $contains: params.slug }
      })
      .fetch()

    return {
      articles
    }
  }
}
</script>

De sitemap

Als laatste hebben we een sitemap nodig om het blog gemakkelijk te indexeren. Echter, de dynamische blog pagina's maken dit iets lastiger dus moeten we hiervoor een andere NuxtJS module installeren. Namelijk Nuxt/Sitemap voer hiervoor het volgende command uit npm install @nuxtjs/sitemap

Na het installeren van de sitemap module dien je alleen nog de nuxt config file aanpassen en je bent klaar.

nuxt.config.js
{
  ...
  modules: [
    '@nuxt/content',
    '@nuxtjs/sitemap' <-- Voeg deze toe aan de modules
  ],
  ...
  sitemap: {
    path: '/sitemap.xml',
    hostname: 'https://www.koenvanzeijl.nl',
    async routes () {
      const { $content } = require('@nuxt/content')
      const files = await $content({ deep: true }).only(['path']).fetch()

      return files.map(file => file.path === '/index' ? '/' : file.path)
    }
  },
}

Dat was het dan! We hebben zojuist een blog site gemaakt met verschillende met een pagina voor elk specifiek blog en een pagina voor het blog overzicht. Daarbij laten we deze pagina's ook generen in de sitemap.xml. Nu voeren we alleen nog het command npm run generate uit en je kan de website hosten waar je maar wilt! In een van de volgende blogs leg ik uit hoe ik mijn blog op netlify heb geplaatst.

Optimalisaties voor het blog

Zoals je hebt gelezen is dit een nieuw blog en kan het nog wel wat optimalisaties gebruiken. Een aantal ideeën zijn:

  • Optimaliseer website afbeeldingen in nuxt
  • Automatisch blogs op instagram plaatsen
  • Optimaliseer afbeeldingen binnen de markdown bestanden

Heb jij nog ideeën / tips of iets anders leuks? Laat het even weten in de comments.