Skip to content

Commit 280d107

Browse files
committed
feat: add meta tag
1 parent 7c9d649 commit 280d107

File tree

5 files changed

+73
-83
lines changed

5 files changed

+73
-83
lines changed

packages/react/src/App.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ router.addRoute("/product/:id", ProductDetailPage);
99
router.addRoute("*", NotFoundPage);
1010

1111
const CartInitializer = () => {
12-
useLoadCartStore();
12+
if (typeof window !== "undefined") {
13+
useLoadCartStore();
14+
}
1315
return null;
1416
};
1517

1618
/**
17-
* 전체 애플리케이션 렌더링
19+
* 클라이언트 사이드 애플리케이션
1820
*/
1921
const ClientApp = () => {
2022
const PageComponent = useCurrentPage();
@@ -28,17 +30,34 @@ const ClientApp = () => {
2830
);
2931
};
3032

31-
const ServerApp = () => {
33+
/**
34+
* 서버 사이드 애플리케이션
35+
*/
36+
const ServerApp = ({ url }: { url?: string }) => {
37+
const splitUrl = (url ?? "").split("/").filter((segment) => segment !== "");
38+
39+
let PageComponent = HomePage;
40+
41+
if (splitUrl?.[0] === "product") {
42+
PageComponent = ProductDetailPage;
43+
} else if ((url ?? "").split("?")[0] === "" || url === "/" || url === "") {
44+
PageComponent = HomePage;
45+
} else {
46+
PageComponent = NotFoundPage;
47+
}
48+
49+
console.log("ServerApp 렌더링:", { url, PageComponent: PageComponent.name });
50+
3251
return (
3352
<ToastProvider>
3453
<ModalProvider>
35-
<HomePage />
54+
<PageComponent />
3655
</ModalProvider>
3756
</ToastProvider>
3857
);
3958
};
4059

41-
export const App = () => {
60+
export const App = ({ url }: { url?: string } = {}) => {
4261
const isServer = typeof window === "undefined";
43-
return isServer ? <ServerApp /> : <ClientApp />;
62+
return isServer ? <ServerApp url={url} /> : <ClientApp />;
4463
};

packages/react/src/entities/products/components/hooks/useLoadProductDetail.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { loadProductDetailForPage } from "../../productUseCase";
55
export const useLoadProductDetail = () => {
66
const productId = useRouterParams((params) => params.id);
77
useEffect(() => {
8+
if (typeof window === "undefined") return;
89
loadProductDetailForPage(productId);
910
}, [productId]);
1011
};

packages/react/src/entities/products/hooks/useProductStore.ts

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface ProductProviderProps {
1111
categories?: Categories;
1212
totalCount?: number;
1313
currentProduct?: Product;
14+
relatedProducts?: Product[];
1415
filters: {
1516
search: string;
1617
limit: string;
@@ -23,22 +24,28 @@ interface ProductProviderProps {
2324

2425
export const ProductProvider = ({ children, initialData }: PropsWithChildren<ProductProviderProps>) => {
2526
// useEffect 대신 즉시 실행
26-
console.log("데이터");
27-
console.log(initialData?.filters);
2827

2928
if (initialData?.currentProduct || (initialData?.products && initialData.products.length > 0)) {
3029
// 현재 스토어 상태 확인
3130
const currentState = productStore.getState();
31+
console.log("데이터000");
32+
// console.log(initialData?.currentProduct);
33+
console.log(currentState.products.length);
34+
console.log(currentState.currentProduct);
3235

3336
// 아직 초기 데이터가 설정되지 않았을 때만 설정
34-
if (currentState.products.length === 0 && currentState.loading !== false) {
37+
if (currentState.loading === true || typeof window === "undefined") {
38+
console.log("데이터");
39+
console.log(initialData?.currentProduct);
40+
3541
productStore.dispatch({
3642
type: PRODUCT_ACTIONS.SET_INITIAL_DATA,
3743
payload: {
3844
products: initialData.products,
3945
categories: initialData.categories || {},
4046
totalCount: initialData.totalCount || (initialData?.products ?? []).length,
4147
currentProduct: initialData.currentProduct || {},
48+
relatedProducts: initialData.relatedProducts || [],
4249
filters: initialData.filters,
4350
loading: false,
4451
},
@@ -48,25 +55,3 @@ export const ProductProvider = ({ children, initialData }: PropsWithChildren<Pro
4855

4956
return children;
5057
};
51-
52-
// export const ProductProvider = ({ children, initialData }: PropsWithChildren<ProductProviderProps>) => {
53-
// useLayoutEffect(() => {
54-
// if ((initialData?.products ?? []).length > 0) {
55-
// const currentState = productStore.getState();
56-
// if (currentState.products.length === 0 && currentState.loading !== false) {
57-
// productStore.dispatch({
58-
// type: PRODUCT_ACTIONS.SET_INITIAL_DATA,
59-
// payload: {
60-
// products: initialData?.products,
61-
// categories: initialData?.categories || {},
62-
// totalCount: initialData?.totalCount || (initialData?.products?.length ?? 0),
63-
// filters: initialData?.filters,
64-
// loading: false,
65-
// },
66-
// });
67-
// }
68-
// }
69-
// }, [initialData]);
70-
71-
// return children;
72-
// };

packages/react/src/entities/products/productStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ const productReducer = (state: typeof initialProductState, action: any) => {
135135
categories: action.payload.categories || {},
136136
totalCount: action.payload.totalCount || 0,
137137
filters: action.payload.filters || {},
138+
currentProduct: action.payload.currentProduct || null,
139+
relatedProducts: action.payload.relatedProducts || [],
138140
loading: false,
139141
error: null,
140142
status: "done",

packages/react/src/main-server.tsx

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import { App } from "./App";
1111

1212
export const render = async (url: string, query: Record<string, string>) => {
1313
console.log("SSR render 시작:", { url, query });
14-
console.log(url);
15-
console.log(query);
1614

1715
const serverRouter = new Router<FunctionComponent>(BASE_URL);
1816

@@ -44,19 +42,32 @@ export const render = async (url: string, query: Record<string, string>) => {
4442
const productId = splitUrl[1];
4543
console.log("상품 상세 페이지 데이터 로딩:", productId);
4644

47-
const product = await getProduct(productId);
48-
initialData.currentProduct = product;
49-
50-
if (product.category2) {
51-
const relatedData = await getProducts({
52-
category2: product.category2,
53-
limit: "20",
54-
});
55-
initialData.relatedProducts = relatedData.products.filter((p) => p.productId !== productId);
45+
try {
46+
const product = await getProduct(productId);
47+
console.log("상품 로딩 성공:", product.title);
48+
49+
initialData.currentProduct = product;
50+
51+
// 관련 상품 로딩
52+
if (product.category2) {
53+
try {
54+
const relatedData = await getProducts({
55+
category2: product.category2,
56+
limit: "20",
57+
});
58+
initialData.relatedProducts = relatedData.products.filter((p) => p.productId !== productId);
59+
console.log("관련 상품 로딩 성공:", initialData.relatedProducts.length, "개");
60+
} catch (relatedError) {
61+
console.error("관련 상품 로딩 실패:", relatedError);
62+
initialData.relatedProducts = [];
63+
}
64+
}
65+
66+
const categoriesData = await getCategories();
67+
initialData.categories = categoriesData;
68+
} catch (productError) {
69+
console.error("상품 로딩 실패:", productError);
5670
}
57-
58-
const categoriesData = await getCategories();
59-
initialData.categories = categoriesData;
6071
} else {
6172
// 홈페이지
6273
console.log("홈페이지 데이터 로딩");
@@ -81,6 +92,8 @@ export const render = async (url: string, query: Record<string, string>) => {
8192
productsCount: initialData.products.length,
8293
categoriesCount: Object.keys(initialData.categories).length,
8394
totalCount: initialData.totalCount,
95+
currentProduct: initialData.currentProduct,
96+
relatedCount: initialData.relatedProducts.length,
8497
});
8598
} catch (error) {
8699
console.error("데이터 로딩 오류:", error);
@@ -90,36 +103,14 @@ export const render = async (url: string, query: Record<string, string>) => {
90103
let html = "";
91104
try {
92105
console.log("React 컴포넌트 렌더링 시작");
93-
console.log("App 컴포넌트 타입:", typeof App);
94-
console.log("ProductProvider 타입:", typeof ProductProvider);
95106

96-
// 단계별 렌더링 테스트
107+
// 스토어 초기화
97108
productStore.dispatch({
98109
type: PRODUCT_ACTIONS.SET_INITIAL_DATA,
99110
payload: initialData,
100111
});
101112

102-
// 1단계: App만 렌더링
103-
try {
104-
const appOnly = renderToString(<App />);
105-
console.log("App 단독 렌더링 성공, 길이:", appOnly.length);
106-
} catch (appError) {
107-
console.error("App 렌더링 오류:", appError);
108-
}
109-
110-
// 2단계: ProductProvider만 렌더링
111-
try {
112-
const providerOnly = renderToString(
113-
<ProductProvider initialData={{ ...initialData }}>
114-
<div>Provider Test</div>
115-
</ProductProvider>,
116-
);
117-
console.log("ProductProvider 단독 렌더링 성공, 길이:", providerOnly.length);
118-
} catch (providerError) {
119-
console.error("ProductProvider 렌더링 오류:", providerError);
120-
}
121-
122-
// 3단계: 전체 렌더링
113+
// 전체 렌더링
123114
html = renderToString(
124115
<ProductProvider initialData={initialData}>
125116
<App url={url} />
@@ -128,24 +119,17 @@ export const render = async (url: string, query: Record<string, string>) => {
128119

129120
console.log("전체 렌더링 완료, HTML 길이:", html.length);
130121

131-
if (html.length > 0) {
132-
//console.log("HTML 시작 부분:", html.substring(0, 200));
133-
//console.log("HTML 끝 부분:", html.substring(html.length - 100));
134-
} else {
122+
if (html.length === 0) {
135123
console.error("⚠️ 렌더링된 HTML이 비어있습니다!");
136-
137-
// 폴백: 간단한 HTML 구조 생성
138-
html = ``;
139-
console.log("폴백 HTML 생성 완료, 길이:", html.length);
124+
// 폴백 HTML
125+
html = `<div id="root"><!-- SSR 실패, 클라이언트에서 렌더링됩니다 --></div>`;
140126
}
141127
} catch (renderError) {
142-
console.error("React 렌더링 심각한 오류:", renderError);
143-
144-
// 최종 폴백 HTML
145-
html = ``;
128+
console.error("React 렌더링 오류:", renderError);
129+
html = `<div id="root"><!-- 렌더링 오류: ${renderError} --></div>`;
146130
}
147131

148-
const head = "<title>쇼핑몰 - 홈</title>";
132+
const head = `<title>${initialData.currentProduct ? `${initialData.currentProduct?.title} - 쇼핑몰` : "쇼핑몰 - 홈"}</title>`;
149133

150134
console.log("SSR render 완료");
151135

@@ -156,7 +140,6 @@ export const render = async (url: string, query: Record<string, string>) => {
156140
};
157141
};
158142

159-
// 추가 디버깅 함수들
160143
export const debugSSR = () => {
161144
console.log("=== SSR 디버깅 정보 ===");
162145
console.log("renderToString 함수:", typeof renderToString);

0 commit comments

Comments
 (0)