Rendering content with Nuxt3
- 📅
- 📝 749 words
- 🕙 4 minutes
- 📦 Development
- 🏷️ Nuxt, webdev
I’ve been a big fan of Nuxt2 and Nuxt3 is definitely a learning curve and I have to admit the documentation is a bit lacking — lots of small fragments and many different ways to do things.
What I wanted
I basically wanted a simple example or page that looks at the slug, finds the markdown content for it and renders it unless it’s missing in which case returns a 404. Oh, and I want to use Typescript.
Simple right? Yeah, not so much if you want to use…
The Composition API
The composition API (that’s the <script setup>
bit) is the new hotness but means you have to use different functions and return different structures from Nuxt3. The other API is still around means a lot of the samples you find online aren’t going to work. Things like useAsyncData
instead of the old asyncData
etc. It can be quite overwhelming when all the snippets are using a different mechanism that doesn’t easily port.
Grabbing the slug
You now need to useRoute
to get the current route and then you can grab parameters off it. If like me you want to use Typescript then you can install nuxt-typed-router which will let you specify the route name into useRoute
and as a result will strongly-type the parameters so route.params.slug
autocompletes and compiles without warnings.
Nice.
Querying content
The content system has changed quite a lot. The new Nuxt3 content does have a lot of stuff that just helps you now such as components that can go and get the page and render it for you a single step — and the markdown itself can specify the template. I’ll dig more into that in the future but for now I just wanted to get the article so get used to things like find()
and findOne()
which you access through queryContent
inside of useAsyncData
.
Note that the first parameter into useAsyncData
is effectively a cache key for rendering the page so don’t let it collide with a component that’s also rendering on that page.
404 when not found
None of the snippets I could find showed how to return a 404 with the composition useAsyncData
pattern (the non-composition one returns an error object which makes life simpler).
createError
is your friend and just throw what it creates with the right statusCode should the content result be missing.
Output Front Matter elements
This turned out to be an easy part — binding is pretty much the same. {{ something }}
for inner-Text and v-bind:attribute
for attributes. The only oddity here was having to ?.
the properties because Typescript believes they can be null.
Render the Markdown
This isn’t too tricky. There are a whole bunch of components now for the Nuxt Content package but these two work well if you want a level of control. <ContentRender>
provides some of the basic infrastructure/setup while ContentRendererMarkdown actually does the Markdown conversion. I could have put the <h1>
for example inside <ContentRenderer>
but this looked fine.
Set the page title etc.
Finally we need to set the page title and the composition API useHead
is what you’re after here. We also set the page meta description from the post article Front Matter.
Show me the code
Okay, here’s the sample for displaying a single blog post using the composition API and all we talked about.
<template>
<article>
<h1>{{ post?.title }}</h1>
<ContentRenderer :value="post">
<ContentRendererMarkdown :value="post" />
</ContentRenderer>
</article>
</template>
<script setup lang="ts">
const route = useRoute('blog-slug')
const { data: post } = await useAsyncData('post/' + route.params.slug, () => queryContent('blog', route.params.slug).findOne())
if (post.value == null) throw createError({ statusCode: 404, message: 'Post not found' })
useHead({
title: post.value.title,
meta: [
{
hid: 'description',
name: 'description',
content: post.value.description,
},
})
</script>
You would name this file /pages/blog/[slug].vue
If you’re using JavaScript…
If you don’t want to use TypeScript remove lang="ts"
as well as the blog-slug
from useRoute
and all should be fine. Obviously also don’t install nuxt-typed-router either.
Have fun!
0 responses to Rendering content with Nuxt3