개발

NextJS, Atomic Design Pattern의 조합에서 프로젝트 구조에 대한 단상

안녕하세요, 오랜만에 짤막한 글을 가지고 돌아왔습니다.

 

최근 회사에서 혼자 맡아 진행 중인 프로젝트 중 생각난 내용입니다.

 

관리자 백오피스 형태에서 중복되지 않고 일회성으로 사용되는 컴포넌트에 대하여 프로젝트를 어떤 구조로 구성하여야 좋을지에 대해 고민하고 있었습니다.

 

Atomic design pattern(https://atomicdesign.bradfrost.com/chapter-2/)

Atomic Design Pattern를 사용한 이번 프로젝트의 큰 구조는 아래와 같습니다.

pages/
├─ index.tsx/
├─ _app.tsx
├─ _document.tsx
src/
├─ components/
│  ├─ atoms/
│  ├─ molecules/
│  ├─ organisms/
│  ├─ template/

일단 크게 pagessrc/components 디렉토리를 확인할 수 있습니다.(스캐폴딩 된 NextJS 프로젝트에서는 최상위 경로에 pages 디렉토리를 생성합니다. 이후 사용자의 설정에 따라 src 디렉터리의 하위로 옮길 수 있습니다.)

 

기존의 React 프로젝트에서 진행하던 대로 단위별로 컴포넌트를 제작하고 요구사항대로 페이지를 만들던 중 특정 페이지에서만 중복되어 사용되고 타 페이지에서는 사용되지 않는 컴포넌트들이 많다는 사실을 알게 되었습니다.

 

CSS in JS 라이브러리인 emotion을 사용하면서 기본적으로 중복되어 자주 사용될법한 컴포넌트들의 스타일들은 따로 정의하여 빼두었음에도 불구하고 중복되지만 중복되지 않는(?) 구조의 컴포넌트들이 빈번하게 발생한다는 점이 큰 문제였습니다. 

 

이 문제에 대해 제가 생각할 수 있는 방법은 두 가지였습니다.

  1. 특정 페이지에 국한되어 사용되는 컴포넌트더라도 패턴에 맞게 추가
  2. 특정 페이지에 국한되어 사용되는 컴포넌트들을 해당 페이지의 하위 디렉터리로 컴포넌트를 추가

이번 프로젝트 구조상 한 페이지에 여러 가지의 입력 폼, 테이블, 모달이 들어가게 되는 경우 늘어나는 페이지와 구현 내용에 따라 컴포넌트들은 늘어나게 될 것이고 이러한 무지성 컴포넌트 작성은 추후 유지보수에도 좋지 않은 영향을 끼칠 것이라고 생각되어 기각하였습니다.

 

pages/
├─ account/
│  ├─ index.tsx
│  ├─ components/
│  │  ├─ SignUpForm/
│  │  ├─ SignInForm/
├─ index.tsx

(2) 번 같은 경우에는 위와 같은 형태의 구조로 구성되어 작성하는 것을 말합니다.

 

저는 해당 구조로 특정 페이지에서 사용되는 컴포넌트들을 정의하기로 결정하였습니다.

 

하지만 NextJS의 특성상 pages 디렉터리 하위의 모든 폴더와 파일들은 페이지 라우팅을 통해 접근이 가능합니다.

예를 들어 /pages/account/components/signupform의 경로를 통해 접근했을 때 NextJS는 해당 컴포넌트를 렌더링 합니다.

 

실제 서비스에서 직접 위 경로를 치고 들어오는 경우는 없을 것 같지만 구현하는 제 마음에는 불편하므로 수정하기로 하였습니다.

 

NextJS에서 제공하는 커스텀 서버를 통해 components가 들어가는 경로에 대해 Not Found Exception을 반환하도록 처리하는 방식을 사용하고 싶었지만, 실제로 확인해본 결과 Http Request를 통해 404 상태 코드를 반환하고 있으나 정상적으로 접근이 가능하여 새로운 방법을 모색하게 되었습니다.

 

  1. 라우트 패스에 특정 경로를 포함하고 있을 경우 다른 경로로 리다이렉트 시키기
  2. 실제 페이지 렌더링을 하기 위한 페이지 컴포넌트를 제외한 다른 페이지는 빌드에 포함시키지 않기

next.config.js 파일에 추가적인 설정을 통하여 위와 같은 방안으로 가능하다는 사실을 알 수 있게되었습니다.

 

(1)의 경우는 아래와 같이 설정할 수 있습니다.

module.exports ={
  async redirects() {
    return [
      {
        source: '/about/components',
        destination: '/about',
      },
    ]
  },
}

source요청이 들어오는 경로의 패턴이고, destination리다이렉트 하는 경로입니다.

 

위와 같이 설정하였을 때 사용자는 /about/components/~ 의 경로로 접근을 시도하였을 때 /about으로 리다이렉트 됩니다.

Not Found Exception을 반환하지 않고 접근을 제한할 수 있는 이상적인 방법 중 하나인 것 같습니다.

 

하지만 여러 개의 페이지에서 components 디렉토리를 갖고있다면 그 만큼 next.config.js 파일을 수정하여 추가해주어야 한다는 단점이 있습니다.

 

또한 pages 디렉토리 내 빌드되어 나올 모든 파일들은 tsx의 형식을 갖추어야 합니다.

제가 구성하고 있는 프로젝트에 적용하기에는 어려울 것 같아서 위에 장/단점을 확인하시고 적용하시면 좋을 것 같습니다.

 

저는 (2)의 방식을 적용하여 고충을 해결하고 원하던 구조로 개선할 수 있었습니다.

module.exports = {
  pageExtensions: ['page.ts', 'page.tsx'],
}

위와 같이 설정하였을 때 pages 디렉토리 내 ~.page.ts, ~.page.tsx가 아닌 파일들은 빌드 대상에 포함되지 않는 설정입니다. components 디렉토리에 접근하려고 하였을 때 빌드 대상이 아니므로 없는 경로에 라우트 요청을 하는 것이므로 Not Found Exception을 반환하지만 비교적 추가해야 할 코드가 적고 기본 파일들의 확장자만 수정해주는 것만으로 쉽게 적용할 수 있었습니다.

 

NextJS에서 지향하는 방향에 Atomic Design Pattern이 고려되어 있진 않지만 위 옵션을 통해서 개선할 수 있다는 내용을 알게 된 좋은 기회였습니다.

 

또한 이 부분에 대해서 고민할 때 아는 개발자분께서 아래와 같은 의견을 주기도 하셨습니다.

 

간단하게 PM2NextJS를 통한 배포를 진행할 예정이었으므로 위 의견은 다른 설정을 통해 구성하게 될 경우 사용할 수 있는 좋은 방안이라고 생각합니다.

 

참고