본문 바로가기

경험

[React / Github Pages] BrowserRouter basename 오류

동기

  Github Pages를 통해 React 프로젝트를 배포하려다가 아주 힘든 시련을 겪었기에,

이건 나만 겪지 않을 것이라는 예상 + 이건 나만 겪어도 되는 시련이라는 생각으로 해결책을 남긴다.

 

 사실 특이한 케이스라서 한국어 포스팅은 물론이고, Stack of Flow에도 없어서 남겨본다.

상황

  • Github Pages
  • React: 18.2.0
  • react-bootstrap: 2.5.0 (이 친구까지 왜 썼는지 싶을지도 모른다. 하하..)
  • react-router-dom: 6.4.3

해결 방법 스토리

1. BrowserRouter에 basename 추가 ref. https://bloodstrawberry.tistory.com/1082

  다들 아시다시피, BrowserRouter를 사용하는 와중에 최상위 경로가 아닌 곳에 프로젝트 root가 잡힌다면 BrowserRouter의 속성에 basename에 root 아래부터 기재해줘야 한다.

 간단하게 하려면, package.json에 homepage URL을 지정하고 process.env.PUBLIC_URL을 넣어주면 된다.

 하지만.. 작동하지 않았다..

2. 404.html을 구현하기 ref. https://solo5star.tistory.com/36

 github pages는 정적 리소스를 배포를 지원한다. 그렇기 때문에 해당 경로에 리소스가 없다면 404.html을 띄워준다.

이때! 404.html을 react가 빌드한 index.html과 똑같이 해준다면 react는 정상적으로 작동할 것이다!

 

이건 github action 안에서 구현했다.

 하지만.. 작동하지 않았다..

3. Nav.Link를 Link로 바꾸기

  자. 아래 코드는 내가 처음에 작성한 코드이다. 자세히 보면 그냥 Link가 아닌 Nav.Link로 react-bootstrap에서 가져온 것을 볼 수 있다.

import React from "react";
import routes from "./Routes/router";
import {Container, Row, Col, Navbar, Nav} from 'react-bootstrap';
import {Route, Routes} from "react-router-dom";

const App = () => {
  const navs = routes.map(({name, route, hidden}) => {
    if (hidden) {
      return undefined;
    }

    return <Nav.Link key={route} href={route}>{name}</Nav.Link>
  })

  return (
      <div className="App">
          <Container fluid>
            <Navbar bg="light" expand="lg">
              <Navbar.Brand href="#">UP-LORD</Navbar.Brand>
              <Navbar.Toggle aria-controls="navbar-nav"/>
              <Navbar.Collapse id="navbar-nav">
                <Nav className="ml-auto">
                  {navs}
                </Nav>
              </Navbar.Collapse>
            </Navbar>
            <Row>
              <Col sm={2} className="sidebar">
                <Nav className="flex-column">
                  {navs}
                </Nav>
              </Col>
              <Col sm={10} className="main-content">
                <Routes>
                  {routes.map(({name, route, component}) =>
                      <Route key={route} path={route} element={component}/>
                  )}
                </Routes>
              </Col>
            </Row>
          </Container>
      </div>
  );
};

export default App;

 

 문제는 여기서 발생했던 것이다. 1, 2번의 작업이 먹히지 않았던 이유는 Nav.Link는 BrowserRouter의 basename에 상관없이 최상위 경로의 바로 아래를 기준으로 작동하기 때문이었다..!

 

 아래와 같이 react-router-dom의 Link로 변경하고 테스트해 보니 잘 작동하는 것을 확인했다.

디자인은 직접 css 만지는 수밖에..

import React from "react";
import routes from "./Routes/router";
import {Container, Row, Col, Navbar, Nav} from 'react-bootstrap';
import {Link, Route, Routes} from "react-router-dom";

const App = () => {
  const navs = routes.map(({name, route, hidden}) => {
    if (hidden) {
      return;
    }

    return <Link key={route} to={route}>{name}</Link>
  })

  ```생략```
};

export default App;

 

암튼! 부디 이 글이 도움이 되길 바라며 글을 마친다.