Skip to content

Commit 209ba3e

Browse files
harryk-imgxxrxn
authored andcommitted
[#349] 메타 데이터 추가 (#617)
* feat: 오픈그래프 이미지 추가 * feat: 메타데이터 title, description * feat: 오픈그래프 이미지와 크기 수정 * fix: 오픈그래프 이미지 용량 축소 * fix: opengraph-image.tsx 파일 수정 * fix: Image Generator 제거 * feat: 오픈그래프 이미지 업데이트 * feat: RootLayout에 메타데이터 추가 * feat: Sitemap 작성 - 북카이브, 도서 검색, 독서 모임, 내 프로필 - 비회원 북카이브에 노출되는 책장 및 도서 - 전체 독서 모임 * feat: robots 작성 * fix: 오픈그래프 이미지 업데이트 * feat: site-verification 추가 (구글, 네이버) * refactor: url주소 매직스트링을 환경변수로 교체 * refactor: sitemap을 route별로 분리 * chore: 불필요한 util 파일 삭제 * chore: 코드 리뷰 반영 * refactor: book sitemap 병합 및 route 변경 * refactor: route 위치 통일성 부여
1 parent 0425223 commit 209ba3e

File tree

7 files changed

+191
-1
lines changed

7 files changed

+191
-1
lines changed

src/app/book/sitemap.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { MetadataRoute } from 'next';
2+
import type { APIRecommendedBookshelf } from '@/types/bookshelf';
3+
import type { APIBook } from '@/types/book';
4+
5+
const options = {
6+
headers: {
7+
'Content-Type': 'application/json',
8+
},
9+
next: { revalidate: 60 * 60 * 24 },
10+
};
11+
12+
export async function booksSitemap() {
13+
try {
14+
const res = await fetch(
15+
`${process.env.NEXT_PUBLIC_API_URL}/api/suggestions/bookshelves/default`,
16+
options
17+
);
18+
19+
if (!res.ok) {
20+
return Promise.reject();
21+
}
22+
23+
const data: APIRecommendedBookshelf = await res.json();
24+
25+
const books = new Set<APIBook['bookId']>();
26+
27+
data.bookshelfResponses.forEach(bookshelf =>
28+
bookshelf.books.forEach(book => books.add(book.bookId))
29+
);
30+
31+
const filteredBooks = Array.from(books);
32+
33+
return filteredBooks;
34+
} catch {
35+
return [];
36+
}
37+
}
38+
39+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
40+
const booksId = await booksSitemap();
41+
const sitemap = ['search', ...booksId];
42+
43+
return sitemap.map(value => ({
44+
url: `${process.env.NEXT_PUBLIC_HOST}/book/${value}`,
45+
lastModified: new Date(),
46+
}));
47+
}

src/app/bookshelf/sitemap.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { MetadataRoute } from 'next';
2+
import type { APIRecommendedBookshelf } from '@/types/bookshelf';
3+
4+
const options = {
5+
headers: {
6+
'Content-Type': 'application/json',
7+
},
8+
next: { revalidate: 60 * 60 * 24 },
9+
};
10+
11+
export async function bookshelvesSitemap() {
12+
try {
13+
const res = await fetch(
14+
`${process.env.NEXT_PUBLIC_API_URL}/api/suggestions/bookshelves/default`,
15+
options
16+
);
17+
18+
if (!res.ok) {
19+
return Promise.reject();
20+
}
21+
22+
const data: APIRecommendedBookshelf = await res.json();
23+
const bookshelves = data.bookshelfResponses.map(({ bookshelfId }) => ({
24+
bookshelfId,
25+
}));
26+
27+
return bookshelves;
28+
} catch {
29+
return [];
30+
}
31+
}
32+
33+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
34+
const bookshelves = await bookshelvesSitemap();
35+
36+
return bookshelves.map(({ bookshelfId }) => ({
37+
url: `${process.env.NEXT_PUBLIC_HOST}/bookshelf/${bookshelfId}`,
38+
lastModified: new Date(),
39+
}));
40+
}

src/app/group/sitemap.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { MetadataRoute } from 'next';
2+
import type { APIGroupPagination } from '@/types/group';
3+
4+
const options = {
5+
headers: {
6+
'Content-Type': 'application/json',
7+
},
8+
next: { revalidate: 60 * 60 * 24 },
9+
};
10+
11+
export const bookGroupSitemap = async () => {
12+
try {
13+
const res = await fetch(
14+
`${process.env.NEXT_PUBLIC_API_URL}/api/book-groups?pageSize=100`,
15+
options
16+
);
17+
18+
if (!res.ok) {
19+
return Promise.reject();
20+
}
21+
22+
const data: APIGroupPagination = await res.json();
23+
const bookGroups = data.bookGroups.map(group => group.bookGroupId);
24+
25+
return bookGroups;
26+
} catch {
27+
return [];
28+
}
29+
};
30+
31+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
32+
const bookGroups = await bookGroupSitemap();
33+
34+
return bookGroups.map(bookGroupId => ({
35+
url: `${process.env.NEXT_HOST}/group/${bookGroupId}`,
36+
lastModified: new Date(),
37+
}));
38+
}

src/app/layout.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,47 @@
1+
import { Metadata } from 'next';
2+
13
import ContextProvider from '@/components/ContextProvider';
24
import AuthFailedErrorBoundary from '@/components/AuthFailedErrorBoundary';
35
import Layout from '@/v1/layout/Layout';
46

57
import { LineSeedKR } from '@/styles/font';
68
import '@/styles/global.css';
79

10+
export const metadata: Metadata = {
11+
metadataBase: new URL(`${process.env.NEXT_HOST}`),
12+
title: {
13+
template: '%s | 다독다독',
14+
default: '다독다독',
15+
},
16+
description: '책에 대한 인사이트를 공유하고 소통하는 독서 소셜 플랫폼',
17+
keywords: [
18+
'다독다독',
19+
'dadok',
20+
'dadokdadok',
21+
'책장',
22+
'책추천',
23+
'도서검색',
24+
'독서모임',
25+
'책',
26+
'독서',
27+
],
28+
verification: {
29+
google: '72kN3MWyQHuvSb8V67dVkfPUPMrw102Tm6BsvTvfKmg',
30+
other: {
31+
'naver-site-verification': '9046af5eda448309a92e2e923a45cb874df986a0',
32+
},
33+
},
34+
};
35+
836
const RootLayout = ({ children }: { children: React.ReactNode }) => {
937
return (
1038
<html lang="ko">
1139
<head>
12-
<title>다독다독</title>
1340
<meta
1441
content="width=device-width, initial-scale=1, maximum-scale=1"
1542
name="viewport"
1643
/>
44+
<meta charSet="UTF-8" />
1745
<link rel="icon" href="/favicon.ico" />
1846
</head>
1947
{/* @todo Chakra 제거시 app-layout 프로퍼티 제거. */}

src/app/opengraph-image.jpg

309 KB
Loading

src/app/robots.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { MetadataRoute } from 'next';
2+
3+
export default function robots(): MetadataRoute.Robots {
4+
return {
5+
rules: {
6+
userAgent: '*',
7+
allow: '/',
8+
},
9+
sitemap: `${process.env.NEXT_HOST}/sitemap.xml`,
10+
host: `${process.env.NEXT_HOST}`,
11+
};
12+
}

src/app/sitemap.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { MetadataRoute } from 'next';
2+
3+
import { default as bookSitemap } from './book/sitemap';
4+
import { default as bookshelfSitemap } from './bookshelf/sitemap';
5+
import { default as bookGroupSitemap } from './group/sitemap';
6+
7+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
8+
return [
9+
{
10+
url: `${process.env.NEXT_HOST}/bookarchive`,
11+
lastModified: new Date(),
12+
},
13+
{
14+
url: `${process.env.NEXT_HOST}/group`,
15+
lastModified: new Date(),
16+
},
17+
{
18+
url: `${process.env.NEXT_HOST}/profile/me`,
19+
lastModified: new Date(),
20+
},
21+
...(await bookSitemap()),
22+
...(await bookshelfSitemap()),
23+
...(await bookGroupSitemap()),
24+
];
25+
}

0 commit comments

Comments
 (0)