Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Nuxt Content v3 #382

Merged
merged 14 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading