Working with images in Nuxt Content
💡 Demo
Since this blog is also built using Nuxt Content, I'll be taking this article as an example of how I added the images to it: Creating a full-stack kanban board: the Vue SPA frontend
⚙️ Code
The example project's code is from this exact blog; the example code can be found here: woetflow-nuxt
Recently, I rebuilt my blog using Nuxt Content to be able to generate my blog as a static website, while also making my blogging life a little easier by using Markdown to write my posts.
The official Nuxt Blog has a great article that will take you through all the steps to set-up a basic blog with Nuxt Content, but it could've used some extra guidance on how to work with images for your articles, so that what we'll be covering here.
1. Images outside article content
Adding an image to your article outside the article content is relatively easy to do.
To add an image this way, we'll first add the image the static
directory.
To keep the static
directory more organised, I also add some sub-directories to manage the images:
Run: mkdir -p static/images/covers
So in static/images/covers
, I'll add an image named cover-image-working-with-images-in-nuxt-content.jpeg
.
To include this image as a cover so we can use it outside our main article content, all we need to do is include it as a custom injected variable in the YAML front matter inside the Markdown of our article:
content/articles/creating-a-full-stack-kanban-board-the-vue-spa-frontend.md:
---
coverImage: cover-image-creating-a-full-stack-kanban-board-the-vue-spa-frontend.jpeg
alt: cover-image-creating-a-full-stack-kanban-board-the-vue-spa-frontend
---
So we added added the name of our image with the key coverImage
and added the alt
text as well. Notice we didn't specify the path here, that's something we'll add later when displaying the image.
I chose not to add the path here, in case I might want to change the organisation of the image directories. Otherwise I'd need to adjust the path in every single article, instead of only in the component(s).
Now that we've added the image, if we want to display it we simply need to provide it to a src
attribute in an img
element. I'm using Vuetify for my blog so instead of the standard img
element, I'm using their v-img
component, but the usage of the src
attribute remains the same.
To use it as the cover for this article, we'll fetch the article's information from our API & then simply call article.coverImage
to get the information we added in the YAML front matter of our article.
pages/posts/_slug.vue:
<template>
<v-container>
<v-row justify="center">
<v-col cols="12" sm="12" md="8">
<article class="nuxt-article">
<v-card shaped>
<v-img
:src="`/images/covers/${article.coverImage}`"
class="pa-9 align-end"
gradient="to bottom left, rgba(100,115,201,.33), rgba(25,32,72,.8)"
min-height="300"
>
<h1 class="baseText--text">{{ article.title }}</h1>
<div class="caption baseText--text">
Posted on {{ formatDate(article.createdAt) }}
</div>
</v-img>
...
</v-card>
</article>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'ArticlePage',
async asyncData({ $content, params }) {
const article = await $content('articles', params.slug).fetch()
return { article }
},
methods: {
formatDate(date) {
const options = { day: 'numeric', month: 'long', year: 'numeric' }
return new Date(date).toLocaleDateString('en-GB', options)
}
}
}
</script>
After adding the image, it will now be displayed on the background like this:
2. Images inside the article content
Since we can't simply access the information from our YAML frontmatter or paste an image directly inside the Markdown content, we'll need to perform some initial setup by creating a separate component for our images.
Before we can start importing components, we need to make sure that components
is set to true
in nuxt.config.js
.
nuxt.config.js:
export default {
components: true,
}
Then we'll create a component that should be auto-imported. In order for auto-importing to work in nuxt-content
, we need to register the desired components globally by adding a global directory inside the components directory.
Run: mkdir components/global
And then we'll also create the file for the new ArticleImage
component.
Run: touch components/global/ArticleImage.vue
In this component, we'll add the following code:
<template>
<img :src="imgSrc()" :alt="alt" class="article-image" />
</template>
<script>
export default {
props: {
src: {
type: String,
required: true
},
alt: {
type: String,
required: true
}
},
methods: {
imgSrc() {
try {
return require(`~/assets/images/${this.src}`)
} catch (error) {
return null
}
}
}
}
</script>
So what did we do in this component?
-
We're rendering a standard HTML
img
element and we'll pass thesrc
andalt
attributes as props when we'll call the component from the Markdown content. -
In order for the
src
attribute to contain the correct URL, we'll first pass oursrc
prop into the methodimgSrc()
and generate the asset's URL withrequire( `~/assets/images/${this.src}`)
And that's all we need to do for this component to work!
Now whenever you want to add an image inside the Markdown content, you can simply call this component and add the props to it.
So if I want to display the image complete-kanban-board.jpg
that is located in assets/images/creating-a-full-stack-kanban-board-the-vue-spa-frontend
inside the content, I can simply do the following:
content/articles/creating-a-full-stack-kanban-board-the-vue-spa-frontend.md:
<article-image
src="creating-a-full-stack-kanban-board-the-vue-spa-frontend/complete-kanban-board.jpg"
alt="complete-kanban-board"
></article-image>