perf: remove TipTap/ProseMirror from client bundle, lazy-load below-fold sections
TipTap (ProseMirror) was causing: - chunks 1007 (85 KiB) and 3207 (58 KiB) in the initial bundle - Array.prototype.at/flat/flatMap, Object.fromEntries/hasOwn polyfills (ProseMirror bundles core-js for these — the 12 KiB legacy JS flag) - 2+ seconds of main thread blocking on mobile Fix: move HTML conversion to the server (API route) and pass the resulting HTML string to the client, eliminating the need to import richTextToSafeHtml (and transitively TipTap) in any client component. Changes: - app/api/content/page/route.ts: call richTextToSafeHtml server-side, add html: string to response alongside existing content - app/components/RichTextClient.tsx: accept html string, remove all TipTap imports — TipTap/ProseMirror now has zero client bundle cost - app/components/About.tsx, Contact.tsx: use cmsHtml from API - app/legal-notice/page.tsx, privacy-policy/page.tsx: same - app/components/ClientWrappers.tsx: change static imports of About, Projects, Contact, Footer to next/dynamic so their JS is in separate lazy-loaded chunks, not in the initial bundle Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,13 +8,12 @@ import Footer from "../components/Footer";
|
||||
import Link from "next/link";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { JSONContent } from "@tiptap/react";
|
||||
import RichTextClient from "../components/RichTextClient";
|
||||
|
||||
export default function LegalNotice() {
|
||||
const locale = useLocale();
|
||||
const t = useTranslations("common");
|
||||
const [cmsDoc, setCmsDoc] = useState<JSONContent | null>(null);
|
||||
const [cmsHtml, setCmsHtml] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -23,8 +22,8 @@ export default function LegalNotice() {
|
||||
`/api/content/page?key=${encodeURIComponent("legal-notice")}&locale=${encodeURIComponent(locale)}`,
|
||||
);
|
||||
const data = await res.json();
|
||||
if (data?.content?.content && data?.content?.locale === locale) {
|
||||
setCmsDoc(data.content.content as JSONContent);
|
||||
if (data?.content?.html && data?.content?.locale === locale) {
|
||||
setCmsHtml(data.content.html as string);
|
||||
}
|
||||
} catch {}
|
||||
})();
|
||||
@@ -64,9 +63,9 @@ export default function LegalNotice() {
|
||||
transition={{ delay: 0.1 }}
|
||||
className="lg:col-span-8 bg-white dark:bg-stone-900 rounded-[3rem] p-10 md:p-16 border border-stone-200/60 dark:border-stone-800/60 shadow-sm"
|
||||
>
|
||||
{cmsDoc ? (
|
||||
{cmsHtml ? (
|
||||
<div className="prose prose-stone dark:prose-invert max-w-none text-lg md:text-xl font-light leading-relaxed">
|
||||
<RichTextClient doc={cmsDoc} />
|
||||
<RichTextClient html={cmsHtml} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-16">
|
||||
|
||||
Reference in New Issue
Block a user