Skip to content

Commit

Permalink
feat: Nuxt Content v3 (#382)
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw authored Jan 20, 2025
1 parent 2331126 commit 300481a
Show file tree
Hide file tree
Showing 17 changed files with 1,487 additions and 2,816 deletions.
16 changes: 6 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,23 @@ on:
- '**/README.md'
- 'docs/**'

permissions:
contents: read # access to check out code and install dependencies

jobs:
build:
runs-on: ${{ matrix.os }}

strategy:
matrix:
node-version: [22.x]
# os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest]
fail-fast: false
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js LTS
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: lts/*
registry-url: https://registry.npmjs.org/
cache: pnpm

Expand Down
11 changes: 11 additions & 0 deletions build.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
declaration: true,
rollup: {
emitCJS: true,
},
entries: [
'src/const.ts',
{ input: 'src/content', name: 'content' },
],
externals: [
'h3',
'std-env',
'nitropack',
'consola',
'@nuxt/content',
'zod',
'ofetch',
'consola/utils',
'nuxt',
Expand Down
1 change: 1 addition & 0 deletions content.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './dist/content'
22 changes: 11 additions & 11 deletions docs/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
SiteConfigModule,
SitemapModule,
} from '../src/const'
import { asSeoCollection } from '../src/content'
import { logger } from './logger'

function getSubModuleCollection(m: NuxtSEOModule) {
Expand All @@ -34,34 +35,34 @@ function getSubModuleCollection(m: NuxtSEOModule) {
}
// use github source
logger.info(`🔗 Docs source \`${m.slug}\` using GitHub: ${m.repo}`)
return defineCollection({
return defineCollection(asSeoCollection({
type: 'page',
source: {
repository: `https://github.com/${m.repo}`,
include: 'docs/content/**/*.md',
prefix: `/docs/${m.slug}`,
},
})
}))
}

export default defineContentConfig({
collections: {
nuxtSeo: defineCollection({
nuxtSeo: defineCollection(asSeoCollection({
type: 'page',
source: {
include: '**/*.md',
cwd: resolve('content/nuxtSeo'),
prefix: '/docs/nuxt-seo',
},
}),
})),
robots: getSubModuleCollection(RobotsModule),
sitemap: getSubModuleCollection(SitemapModule),
ogImage: getSubModuleCollection(OgImageModule),
schemaOrg: getSubModuleCollection(SchemaOrgModule),
linkChecker: getSubModuleCollection(LinkCheckerModule),
seoUtils: getSubModuleCollection(SeoUtilsModule),
siteConfig: getSubModuleCollection(SiteConfigModule),
learn: defineCollection({
learn: defineCollection(asSeoCollection({
type: 'page',
source: {
include: '**/*.md',
Expand All @@ -76,8 +77,8 @@ export default defineContentConfig({
readTime: z.string(),
ogImageComponent: z.string().optional(),
}),
}),
root: defineCollection({
})),
root: defineCollection(asSeoCollection({
type: 'page',
source: {
include: '**/*.md',
Expand All @@ -92,8 +93,8 @@ export default defineContentConfig({
readTime: z.string(),
ogImageComponent: z.string().optional(),
}),
}),
recipes: defineCollection({
})),
recipes: defineCollection(asSeoCollection({
type: 'page',
source: {
include: '**/*.md',
Expand All @@ -106,8 +107,7 @@ export default defineContentConfig({
updatedAt: z.string().optional(),
keywords: z.array(z.string()).optional(),
readTime: z.string(),
ogImageComponent: z.string().optional(),
}),
}),
})),
},
})
97 changes: 97 additions & 0 deletions docs/content/nuxtSeo/2.guides/2.nuxt-content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: Nuxt Content
description: Integrating Nuxt SEO with Nuxt Content.
---

## Introduction

Most Nuxt SEO modules integrates with Nuxt Content out of the box.

- Nuxt Robots: `robots` ([docs](/docs/robots/guides/content))
- Nuxt Sitemap: `sitemap` ([docs](/docs/sitemap/guides/content))
- Nuxt OG Image: `ogImage` ([docs](/docs/og-image/integrations/content))
- Nuxt Schema.org: `schemaOrg` ([docs](/docs/schema-org/guides/content))
- Nuxt Link Checker: Uses content APIs to check links

For Nuxt Content v3 you would need to configure the modules to work with Nuxt Content individually, however, Nuxt SEO
provides a way to configure all modules at once.

For Nuxt Content v2, please see the individual module documentation for how to configure them.

## Setup Nuxt Content v3

In Nuxt Content v3 we need to use the `asSeoCollection()`{lang="ts"} function to augment any collections
to be able to use the SEO modules.

```ts [content.config.ts]
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { asSeoCollection } from '@nuxtjs/seo/content'

export default defineContentConfig({
collections: {
content: defineCollection(
asSeoCollection({
type: 'page',
source: '**/*.md',
}),
),
},
})
```

To ensure the tags actually gets rendered you need to ensure you're using the SEO composable.

```vue [[...slug].vue]
<script setup lang="ts">
import { queryCollection, useRoute } from '#imports'
const route = useRoute()
const { data: page } = await useAsyncData(`page-${route.path}`, () => {
return queryCollection('content').path(route.path).first()
})
if (page.value?.ogImage) {
defineOgImage(page.value?.ogImage) // <-- Nuxt OG Image
}
// Ensure the schema.org is rendered
useHead(page.value.head || {}) // <-- Nuxt Schema.org
useSeoMeta(page.value.seo || {}) // <-- Nuxt Robots
</script>
```

Due to current Nuxt Content v3 limitations, you must load the Nuxt SEO module before the content module.

```ts
export default defineNuxtConfig({
modules: [
'@nuxtjs/seo',
'@nuxt/content' // <-- Must be after @nuxtjs/seo
]
})
```

## Usage

For the full options available for each module, please see the individual module documentation.

```md
---
ogImage:
component: HelloWorld
props:
title: "Hello World"
description: "This is a description"
image: "/hello-world.png"
sitemap:
lastmod: 2025-01-01
robots: index, nofollow
schemaOrg:
- "@type": "BlogPosting"
headline: "How to Use Our Product"
author:
type: "Person"
name: "Jane Smith"
datePublished: "2023-10-01"
---

# Hello World
```
32 changes: 16 additions & 16 deletions docs/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,18 @@ export default defineNuxtConfig({
'@vueuse/nuxt',
'@nuxthub/core',
'@nuxt/fonts',
'@nuxt/content',
'@nuxt/scripts',
'@nuxt/image',
// maybe buggy
'nuxt-rebundle',
'nuxt-build-cache',
NuxtSEO,
'@nuxt/content',
async (_, nuxt) => {
nuxt.hooks.hook('nitro:init', (nitro) => {
// from sponsorkit
nitro.options.alias.sharp = 'unenv/runtime/mock/empty'
nitro.options.alias.pnpapi = 'unenv/runtime/mock/empty' // ?
nitro.options.alias['#content/server'] = resolve('./server/content-v2')
nitro.hooks.hook('compiled', async (_nitro) => {
const routesPath = resolve(nitro.options.output.publicDir, '_routes.json')
if (existsSync(routesPath)) {
Expand Down Expand Up @@ -66,12 +65,7 @@ export default defineNuxtConfig({
},
},

robots: {
disableNuxtContentIntegration: true,
},

sitemap: {
strictNuxtContentPaths: true,
xslColumns: [
{ label: 'URL', width: '100%' },
],
Expand Down Expand Up @@ -258,6 +252,12 @@ export default defineNuxtConfig({
},
},

linkChecker: {
report: {
markdown: true,
},
},

routeRules: {
// for doc linking purposes
'/robots': { redirect: { to: '/docs/robots/getting-started/installation', statusCode: 301 } },
Expand Down Expand Up @@ -345,7 +345,6 @@ export default defineNuxtConfig({

ogImage: {
zeroRuntime: true,
strictNuxtContentPaths: true,
fonts: [
'Hubot+Sans:400',
'Hubot+Sans:700',
Expand All @@ -364,26 +363,27 @@ export default defineNuxtConfig({
provider: 'iconify',
},

seo: {
meta: {
themeColor: [
{ content: '#18181b', media: '(prefers-color-scheme: dark)' },
{ content: 'white', media: '(prefers-color-scheme: light)' },
],
},
},

app: {
pageTransition: {
name: 'page',
mode: 'out-in',
},
head: {
seoMeta: {
themeColor: [
{ content: '#18181b', media: '(prefers-color-scheme: dark)' },
{ content: 'white', media: '(prefers-color-scheme: light)' },
],
},
templateParams: {
separator: '·',
},

bodyAttrs: {
class: 'antialiased font-sans text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-900',
},

},
},

Expand Down
20 changes: 10 additions & 10 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,41 @@
"@iconify-json/noto": "^1.2.2",
"@iconify-json/ph": "^1.2.2",
"@iconify-json/radix-icons": "^1.2.2",
"@iconify-json/simple-icons": "^1.2.19",
"@iconify-json/simple-icons": "^1.2.20",
"@iconify-json/uil": "^1.2.3",
"@iconify-json/unjs": "^1.2.0",
"@iconify-json/vscode-icons": "^1.2.10",
"@inspira-ui/plugins": "^0.0.1",
"@nuxt/content": "3.0.0-alpha.8",
"@nuxt/devtools": "1.6.0",
"@nuxt/content": "^3.0.0",
"@nuxt/devtools": "2.0.0-beta.3",
"@nuxt/fonts": "^0.10.3",
"@nuxt/image": "^1.9.0",
"@nuxt/scripts": "^0.9.5",
"@nuxt/ui": "3.0.0-alpha.6",
"@nuxt/ui-pro": "2.0.0-alpha.6",
"@nuxthub/core": "0.8.6",
"@nuxtjs/mdc": "^0.12.1",
"@unovis/vue": "1.4.4",
"@nuxthub/core": "^0.8.12",
"@nuxtjs/mdc": "^0.13.1",
"@unovis/vue": "^1.5.0",
"@vueuse/core": "^12.4.0",
"@vueuse/motion": "^2.2.6",
"@vueuse/nuxt": "^12.4.0",
"case-police": "^0.7.2",
"clsx": "^2.1.1",
"consola": "^3.4.0",
"markdownlint-cli": "^0.43.0",
"nuxt": "^3.15.1",
"nuxt": "^3.15.2",
"nuxt-build-cache": "^0.1.1",
"nuxt-content-twoslash": "^0.1.2",
"nuxt-lodash": "^2.5.3",
"nuxt-rebundle": "^0.0.2",
"octokit": "^4.1.0",
"ofetch": "^1.4.1",
"radix-vue": "^1.9.12",
"shiki": "^1.26.2",
"shiki": "^2.0.0",
"shiki-transformer-color-highlight": "^0.2.0",
"sponsorkit": "^0.16.2",
"sponsorkit": "^16.3.0",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"wrangler": "^3.101.0"
"wrangler": "^3.103.2"
}
}
7 changes: 0 additions & 7 deletions docs/server/content-v2.ts

This file was deleted.

Loading

0 comments on commit 300481a

Please sign in to comment.