perf: sohbet markdown lazy + marked client'tan çıktı, mermaid görünürlükte (Faz 4)
- markdown.tsx: blok bölme marked.lexer yerine çit-farkındalıklı boş satır bölücüsü — react-markdown'ın yanında ikinci tam parser (~460 KB paket) client'a inmiyordu artık gerekmiyor; memoized blok yapısı aynen korunur - markdown-lazy: react-markdown+remark zinciri (~215 KB) lazy; fallback aynı class'lı düz metin (stream'de flash/CLS yok), sohbet mount'unda preloadMarkdown ile chunk önden ısınır — /listem 1315->1133 KB eager JS - el-cizimi-sema: mermaid importu IntersectionObserver'a bağlandı (rootMargin 200px); şemalar hep fold altında, ~1 MB mount'ta inmiyor Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
// Mermaid ağır bir paket olduğu için useEffect içinde dinamik import edilir;
|
||||
// sayfa paketine girmez.
|
||||
|
||||
import { useEffect, useId, useState } from "react";
|
||||
import { useEffect, useId, useRef, useState } from "react";
|
||||
import localFont from "next/font/local";
|
||||
|
||||
// Şemanın "el çizimi" görünümüne uyan el yazısı fontu (Sweet Cucumber
|
||||
@@ -30,38 +30,58 @@ export function ElCizimiSema({
|
||||
figcaption?: React.ReactNode;
|
||||
}) {
|
||||
const [svg, setSvg] = useState<string | null>(null);
|
||||
const figureRef = useRef<HTMLElement>(null);
|
||||
// mermaid.render'ın istediği DOM id'si: useId'nin ":" karakterleri geçersiz
|
||||
const semaId = `sema-${useId().replace(/[^a-zA-Z0-9-]/g, "")}`;
|
||||
|
||||
// ~1 MB'lık mermaid mount'ta değil, şema görünürlüğe yaklaşınca insin —
|
||||
// şemalar hep fold altında (/meraklisina sayfa sonu, rehber makale ortası).
|
||||
useEffect(() => {
|
||||
const el = figureRef.current;
|
||||
if (!el) return;
|
||||
let iptal = false;
|
||||
import("mermaid").then(async ({ default: mermaid }) => {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
look: "handDrawn",
|
||||
handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik)
|
||||
theme: "base",
|
||||
fontFamily: `${elYazisi.style.fontFamily}, cursive`,
|
||||
themeVariables: {
|
||||
primaryColor: "#ffffff",
|
||||
primaryBorderColor: "#e2e8f0",
|
||||
primaryTextColor: "#0f172a",
|
||||
lineColor: "#94a3b8",
|
||||
edgeLabelBackground: "#ffffff",
|
||||
const io = new IntersectionObserver(
|
||||
(girisler) => {
|
||||
if (!girisler.some((g) => g.isIntersecting)) return;
|
||||
io.disconnect();
|
||||
cizdir();
|
||||
},
|
||||
// Kullanıcı şemaya varmadan yükleme başlasın
|
||||
{ rootMargin: "200px 0px" },
|
||||
);
|
||||
io.observe(el);
|
||||
|
||||
function cizdir() {
|
||||
import("mermaid").then(async ({ default: mermaid }) => {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
look: "handDrawn",
|
||||
handDrawnSeed: 7, // her render'da aynı çizgi titremesi (deterministik)
|
||||
theme: "base",
|
||||
fontFamily: `${elYazisi.style.fontFamily}, cursive`,
|
||||
fontSize: "17px", // script fontun x-yüksekliği düşük; okunurluk için büyütüldü
|
||||
},
|
||||
themeVariables: {
|
||||
primaryColor: "#ffffff",
|
||||
primaryBorderColor: "#e2e8f0",
|
||||
primaryTextColor: "#0f172a",
|
||||
lineColor: "#94a3b8",
|
||||
edgeLabelBackground: "#ffffff",
|
||||
fontFamily: `${elYazisi.style.fontFamily}, cursive`,
|
||||
fontSize: "17px", // script fontun x-yüksekliği düşük; okunurluk için büyütüldü
|
||||
},
|
||||
});
|
||||
const sonuc = await mermaid.render(semaId, tanim);
|
||||
if (!iptal) setSvg(sonuc.svg);
|
||||
});
|
||||
const sonuc = await mermaid.render(semaId, tanim);
|
||||
if (!iptal) setSvg(sonuc.svg);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
iptal = true;
|
||||
io.disconnect();
|
||||
};
|
||||
}, [semaId, tanim]);
|
||||
|
||||
return (
|
||||
<figure className="mt-6">
|
||||
<figure ref={figureRef} className="mt-6">
|
||||
{svg ? (
|
||||
<div
|
||||
role="img"
|
||||
|
||||
Reference in New Issue
Block a user