Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: SEO 개선 작업 진행 (metadata, sitemap, robots.txt) #243

Merged
merged 9 commits into from
Jun 24, 2024
Merged
36 changes: 18 additions & 18 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ReactNode } from 'react';
import type { Metadata, Viewport } from 'next';
import { ReferrerEnum } from 'next/dist/lib/metadata/types/metadata-types';
import { OpenGraphType } from 'next/dist/lib/metadata/types/opengraph-types';
import { ToastContainer } from 'react-toastify';
import { GoogleTagManager } from '@next/third-parties/google';

Expand All @@ -9,6 +11,7 @@ import '@/styles/GlobalStyles.css';
import * as styles from './layout.css';

import CommonProvider from './_context/CommonProvider';
import METADATA from '@/lib/constants/metadata';

export const viewport: Viewport = {
width: 'device-width',
Expand All @@ -19,27 +22,24 @@ export const viewport: Viewport = {
};

export const metadata: Metadata = {
// Template Object
title: {
template: '%s | ListyWave',
default: 'ListyWave', // 대체 제목 (required),
template: METADATA.title.template,
default: METADATA.title.default,
},
description:
"What’s In Your List? 🌊 나의 취향을 리스트로 기록하고, 공유하고, 발견해요. 리스티웨이브에서 모든 기준은 '나의 취향'이에요. 내 취향 가득한 편안한 공간이 되면 좋겠습니다.",
authors: [{ name: '에잇🩷' }],
generator: 'Next.js',
applicationName: 'ListyWave',
referrer: 'origin-when-cross-origin', // Referrer-Policy
keywords: ['ListyWave', 'list', 'SNS'],
metadataBase: new URL('https://listywave.com'),
description: METADATA.description.default,
authors: [{ name: METADATA.authors.name, url: METADATA.authors.url }],
generator: METADATA.generator,
applicationName: METADATA.applicationName,
referrer: METADATA.referrer as ReferrerEnum,
keywords: METADATA.keywords,
metadataBase: new URL(METADATA.url),
openGraph: {
title: 'ListyWave',
description:
"What’s In Your List? 🌊 나의 취향을 리스트로 기록하고, 공유하고, 발견해요. 리스티웨이브에서 모든 기준은 '나의 취향'이에요. 내 취향 가득한 편안한 공간이 되면 좋겠습니다.",
url: 'https://listywave.com',
type: 'website',
siteName: 'ListyWave',
locale: 'ko',
title: METADATA.title.openGraph,
description: METADATA.description.default,
url: METADATA.url,
type: METADATA.type as OpenGraphType,
siteName: METADATA.siteName,
locale: METADATA.locale,
},
};

Expand Down
31 changes: 31 additions & 0 deletions src/app/list/[listId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
import { Metadata, ResolvingMetadata } from 'next';
import * as styles from './ListDetail.css';

import ListInformation from '@/app/list/[listId]/_components/ListDetailOuter/ListInformation';
import axiosInstance from '@/lib/axios/axiosInstance';
import { ListDetailType } from '@/lib/types/listType';
import METADATA from '@/lib/constants/metadata';

interface ListDetailProps {
params: { listId: number };
}

export async function generateMetadata({ params }: ListDetailProps, parent: ResolvingMetadata): Promise<Metadata> {
const listId = params.listId;
const { data } = await axiosInstance.get<ListDetailType>(`/lists/${listId}`);
const { title, ownerNickname, collaborators, description, items } = data;

const previousImages = (await parent).openGraph?.images || [];
const listType = collaborators.length === 0 ? 'Mylist' : 'Collabo-list';

return {
title: {
absolute: `${ownerNickname}'s ${listType} - ${data.title}`,
},
description: `${description}`,
authors: [{ name: `${ownerNickname}` }],
openGraph: {
title: `${title} By.${ownerNickname}`,
description: `${description || `${ownerNickname}님의 취향을 기록한 리스트입니다.`}`,
url: `${METADATA.url}/list/${listId}`,
images: [`${items[0].imageUrl}`, ...previousImages],
},
};
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 페이지마다 설정해주면 SEO가 되는거군요..! 🤩

export default function ListDetailPage() {
return (
Expand Down
12 changes: 12 additions & 0 deletions src/app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import DOMAIN_URL from '@/lib/constants/domain';
import type { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
},
sitemap: `${DOMAIN_URL}/sitemap.xml`,
};
}
25 changes: 25 additions & 0 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { MetadataRoute } from 'next';
import DOMAIN_URL from '@/lib/constants/domain';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
return [
{
url: DOMAIN_URL,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 1,
},
{
url: `${DOMAIN_URL}/intro`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.8,
},
{
url: `${DOMAIN_URL}/search`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
];
}
33 changes: 25 additions & 8 deletions src/app/user/[userId]/collabolist/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import { Metadata } from 'next';
import { Metadata, ResolvingMetadata } from 'next';

import Profile from '../_components/Profile';
import Content from '../_components/Content';
import FloatingContainer from '@/components/floatingButton/FloatingContainer';
import PlusOptionFloatingButton from '@/components/floatingButton/PlusOptionFloatingButton';
import ArrowUpFloatingButton from '@/components/floatingButton/ArrowUpFloatingButton';

import axiosInstance from '@/lib/axios/axiosInstance';
import { UserType } from '@/lib/types/userProfileType';
import METADATA from '@/lib/constants/metadata';

interface CollaboListPageProps {
params: {
userId: number;
};
params: { userId: number };
}

export const metadata: Metadata = {
title: 'Collabo List',
description: '콜라보레이터와 함께 기록한 리스트 입니다.',
};
export async function generateMetadata({ params }: CollaboListPageProps, parent: ResolvingMetadata): Promise<Metadata> {
const userId = params.userId;
const { data } = await axiosInstance.get<UserType>(`/users/${userId}`);

const previousImages = (await parent).openGraph?.images || [];

return {
title: {
absolute: `${data.nickname}'s Collabo-list`,
},
authors: [{ name: `${data.nickname}` }],
description: METADATA.description.collabolist,
openGraph: {
description: `${data.description || METADATA.description.collabolist}`,
url: `${METADATA.url}/user/${userId}/collabolist`,
images: [`${data.profileImageUrl}`, ...previousImages],
},
};
}

export default function CollaboListPage({ params }: CollaboListPageProps) {
return (
Expand Down
33 changes: 25 additions & 8 deletions src/app/user/[userId]/mylist/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import { Metadata } from 'next';
import { Metadata, ResolvingMetadata } from 'next';

import Profile from '../_components/Profile';
import Content from '../_components/Content';
import FloatingContainer from '@/components/floatingButton/FloatingContainer';
import PlusOptionFloatingButton from '@/components/floatingButton/PlusOptionFloatingButton';
import ArrowUpFloatingButton from '@/components/floatingButton/ArrowUpFloatingButton';

import axiosInstance from '@/lib/axios/axiosInstance';
import { UserType } from '@/lib/types/userProfileType';
import METADATA from '@/lib/constants/metadata';

interface MyListPageProps {
params: {
userId: number;
};
params: { userId: number };
}

export const metadata: Metadata = {
title: 'My List',
description: '나의 취향을 기록한 나만의 리스트 입니다.',
};
export async function generateMetadata({ params }: MyListPageProps, parent: ResolvingMetadata): Promise<Metadata> {
const userId = params.userId;
const { data } = await axiosInstance.get<UserType>(`/users/${userId}`);

const previousImages = (await parent).openGraph?.images || [];

return {
title: {
absolute: `${data.nickname}'s Mylist`,
},
authors: [{ name: `${data.nickname}` }],
description: METADATA.description.mylist,
openGraph: {
description: `${data.description || METADATA.description.mylist}`,
url: `${METADATA.url}/user/${userId}/mylist`,
images: [`${data.profileImageUrl}`, ...previousImages],
},
};
}
Comment on lines +23 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

웅와........


export default function MyListPage({ params }: MyListPageProps) {
return (
Expand Down
3 changes: 3 additions & 0 deletions src/lib/constants/domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const DOMAIN_URL = 'https://listywave.com';

export default DOMAIN_URL;
29 changes: 29 additions & 0 deletions src/lib/constants/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import DOMAIN_URL from './domain';

const METADATA = {
title: {
template: '%s | ListyWave', // Template Object
default: 'ListyWave | 리스티웨이브',
openGraph: 'ListyWave',
},
description: {
default:
"나의 취향을 리스트로 기록하고, 공유하고, 발견해요. 리스티웨이브에서 모든 기준은 '나의 취향'이에요. 내 취향 가득한 편안한 공간이 되면 좋겠습니다.",
mylist: '나의 취향을 기록한 리스트 입니다.',
collabolist: '콜라보레이터와 함께 기록한 콜라보 리스트 입니다.',
},
authors: {
name: '에잇🩷',
url: 'https://github.com/8-Sprinters',
},
generator: 'Next.js',
applicationName: 'ListyWave',
referrer: 'origin-when-cross-origin', // Referrer-Policy
keywords: ['ListyWave', 'list', '리스티웨이브'],
url: DOMAIN_URL,
type: 'website',
siteName: 'ListyWave',
locale: 'ko',
};

export default METADATA;