From aedcece9c74b705808a0ef2a8871a0fe663bb790 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Tue, 28 Mar 2023 23:15:51 +0200 Subject: [PATCH 1/3] Expose metadata types --- .../metadata/resolve-route-data.test.ts | 8 ++++---- .../loaders/metadata/resolve-route-data.ts | 20 ++++++++----------- .../lib/metadata/types/metadata-interface.ts | 13 +++++++++--- packages/next/types/index.d.ts | 9 +++++++-- .../metadata-dynamic-routes/app/manifest.ts | 4 +++- .../metadata-dynamic-routes/app/robots.ts | 4 +++- .../metadata-dynamic-routes/app/sitemap.ts | 4 +++- .../app/type-checking/generate-async/page.tsx | 4 +++- 8 files changed, 41 insertions(+), 25 deletions(-) diff --git a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts index a83999efc7d02..64c6692a5ed72 100644 --- a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts +++ b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts @@ -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', () => { @@ -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 { @@ -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: '/' }, } diff --git a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts index d9589370a7f5e..26a74cca9a0dc 100644 --- a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts +++ b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts @@ -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) { @@ -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 += '\n' content += '\n' @@ -67,22 +63,22 @@ 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, + data: MetadataRoute.Robots | MetadataRoute.Sitemap | MetadataRoute.Manifest, fileType: 'robots' | 'sitemap' | 'manifest' ): 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 '' } diff --git a/packages/next/src/lib/metadata/types/metadata-interface.ts b/packages/next/src/lib/metadata/types/metadata-interface.ts index bf4dd99bf2788..559bed5a2907b 100644 --- a/packages/next/src/lib/metadata/types/metadata-interface.ts +++ b/packages/next/src/lib/metadata/types/metadata-interface.ts @@ -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' @@ -554,10 +555,16 @@ type RobotsFile = { host?: string } -type Sitemap = Array<{ +type SitemapFile = Array<{ url: string lastModified?: string | Date }> -export type ResolvingMetadata = Promise -export { Metadata, ResolvedMetadata, RobotsFile as Robots, Sitemap } +type ResolvingMetadata = Promise +namespace MetadataRoute { + export type Robots = RobotsFile + export type Sitemap = SitemapFile + export type Manifest = ManifestFile +} + +export { Metadata, ResolvedMetadata, ResolvingMetadata, MetadataRoute } diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 711cbacf434d7..3aeb3b8913b0b 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -28,8 +28,13 @@ 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, +} from // @ts-ignore This path is generated at build time and conflicts otherwise +'../dist/lib/metadata/types/metadata-interface' // Extend the React types with missing properties declare module 'react' { diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts index 736cffed86b60..aa9acc113b498 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts +++ b/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', diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts index 749881098a1ea..ed0b3cdf7d272 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts +++ b/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: [ { diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts index 7b1426aa7ea45..ff5e3ddff866f 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts +++ b/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', diff --git a/test/e2e/app-dir/metadata/app/type-checking/generate-async/page.tsx b/test/e2e/app-dir/metadata/app/type-checking/generate-async/page.tsx index d17bc146fd295..3eac399debb7d 100644 --- a/test/e2e/app-dir/metadata/app/type-checking/generate-async/page.tsx +++ b/test/e2e/app-dir/metadata/app/type-checking/generate-async/page.tsx @@ -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', } From 302be08d6d08c6f4e50068a07b1316d778fc87c6 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 29 Mar 2023 00:01:36 +0200 Subject: [PATCH 2/3] prettier --- packages/next/types/index.d.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 3aeb3b8913b0b..d2afeeab06a52 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -32,9 +32,8 @@ export type { Metadata, MetadataRoute, ResolvedMetadata, - ResolvingMetadata, -} from // @ts-ignore This path is generated at build time and conflicts otherwise -'../dist/lib/metadata/types/metadata-interface' + 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' { From babb1bf3496524eead5a21969bf0d58ca5aa4461 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 29 Mar 2023 00:33:28 +0200 Subject: [PATCH 3/3] use type --- .../metadata/resolve-route-data.test.ts | 6 +++--- .../loaders/metadata/resolve-route-data.ts | 19 +++++++++++-------- .../lib/metadata/types/metadata-interface.ts | 8 ++++---- .../metadata-dynamic-routes/app/manifest.ts | 2 +- .../metadata-dynamic-routes/app/robots.ts | 2 +- .../metadata-dynamic-routes/app/sitemap.ts | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts index 64c6692a5ed72..f24da86a19bcf 100644 --- a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts +++ b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.test.ts @@ -30,7 +30,7 @@ describe('resolveRouteData', () => { }) it('should error with ts when specify both wildcard userAgent and specific userAgent', () => { - const data1: MetadataRoute.Robots = { + const data1: MetadataRoute['robots'] = { rules: [ // @ts-expect-error userAgent is required for Array { @@ -43,14 +43,14 @@ describe('resolveRouteData', () => { ], } - const data2: MetadataRoute.Robots = { + const data2: MetadataRoute['robots'] = { rules: { // Can skip userAgent for single Robots allow: '/', }, } - const data3: MetadataRoute.Robots = { + const data3: MetadataRoute['robots'] = { rules: { allow: '/' }, } diff --git a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts index 26a74cca9a0dc..a149dc1755d69 100644 --- a/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts +++ b/packages/next/src/build/webpack/loaders/metadata/resolve-route-data.ts @@ -2,7 +2,7 @@ import type { MetadataRoute } from '../../../../lib/metadata/types/metadata-inte import { resolveArray } from '../../../../lib/metadata/generate/utils' // convert robots data to txt string -export function resolveRobots(data: MetadataRoute.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) { @@ -43,7 +43,7 @@ export function resolveRobots(data: MetadataRoute.Robots): string { // TODO-METADATA: support multi sitemap files // convert sitemap data to xml string -export function resolveSitemap(data: MetadataRoute.Sitemap): string { +export function resolveSitemap(data: MetadataRoute['sitemap']): string { let content = '' content += '\n' content += '\n' @@ -63,22 +63,25 @@ export function resolveSitemap(data: MetadataRoute.Sitemap): string { return content } -export function resolveManifest(data: MetadataRoute.Manifest): string { +export function resolveManifest(data: MetadataRoute['manifest']): string { return JSON.stringify(data) } export function resolveRouteData( - data: MetadataRoute.Robots | MetadataRoute.Sitemap | MetadataRoute.Manifest, - fileType: 'robots' | 'sitemap' | 'manifest' + data: + | MetadataRoute['robots'] + | MetadataRoute['sitemap'] + | MetadataRoute['manifest'], + fileType: keyof MetadataRoute ): string { if (fileType === 'robots') { - return resolveRobots(data as MetadataRoute.Robots) + return resolveRobots(data as MetadataRoute['robots']) } if (fileType === 'sitemap') { - return resolveSitemap(data as MetadataRoute.Sitemap) + return resolveSitemap(data as MetadataRoute['sitemap']) } if (fileType === 'manifest') { - return resolveManifest(data as MetadataRoute.Manifest) + return resolveManifest(data as MetadataRoute['manifest']) } return '' } diff --git a/packages/next/src/lib/metadata/types/metadata-interface.ts b/packages/next/src/lib/metadata/types/metadata-interface.ts index 559bed5a2907b..23762a6a5cb53 100644 --- a/packages/next/src/lib/metadata/types/metadata-interface.ts +++ b/packages/next/src/lib/metadata/types/metadata-interface.ts @@ -561,10 +561,10 @@ type SitemapFile = Array<{ }> type ResolvingMetadata = Promise -namespace MetadataRoute { - export type Robots = RobotsFile - export type Sitemap = SitemapFile - export type Manifest = ManifestFile +type MetadataRoute = { + robots: RobotsFile + sitemap: SitemapFile + manifest: ManifestFile } export { Metadata, ResolvedMetadata, ResolvingMetadata, MetadataRoute } diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts index aa9acc113b498..cff52e74ae12d 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/manifest.ts @@ -1,6 +1,6 @@ import { MetadataRoute } from 'next' -export default function manifest(): MetadataRoute.Manifest { +export default function manifest(): MetadataRoute['manifest'] { return { name: 'Next.js App', short_name: 'Next.js App', diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts index ed0b3cdf7d272..80436c28dc90d 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/robots.ts @@ -1,6 +1,6 @@ import type { MetadataRoute } from 'next' -export default function robots(): MetadataRoute.Robots { +export default function robots(): MetadataRoute['robots'] { return { rules: [ { diff --git a/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts b/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts index ff5e3ddff866f..7e609558e30c4 100644 --- a/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts +++ b/test/e2e/app-dir/metadata-dynamic-routes/app/sitemap.ts @@ -1,6 +1,6 @@ import { MetadataRoute } from 'next' -export default function sitemap(): MetadataRoute.Sitemap { +export default function sitemap(): MetadataRoute['sitemap'] { return [ { url: 'https://example.com',