CRA(Create-React-App)로 React 프로젝트를 생성하면 기본적으로 상대 경로를 사용하는데,
폴더가 많아지면서 불편해지게 되었습니다.
모든 파일에서 동일한 경로를 사용해서 개발 효율을 높이기 위해서 수정하게 되었습니다.
목표는 아래와 같이 상대 경로로 표시 되는 것을 절대 경로로 처리하는 겁니다.
import Layout from "./componenet/layout/layout";
import Main from "./page/main";
import { PATH } from "./utils/constant";
그런데 아래처럼 완전히 절대 경로도 설정해 보았더니,
eslint의 import/order 정렬 설정에 의해 internal로 그룹화되었습니다.
import Layout from 'components/layout/layout';
import Main from 'pages/main';
import { PATH } from 'utils/constant';
src 내 파일들을 pathGroup으로 만들기 위해 @로 시작되도록 매핑하고자 합니다.
import Layout from '@layout/layout';
import Main from '@pages/main';
import { PATH } from '@utils/constant';
Root Directory에 jsconfig.json 파일을 생성합니다.
만약 타입스크립트를 사용하고 있다면 tsconfig.json 파일을 생성하면 됩니다.
exclude나 include를 사용해서 프로젝트에 포함할 파일을 지정합니다.
baseUrl은 기본 디렉토리를 지정합니다.
저는 절대 경로를 src부터 쓰고 싶다면 baseUrl에 .을 입력하고,
src 하위 디렉토리부터 쓰고 싶다면 baseUrl에 src를 입력하세요.
paths에는 경로 매핑을 지정합니다.
(제 경우 eslint 설정을 위해 @를 붙여서 매핑했는데, @ 없이 매핑해도 괜찮아요.)
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@cloud/*": ["cloud/*"],
"@common/*": ["components/common/*"],
"@layout/*": ["components/layout/*"],
"@hooks/*": ["hooks/*"],
"@pages/*": ["pages/*"],
"@utils/*": ["utils/*"]
}
},
"include": [
"src"
]
}
jsconfig.json에 대한 자세한 내용은 이 링크를 참고 바랍니다.
jsconfig.json의 내용이 바로 적용되지 않을 수 있습니다.
제 경우 VSCode를 종료시켰다가 다시 열어주니 잘 동작했습니다.
아마 에디터를 열었을 때 캐시를 업데이트하는 게 아닐까합니다. (제 생각에!)
ctrl을 누른 상태로 경로에 마우스를 대면 연결된 모듈의 경로가 자동 완성되어 표시됩니다.

jsconfig.json 파일이 없을 때는 절대 경로에 대해 모듈이 표시되지 않았는데,
지금은 올바른 모듈 경로를 인식하는 것을 확인할 수 있습니다.

jsconfig.json만 설정한 상태에서는 실행(npm start)했을 때 아래와 같이 컴파일 오류가 발생합니다.
Failed to compile.
Module not found: Error: Can't resolve '@layout/layout' in 'C:\workspace\portfolio\src'
CRA(create-react-app) 프로젝트는 빌드할 때 내부적으로 webpack을 이용합니다.
VSCode같은 에디터는 jsconfig.json를 통해 경로를 인식하고 경로 자동 완성을 통해 코드 작성을 도와주지만 webpack은 jsconfig.json에서 설정한 경로를 인식하지 못합니다.
따라서 webpack의 모듈 해석을 변경하기 위한 별도의 설정이 필요합니다.
주의: 빨간색 명령어 입력하지 마세요. 이전 상태로 돌아갈 수 없어요.
CRA(create-react-app)로 프로젝트를 생성했을 때는 간결한 디렉토리를 위해 여러 설정이 숨겨져 있는데, webpack에 대한 설정을 건드리려면 터미널에서 npm run eject를 입력해서 이 숨겨진 폴더 config를 끄집어내서 웹팩 설정 파일인 webpack.config.js를 수정해야 합니다.
그런데 문제는 npm run eject를 실행하면 숨겨진 모든 설정이 밖으로 추출됩니다. config 폴더 뿐만 아니라 scripts 폴더, package.json 파일 내에서도 그동안 안보였던 dependency나 babel, jest 설정 등 모든 게 드러납니다. eject한 순간부터 CRA가 자동으로 처리해주던 babel과 webpack 설정을 직접 유지 보수해야합니다. (자세한 내용은 이 링크에서 확인 바랍니다.)
아직 CRA로부터 독립하기엔 갈길이 멀기 때문에 왠만하면 eject는 하지 않고자 합니다.
babel도 잘 모르고, 의존성을 매번 체크하자니 간단한 프로젝트를 만들려다가 일이 커질 것 같습니다.
그리고 무시무시한 점은 한번 eject하면 원래 상태로 돌아갈 수 없습니다. "Are you sure you want to eject? this action is permenent"라는 경고 문구가 아주 무섭습니다.
그러나 다행인 부분은 eject하지 않아도 CRA의 설정을 오버라이딩하는 라이브러리가 있다는 점입니다. 대표적으로 'craco(Create React App Configuration Override)'와 'react-app-rewired'가 있습니다.
그런데 'craco'는 CRA5를 지원하지 않는다는 말이 있더라구요?
craco.js.org를 보니craco 7.0.0은 지원한다고 명시되어 있는데, 최근에 업데이트된 모양이에요.
'craco'가 업데이트도 더 자주하고 확장성이 있는 모양이지만 거기까진 바라지 않고,
이 프로젝트에서는 단순히 모듈 해석만 변경하고 싶기 때문에
CRA의 기본 스크립트를 간단하게 대체하는 방식으로 동작하는 'react-app-rewired'로 진행하겠습니다.
npm i -D react-app-rewired 명령어로 devDependencies에 react-app-rewired 라이브러리를 추가해주세요.
Root Directory에 있는 package.json 파일을 수정합니다.
아래처럼 package 파일의 scripts 부분의 명령어를 react-scripts 에서 react-app-rewired로 변경하세요. (eject는 수정하지 않아도 됩니다.)
아래와 같이 script를 수정하고 실행(npm start) 시 CRA의 webpack 설정을 오버라이딩 하기 위해 config-overrides.js 파일을 실행하게 되는데, 아직 config-overrides.js 파일이 없으니 파일을 생성하고 webpack 설정을 하면 됩니다.
{
//...
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
//...
}
Root Directory에 config-overrides.js 파일 생성합니다.
jsconfig.json의 compilerOptions에 paths까지 설정하지 않았다면 아래와 같은 구성으로 마무리해도 될 것 같습니다.
module.exports = function override(config, env) {
//기존의 모듈 경로 설정을 절대 경로로 수정합니다.
config.resolve.modules.push(path.resolve('./src'));
return config;
}
(자세한 내용은 이 링크를 참고하시기 바랍니다.)
모듈 경로를 매핑시키기 위해 CRA의 웹팩 설정을 조정하고 커스터마이즈하는 데에 특화된 라이브러리인 customize-cra를 추가로 설치하겠습니다.
npm i -D customize-cra 명령어로 devDependencies에 'customize-cra' 라이브러리를 추가해주세요.
아까의 임의로 만든 함수 override를 지우고 'customize-cra'의 override, addWebpackAlias를 사용해서 모듈 경로를 매핑하도록 하겠습니다.
jsconfig.json의 compilerOptions에 paths의 key값을 그대로 가져오고 path모듈에 __dirname를 함께 사용한 절대 경로를 만들어서 value로 사용합니다.
const { override, addWebpackAlias } = require('customize-cra');
const path = require('path');
module.exports = override(
addWebpackAlias({
'@cloud': path.resolve(__dirname, 'src', 'cloud'),
'@common': path.resolve(__dirname, 'src', 'components', 'common'),
'@layout': path.resolve(__dirname, 'src', 'components', 'layout'),
'@hooks': path.resolve(__dirname, 'src', 'hooks'),
'@pages': path.resolve(__dirname, 'src', 'pages'),
'@utils': path.resolve(__dirname, 'src', 'utils'),
})
);
이제 webpack이 매핑된 모듈 경로를 인식할 수 있게 되었습니다.
실행(npm start)과 빌드(npm run build)가 잘되는 지 테스트해보세요.
절대 경로를 매핑하고 난 뒤 가장 좋은 점은 경로를 짧게 유지할 수 있다는 것과 모든 파일에서 같은 경로가 사용된 다는 거죠. 다른 파일에서 경로 복사해서 붙여넣으면 금방이에요.