IntelliJ에서 Tomcat으로 프로젝트를 띄워 놓고 HTML, CSS, JS를 고쳤는데 브라우저에는 그대로였다. 새로고침을 해도, 쿠키를 지워도 달라지지 않았다. 브라우저 쪽을 아무리 만져도 소용이 없었던 건 문제가 브라우저가 아니라 서버가 무엇을 읽고 있느냐에 있었기 때문.

Tomcat은 소스가 아니라 배포된 Artifact를 읽는다

IntelliJ가 Tomcat에 올리는 것은 src/main/webapp의 원본 파일이 아니라 빌드된 Artifact. Artifact가 war면 압축된 한 덩어리라서 안의 CSS 파일 하나만 바꿔 끼울 수 없고, 다시 패키징해서 다시 배포해야 한다.

war exploded는 같은 내용을 압축하지 않은 디렉토리로 둔 것이라 파일 단위로 갱신할 수 있다. 정적 리소스를 서버 재시작 없이 반영하려면 Artifact부터 exploded여야 한다. 뒤에 나오는 Update classes and resources 옵션이 목록에 안 보이는 것도 이 때문이다.

Run Configuration의 업데이트 동작을 바꾼다

상단 실행 설정 목록에서 Edit Configurations...

Tomcat 설정의 Server 탭에서 두 항목을 모두 Update classes and resources로 변경.

  • On 'Update' action: Update 액션을 실행했을 때

  • On frame deactivation: IntelliJ 창에서 포커스가 빠질 때

“자동 반영"의 정체는 두 번째 항목. 코드를 고치고 브라우저로 넘어가는 순간 IntelliJ 창이 비활성화되고, 그때 바뀐 리소스가 배포 디렉토리로 넘어간다. 브라우저에서는 새로고침만 하면 된다.

옵션이 안 보이면 Artifact가 war로 잡혀 있다

Server 탭 드롭다운에 Update classes and resources가 없다면 Deployment 탭을 본다. Deploy at the server startup 목록에 {프로젝트명}:war가 들어 있을 것이다. 이걸 Remove하고 새 Artifact로 {프로젝트명}:war exploded를 추가한다.

같은 탭에서 두 가지를 더 확인한다.

  1. Application context가 /인지 본다. 아니면 /로 고친다.

  2. 추가한 Artifact를 선택하고 연필 아이콘(Edit Artifact)을 눌러 Output directory를 {프로젝트경로}/src/main/webapp으로 바꾼다.

설정 순서를 한데 모으면 이렇다.

Edit Configurations → Deployment → {프로젝트명}:war Remove → + Artifact → {프로젝트명}:war exploded
  → Application context: /
  → Edit Artifact → Output directory: {프로젝트경로}/src/main/webapp
Edit Configurations → Server → On 'Update' action / On frame deactivation: Update classes and resources

Output directory를 소스 경로로 두면 Tomcat이 읽는 곳과 내가 고치는 곳이 같은 디렉토리가 된다. 대신 빌드 산출물(WEB-INF/classes 같은 것)이 소스 트리 안에 생길 수 있으니 처음 적용한 뒤에는 git status로 커밋 대상에 섞이지 않았는지 한 번 확인해 두는 게 좋다.

정리

정적 리소스가 반영되지 않으면 브라우저보다 배포 방식을 먼저 본다. war를 war exploded로 바꾸고 Server 탭의 두 업데이트 동작을 Update classes and resources로 두면 창을 전환하는 것만으로 수정 사항이 올라간다. Java 클래스 쪽은 같은 옵션에 HotSwap이 얽혀 있어서 따로 정리했다.