类型
Next项目中有三个全局类型 LayoutProps PageProps RouteContext 后两个用于获取当前组件的路径参数 第一个还可以获取平行路由的插槽
这些类型都是next收集当前路径自动生成的 需要next dev/build之后才有
例如 在/[locale]/layout.tsx中
ts
export async function generateMetadata(context: PageProps<'/[locale]'>): Promise<Metadata>{
return {
// xxx
}
}
const RootLayout: FC<LayoutProps<'/[locale]'>> = async (props) => {
// 自带了默认插槽children 如果其他插槽也会携带
const { children, params } = props
const { locale } = await params
// ...xxx
return <html><body>{children}</body></html>
}
export default RootLayout
PageProps还可以用于page.tsx里
RouteContext则是专用于route.ts中
ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(req: NextRequest, context: RouteContext<'/[locale]/a'>) {
const { params } = context
const { locale } = params
return NextResponse.json({
// xxx
})
}
根据路径动态生成元数据
next允许动态生成元数据 不过这里的动态并不包含路径
举个例子 我的网站使用next-intl国际化了 不同语言会通过形如'/zh' '/en'的前缀进行区分
两种语言的manifest.json自然应该有所不同 也涉及到国际化的问题
此外 为了将应用转化为pwa 我还需要以output:'export'的方式导出 这就导致headers等一系列api都不可用 我必须为每个语言都生成一份静态的manifest.json 做法如下
ts
// src/app/[locale]/layout.tsx
export async function generateMetadata(props: LayoutProps<'/[locale]'>): Promise<Metadata> {
const { params } = props
const { locale } = await params
if (!hasLocale(routing.locales, locale)) {
return {}
}
const t = await getTranslations({ locale })
const app = t('metadata.app')
const app_default_title = t('metadata.app_default_title')
const app_title_template = `%s - ${app}`
const desc = t('metadata.desc')
return {
manifest: `/${locale}/manifest.json`,
}
}
浏览器读取/${locale}/manifest.json 实际上发起一个get请求 会得到这个GET函数返回的结果
ts
// src/app/[locale]/manifest.json/route.ts
import { hasLocale } from 'next-intl'
import { getTranslations } from 'next-intl/server'
import { notFound } from 'next/navigation'
import { type NextRequest, NextResponse } from 'next/server'
import { routing } from '@/i18n/routing'
export async function GET(req: NextRequest, ctx: RouteContext<'/[locale]/manifest.json'>) {
const { locale } = await ctx.params
if (!hasLocale(routing.locales, locale)) {
notFound()
}
const t = await getTranslations({ locale })
return NextResponse.json({
name: t('metadata.app'),
short_name: t('metadata.short_name'),
icons: [
{
src: '/logo.svg',
sizes: 'any',
type: 'image/svg+xml',
},
],
theme_color: '#FFFFFF',
background_color: '#FFFFFF',
start_url: `/${locale}`,
display: 'standalone',
orientation: 'portrait',
})
}
// 类似SSG
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }))
}
返回json的route会被转化为字符串 正好符合需求
其他类型的元数据类似