next
Version:
The React Framework
198 lines (197 loc) • 9.59 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
import React, { Suspense, cache, cloneElement } from 'react';
import { AppleWebAppMeta, FormatDetectionMeta, ItunesMeta, BasicMeta, ViewportMeta, VerificationMeta, FacebookMeta, PinterestMeta } from './generate/basic';
import { AlternatesMetadata } from './generate/alternate';
import { OpenGraphMetadata, TwitterMetadata, AppLinksMeta } from './generate/opengraph';
import { IconsMetadata } from './generate/icons';
import { resolveMetadata, resolveViewport } from './resolve-metadata';
import { MetaFilter } from './generate/meta';
import { isHTTPAccessFallbackError } from '../../client/components/http-access-fallback/http-access-fallback';
import { createServerSearchParamsForMetadata } from '../../server/request/search-params';
import { createServerPathnameForMetadata } from '../../server/request/pathname';
import { isPostpone } from '../../server/lib/router-utils/is-postpone';
import { MetadataBoundary, ViewportBoundary, OutletBoundary } from '../framework/boundary-components';
// Use a promise to share the status of the metadata resolving,
// returning two components `MetadataTree` and `MetadataOutlet`
// `MetadataTree` is the one that will be rendered at first in the content sequence for metadata tags.
// `MetadataOutlet` is the one that will be rendered under error boundaries for metadata resolving errors.
// In this way we can let the metadata tags always render successfully,
// and the error will be caught by the error boundary and trigger fallbacks.
export function createMetadataComponents({ tree, pathname, parsedQuery, metadataContext, getDynamicParamFromSegment, errorType, workStore, serveStreamingMetadata }) {
const searchParams = createServerSearchParamsForMetadata(parsedQuery, workStore);
const pathnameForMetadata = createServerPathnameForMetadata(pathname, workStore);
async function Viewport() {
const tags = await getResolvedViewport(tree, searchParams, getDynamicParamFromSegment, workStore, errorType).catch((viewportErr)=>{
// When Legacy PPR is enabled viewport can reject with a Postpone type
// This will go away once Legacy PPR is removed and dynamic metadata will
// stay pending until after the prerender is complete when it is dynamic
if (isPostpone(viewportErr)) {
throw viewportErr;
}
if (!errorType && isHTTPAccessFallbackError(viewportErr)) {
return getNotFoundViewport(tree, searchParams, getDynamicParamFromSegment, workStore).catch(()=>null);
}
// We're going to throw the error from the metadata outlet so we just render null here instead
return null;
});
return tags;
}
Viewport.displayName = 'Next.Viewport';
function ViewportWrapper() {
return /*#__PURE__*/ _jsx(ViewportBoundary, {
children: /*#__PURE__*/ _jsx(Viewport, {})
});
}
async function Metadata() {
const tags = await getResolvedMetadata(tree, pathnameForMetadata, searchParams, getDynamicParamFromSegment, metadataContext, workStore, errorType).catch((metadataErr)=>{
// When Legacy PPR is enabled metadata can reject with a Postpone type
// This will go away once Legacy PPR is removed and dynamic metadata will
// stay pending until after the prerender is complete when it is dynamic
if (isPostpone(metadataErr)) {
throw metadataErr;
}
if (!errorType && isHTTPAccessFallbackError(metadataErr)) {
return getNotFoundMetadata(tree, pathnameForMetadata, searchParams, getDynamicParamFromSegment, metadataContext, workStore).catch(()=>null);
}
// We're going to throw the error from the metadata outlet so we just render null here instead
return null;
});
return tags;
}
Metadata.displayName = 'Next.Metadata';
function MetadataWrapper() {
// TODO: We shouldn't change what we render based on whether we are streaming or not.
// If we aren't streaming we should just block the response until we have resolved the
// metadata.
if (!serveStreamingMetadata) {
return /*#__PURE__*/ _jsx(MetadataBoundary, {
children: /*#__PURE__*/ _jsx(Metadata, {})
});
}
return /*#__PURE__*/ _jsx("div", {
hidden: true,
children: /*#__PURE__*/ _jsx(MetadataBoundary, {
children: /*#__PURE__*/ _jsx(Suspense, {
name: "Next.Metadata",
children: /*#__PURE__*/ _jsx(Metadata, {})
})
})
});
}
function MetadataOutlet() {
const pendingOutlet = Promise.all([
getResolvedMetadata(tree, pathnameForMetadata, searchParams, getDynamicParamFromSegment, metadataContext, workStore, errorType),
getResolvedViewport(tree, searchParams, getDynamicParamFromSegment, workStore, errorType)
]).then(()=>null);
// TODO: We shouldn't change what we render based on whether we are streaming or not.
// If we aren't streaming we should just block the response until we have resolved the
// metadata.
if (!serveStreamingMetadata) {
return /*#__PURE__*/ _jsx(OutletBoundary, {
children: pendingOutlet
});
}
return /*#__PURE__*/ _jsx(OutletBoundary, {
children: /*#__PURE__*/ _jsx(Suspense, {
name: "Next.MetadataOutlet",
children: pendingOutlet
})
});
}
MetadataOutlet.displayName = 'Next.MetadataOutlet';
return {
Viewport: ViewportWrapper,
Metadata: MetadataWrapper,
MetadataOutlet
};
}
const getResolvedMetadata = cache(getResolvedMetadataImpl);
async function getResolvedMetadataImpl(tree, pathname, searchParams, getDynamicParamFromSegment, metadataContext, workStore, errorType) {
const errorConvention = errorType === 'redirect' ? undefined : errorType;
return renderMetadata(tree, pathname, searchParams, getDynamicParamFromSegment, metadataContext, workStore, errorConvention);
}
const getNotFoundMetadata = cache(getNotFoundMetadataImpl);
async function getNotFoundMetadataImpl(tree, pathname, searchParams, getDynamicParamFromSegment, metadataContext, workStore) {
const notFoundErrorConvention = 'not-found';
return renderMetadata(tree, pathname, searchParams, getDynamicParamFromSegment, metadataContext, workStore, notFoundErrorConvention);
}
const getResolvedViewport = cache(getResolvedViewportImpl);
async function getResolvedViewportImpl(tree, searchParams, getDynamicParamFromSegment, workStore, errorType) {
const errorConvention = errorType === 'redirect' ? undefined : errorType;
return renderViewport(tree, searchParams, getDynamicParamFromSegment, workStore, errorConvention);
}
const getNotFoundViewport = cache(getNotFoundViewportImpl);
async function getNotFoundViewportImpl(tree, searchParams, getDynamicParamFromSegment, workStore) {
const notFoundErrorConvention = 'not-found';
return renderViewport(tree, searchParams, getDynamicParamFromSegment, workStore, notFoundErrorConvention);
}
async function renderMetadata(tree, pathname, searchParams, getDynamicParamFromSegment, metadataContext, workStore, errorConvention) {
const resolvedMetadata = await resolveMetadata(tree, pathname, searchParams, errorConvention, getDynamicParamFromSegment, workStore, metadataContext);
const elements = createMetadataElements(resolvedMetadata);
return /*#__PURE__*/ _jsx(_Fragment, {
children: elements.map((el, index)=>{
return /*#__PURE__*/ cloneElement(el, {
key: index
});
})
});
}
async function renderViewport(tree, searchParams, getDynamicParamFromSegment, workStore, errorConvention) {
const resolvedViewport = await resolveViewport(tree, searchParams, errorConvention, getDynamicParamFromSegment, workStore);
const elements = createViewportElements(resolvedViewport);
return /*#__PURE__*/ _jsx(_Fragment, {
children: elements.map((el, index)=>{
return /*#__PURE__*/ cloneElement(el, {
key: index
});
})
});
}
function createMetadataElements(metadata) {
return MetaFilter([
BasicMeta({
metadata
}),
AlternatesMetadata({
alternates: metadata.alternates
}),
ItunesMeta({
itunes: metadata.itunes
}),
FacebookMeta({
facebook: metadata.facebook
}),
PinterestMeta({
pinterest: metadata.pinterest
}),
FormatDetectionMeta({
formatDetection: metadata.formatDetection
}),
VerificationMeta({
verification: metadata.verification
}),
AppleWebAppMeta({
appleWebApp: metadata.appleWebApp
}),
OpenGraphMetadata({
openGraph: metadata.openGraph
}),
TwitterMetadata({
twitter: metadata.twitter
}),
AppLinksMeta({
appLinks: metadata.appLinks
}),
IconsMetadata({
icons: metadata.icons
})
]);
}
function createViewportElements(viewport) {
return MetaFilter([
ViewportMeta({
viewport: viewport
})
]);
}
//# sourceMappingURL=metadata.js.map