어제 밤, 오랜만에 달달쇼핑 코드를 업데이트하던 중, 이해할 수 없는 오류가 발생했다.
위 이미지는 달달 쇼핑 웹의 vercel deployments를 캡쳐한 이미지이다.
코드를 수정하고, 배포를 확인해보러 vercel로 넘어가니, 언젠가부터 vercel build에서 오류가 나고 있었음을 알게 되었다.
내가 코드 합쳤을 때까지만 해도 아무 오류가 없었으니 함께 작업한 친구가 build 오류를 확인하지 않고 코드를 올렸구나 생각했다.
하지만 로컬에서 yarn build
명령어를 실행해보니 된다...?
또, vercel에서는 이와 같은 오류가 났다는데,
src/components/common/SvgIcon.tsx(1,8): error TS2865: Import 'SvgIcon' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Command "yarn run build" exited with 2
친구가 변경한 코드들을 살펴보니 단순 오타 수정뿐이었다.
심지어 오류가 발생했다는 SvgIcon
컴포넌트는 건들지도 않았다.
(의심해서 미안...)
SvgIcon 컴포넌트에서 발생하는 문제로 보이니 해당 컴포넌트의 코드를 자세히 살펴보자.
import SvgIcon from '@type/svgIcon';
const SvgIcon = ({ id, color = 'none', size, width, height }: SvgIcon) => (
<svg fill={color} width={size || width} height={size || height}>
<use href={`#${id}`} />
</svg>
);
export default SvgIcon;
위 코드에서 의심스러운 것은, SvgIcon을 사용하는 코드에서 동일한 이름의 타입을 호출하고 있다는 것이다.
VSCode로 보면 더 명확하게 보인다.
현재 사용하고 있는 VSCode 설정에서는 const로 선언된 변수의 경우 변수명이 노란색으로 표기되고, 타입은 초록색으로 표기된다.
하지만 위 사진을 보면 const SvgIcon
부분이 노란색이 아니라 초록색으로 표시되고 있다.
이 부분이 build가 실패하는 이유일 것이라고 생각했다.
변수와 타입이 구분될 수 있도록 타입 SvgIcon
을 svgIcon
으로 변경해보았고,
import svgIcon from '@type/svgIcon';
const SvgIcon = ({ id, color = 'none', size, width, height }: svgIcon) => (
<svg fill={color} width={size || width} height={size || height}>
<use href={`#${id}`} />
</svg>
);
export default SvgIcon;
드디어 배포에 성공하였다.
위 질문의 답을 찾기 위해 긴 뻘짓을 하다가 이유를 깨달았다.
인터넷에 로컬에서는 build가 되는 파일이 vercel에서는 build가 안 되는 오류에 대해 검색하면 아주 다양한 오류들이 나온다.
이 오류들의 공통점은 대소문자의 변경
이 있었다는 것이다.
사실 SvgIcon 코드는
import svgIcon from '@type/svgIcon';
const SvgIcon = ({ id, color = 'none', size, width, height }: svgIcon) => (
<svg fill={color} width={size || width} height={size || height}>
<use href={`#${id}`} />
</svg>
);
export default SvgIcon;
이렇게 생긴 코드였다.
코드를 작성하는 과정에서 누구는 타입을 camel case로, 누구는 pascal case로 작성하다 보니 이 부분에 대한 convention을 정하기로 하였고, 한 차례 모든 타입을 pascal case로 통일시키는 과정을 거치다 보니
import SvgIcon from '@type/svgIcon';
const SvgIcon = ({ id, color = 'none', size, width, height }: SvgIcon) => (
<svg fill={color} width={size || width} height={size || height}>
<use href={`#${id}`} />
</svg>
);
export default SvgIcon;
지금의 이 코드가 되었다.
이렇게 대소문자가 변경이 있었던 것이 문제의 원인이지 않을까?
이전에 특정 파일의 이름을 camel case에서 pascal case로 변경한 적이 있다.
해당 변경은 github에서 잡히질 않아서 온갖 import 오류를 만들어 내었고, 해당 파일 삭제 -> commit하여 git에 반영 -> 변경할 이름으로 파일 재생성
하여 문제를 해결했다.
이 과정에서 case sensitive
라는 개념을 처음 알게 되었다.
운영체제마다 가지고 있는 file system은 case sensitive를 선택할 수도 있고, case insensitive를 선택할 수도 있다.
이 개념은 이름 뜻 그대로 대소문자에 연연할지 말지를 결정한다.
git과 vercel은 case sensitive하다.
하지만, 내가 사용하고 있는 window는 case sensitive하지 않다.
따라서, 타입이 camel case에서 pascal case로 업데이트되면서
분명히 이상한 코드인데 로컬은 왜 동작했을까? 로컬에서 해당 오류를 잡아주는 기능이 없었을까?
확인을 위해 단순한 코드를 똑같이 만들어보니
lint에서 해당 코드의 심상치 않음을 감지한다.
하지만,
SvgIcon 컴포넌트에는 밑줄이 뜨지 않는다.
추측으로는 위 이유(case sensitive)와 마찬가지로 camel case로 작성되어 있던 시기가 있었으므로 해당 시기에서 변경사항이 없다고 판단하여 타입과 변수를 여전히 다르게 판단하고 있는 것 같다.
또, 해당 코드가 멀쩡하게 yarn run
이 되는 이유는, 타입과 관련된 코드는 실제 실행이 일어날 때 모두 제거가 되므로 실제 실행되는 코드에는 타입이 사라지기 때문이다.
그동안 잘 동작하다가 상관없는 pr을 합치는 타이밍에 build 오류가 난 이유에 대해서는 알아내지 못해서 좀 아쉽다.
그래도 처음 오류를 발견했을 때는 억까를 당하는 기분이었는데 이유를 알아내고 정리하면서 조금이나마 개운해졌다.
저를 의심하셨군요...ㅋㅋㅋㅋㅋㅋㅋ