Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions apps/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@ const withBundleAnalyzer = bundleAnalyzer({

/** @type {import('next').NextConfig} */
const nextConfig = {
swcMinify: true,
images: {
unoptimized: true,
domains: ["k.kakaocdn.net", "cdn.default.solid-connection.com", "cdn.upload.solid-connection.com"],
remotePatterns: [
{ protocol: "https", hostname: "k.kakaocdn.net" },
{ protocol: "https", hostname: "cdn.default.solid-connection.com" },
{ protocol: "https", hostname: "cdn.upload.solid-connection.com" },
],
formats: ["image/avif", "image/webp"],
deviceSizes: [360, 640, 768, 1024, 1280],
},
// 폰트 최적화 설정
optimizeFonts: true,
// 압축 활성화
compress: true,
// 정적 리소스 최적화
// 패키지 import 최적화
experimental: {
optimizeCss: true,
gzipSize: true,
// Sentry instrumentation 활성화 (Web Vitals 수집에 필요)
instrumentationHook: true,
optimizePackageImports: [
"lucide-react",
"@radix-ui/react-select",
Expand All @@ -40,11 +37,6 @@ const nextConfig = {
"@hookform/resolvers",
],
},
eslint: {
// Warning: This allows production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
typescript: {
ignoreBuildErrors: true,
},
Expand Down
16 changes: 8 additions & 8 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "2.2445",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "next start",
"lint": "biome check --write .",
"lint:check": "biome check .",
Expand All @@ -13,17 +13,17 @@
"typecheck": "tsc --noEmit",
"typecheck:ci": "tsc --noEmit -p tsconfig.ci.json",
"ci:check": "pnpm run lint:check && pnpm run typecheck:ci",
"analyze": "ANALYZE=true next build"
"analyze": "ANALYZE=true next build --webpack"
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@next/third-parties": "^14.2.4",
"@next/third-parties": "^16.1.6",
"@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-progress": "^1.1.2",
"@radix-ui/react-select": "^2.1.6",
"@react-google-maps/api": "^2.19.2",
"@sentry/nextjs": "^10.22.0",
"@sentry/nextjs": "^10.43.0",
"@stomp/stompjs": "^7.1.1",
"@tanstack/react-query": "^5.84.1",
"@tanstack/react-query-devtools": "^5.84.1",
Expand All @@ -36,10 +36,10 @@
"linkify-react": "^4.3.2",
"linkifyjs": "^4.3.2",
"lucide-react": "^0.479.0",
"next": "^14.2.35",
"next": "^16.1.6",
"next-render-analyzer": "^0.1.2",
"react": "^18",
"react-dom": "^18",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-hook-form": "^7.60.0",
"sockjs-client": "^1.6.1",
"tailwind-merge": "^3.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const getSearchUniversitiesByFilter = async (
};

export const getSearchUniversitiesAllRegions = async (): Promise<ListUniversity[]> => {
const endpoint = `/univ-apply-infos/search/filter`;
const endpoint = `/univ-apply-infos/search/text?value=`;
const response = await serverFetch<UniversitySearchResponse>(endpoint);

if (!response.ok) {
Expand Down
35 changes: 7 additions & 28 deletions apps/web/src/app/(home)/_ui/PopularUniversitySection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import dynamic from "next/dynamic";
import { Suspense } from "react";
import type { ListUniversity } from "@/types/university";
import PopularUniversityCard from "./_ui/PopularUniversityCard";

// PopularUniversityCard를 동적 임포트
const PopularUniversityCardDynamic = dynamic(() => import("./_ui/PopularUniversityCard"), {
ssr: false,
loading: () => (
<div className="relative w-[153px]">
<div className="h-[120px] w-[153px] animate-pulse rounded-lg bg-gray-200" />
</div>
),
});

type PopularUniversitySectionProps = {
universities: ListUniversity[];
};
Expand All @@ -36,24 +24,15 @@ const PopularUniversitySection = ({ universities }: PopularUniversitySectionProp
/>
))}

{/* 나머지는 동적 렌더링으로 위임 */}
{belowFold.map((university) => (
<Suspense
<PopularUniversityCard
key={university.id}
fallback={
<div className="relative w-[153px]">
<div className="h-[120px] w-[153px] animate-pulse rounded-lg bg-gray-200" />
</div>
}
>
<PopularUniversityCardDynamic
university={university}
priority={false}
loading="lazy"
fetchPriority="low"
quality={50} // 동적 로딩 이미지는 50으로 최대 압축
/>
</Suspense>
university={university}
priority={false}
loading="lazy"
fetchPriority="low"
quality={50} // 동적 로딩 이미지는 50으로 최대 압축
/>
))}
</div>
</div>
Expand Down
12 changes: 3 additions & 9 deletions apps/web/src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import type { Metadata } from "next";
import dynamic from "next/dynamic";
import Link from "next/link";
import { getCategorizedUniversities, getRecommendedUniversity } from "@/apis/universities/server";
import { fetchAllNews } from "@/lib/firebaseNews";
import { IconIdCard, IconMagnifyingGlass, IconMuseum, IconPaper } from "@/public/svgs/home";
import FindLastYearScoreBar from "./_ui/FindLastYearScoreBar";
import NewsSectionSkeleton from "./_ui/NewsSection/skeleton";
import NewsSection from "./_ui/NewsSection";
import PopularUniversitySection from "./_ui/PopularUniversitySection";
import UniversityList from "./_ui/UniversityList";

const NewsSectionDynamic = dynamic(() => import("./_ui/NewsSection"), {
ssr: false,
loading: () => <NewsSectionSkeleton />,
});

const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com";
const ogImageUrl = `${baseUrl}/opengraph-image.png`;

Expand Down Expand Up @@ -139,12 +133,12 @@ const HomePage = async () => {
<UniversityList allRegionsUniversityList={allRegionsUniversityList} />
</div>

<NewsSectionDynamic newsList={newsList} />
<NewsSection newsList={newsList} />
</div>
</>
);
};

export default HomePage;

export const revalidate = 60 * 60 * 24; // 1 day
export const revalidate = 86400; // 1 day
4 changes: 2 additions & 2 deletions apps/web/src/app/api/revalidate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async function POST(request: NextRequest) {
// boardCode가 있으면 해당 커뮤니티 페이지 revalidate
if (boardCode) {
revalidatePath(`/community/${boardCode}`);
revalidateTag(`posts-${boardCode}`);
revalidateTag(`posts-${boardCode}`, "max");

return NextResponse.json({
revalidated: true,
Expand All @@ -79,7 +79,7 @@ async function POST(request: NextRequest) {

// 특정 태그 revalidate
if (tag) {
revalidateTag(tag);
revalidateTag(tag, "max");
return NextResponse.json({
revalidated: true,
message: `Tag ${tag} revalidated`,
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/app/community/[boardCode]/[postId]/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ const PostImage = ({ images, onImageClick }: { images: PostImageType[]; onImageC
<div className="relative pt-[75%]">
<Image
src={convertUploadedImageUrl(images[0].url)}
layout="fill"
objectFit="cover"
fill
className="object-cover"
alt="image"
onClick={() => onImageClick(0)}
/>
Expand Down Expand Up @@ -193,7 +193,7 @@ const ImagePopup = ({ image, title, onClose }: ImagePopupProps) => (
<div />
</div>
<div className="relative flex-grow">
<Image src={convertUploadedImageUrl(image.url)} layout="fill" objectFit="contain" alt="Popup" />
<Image src={convertUploadedImageUrl(image.url)} fill className="object-contain" alt="Popup" />
</div>
</div>
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import TopDetailNavigation from "@/components/layout/TopDetailNavigation";
import PostModifyContent from "./PostModifyContent";

interface PostModifyPageProps {
params: {
params: Promise<{
boardCode: string;
postId: string;
};
}>;
}

export const metadata: Metadata = {
title: "글 수정",
};

const PostModifyPage = ({ params }: PostModifyPageProps) => {
const PostModifyPage = async (props: PostModifyPageProps) => {
const params = await props.params;
const { boardCode, postId } = params;

return (
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/app/community/[boardCode]/[postId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ import type { Metadata } from "next";
import PostPageContent from "./PostPageContent";

interface PostPageProps {
params: {
params: Promise<{
boardCode: string;
postId: string;
};
}>;
}

export const metadata: Metadata = {
title: "게시글",
};

const PostPage = ({ params }: PostPageProps) => {
const PostPage = async (props: PostPageProps) => {
const params = await props.params;
const { boardCode } = params;
const postId = Number(params.postId);

Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/app/community/[boardCode]/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export const metadata = {
title: "글쓰기",
};

const PostCreatePage = ({ params }: { params: { boardCode: string } }) => {
const PostCreatePage = async (props: { params: Promise<{ boardCode: string }> }) => {
const params = await props.params;
const { boardCode } = params;
return (
<div className="w-full">
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/app/community/[boardCode]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ export const metadata: Metadata = {
};

interface CommunityPageProps {
params: {
params: Promise<{
boardCode: string;
};
}>;
}

const CommunityPage = ({ params }: CommunityPageProps) => {
const CommunityPage = async (props: CommunityPageProps) => {
const params = await props.params;
const { boardCode } = params;

return (
Expand Down
Binary file modified apps/web/src/app/favicon.ico
Binary file not shown.
8 changes: 1 addition & 7 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Metadata, Viewport } from "next";
import dynamic from "next/dynamic";
import localFont from "next/font/local";
import type { ReactNode } from "react";

import GlobalLayout from "@/components/layout/GlobalLayout";
import ToastContainer from "@/components/ui/Toast";

import QueryProvider from "@/lib/react-query/QueryProvider";
import AppleScriptLoader from "@/lib/ScriptLoader/AppleScriptLoader";
import "@/styles/globals.css";
import { GoogleAnalytics } from "@next/third-parties/google";
import { SpeedInsights } from "@vercel/speed-insights/next";
Expand All @@ -33,11 +32,6 @@ const pretendard = localFont({
],
});

const AppleScriptLoader = dynamic(() => import("@/lib/ScriptLoader/AppleScriptLoader"), {
ssr: false,
loading: () => null,
});

declare global {
interface Window {
Kakao: {
Expand Down
24 changes: 24 additions & 0 deletions apps/web/src/app/login/LoginPageClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import dynamic from "next/dynamic";

const KakaoScriptLoader = dynamic(() => import("@/lib/ScriptLoader/KakaoScriptLoader"), {
ssr: false,
loading: () => null,
});

const LoginContent = dynamic(() => import("./LoginContent"), {
ssr: false,
loading: () => null,
});

const LoginPageClient = () => {
return (
<div className="w-full px-5">
<KakaoScriptLoader />
<LoginContent />
</div>
);
};

export default LoginPageClient;
15 changes: 2 additions & 13 deletions apps/web/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import type { Metadata } from "next";
import dynamic from "next/dynamic";

const KakaoScriptLoader = dynamic(() => import("@/lib/ScriptLoader/KakaoScriptLoader"), {
ssr: false,
loading: () => null,
});
const LoginContent = dynamic(() => import("./LoginContent"), { ssr: false });
import LoginPageClient from "./LoginPageClient";

export const metadata: Metadata = {
title: "로그인",
};

const LoginPage = () => {
return (
<div className="w-full px-5">
<KakaoScriptLoader />
<LoginContent />
</div>
);
return <LoginPageClient />;
};

export default LoginPage;
5 changes: 3 additions & 2 deletions apps/web/src/app/mentor/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export const metadata: Metadata = {
};

interface MentorDetailPageProps {
params: { id: string };
params: Promise<{ id: string }>;
}

const MentorDetailPage = ({ params }: MentorDetailPageProps) => {
const MentorDetailPage = async (props: MentorDetailPageProps) => {
const params = await props.params;
const mentorId = Number(params.id);

return (
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/app/mentor/chat/[chatId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export const metadata: Metadata = {
};

interface ChatDetailPageProps {
params: { chatId: string };
params: Promise<{ chatId: string }>;
}

const ChatDetailPage = ({ params }: ChatDetailPageProps) => {
const ChatDetailPage = async (props: ChatDetailPageProps) => {
const params = await props.params;
const chatId = Number(params.chatId);

if (Number.isNaN(chatId)) notFound();
Expand Down
Loading