본문 바로가기
리액트(React)

[React] gh-pages 배포시 주의사항 및 오류 해결

by 즐거운코딩 2023. 8. 15.
반응형

이전의 gh-pages 로 정적 홈페이지 배포방법에 대해 설명하였고,

2023.08.15 - [리액트(React)] - 웹사이트 Build 및 깃허브(Github) Pages로 배포하기

추가로 깃허브(Github)의 무료 호스팅인 page 로 create-react-app 으로 만든 리액트 프로젝트을 배포하는데 몇가지 주의사항이 있어서 별도로 설명하고자 합니다..

기본적으로 gh-pages의 경우 리액트와 같은 SPA(Single Page Application)를 지원하지 않습니다. 따라서 다양한 페이지로 접근시 404 에러(페이지를 찾을 수 없음)가 나타납니다.

이에 따라 단순하게 페이지 하나만 보여주는 것은 별 문제가 되지 않으나 기본적으로 gh-pages 에서는 https://[사용자명].github.io 로 바로 접속이 되지 않고 하위로 프로젝트명이 추가되어야 합니다.

즉, package.json 에 homepage 로 https://[사용자명].github.io/[프로젝트명] 이 기본 URL이 되고 리액트에서 사용하는 sub page는 그 하위로 붙어야 합니다.

 

개발작업시에는 기본적으로 localhost:3000 하위로 sub page가 구성되어 문제는 없으나 실제 배포시에는 동작하지 않으므로 다음과 같은 추가작업이 필요합니다.

 

1.  프로젝트 기본 환경

  • npm creat-react-app [프로젝트명] 으로 프로젝트 생성
  • 추가 라이브러리로 react-router-dom 설치 (npm install react-router-dom)
  • 페이지 라우팅으로  <BrowserRouter />, <Routes />, <Route />,  <Link /> 컴포넌트를 사용
  • CSS 로 tailwind 설치 (npm install -D tailwindcss)

 

2. PUBLIC_URL 등록

실제 배포되는 homepage URL을 PUBLIC_URL로 등록하여 사용하면 <Route /> 에 설정한 경로의 앞에 해당 URL을 붙여서 라우팅이 됩니다.

  • 프로젝트 상위 폴더에 .env 파일 생성
  • 파일에  REACT_APP_PUBLIC_URL=https://홈페이지URL 작성
  • 라우트를 설정하는 App.js 에 <BrowserRouter basename={process.env.PUBLIC_URL}> 로 basename 을 추가
(...)
function App() {
  return (
    <BrowserRouter basename={process.env.PUBLIC_URL}>
      <Header />
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route exact path="/about" element={<About />} />
        <Route exact path="/eduprogram" element={<EduProgram />} />
        <Route exact path="/eduprogram/:id" element={<EduDetail />} />
        <Route exact path="/healingprogram" element={<HealingProgram />} />
        <Route exact path="/healingprogram/:id" element={<HealingDetail />} />
        <Route exact path="/training" element={<Training />} />
        <Route exact path="/counseling" element={<Counseling />} />
      </Routes>
    </BrowserRouter>
  );
}
 
  • 다른 페이지에서 <Link /> 컴포넌트 사용으로 페이지간 이동을 하는 경우도 basename 설정으로 자동 라우팅 변경
  • tailwind css 로 navbar 사용시 <Disclosure /> 컴포넌트를 이용하는데 이 때 사용하는 <Disclosure.button /> 컴포넌트에서는 다음과 같이 속성에 href 를 사용하게 되어 {process.env.PUBLIC_URL + item.to} 로 PUBLIC_URL을 추가 적용
            <div className="space-y-1 px-2 pb-3 pt-2">
              {navigation.map((item) => (
                <Disclosure.Button
                  key={item.name}
                  as="a"
                  href={process.env.PUBLIC_URL + item.to}
                  className={classNames(
                    item.current
                      ? 'bg-gray-900 text-white'
                      : 'text-gray-300 hover:bg-gray-700 hover:text-white',
                    'block rounded-md px-3 py-2 text-base font-medium',
                  )}
                  aria-current={item.current ? 'page' : undefined}
                >
                  {item.name}
                </Disclosure.Button>
              ))}
            </div>

 

3.  BrowserRouter 사용시 404 오류 해결

BrowserRouter 특성은 동적인 페이지에 적합하나 새로고침시 경로를 찾지 못해 404 에러를 발생시킵니다.

이러한 404 에러를 고치기 위해 추가적인 작업이 필요합니다.

404 page not found

  • Public 폴더에 있는 index.html 과 404 오류 발생시 이동할 페이지로 404.html 을 작성
더보기

 MIT license 의 오픈 소스로 프로젝트 포함시 라이센스를 명시

[404.html]

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <title>Single Page Apps for GitHub Pages</title>
      <script type="text/javascript">
          // Single Page Apps for GitHub Pages
          // https://github.com/rafrex/spa-github-pages
          // Copyright (c) 2016 Rafael Pedicini,  licensed under the MIT License
          //  ---------------------------------------------- ------------------------
          // This script takes the current url and  converts the path and query
          // string into just a query string, and then  redirects the browser
          // to the new url with only a query string  and hash fragment,
          // e.g. http://www.foo.tld/one/two?a=b& c=d#qwe, becomes
          // http://www.foo.tld/?p=/one/two&  q=a=b~and~c=d#qwe
          // Note: this 404.html file must be at least  512 bytes for it to work
          // with Internet Explorer (it is currently >  512 bytes)

          // If you're creating a Project Pages site  and NOT using a custom domain,
          // then set segmentCount to 1 (enterprise   users may need to set it to > 1).
          // This way the code will only replace the  route part of the path, and not
          // the real directory in which the app  resides, for example:
          //  https://username.github.io/repo-name/one/two?  a=b&c=d#qwe becomes
          // https://username.github.io/repo-name/? p=/one/two&q=a=b~and~c=d#qwe
          // Otherwise, leave segmentCount as 0.
          var segmentCount = 1;

          var l = window.location;
          l.replace(
              l.protocol + '//' + l.hostname + (l.port ?   ':' + l.port : '') +
              l.pathname.split('/').slice(0, 1 +  segmentCount).join('/') + '/?p=/' +
              l.pathname.slice(1).split('/').slice  (segmentCount).join('/').replace(/&/g,  '~and~') +
              (l.search ? '&q=' + l.search.slice(1) .replace(/&/g, '~and~') : '') +
              l.hash
          );

      </script>
  </head>
  <body>
  </body>
</html>

[index.html scripts 추가]

  <script type="text/javascript">
    // Single Page Apps for GitHub Pages
    // https://github.com/rafrex/spa-github-pages
    // Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
    // ----------------------------------------------------------------------
    // This script checks to see if a redirect is present in the query string
    // and converts it back into the correct url and adds it to the
    // browser's history using window.history.replaceState(...),
    // which won't cause the browser to attempt to load the new url.
    // When the single page app is loaded further down in this file,
    // the correct url will be waiting in the browser's history for
    // the single page app to route accordingly.
    (function (l) {
      if (l.search) {
        var q = {};
        l.search.slice(1).split('&').forEach(function (v) {
          var a = v.split('=');
          q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&');
        });
        if (q.p !== undefined) {
          window.history.replaceState(null, null,
            l.pathname.slice(0, -1) + (q.p || '') +
            (q.q ? ('?' + q.q) : '') +
            l.hash
          );
        }
      }
    }(window.location))
  </script>

이와 같이 설정하면 정상적으로 페이지가 표출됩니다.

 

추가로 BrowserRouter 가 아닌 HashRouter를 사용하면 이와 같이 404 에러가 발생하지 않으므로 단순히 static 페이지는 HashRouter 사용이 편리합니다.  

단, HashRouter 사용시 URL에 #(hash)가 붙게 되는데 이럴 경우 검색엔진에서 해당 페이지가 검색되지 않기 때문에 잘 사용하지 않습니다.

반응형