Skip to content

Commit

Permalink
Expose metadata types (#47630)
Browse files Browse the repository at this point in the history
### What?

- Besides existing `Metadata` type, expose `ResolvingMetadata` and `ResolvedMetadata` to `'next'`.
- Group `Robots` / `Sitemap` / `Manifest` these dynamic data routes types as `MetadataRoute` type and expose to `'next'`

### Why?

Allow users to type the more API easily, and grouping them to avoid type conflicts (e.g. we have `Robots` in metadata interface field, `MetadataRoute.Robots` can avoid conflicts)

### How?

Closes NEXT-908
  • Loading branch information
huozhi committed Mar 29, 2023
1 parent 46151dd commit facea99
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 26 deletions.
@@ -1,4 +1,4 @@
import type { Robots } from '../../../../lib/metadata/types/metadata-interface'
import type { MetadataRoute } from '../../../../lib/metadata/types/metadata-interface'
import { resolveRobots, resolveSitemap } from './resolve-route-data'

describe('resolveRouteData', () => {
Expand Down Expand Up @@ -30,7 +30,7 @@ describe('resolveRouteData', () => {
})

it('should error with ts when specify both wildcard userAgent and specific userAgent', () => {
const data1: Robots = {
const data1: MetadataRoute['robots'] = {
rules: [
// @ts-expect-error userAgent is required for Array<Robots>
{
Expand All @@ -43,14 +43,14 @@ describe('resolveRouteData', () => {
],
}

const data2: Robots = {
const data2: MetadataRoute['robots'] = {
rules: {
// Can skip userAgent for single Robots
allow: '/',
},
}

const data3: Robots = {
const data3: MetadataRoute['robots'] = {
rules: { allow: '/' },
}

Expand Down
@@ -1,12 +1,8 @@
import type {
Robots,
Sitemap,
} from '../../../../lib/metadata/types/metadata-interface'
import type { Manifest } from '../../../../lib/metadata/types/manifest-types'
import type { MetadataRoute } from '../../../../lib/metadata/types/metadata-interface'
import { resolveArray } from '../../../../lib/metadata/generate/utils'

// convert robots data to txt string
export function resolveRobots(data: Robots): string {
export function resolveRobots(data: MetadataRoute['robots']): string {
let content = ''
const rules = Array.isArray(data.rules) ? data.rules : [data.rules]
for (const rule of rules) {
Expand Down Expand Up @@ -47,7 +43,7 @@ export function resolveRobots(data: Robots): string {

// TODO-METADATA: support multi sitemap files
// convert sitemap data to xml string
export function resolveSitemap(data: Sitemap): string {
export function resolveSitemap(data: MetadataRoute['sitemap']): string {
let content = ''
content += '<?xml version="1.0" encoding="UTF-8"?>\n'
content += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
Expand All @@ -67,22 +63,25 @@ export function resolveSitemap(data: Sitemap): string {
return content
}

export function resolveManifest(data: Manifest): string {
export function resolveManifest(data: MetadataRoute['manifest']): string {
return JSON.stringify(data)
}

export function resolveRouteData(
data: Robots | Sitemap | Manifest,
fileType: 'robots' | 'sitemap' | 'manifest'
data:
| MetadataRoute['robots']
| MetadataRoute['sitemap']
| MetadataRoute['manifest'],
fileType: keyof MetadataRoute
): string {
if (fileType === 'robots') {
return resolveRobots(data as Robots)
return resolveRobots(data as MetadataRoute['robots'])
}
if (fileType === 'sitemap') {
return resolveSitemap(data as Sitemap)
return resolveSitemap(data as MetadataRoute['sitemap'])
}
if (fileType === 'manifest') {
return resolveManifest(data as Manifest)
return resolveManifest(data as MetadataRoute['manifest'])
}
return ''
}
13 changes: 10 additions & 3 deletions packages/next/src/lib/metadata/types/metadata-interface.ts
Expand Up @@ -28,6 +28,7 @@ import type {
Verification,
ThemeColorDescriptor,
} from './metadata-types'
import type { Manifest as ManifestFile } from './manifest-types'
import type { OpenGraph, ResolvedOpenGraph } from './opengraph-types'
import type { ResolvedTwitterMetadata, Twitter } from './twitter-types'

Expand Down Expand Up @@ -554,10 +555,16 @@ type RobotsFile = {
host?: string
}

type Sitemap = Array<{
type SitemapFile = Array<{
url: string
lastModified?: string | Date
}>

export type ResolvingMetadata = Promise<ResolvedMetadata>
export { Metadata, ResolvedMetadata, RobotsFile as Robots, Sitemap }
type ResolvingMetadata = Promise<ResolvedMetadata>
type MetadataRoute = {
robots: RobotsFile
sitemap: SitemapFile
manifest: ManifestFile
}

export { Metadata, ResolvedMetadata, ResolvingMetadata, MetadataRoute }
8 changes: 6 additions & 2 deletions packages/next/types/index.d.ts
Expand Up @@ -28,8 +28,12 @@ export type ServerRuntime = 'nodejs' | 'experimental-edge' | 'edge' | undefined
// @ts-ignore This path is generated at build time and conflicts otherwise
export { NextConfig } from '../dist/server/config'

// @ts-ignore This path is generated at build time and conflicts otherwise
export type { Metadata } from '../dist/lib/metadata/types/metadata-interface'
export type {
Metadata,
MetadataRoute,
ResolvedMetadata,
ResolvingMetadata, // @ts-ignore This path is generated at build time and conflicts otherwise
} from '../dist/lib/metadata/types/metadata-interface'

// Extend the React types with missing properties
declare module 'react' {
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts
@@ -1,4 +1,6 @@
export default function manifest() {
import { MetadataRoute } from 'next'

export default function manifest(): MetadataRoute['manifest'] {
return {
name: 'Next.js App',
short_name: 'Next.js App',
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts
@@ -1,4 +1,6 @@
export default function robots() {
import type { MetadataRoute } from 'next'

export default function robots(): MetadataRoute['robots'] {
return {
rules: [
{
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts
@@ -1,4 +1,6 @@
export default function sitemap() {
import { MetadataRoute } from 'next'

export default function sitemap(): MetadataRoute['sitemap'] {
return [
{
url: 'https://example.com',
Expand Down
@@ -1,8 +1,10 @@
import type { ResolvingMetadata } from 'next'

export default function Page() {
return null
}

export async function generateMetadata() {
export async function generateMetadata(_, __: ResolvingMetadata) {
return {
title: 'foo',
}
Expand Down

0 comments on commit facea99

Please sign in to comment.