NuxtContent v2 to v3 Migration

When moving my blog files over to the new JAMStart repo and running the npm install
it warned of errors in Nuxt Content 2. I upgraded to Nuxt Content 3 with npm audit fix --force
and here are the issues I encountered and here is how I resolved them.
Migration and Installation
Nuxt Content v3 migration documentation can be found at:
Collections
The first concern was related to the breaking change introduced with Nuxt 3, i.e. collections.
WARN No content configuration found, falling back to default collection. In order to have full control over your collections, create the config file in project root.
Instead of defaulting to a single assumed collection of content stored in /content
folder, you now define multiple collections and for each specify the root directory, files, and schemas in a new configuration file content.config.ts
with the use of two new functions:
defineContentConfig()
defineCollection()
The basic structure of the content.config.ts
looks like this.
import { defineContentConfig, defineCollection } from '@nuxt/content'
export default defineContentConfig({
collections: {
content: defineCollection({
type: 'page',
source: '**/*.md'
})
}
})
It took me a while to figure out is that the key name is the directory name for the collection. For example, in the basic configuration above, the key content
said this collection root folder will be /content
. If you want to put your content files for your collection in a different directory, for example in the /static
directory, you would change the configuration like this.
export default defineContentConfig({
collections: {
static: defineCollection({
type: 'page',
source: '**/*.md'
})
}
})
Overlapping Collections
Note, as of v3.6.0
there is an issue with overlapping collection. It is noted in the documentation with
Currently, a document is designed to be present in only one collection at a time. If a file is referenced in multiple collections, live reload will not work correctly. To avoid this, it is recommended to use the exclude attribute to explicitly exclude a document from other collections using appropriate regex patterns.This topic is still under discussion in this issue: nuxt/content#2966.
Effectively for me this meant that I couldn't define a content
collection for /content
directory and blog
collection mapped to /content/blog
directory since the blog
directory was within content
directory. While there are ways to exclude and include using glob patters it was tricky.
Instead I achieved the same goal by specifying the /blog
directory within the path variable of the content
collection in the queryCollection.
const query = queryCollection('content')
.where('path', 'LIKE', '/blog/%')
.select('title', 'path', 'description', 'topic', 'dateCreated')
Collection Queries
queryCollection replaces queryContent()
queryCollection
FrontMatter Changes
I was using front matter variables to control how a page might behave. The variables manifest differently from NuxtContent v2 than in NuxtContent v3. Specifically, only the following front-matter variables are native by default:
title
description
navigation
My other top level front-matter variables were not available at the top level (there were actually defined within the meta
key, but these are consequently not easy to query against) You have to explicitly include them in the scheme
of your collection definition. For example, to include a dateCreated
date variable you have to add it to the schema
key in the defineCollection
in your content.config.ts
file.
export default defineContentConfig({
collections: {
content: defineCollection({
source: '**',
type: 'page',
// JAMStart custom Markdown Frontmatter Schema
schema: z.object({
dateCreated: z.date()
})
})
},
})
Then you can easily query against dateCreated
variable, and so forth.
Could not resolve import "#content/server"
Reviewing the NuxtContent documentation
$ Could not resolve import "#content/server" in C:\dev\JAMStart\server\routes\sitemap.xml.js using imports defined in C:\dev\JAMStart\package.json.
After investigation this appears to be an issue with the server/routes/sitemap.xml.js
file which I had added to support the sitemap
module. It's contents looked like this.
import { serverQueryContent } from '#content/server'
import { SitemapStream, streamToPromise } from 'sitemap'
export default defineEventHandler(async (event) => {
// Fetch all documents
const docs = await serverQueryContent(event).find()
const sitemap = new SitemapStream({
hostname: 'http://localhost:3001'
})
for (const doc of docs) {
sitemap.write({
url: doc._path,
changefreq: 'monthly'
})
}
sitemap.end()
return streamToPromise(sitemap)
})
The module in package.json that needed was sitemap
was v. 8.0.0 at NPM module site
{
// ...
"dependencies": {
// ...
"sitemap": "^8.0.0",
}
}
NuxtContent recommends @nuxtjs/sitemap
module which is a part of NuxtSEO
Steps to Resolve
- Uninstall "sitemap" -
npm uninstall sitemap
- Remove the
server/routes/sitemap.xml.js
file - Installed NuxtSEO "sitemap" -
npm install @nuxtjs/sitemap
- Added the sitemap information to a new file called
content.config.ts
in the root.
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { asSitemapCollection } from '@nuxtjs/sitemap/content'
export default defineContentConfig({
collections: {
content: defineCollection(
asSitemapCollection({
type: 'page',
source: '**/*.md'
}),
),
},
})