첫 편에서 빌드는 만드는 일, 배포는 잇는 일이라고 갈랐던 거 기억나시죠. 이번 편에서는 그 앞쪽인 빌드를 제대로 파고들어 볼게요. 빌드는 우리가 쓴 소스코드를 브라우저랑 서버가 잘 다룰 수 있는 산출물로 바꾸는 과정인데, 겉으론 명령 하나로 끝나 보여도 안에선 꽤 많은 일이 벌어져요. 이 안을 들여다보면, 배포가 왜 그렇게 도는지도 훨씬 또렷해져요. 저는 빌드를 블랙박스로 두지 말라고 늘 말해요. 안을 알아야 문제가 났을 때 어디를 열어 볼지 알거든요.
이번 편에서는 빌드가 구체적으로 무슨 일을 하는지, 왜 여러 파일을 묶고 줄이고 쪼개는지, 빌드 도구가 우리를 위해 무얼 대신해 주는지, 그리고 빌드가 느리거나 깨질 때 어떻게 다루는지를 이야기할게요. 코드 이야기가 좀 나오지만 겁먹지 마시고, 큰 흐름만 잡는다는 마음으로 따라와 주세요. 원리를 잡으면 세부는 자연히 따라오거든요.
빌드가 정확히 무슨 일을 해요?
빌드가 하는 일을 한마디로 하면 사람 편한 코드를 기계 편한 코드로 옮기는 거예요. 우리는 코드를 짤 때 읽기 좋게, 최신 문법으로, 여러 파일로 나눠서 써요. 그런데 이대로는 브라우저가 못 알아듣거나 비효율적인 부분이 있거든요. 빌드는 이 사람을 위한 편의를 벗겨 내고, 브라우저랑 서버가 바로 삼킬 수 있는 형태로 바꿔 줘요. 그래서 우리는 개발할 땐 편하게 쓰고, 내보낼 땐 효율적인 걸 내보내는 두 마리 토끼를 잡을 수 있죠.
구체적으로 빌드는 여러 단계를 거쳐요. 최신 문법으로 쓴 코드를 오래된 브라우저도 알아듣게 옛 문법으로 바꾸고, 유형 검사가 붙은 코드에서 검사용 표시를 걷어 내고, 흩어진 파일을 몇 개로 묶고, 필요 없는 공백이랑 주석을 덜어 내요. 화면 꾸미는 파일이나 그림 같은 자원도 함께 정리하죠. 이 과정을 다 거치고 나면, 소스랑 똑같이 동작하지만 훨씬 가볍고 빠른 산출물이 나와요.
여기서 중요한 건, 빌드 결과가 소스랑 동작이 같아야 한다는 거예요. 빌드는 겉모습만 바꾸는 거지 하는 일을 바꾸면 안 되거든요. 그런데 가끔 빌드 과정에서 코드를 줄이다 미묘하게 동작이 달라지는 경우가 있어요. 그래서 저는 빌드된 산출물도 실제로 돌려 확인하는 걸 빼먹지 않아요. 소스에선 됐는데 빌드 후엔 안 되는 문제가 실제로 있거든요.
또 하나, 빌드는 같은 소스를 넣으면 같은 산출물이 나와야 좋아요. 넣을 때마다 결과가 달라지면, 첫 편에서 말한 재현성이 무너지니까요. 그래서 딸린 꾸러미 버전을 딱 고정해 두는 게 중요해요. 버전이 그때그때 달라지면, 어제는 되던 빌드가 오늘은 다른 결과를 내거든요. 저는 이 버전 고정을 빌드 안정성의 기본으로 삼아요.
빌드에는 개발용이랑 내보내기용, 이렇게 두 얼굴이 있다는 것도 알아 두면 좋아요. 개발할 땐 문제를 빨리 찾으려고 줄이지 않고 원본에 가깝게 만들고, 실제로 내보낼 땐 최대한 작고 빠르게 만들거든요. 그래서 개발할 때 보이던 친절한 오류 메시지가 내보낸 산출물엔 없기도 해요. 저는 이걸 몰라서 개발에선 잘 보이던 오류 위치가 운영에선 뭉개져 당황한 적이 있어요. 내보내기용 빌드는 사람을 위한 친절함을 속도랑 맞바꾼다는 걸 기억해 두세요.
여러 파일을 왜 하나로 묶어요?
우리는 코드를 여러 파일로 나눠서 써요. 기능마다 파일을 갈라 두면 사람이 관리하기 좋으니까요. 그런데 브라우저 입장에선 파일이 많으면 그만큼 여러 번 받아 와야 해서 느려질 수 있어요. 그래서 빌드는 이 흩어진 파일을 몇 개로 묶어 줘요. 이걸 번들링이라 부르는데, 파일 수를 줄여 브라우저가 덜 왕복하게 만드는 거죠. 사람이 나눠 놓은 걸 기계가 다시 합치는 셈이에요.
번들링은 단순히 이어 붙이는 게 아니에요. 어느 파일이 어느 파일을 필요로 하는지 관계를 따라가며, 실제로 쓰이는 것만 골라 담아요. 그 과정에서 아무도 안 쓰는 코드는 알아서 빼기도 하죠. 이걸 가지치기라 부르는데, 안 쓰는 걸 덜어 내니 산출물이 더 가벼워져요. 저는 이 가지치기 덕분에, 큰 도구를 가져다 써도 실제 쓰는 부분만 담겨 나가는 게 참 고마워요.
다만 무작정 하나로 다 묶는 게 능사는 아니에요. 전부 한 파일로 묶으면, 사용자가 당장 필요 없는 부분까지 한꺼번에 받게 되거든요. 그래서 요즘은 필요할 때 필요한 만큼 나눠 받게 쪼개기도 해요. 첫 화면에 필요한 것만 먼저 받고, 나머지는 그 화면에 갈 때 받는 식이죠. 이 쪼개기 이야기는 바로 다음 꼭지에서 이어 갈게요.
실무에서 번들링은 빌드 도구가 알아서 해 줘요. 우리는 어디가 시작점인지만 알려 주면, 도구가 거기서부터 관계를 쭉 따라가며 필요한 걸 다 모아 묶어 줘요. 저는 처음 번들링을 배울 때 이 관계를 따라간다는 개념이 참 신기했어요. 파일 하나를 가리키면, 그게 부르는 것, 또 그게 부르는 것을 줄줄이 다 찾아내 담아 주니까요.
그래서 번들링을 이해하면 왜 어떤 파일이 산출물에 안 담기는지도 알게 돼요. 어디서도 부르지 않는 파일은 관계의 그물에 안 걸려 빠지거든요. 저는 분명히 만든 코드가 산출물에 없어서 헤매다가, 아무도 그 파일을 안 불렀다는 사실을 뒤늦게 깨달은 적이 있어요. 반대로 그림이나 자료 파일처럼 코드가 직접 안 부르는 것들은, 따로 챙겨 담으라고 도구에 일러 줘야 해요. 번들링은 부르는 것만 담는다는 이 성질을 알면, 산출물이 왜 이 모양인지가 훤히 보여요.
왜 코드를 줄이고 쪼개요?
빌드는 코드를 최대한 작게 만들려고 해요. 공백이랑 줄바꿈을 없애고, 긴 이름을 짧은 이름으로 바꾸고, 주석을 걷어 내죠. 사람은 못 읽게 되지만 브라우저는 상관없고, 파일이 작아지니 빨리 전달돼요. 이걸 압축이라 부르는데, 같은 동작을 하면서 크기만 줄이니 공짜로 빨라지는 셈이에요. 큰 사이트일수록 이 차이가 사용자 체감으로 이어져요.
쪼개기는 조금 다른 이야기예요. 산출물을 여러 조각으로 나눠, 사용자가 지금 필요한 조각만 받게 하는 거죠. 예를 들어 관리자만 쓰는 무거운 화면이 있다면, 일반 사용자는 그 조각을 아예 안 받아도 되잖아요. 이렇게 나눠 두면 첫 화면이 훨씬 빨리 떠요. 코드에서 이건 대개 import()를 함수처럼 써서 필요한 순간에 불러오게 표시해요. 그러면 빌드 도구가 그 부분을 따로 떼어 조각으로 만들어 줘요.
다만 쪼개기도 지나치면 독이에요. 너무 잘게 쪼개면 조각이 많아져, 오히려 여러 번 받느라 느려지거든요. 그래서 저는 화면 단위나 큰 기능 단위로 굵직하게 쪼개요. 자잘하게 쪼개는 것보다, 사용자가 실제로 안 볼 수도 있는 큰 덩어리를 떼어 내는 게 효과가 커요. 쪼개기는 목적이 첫 화면을 빠르게라는 걸 잊지 않으면 방향을 안 잃어요.
이 압축이랑 쪼개기 덕분에, 우리는 개발할 땐 마음껏 크게 쓰고 내보낼 땐 날씬하게 내보낼 수 있어요. 저는 이게 빌드의 가장 큰 선물이라고 봐요. 사람의 편의랑 사용자의 속도를 둘 다 챙겨 주니까요. 예전엔 이걸 손으로 하느라 고생했는데, 요즘은 도구가 다 해 주니 우리는 켜 두기만 하면 돼요.
산출물이 얼마나 커졌는지 가끔 들여다보는 습관도 권하고 싶어요. 빌드 도구들은 어떤 조각이 얼마나 무거운지를 보여 주는 기능을 갖고 있는데, 이걸 보면 생각보다 무거운 덩어리가 눈에 띄곤 하거든요. 저는 이 확인으로 안 써도 되는 무거운 도구가 통째로 딸려 들어온 걸 발견해 걷어 낸 적이 여러 번이에요. 산출물이 무거우면 첫 화면이 느려지니, 내가 내보내는 게 얼마나 큰지를 아는 것만으로도 성능의 절반은 챙기는 셈이에요.
빌드 도구는 뭘 대신해 줘요?
지금까지 말한 문법 변환, 번들링, 압축, 쪼개기를 다 알아서 해 주는 게 빌드 도구예요. 우리는 설정 몇 가지만 정해 주고 npm run build 한 줄이면, 도구가 이 복잡한 과정을 순서대로 착착 밟아 산출물을 만들어 줘요. 예전엔 이걸 하나하나 손으로 엮어야 했는데, 요즘 도구들은 기본 설정만으로도 웬만한 걸 다 해 줘서 참 편해졌어요.
빌드 도구는 개발할 때도 큰 도움을 줘요. 코드를 고치면 바뀐 부분만 순식간에 다시 만들어 화면에 바로 비춰 주거든요. 이 덕분에 우리는 저장하자마자 결과를 즉시 보며 작업할 수 있어요. 이건 빌드랑은 조금 다른 개발용 기능이지만, 같은 도구가 개발용이랑 내보내기용을 함께 맡는 경우가 많아요. 저는 이 즉시 반영이 없던 시절을 떠올리면, 요즘 개발이 얼마나 편해졌나 실감해요.
도구를 고를 땐 우리 프로젝트에 맞는지를 봐요. 요즘 도구들은 대부분 빠르고 기본 설정이 훌륭해서, 저는 많이 쓰이고 문서가 친절한 것을 고르는 편이에요. 사람이 많이 쓰면 문제가 생겨도 먼저 겪은 사람의 답을 쉽게 찾을 수 있거든요. 화려한 신기술보다 든든한 뒷받침이 실무에선 더 값져요.
한 가지 강조하고 싶은 건, 도구가 다 해 준다고 원리를 안 알아도 되는 건 아니라는 거예요. 빌드가 깨지거나 산출물이 이상할 때, 안에서 무슨 일이 벌어지는지 알아야 어디를 손볼지 감이 잡히거든요. 저는 도구에 기대되, 문법 변환이나 번들링 같은 기본 개념은 꼭 이해하라고 권해요. 도구는 바뀌어도 원리는 오래가니까요.
빌드가 느리거나 깨지면 어떻게 해요?
프로젝트가 커지면 빌드가 점점 느려져요. 매번 처음부터 다 만들면 오래 걸리니, 요즘 도구는 바뀐 부분만 다시 만들고 나머지는 아껴 두는 방식으로 속도를 챙겨요. 이걸 빌드 캐시라 부르는데, 자동화 과정에서도 이 아껴 둔 걸 잘 활용하면 빌드 시간이 확 줄어요. 저는 빌드가 유난히 느려지면, 매번 처음부터 다 만들고 있진 않은지부터 살펴봐요.
빌드가 아예 깨질 때도 있어요. 이럴 땐 대개 빌드 기록에 이유가 적혀 있으니, 저는 성급하게 여기저기 고치기 전에 기록부터 차분히 읽어요. 어느 파일 어느 줄에서 무엇 때문에 멈췄는지가 대개 나와 있거든요. 초보일수록 이 기록을 안 읽고 감으로 고치려다 시간을 버리는데, 답은 거의 늘 기록 안에 있어요.
흔한 원인 하나는 내 컴퓨터에선 되는데 자동화 환경에선 깨지는 거예요. 내 컴퓨터에만 있는 파일이나 설정에 은근히 기대고 있었던 거죠. 그래서 저는 빌드가 내 컴퓨터 바깥의 깨끗한 환경에서도 되는지 가끔 확인해요. 딸린 꾸러미를 처음부터 새로 받아 빌드해 보면, 내 컴퓨터에 우연히 있던 것에 기대던 문제가 드러나거든요.
또 하나는 버전이 안 맞아 깨지는 거예요. 도구나 딸린 꾸러미 버전이 사람마다, 환경마다 다르면 누구는 되고 누구는 안 되는 골치 아픈 일이 생겨요. 그래서 버전을 딱 고정해 모두가 같은 걸 쓰게 하는 게 중요해요. 저는 이 버전 고정 파일을 팀의 약속처럼 여기고, 함부로 안 흔들어요. 이 약속이 흔들리면 내 컴퓨터에선 되는데라는 유령이 다시 나타나거든요.
빌드가 자꾸 말썽이면, 저는 메모리가 모자라진 않은지도 의심해요. 프로젝트가 크면 빌드가 메모리를 많이 먹는데, 자동화 환경은 메모리가 넉넉지 않아 중간에 뚝 멈추기도 하거든요. 이럴 땐 산출물을 더 잘게 쪼개 한 번에 다루는 양을 줄이거나, 빌드에 쓸 메모리를 늘려 줘요. 이유가 내 코드가 아니라 환경의 한계일 수도 있다는 걸 염두에 두면, 엉뚱한 데서 헤매는 걸 줄일 수 있어요. 빌드 문제는 늘 코드, 버전, 환경 이 셋을 차례로 의심하는 게 제 요령이에요.
정리하면, 빌드는 사람 편한 코드를 기계 편한 산출물로 바꾸는 과정이에요. 문법을 맞추고, 파일을 묶고, 크기를 줄이고, 필요에 따라 쪼개며, 이 모든 걸 도구가 대신해 주죠. 원리를 알아 두면 빌드가 느리거나 깨질 때 침착하게 다룰 수 있어요. 다음 편에서는 이 빌드랑 배포를 사람 손 없이 자동으로 잇는 자동 배포 파이프라인 이야기로 넘어가 볼게요.