프로젝트/하루한냥

[리팩토링] 디렉토리별 index를 이용한 모듈화 작업하기

알파카털파카 2023. 9. 15. 06:09
[리팩토링]
디렉토리별 index를 이용한 모듈화 작업하기

 

 

중요한 캘린더 부분을 마치고, 중간 점검하는 시간을 가지기로 했다. 이슈와 PR 이름을 아예 '리팩토링'으로 지었다. 그동안 인지는 했지만 미처 신경쓰지 못한 부분이나, 후순위로 밀렸던 태스크, 효율적으로 개선할 수 있을만한 내용을 이번 PR에서 작업 중이다. 멘토님께 리뷰를 받아가며 작업하니, 내 수준에서 몰랐던 노하우도 많이 배우고 있다. 이번 포스트에는 import 할 때 좀 더 깔끔하게 가져오도록 하는 index 사용 방법과 주의점을 적어본다.

 

 


 

 

1. 기존의 import 

CalendarPage.tsx 파일의 import 현황이다. export default로 내보낸 것과, 그냥 export로 내보내서 객체로 묶어 가져온 것이 섞여있다. 

 

기존의 import

 

 

 

 

2. index를 이용해 모듈화한 import 

동일한 CalendarPage 파일의 import 모습이다. index.ts를 생성하고, 모듈화 작업을 한 후의 상태이며 전체적으로 깔끔해졌다. 

 

모듈화한 import

 

 

 

 

3. index.ts 파일 생성하기

각 디렉토리별로 하나의 index 파일을 생성한다. 예시로 pages 디렉토리의 구조를 가져왔다. hooks 디렉토리에도 index 파일을 하나 만들고, 컴포넌트 파일의 하위 디렉토리들에도 하나씩 index 파일을 만들어 주었다. 

 

│  ├─ pages
│   │     ├─ AuthKakaoPage.tsx
│   │     ├─ CalendarPage.tsx
│   │     ├─ EditPostPage.tsx
│   │     ├─ HomePage.tsx
│   │     ├─ ProtectedRoute.tsx
│   │     ├─ ReportPage.tsx
│   │     ├─ SettingPage.tsx
│   │     ├─ SigninPage.tsx
│   │     ├─ SignupPage.tsx
│   │     ├─ TimelinePage.tsx
│   │     ├─ WritePostPage.tsx
│   │     └─ index.ts ✅

 

 

 

4. index.ts 파일 작성하기 

전체 선택자 * 를 사용해 각 파일의 export가 붙은 요소를 내보낸다. 이 때 주의점은, export default로 내보냈던 요소가 있다면 default를 삭제해주어야 한다.

 

export * from './AuthKakaoPage';
export * from './CalendarPage';
export * from './EditPostPage';
export * from './HomePage';
export * from './ProtectedRoute';
export * from './ReportPage';
export * from './SigninPage';
export * from './SignupPage';
export * from './SettingPage';
export * from './TimelinePage';
export * from './WritePostPage';

 

// 기존
export default function CalendarPage() {
  // ...
}


// 수정 후 ✅
export function CalendarPage() { 
  // ...
}

 

이렇게 하면 pages의 파일을 사용하는 곳에서는 한 번에 불러올 수 있다. 스크린샷을 첨부한 기존의 모습과 비교해보면 차이를 알 수 있다. 

 

import {
  AuthKakaoPage,
  CalendarPage,
  EditPostPage,
  HomePage,
  ProtectedRoute,
  ReportPage,
  SettingPage,
  SigninPage,
  SignupPage,
  TimelinePage,
  WritePostPage,
} from './pages';

 

기존의 import

 

 

 

 

5. 테스트에서의 주의점

모든 디렉토리에 index 파일을 만들고, import를 다시 하는 수고스러운 작업을 마쳤다. 머리를 쓰기 보다는 반복 작업이라 어렵진 않았다. 문제는 테스트에서 일어났다. 분명 브라우저에서 작동은 잘 되고 오류도 없는데, 테스트를 돌리면 오류가 발생했다. 

 

테스트 오류

 

문제가 발생한 Overlay 파일에서 41번 째 줄을 삭제하고 테스트를 돌려봤더니, 이번엔 또 다른 곳에서 동일한 내용의 오류가 발생했다. 어떤 흐름인가 살펴보니 테스트 코드에서 가장 상위에 렌더링되는 OverlayProvider 파일에서부터 하나씩 아래로 오류가 흘러내려오는 모습이었다. 

 

// 테스트 코드
describe('App', () => {
  function renderRouter(path: string) {
    const router = createMemoryRouter(routes, { initialEntries: [path] });
    render(
      <OverlayProvider>
        <RouterProvider router={router} />
      </OverlayProvider>,
    );
  }
// ...

 

문제는 styles 디렉토리의 index 파일에서 발생했다. styles 디렉토리에서도 여느 index와 같이 export * from './파일명'으로 내보내고 있었다. 이 파일을 사용하는 곳에서 미처 다 import 해오기 전에, 테스트 코드가 이미 실행이 되어버려서 문제가 되는 것 같았다. index 파일에서 해당 부분을 다음과 같이 바꿔주었다. styles 디렉토리 안의 파일들만 예외적으로 default를 붙여서 기존과 동일한 형태로 사용되고 있다. 이렇게 하면 테스트에서도 오류가 발생하지 않는다. 

 

// index.ts
export { default as globalStyle } from './globalStyle.css';
export { default as styleToken } from './styleToken.css';

 

// globalStyle.css.ts
export default globalStyle;

// styleToken.css.ts
export default styleToken;

 

사용할 때는 이렇다.

 

import { styleToken } from '@ui/styles';

 

 

 

 

마치며

이미 알고 있는 내용이었지만 막상 손에 익지 않아 프로젝트를 진행하면서 놓치고 지나간 내용이었다. 이번에 리팩토링하는 기회에 전체 코드를 손봤다. 거의 대부분의 import를 찾아 일일이 수정해야 했기 때문에 어렵진 않았는데 시간이 좀 걸렸다. 새로 임포트하면서 느낀 점은, '기존에 프로젝트를 하면서 제 멋대로 import 했구나' 라는 부분이었다. 특히 스타일토큰을 가져올 때, styleToken.css와 styleToken을 혼용해서 쓰고 있었다. 그렇게 사용했다는 것도 모르고 있었다. 린트가 대부분 해주긴 하지만, 로직 작성하기에 바빠 import 순서 정리나 어디서 어떻게 가져왔는지를 많이 놓치고 있던 것이 아닌가 하는 생각을 했다. 인덱스 파일로 정리가 되니 깔끔하고 정돈되어 보였다. 앞으로는 시간을 따로 내어 index 작업을 하기보다는, 손에 익도록 습관처럼 사용해야겠다.