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 (although if you use @nuxtjs/sitemap it is different, see Sitemap content.config.ts)
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:
titledescriptionnavigation
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',
schema: z.object({
dateCreated: z.date()
})
})
},
})
Then you can easily query against dateCreated variable, and so forth.
#content/server error
An unexpected error I encountered was:
$ Could not resolve import "#content/server" in ...sitemap.xml.js using imports defined in ...package.json.
In reviewing the NuxtContent documentation and investigation, this was an issue with the server/routes/sitemap.xml.js file. This file was added to support the sitemap NPM module site 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)
})
Sitemap
Instead of sitemap, NuxtContent recommends @nuxtjs/sitemap for sitemap.xml.
Steps to Replace
- Uninstall "sitemap" -
npm uninstall sitemap - Remove the
server/routes/sitemap.xml.jsfile, i.e.git rm server/routes/sitemap.xml.js - Installed NuxtSEO "sitemap" -
npm install @nuxtjs/sitemap - Create a new file called
content.config.tsin the root of the project and add the following contents:
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { asSitemapCollection } from '@nuxtjs/sitemap/content'
export default defineContentConfig({
collections: {
content: defineCollection(
asSitemapCollection({
type: 'page',
source: '**/*.md'
}),
),
},
})
- Also upgrade your
nuxt.config.jsfile
- Due to current Nuxt Content v3 limitations, you must load the sitemap module before the content module.
- Add a Nitro prerender key
export default defineNuxtConfig({
modules: [
// ...
'@nuxtjs/sitemap',
'@nuxt/content' // <-- Must be after @nuxtjs/sitemap
// ...
],
// ...
nitro: {
prerender: {
autoSubfolderIndex: false,
crawlLinks: true,
routes: ['/sitemap.xml', '/']
}
}
// ...
})
- Finally, make sure your
nuxtand@nuxt/contentmodules are updated (without breaking changes) (I received an error until I made sure both of those and@nuxtjs/sitemapwere up to date.)
npm update nuxt @nuxt/content