효율적인 Document Title 설정하기

 

안녕하세요. 꾸생입니다 :)

오늘은 리액트에서 효율적으로 Document Title을 설정하는 방법에 대해 기록해봅니다.

 

Document Title이란 무엇인지 부터 알아보며 시작하도록 하겠습니다.

 

Document Title이란?


 

브라우저를 통해 웹사이트에 접속하면 대표적으로 상단 탭에 페이지 제목이 위치하게 되는데요. 이 페이지 제목이 Document Title입니다. 가장 대표적인 웹사이트의 타이틀로, 고정적인 경우도 있으나 해당하는 페이지마다 달라지는 경우가 대부분입니다. 검색엔진 뿐만 아니라 사용자한테도 중요하게 보이는 요소라 생각합니다.

 

Document Title은 HTML 문서에서 아래와 같이 작성됩니다. 

 

<!DOCTYPE html>
    <head>
    		...
    	<title>Web Site Title</title>
        	...
    </head>
    <body>
    	...
    </body>
</html>

 

타이틀의 변경이 필요하다면 index.html 파일의 <title/> 태그 내용을 수정해주면 되지만 모든 페이지의 타이틀이 같을 수는 없습니다.

 

 

같은 네이버 웹사이트이지만 네이버 메인의 타이틀과 네이버 사전의 타이틀은 현저히 다릅니다. 같은 HTML 파일을 사용하고 있진 않겠지만, 리액트나 뷰 처럼 SPA 방식의 프로젝트는 똑같은 index.html 파일을 사용하기 때문에 페이지 별로 다른 타이틀을 보여주어야 합니다. 그러므로 <title/> 태그에 고정적으로 넣어 사용하는 것이 아닌 변수로 할당해 페이지마다 바꿔주는 전략을 사용합니다.

 

1. 환경변수로 대표 페이지 제목 선언


CRA 명령어로 프로젝트를 생성했다면 환경 변수를 등록할 때 아래와 같은 규칙으로 작성해줍니다.

 

 

리액트:  REACT_APP_변수명="변수내용"

 

큰 따옴표는 사용하지 않습니다

./.env

REACT_APP_TITLE=꾸생 // CRA로 생성된 프로젝트
TITLE=꾸생 // 수동 웹팩 설정한 프로젝트

 

프로젝트 상위 경로에 .env파일로 환경변수를 선언했습니다.

 

2. index.html  타이틀  변경


.public/index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    ...
    <title><%= htmlWebpackPlugin.options.title %></title>
    ...
</head>
<body>
    <div id="app" />
</body>
</html>

 

빌드 시 웹팩 설정에서 가져온 제목을 넣어주기 위해 <title/> 태그의 내용을 위 처럼 변경해줍니다.

 

4. 웹팩 설정


수동으로 웹팩을 설정했을 경우입니다. CRA를 사용한다면 process.env 명령어를 바로 사용할 수 있겠지만 수동으로 설정했다면 아래와 같이 설정해줍니다.

 

플러그인 및 라이브러리 설치

npm i -D html-webpack-plugin dotenv

 

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
require('dotenv').config()

module.exports = {
    ...
    plugins: [
        new webpack.DefinePlugin({
            "process.env": JSON.stringify(process.env)
        }),
        new HtmlWebpackPlugin(
            { 
                template: './public/index.html', // 템플릿 설정
                title: process.env.REACT_APP_TITLE, // 문서 타이틀
            }
        ),
    ]
    ...
}

 

모든 파일에서 process.env 명령어로 환경변수에 접근 할 수 있도록 해주려면 plugins에 DefinePlugin을 만들어줘야합니다. 위 코드 처럼 생성해주면 어떤 파일에서든 환경 변수에 접근할 수 있습니다. 

 

다음으로 HtmlWebpackPlugin을 추가하고 template에는 html 파일 경로와 title에 환경변수에 만들어뒀던 타이틀을 선언해주면 웹팩에서 빌드할 때 알아서 타이틀을 넣어주게됩니다.

 

이제부터는 페이지 타이틀을 변경한다면 index.html 파일이 아닌 .env파일에서 변경합니다. 그렇다면 이제 페이지별로 타이틀을 다르게 보여주도록 하겠습니다.

 

5. react-router-dom 설정


아래는 제가 react-router-dom을 사용하는 방법입니다.

 

1. 페이지별 컴포넌트 만들기

 

Pages 폴더에 경로마다 보여줄 컴포넌트들을 생성해줍니다. 

 

2. 페이지별 라우터 정보 만들기

.pages.js

import Home from "./Pages/Home"
import About from "./Pages/About"
import About from "./Notice/"

export const pages = [
    { id: 0, path: '/', title: 'Home', comp: <Home/> },
    { id: 1, path: '/about', title: 'About', comp: <About/> },
    { id: 2, path: '/notice', title: 'Notice', comp: <Notice/> },
]

 

그리고 pages.js 파일을 하나 만들어 라우팅에 필요한 path와 component, title 등 배열로 선언해줍니다. 

 

app.js

import { useEffect } from 'react'
import { Routes, Route, useLocation } from 'react-router-dom' 
import { pages } from './pages'
import Header from "./Layout/Header"
import Main from "./Layout/Main"
import Footer from "./Layout/Footer"


export default function App() {

    const { pathname } = useLocation() // 현재 페이지 pathname
    const title = process.env.TITLE // 메인 타이틀 

    useEffect(()=> {
        // 현재 경로에 맞는 타이틀 찾기
        const { title: subTitle } = pages.find(p => p.path === pathname )
        document.title = title + ' - ' + subTitle // title 적용
    }, [pathname])

    return(
    <> 
        <Header />
        <Main>
            <Routes>
                { pages.map(p => <Route key={p.id} path={p.path} element={p.comp} /> ) }
            </Routes>
        </Main>
        <Footer/>
    </>
    )

}

 

1) app.js 안에서 pages.js를 불러와 <Routes/>로 경로마다 보여줄 수 있게 해줍니다.

2) useEffect() Hook에서 pathname을 의존성으로 설정해 페이지가 이동될 때 마다 pathname에 맞는 타이틀을 찾아 적용해줍니다.

 

good doc title

 

헤더의 메뉴들은 아래처럼 만들어 줬습니다.

 

./Layout/header.js

import { NavLink } from 'react-router-dom'
import { pages } from '../pages'

const Header = () => {

    return(
        <header className='header'>
            <h1 className="title">
            { 
                pages.map(p => <NavLink to={ p.path } key={ p.id }>{ p.title }</NavLink>)
            }    
            </h1>
        </header>
    )
}

export default Header

 

+) 메인 페이지 타이틀 심플하게


위 처럼 코드를 사용했다면 메인 페이지에서 "Title - Home" 으로 표시됩니다. 네이버의 경우 메인페이지는 "NAVER"로 심플하게 나오는데요. if문 하나만 추가해주면 됩니다.

 

    useEffect(()=> {
        const { title: subTitle } = pages.find(p => p.path === pathname )
        if(subTitle === 'Home') document.title = title
        else document.title = title + ' - ' + subTitle
    }, [pathname])

 

 

good doc title