|| 들어가기전
안녕하세요. 레몬베이스에서 Full-stack Software Engineer로 일하고 있는 Jamie입니다.
린터는 코드 품질을 지키는 데 빠질 수 없는 도구인데요. 특히 ESLint는 프론트엔드 생태계에서 사실상 표준처럼 자리 잡고 있죠. 팀의 코드 스타일을 규칙 기반으로 일관되게 유지하는 데 큰 도움을 주는 도구지만, 프로젝트 규모가 커지면 지켜야 하는 규칙도 자연스럽게 많아지고 검사해야 하는 코드의 양도 늘어나면서 실행 속도가 체감될 정도로 느려지기도 해요. 또 메이저 버전이 올라가면서 설정 방식 자체가 바뀌면, 이를 대응하는 데 적지 않은 비용을 치러야 할 때도 있고요.
이번 글에서는 레몬베이스 프론트엔드 챕터가 ESLint V8 지원 종료에 대응하면서 겪은 마이그레이션 과정과, 성능 문제를 해결하기 위해 Biome을 하이브리드로 도입한 경험을 이야기해 보려고 합니다.
목차
ESLint V8 지원 종료, 마이그레이션이 시작되다
AI와 함께한 마이그레이션, 그리고 한계
마이그레이션 완료, 그런데 성능이…?
Biome이라는 선택지
완벽한 대체 대신 “하이브리드”를 선택하다
Phase 1: Formatter 교체 적용기
하이브리드의 현실: 트레이드오프
마치며: 완벽한 도구보다 유연한 조합
ESLint V8 지원 종료, 마이그레이션이 시작되다ESLint 로고
2024년 9월, ESLint V8 지원 종료 공지가 떴습니다.
ESLint의 지원이 종료된다는 것은 곧 보안 패치나 버그가 발생해도 지원을 받을 수 없다는 것인데요. 서비스를 지속적으로 관리해야 하는 입장에선 무조건 대응이 필요한 상황이 되었습니다.
하지만 V8에서 V9으로 올린다는 것은 단순히 버전만 올리면 되는 게 아니었어요. V9부터는 설정 방식이 달라졌거든요. 기존의 .eslintrc.js 파일 기반 설정이 deprecated 되고, Flat Config라는 새로운 형식이 기본이 됐습니다. 기존에 계층적으로 설정을 상속받던 방식에서, 하나의 배열로 모든 설정을 명시적으로 나열하는 방식으로 바뀐 거예요.
우리 프로젝트 상황을 먼저 파악해봤습니다.
레몬베이스 ESLint 설정 현황
적용된 규칙 수: 약 400개
설정 파일 구조: 이원화 — 루트 프로젝트의 .eslintrc.js와 특정 하위 프로젝트의 .eslintrc.js
사용 중인 주요 플러그인: @typescript-eslint, eslint-plugin-import, eslint-plugin-react, prettier, tailwindcss, 그 외 boundaries, compat등
여기서 까다로운 부분이 있었어요. 설정이 이원화되어 있다는 건, 루트에서 정의한 규칙 일부를 하위 프로젝트에서 오버라이드하거나 추가하고 있다는 뜻이거든요. Flat Config으로 전환하려면 이 두 설정을 하나로 통합하면서도, 각 프로젝트에 맞는 규칙 적용은 유지해야 했습니다.
게다가 사용 중인 플러그인들도 V9 Flat Config을 지원하는 버전으로 업데이트해야 했어요. 플러그인마다 지원 시점이 달랐고, 일부는 아직 완벽하게 지원하지 않는 상태였죠.
정리하면 해야 할 일은 이랬습니다.
두 설정 파일을 Flat Config 형식으로 통합
기존 400개 규칙을 최대한 보존
각 플러그인의 V9 호환성 확인 및 업데이트
마이그레이션 후에도 기존과 동일한 린트 결과 보장
이걸 전부 사람이 직접 한다면 얼마나 걸릴까요?
“이것만 풀타임으로 해도 꼬박 3~4일은 걸리겠는데…?”
솔직히 말하자면, 본업이 있는 상황에서 이 작업에만 며칠을 쏟기는 부담스러웠습니다. 그래서 팀에서는 ”AI의 힘을 빌려보자!”라고 판단하게 되었죠.
AI와 함께한 마이그레이션, 그리고 한계ESLint 공식 마이그레이션 도구 시도
ESLint에서 공식으로 마이그레이션 도구를 제공하고 있어서 먼저 돌려봤습니다.
npx @eslint/migrate-config .eslintrc.js
@eslint/compat 같은 호환성 레이어 없이, 각 플러그인의 V9 설정 방식에 맞게 재작성해주길 기대했는