From 9821923f8634c6b4332922486d90a66003986fc7 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 9 Aug 2024 15:29:54 +0200 Subject: [PATCH] fix(changelog): Fix hydration errors because of nested `` tags (#11041) --- .../src/app/changelog/[slug]/loading.tsx | 4 +- .../src/app/changelog/[slug]/page.tsx | 46 +++++++++---------- apps/changelog/src/app/changelog/loading.tsx | 4 +- apps/changelog/src/app/changelog/page.tsx | 32 ++++++++++++- .../src/client/components/article.tsx | 10 +--- apps/changelog/src/client/components/list.tsx | 4 +- 6 files changed, 60 insertions(+), 40 deletions(-) diff --git a/apps/changelog/src/app/changelog/[slug]/loading.tsx b/apps/changelog/src/app/changelog/[slug]/loading.tsx index 1768c84879346..d2e17141de573 100644 --- a/apps/changelog/src/app/changelog/[slug]/loading.tsx +++ b/apps/changelog/src/app/changelog/[slug]/loading.tsx @@ -1,11 +1,11 @@ -import Article from '@/client/components/article'; +import {LoadingArticle} from '@/client/components/article'; export default function Loading() { return (
-
+
diff --git a/apps/changelog/src/app/changelog/[slug]/page.tsx b/apps/changelog/src/app/changelog/[slug]/page.tsx index 21d8c0c9ca6e8..76e823d3da9a8 100644 --- a/apps/changelog/src/app/changelog/[slug]/page.tsx +++ b/apps/changelog/src/app/changelog/[slug]/page.tsx @@ -1,29 +1,29 @@ -import { Fragment, Suspense } from "react"; -import { type Changelog } from "@prisma/client"; -import type { Metadata, ResolvingMetadata } from "next"; -import { unstable_cache } from "next/cache"; -import Link from "next/link"; -import { notFound } from "next/navigation"; -import { getServerSession } from "next-auth/next"; -import { MDXRemote } from "next-mdx-remote/rsc"; +import {Fragment, Suspense} from 'react'; +import {type Changelog} from '@prisma/client'; +import type {Metadata, ResolvingMetadata} from 'next'; +import {unstable_cache} from 'next/cache'; +import Link from 'next/link'; +import {notFound} from 'next/navigation'; +import {getServerSession} from 'next-auth/next'; +import {MDXRemote} from 'next-mdx-remote/rsc'; -import { prismaClient } from "@/server/prisma-client"; -import Article from "@/client/components/article"; -import ArticleFooter from "@/client/components/articleFooter"; -import { authOptions } from "@/server/authOptions"; -import { mdxOptions } from "@/server/mdxOptions"; +import {prismaClient} from '@/server/prisma-client'; +import {Article} from '@/client/components/article'; +import ArticleFooter from '@/client/components/articleFooter'; +import {authOptions} from '@/server/authOptions'; +import {mdxOptions} from '@/server/mdxOptions'; -export const dynamic = "force-dynamic"; +export const dynamic = 'force-dynamic'; export async function generateMetadata( - { params }: { params: { slug: string } }, + {params}: {params: {slug: string}}, parent: ResolvingMetadata ): Promise { let changelog: Changelog | null = null; try { changelog = await getChangelog(params.slug); } catch (e) { - return { title: (await parent).title }; + return {title: (await parent).title}; } return { @@ -39,7 +39,7 @@ export async function generateMetadata( } const getChangelog = unstable_cache( - async (slug) => { + async slug => { try { return await prismaClient.changelog.findUnique({ where: { @@ -53,15 +53,11 @@ const getChangelog = unstable_cache( return null; } }, - ["changelog-detail"], - { tags: ["changelog-detail"] } + ['changelog-detail'], + {tags: ['changelog-detail']} ); -export default async function ChangelogEntry({ - params, -}: { - params: { slug: string }; -}) { +export default async function ChangelogEntry({params}: {params: {slug: string}}) { const changelog = await getChangelog(params.slug); if (!changelog) { @@ -112,7 +108,7 @@ export default async function ChangelogEntry({ > Loading...}>
-
+
diff --git a/apps/changelog/src/app/changelog/page.tsx b/apps/changelog/src/app/changelog/page.tsx index f00acce15b6d1..acb2b0a9c6346 100644 --- a/apps/changelog/src/app/changelog/page.tsx +++ b/apps/changelog/src/app/changelog/page.tsx @@ -6,6 +6,9 @@ import Header from './header'; import {getChangelogs} from '../../server/utils'; import {ChangelogEntry, ChangelogList} from '@/client/components/list'; import {startSpan} from '@sentry/nextjs'; +import type {Plugin} from 'unified'; +import {visit} from 'unist-util-visit'; +import {Element} from 'hast'; export const dynamic = 'force-dynamic'; @@ -21,7 +24,20 @@ export default async function Page() { () => Promise.all( changelogsWithPublishedAt.map(async (changelog): Promise => { - const mdxSummary = await serialize(changelog.summary || ''); + const mdxSummary = await serialize( + changelog.summary || '', + { + mdxOptions: { + rehypePlugins: [ + // Because we render the changelog entries as tags, and it is not allowed to render tags + // within other a tags, we need to strip away the tags inside the previews here. + // @ts-ignore + stripLinks, + ], + }, + }, + true + ); return { id: changelog.id, title: changelog.title, @@ -52,3 +68,17 @@ export function generateMetadata(): Metadata { }, }; } + +const stripLinks: Plugin = () => { + return tree => { + return visit(tree, 'element', (node: Element) => { + if (node.tagName === 'a') { + node.tagName = 'span'; + if (node.properties) { + delete node.properties.href; + delete node.properties.class; + } + } + }); + }; +}; diff --git a/apps/changelog/src/client/components/article.tsx b/apps/changelog/src/client/components/article.tsx index 9223a60655bc8..9dd993072a158 100644 --- a/apps/changelog/src/client/components/article.tsx +++ b/apps/changelog/src/client/components/article.tsx @@ -13,19 +13,14 @@ type ArticleProps = { title?: string; }; -export default function Article({ +export function Article({ title = '', image, tags = [], date = null, children, - loading, className, }: ArticleProps) { - if (loading) { - return ; - } - return (
{/* this needs to be a plain next/image doesn't work here because of redirects we do */} @@ -43,7 +38,6 @@ export default function Article({
{Array.isArray(tags) && tags.map(tag => )}
-
{children}
@@ -56,7 +50,7 @@ export default function Article({ ); } -function LoadingArticle() { +export function LoadingArticle() { return (
diff --git a/apps/changelog/src/client/components/list.tsx b/apps/changelog/src/client/components/list.tsx index c981f577a49b5..410ff06316d3b 100644 --- a/apps/changelog/src/client/components/list.tsx +++ b/apps/changelog/src/client/components/list.tsx @@ -5,7 +5,7 @@ import {MDXRemote, MDXRemoteSerializeResult} from 'next-mdx-remote'; import Link from 'next/link'; import {parseAsArrayOf, parseAsInteger, parseAsString, useQueryState} from 'nuqs'; import {Fragment} from 'react'; -import Article from './article'; +import {Article} from './article'; import {Pagination} from './pagination'; import {CategoryTag} from './tag'; @@ -149,7 +149,7 @@ export function ChangelogList({changelogs}: {changelogs: ChangelogEntry[]}) {
)} - +