chore: update memory limits in Dockerfile and next.config.ts
All checks were successful
Deploy / deploy (push) Successful in 7m21s
All checks were successful
Deploy / deploy (push) Successful in 7m21s
- Reduced NODE_OPTIONS max-old-space-size from 1536 to 1024 MB in Dockerfile. - Adjusted turbopackMemoryLimit in next.config.ts from 1.5 GB to 1 GB to prevent OOM-kills during build on VPS with limited memory. - Added a search input for filtering Turkish provinces in the SihirbazAdimlar component, improving user experience with real-time search functionality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,7 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
|||||||
# V8 heap sınırı ana süreç + statik üretim worker'larına miras kalır.
|
# V8 heap sınırı ana süreç + statik üretim worker'larına miras kalır.
|
||||||
# Turbopack'ın Rust tarafı bu sınırın dışında; onun hedefi next.config.ts'te
|
# Turbopack'ın Rust tarafı bu sınırın dışında; onun hedefi next.config.ts'te
|
||||||
# turbopackMemoryLimit ile verilir (BUILD_KAYNAK_KISITLI bloğu).
|
# turbopackMemoryLimit ile verilir (BUILD_KAYNAK_KISITLI bloğu).
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=1536"
|
ENV NODE_OPTIONS="--max-old-space-size=1024"
|
||||||
ENV BUILD_KAYNAK_KISITLI=1
|
ENV BUILD_KAYNAK_KISITLI=1
|
||||||
RUN --mount=type=cache,id=next-cache,target=/app/.next/cache \
|
RUN --mount=type=cache,id=next-cache,target=/app/.next/cache \
|
||||||
pnpm build
|
pnpm build
|
||||||
|
|||||||
BIN
data/app.db
BIN
data/app.db
Binary file not shown.
@@ -30,8 +30,10 @@ const nextConfig: NextConfig = {
|
|||||||
...(kaynakKisitli
|
...(kaynakKisitli
|
||||||
? {
|
? {
|
||||||
// Turbopack'ın Rust tarafı NODE_OPTIONS heap sınırını görmez; bellek
|
// Turbopack'ın Rust tarafı NODE_OPTIONS heap sınırını görmez; bellek
|
||||||
// hedefi byte cinsinden ayrıca verilir (1.5 GB).
|
// hedefi byte cinsinden ayrıca verilir (1 GB). 1.5 GB hedef + Node
|
||||||
turbopackMemoryLimit: 1_610_612_736,
|
// heap'i, ~1.5 GB boş belleği olan VPS'te derleme fazında OOM-kill
|
||||||
|
// üretiyordu (lokalde --memory=1536m ile reprodüke edildi).
|
||||||
|
turbopackMemoryLimit: 1_073_741_824,
|
||||||
// Statik üretim: varsayılan 4 worker × 8 eşzamanlı sayfa yerine tek
|
// Statik üretim: varsayılan 4 worker × 8 eşzamanlı sayfa yerine tek
|
||||||
// worker × 4 sayfa. Her worker ayrı bir Node süreci/heap'idir.
|
// worker × 4 sayfa. Her worker ayrı bir Node süreci/heap'idir.
|
||||||
cpus: 1,
|
cpus: 1,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// üniversite tipi sayıları kategori+il'e göre /api/facetler'den tazelenir.
|
// üniversite tipi sayıları kategori+il'e göre /api/facetler'den tazelenir.
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { ArrowLeft, ArrowRight, X } from "lucide-react";
|
import { ArrowLeft, ArrowRight, Search, X } from "lucide-react";
|
||||||
import { useReducedMotion } from "motion/react";
|
import { useReducedMotion } from "motion/react";
|
||||||
import useMeasure from "react-use-measure";
|
import useMeasure from "react-use-measure";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -27,11 +27,14 @@ export function Cip({
|
|||||||
secili,
|
secili,
|
||||||
onClick,
|
onClick,
|
||||||
children,
|
children,
|
||||||
|
kucuk = false,
|
||||||
}: {
|
}: {
|
||||||
secili: boolean;
|
secili: boolean;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
kucuk?: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const boyut = kucuk ? "px-2.5 py-1 text-xs" : "px-3.5 py-2 text-sm";
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -39,8 +42,8 @@ export function Cip({
|
|||||||
aria-pressed={secili}
|
aria-pressed={secili}
|
||||||
className={
|
className={
|
||||||
secili
|
secili
|
||||||
? "cursor-pointer rounded-full border border-primary bg-primary px-3.5 py-2 text-sm font-medium text-white transition-colors duration-200"
|
? `cursor-pointer rounded-full border border-primary bg-primary font-medium text-white transition-colors duration-200 ${boyut}`
|
||||||
: "cursor-pointer rounded-full border border-slate-200 bg-white px-3.5 py-2 text-sm text-slate-700 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50"
|
: `cursor-pointer rounded-full border border-slate-200 bg-white text-slate-700 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50 ${boyut}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -103,6 +106,26 @@ export function SihirbazAdimlar({
|
|||||||
() => siraliIller.filter((i) => !HARITA_ILLERI.has(i.il)),
|
() => siraliIller.filter((i) => !HARITA_ILLERI.has(i.il)),
|
||||||
[siraliIller],
|
[siraliIller],
|
||||||
);
|
);
|
||||||
|
// İl araması: Türkçe büyük/küçük harf ve şapkalı harf farklarına duyarsız
|
||||||
|
// eşleşme için iki taraf da normalizeIlAdi'dan geçirilir.
|
||||||
|
const [ilArama, setIlArama] = useState("");
|
||||||
|
const ilAramaNorm = normalizeIlAdi(ilArama.trim());
|
||||||
|
const gorunenTurkiyeIlleri = useMemo(
|
||||||
|
() =>
|
||||||
|
ilAramaNorm
|
||||||
|
? turkiyeIlleri.filter((i) =>
|
||||||
|
normalizeIlAdi(i.il).includes(ilAramaNorm),
|
||||||
|
)
|
||||||
|
: turkiyeIlleri,
|
||||||
|
[turkiyeIlleri, ilAramaNorm],
|
||||||
|
);
|
||||||
|
const gorunenDisIller = useMemo(
|
||||||
|
() =>
|
||||||
|
ilAramaNorm
|
||||||
|
? disIller.filter((i) => normalizeIlAdi(i.il).includes(ilAramaNorm))
|
||||||
|
: disIller,
|
||||||
|
[disIller, ilAramaNorm],
|
||||||
|
);
|
||||||
const haritaIlleri = useMemo(
|
const haritaIlleri = useMemo(
|
||||||
() => canliFacetler.iller.filter((i) => HARITA_ILLERI.has(i.il)),
|
() => canliFacetler.iller.filter((i) => HARITA_ILLERI.has(i.il)),
|
||||||
[canliFacetler.iller],
|
[canliFacetler.iller],
|
||||||
@@ -266,45 +289,79 @@ export function SihirbazAdimlar({
|
|||||||
En fazla 5 il seçebilirsin. İstersen boş bırak, fark etmez.
|
En fazla 5 il seçebilirsin. İstersen boş bırak, fark etmez.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="mt-4 flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3.5 py-2 transition-colors focus-within:border-slate-300">
|
||||||
|
<Search className="size-4 shrink-0 text-slate-400" aria-hidden />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={ilArama}
|
||||||
|
onChange={(e) => setIlArama(e.target.value)}
|
||||||
|
placeholder="İl ara..."
|
||||||
|
aria-label="İl ara"
|
||||||
|
autoComplete="off"
|
||||||
|
className="min-w-0 flex-1 bg-transparent text-sm text-slate-950 outline-none placeholder:text-slate-400"
|
||||||
|
/>
|
||||||
|
{ilArama ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setIlArama("")}
|
||||||
|
aria-label="Aramayı temizle"
|
||||||
|
className="flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-full text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700"
|
||||||
|
>
|
||||||
|
<X className="size-3.5" aria-hidden />
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Çipler birincil seçim yolu (haritadaki küçük iller mobilde
|
{/* Çipler birincil seçim yolu (haritadaki küçük iller mobilde
|
||||||
güvenilir dokunma hedefi değil); iller seçili kategorilere göre
|
güvenilir dokunma hedefi değil); iller seçili kategorilere göre
|
||||||
süzülmüş, program sayısına göre sıralı listelenir. Penceresinde
|
süzülmüş, program sayısına göre sıralı listelenir. Penceresinde
|
||||||
programı olan TÜM iller görünür (kırpma yok). */}
|
programı olan TÜM iller görünür (kırpma yok); arama yalnızca
|
||||||
|
görünümü daraltır, seçimleri etkilemez. */}
|
||||||
<div
|
<div
|
||||||
className={`mt-4 flex max-h-56 flex-wrap gap-2 overflow-y-auto sm:max-h-none sm:overflow-visible ${
|
className={`mt-3 flex max-h-56 flex-wrap gap-1.5 overflow-y-auto sm:max-h-none sm:overflow-visible ${
|
||||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{turkiyeIlleri.map((i) => (
|
{gorunenTurkiyeIlleri.map((i) => (
|
||||||
<Cip
|
<Cip
|
||||||
key={i.il}
|
key={i.il}
|
||||||
|
kucuk
|
||||||
secili={iller.includes(i.il)}
|
secili={iller.includes(i.il)}
|
||||||
onClick={() => listeDegistir(iller, setIller, i.il, 5)}
|
onClick={() => listeDegistir(iller, setIller, i.il, 5)}
|
||||||
>
|
>
|
||||||
{trBaslikDuzeni(i.il)}
|
{trBaslikDuzeni(i.il)}
|
||||||
<span className="ml-1.5 text-xs opacity-70">{i.adet}</span>
|
<span className="ml-1 text-[10px] opacity-70">{i.adet}</span>
|
||||||
</Cip>
|
</Cip>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{disIller.length > 0 ? (
|
{ilAramaNorm &&
|
||||||
|
gorunenTurkiyeIlleri.length === 0 &&
|
||||||
|
gorunenDisIller.length === 0 ? (
|
||||||
|
<p className="mt-3 text-sm text-slate-500">
|
||||||
|
“{ilArama.trim()}” ile eşleşen il yok.
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{gorunenDisIller.length > 0 ? (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<p className="mb-2 text-xs font-semibold tracking-wide text-slate-400 uppercase">
|
<p className="mb-2 text-xs font-semibold tracking-wide text-slate-400 uppercase">
|
||||||
KKTC & Yurt Dışı
|
KKTC & Yurt Dışı
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div
|
||||||
className={`flex flex-wrap gap-2 ${
|
className={`flex flex-wrap gap-1.5 ${
|
||||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{disIller.map((i) => (
|
{gorunenDisIller.map((i) => (
|
||||||
<Cip
|
<Cip
|
||||||
key={i.il}
|
key={i.il}
|
||||||
|
kucuk
|
||||||
secili={iller.includes(i.il)}
|
secili={iller.includes(i.il)}
|
||||||
onClick={() => listeDegistir(iller, setIller, i.il, 5)}
|
onClick={() => listeDegistir(iller, setIller, i.il, 5)}
|
||||||
>
|
>
|
||||||
{trBaslikDuzeni(i.il)}
|
{trBaslikDuzeni(i.il)}
|
||||||
<span className="ml-1.5 text-xs opacity-70">{i.adet}</span>
|
<span className="ml-1 text-[10px] opacity-70">{i.adet}</span>
|
||||||
</Cip>
|
</Cip>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user