- 발행일
"배포 전 SEO 설정"이라고 적고 src/app을 통째로 지웠다 — Next 12 옆에 남아 있던 App Router 뼈대
"배포 전 SEO 설정"이라고 적고 src/app을 통째로 지웠다
이 글은 2026년 9월에 당시 커밋 이력을 다시 보며 정리한 것입니다. 날짜는 작업한 날 기준입니다.
직짱건강 저장소의 첫 커밋은 2024년 2월 11일 팀원의 "Initial commit from Create Next App"입니다. 그날 저녁 팀원이 Next 버전을 12.3.4로 내렸고(451e9fb "next version 12 수정"), 저는 밤 10시에 README와 목업 JSON으로 첫 커밋을 올렸어요.
create-next-app은 그 시점 기본값대로 src/app 폴더를 만들어 놓았습니다. layout.tsx, page.tsx, globals.css, page.module.css, 파비콘. 열어 보면 이렇습니다.
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
App Router는 Next 13에서 들어온 것이라 12.3.4에서는 이 폴더를 읽지 않습니다. 팀은 src/pages 아래에 화면을 짜고 있었고, src/app은 아무 데도 안 걸리는 뼈대로 보름 넘게 옆에 있었어요.
지운 날, 커밋 제목은 SEO
2월 28일 오후 95cef05 "[24-02-28] 배포 하기 전 seo 설정". 6개 파일, +2/−372.
public/index.html | 4 +-
src/app/favicon.ico | Bin 25931 -> 0 bytes
src/app/globals.css | 107 ----------------------
src/app/layout.tsx | 22 -----
src/app/page.module.css | 230 ------------------------------------------------
src/app/page.tsx | 11 ---
372줄 삭제가 src/app이고, 커밋 제목이 말하는 SEO는 public/index.html의 네 줄 변경입니다.
<title>직.짱.건.강</title>
+ <script src="https://developers.kakao.com/sdk/js/kakao.min.js"></script>
+ <script defer src="https://cdn.swygbro.com/public/widget/swyg-widget.js"></script>
</head>
<!-- public/index.html -->
-<script src="https://developers.kakao.com/sdk/js/kakao.min.js"></script>
카카오 SDK 스크립트를 head 안으로 옮기고, 스위그 위젯 스크립트를 하나 더 넣었습니다. 메타 태그도 OG 이미지도 없어요. "배포 전에 해야 할 것"을 한 커밋에 넣고 제목은 그중 하나로 붙인 건데, 제목만 읽으면 372줄이 어디서 나왔는지 알 수 없습니다.
그 index.html은 페이지가 아니었다
더 곤란한 건 public/index.html 자체입니다. 이 파일은 2월 25일에 제가 만들었어요(9e10b29). Next에서 public/은 정적 파일 폴더라 이 파일은 /index.html이라는 주소로 그냥 내려갈 뿐, 홈 화면(src/pages/index.tsx)의 HTML에 끼어들지 않습니다. head에 넣은 스크립트 두 줄은 어느 화면에서도 실행되지 않았어요.
카카오 SDK가 실제로 어디서 실렸는지를 찾아보면, src 쪽 커밋 둘(50e5037·b5acb95)이 같은 스크립트 주소를 만집니다. 화면 코드가 따로 불러 쓰고 있었던 거예요. public/index.html은 3월 12일에 스위그 위젯 줄이 빠진 채로 지금까지 남아 있습니다.
create-react-app에서는 public/index.html이 진짜 문서라, 거기에 스크립트를 넣던 버릇이 그대로 온 것으로 보입니다. 그렇다고 단정할 근거는 커밋에 없고, 그때 왜 그 파일을 만들었는지도 적혀 있지 않습니다.
검증
- 그날 확인한 것: 빌드가 되고 배포된 화면이 뜨는 것.
src/app을 지워도 아무것도 안 깨진 게 그 폴더가 안 읽히고 있었다는 증거였는데, 그렇게 연결해서 생각한 기록은 없습니다. - 이 글을 쓰며 확인한 것:
git ls-tree 95cef05^ src/app src/pages로 두 폴더가 같이 있던 것,95cef05^:package.json의"next": "12.3.4",git log -- public/index.html로 파일을 만든 커밋이 2월 25일 제 것이라는 것. git log -S'kakao.min.js' -- src로src쪽에서 같은 스크립트를 다루는 커밋 둘을 찾았습니다. 정확히 어느 파일에서 어떻게 실었는지는 이 글에서 추적하지 않았습니다.- 스위그 위젯이 실제로 어느 화면에 떴는지는 확인하지 못했습니다.
남은 것 · 한계
- 커밋 제목이 내용을 안 담습니다. 372줄 삭제를 "SEO 설정"이라고 불렀어요. 1년 뒤 TripTune에서도 "BFF"라고 적어 두고 msw를 지운2025-03-17BFF라고 적어 두고 msw를 지운 홈 화면 — 커밋 제목에 있던 두 단어가 코드에는 없었다홈 화면의 인기·추천 여행지를 실제 API로 붙이면서 커밋 제목에 "for BFF"와 "msw 제거"라고 썼습니다. 그런데 코드에는 BFF 계층이 없었고 msw는 설치된 적도 없었어요. 지운 건 컴포넌트 안에 박아 둔 배열이었고, 같은 날 API 경로 형식과 응답 모양이 바뀌었습니다. 나흘 사이의 커밋 셋을 차례대로 적었습니다. 커밋을 올렸습니다. 제목에 하고 싶었던 일을 적고 실제로 한 일은 diff에만 남기는 버릇이 그때까지 이어졌어요.
public/index.html이 지금도 저장소에 있습니다. 아무 화면에도 안 쓰이는 파일을 만든 사람이 저인데, 지우지 않았습니다.src/app을 왜 팀원이 아니라 제가 지웠는지, 그 전에 누가 알고 있었는지는 기록이 없습니다. 보름 동안 아무도 안 건드린 걸 보면 둘 다 그 폴더를 신경 쓰지 않았던 것 같은데, 이것도 추측입니다.- 이때
pages라우터를 고른 이유는 팀원의 버전 다운그레이드 커밋에 적혀 있지 않습니다. 넉 달 뒤 TripTune은 App Router로 시작했고, 거기서는 루트 레이아웃에 'use client'가 붙는2026-03-14루트 레이아웃에 'use client'가 붙어 있었다 — 라이트하우스 점수를 보러 갔다가App Router로 만들었다고 믿었던 프로젝트의 루트 레이아웃에 use client가 붙어 있었습니다. 그 한 줄 때문에 트리 전체가 클라이언트 컴포넌트였고, next/head는 무동작이었으며, QueryClient는 모듈 최상단에서 만들어지고 있었어요. 점수를 올리러 갔다가 경계를 다시 그은 기록입니다. 다른 종류의 문제를 만났습니다.
관련 글: 직짱건강 — 백엔드를 기다리지 않고 설문 인터페이스를 먼저 완성한 방법2024-03-31직짱건강 — 백엔드를 기다리지 않고 설문 인터페이스를 먼저 완성한 방법직장인 대상 건강 설문과 위치 기반 병원 추천을 묶은 헬스케어 서비스입니다. 6인 협업 프로젝트에서 프런트엔드로 참여했고, 백엔드 API가 없는 상태에서 JSON 목업으로 설문 플로우를 먼저 완성해 병렬 작업이 가능하게 만든 게 핵심 기여였어요. · "BFF"라고 적어 두고 msw를 지운 홈 화면2025-03-17BFF라고 적어 두고 msw를 지운 홈 화면 — 커밋 제목에 있던 두 단어가 코드에는 없었다홈 화면의 인기·추천 여행지를 실제 API로 붙이면서 커밋 제목에 "for BFF"와 "msw 제거"라고 썼습니다. 그런데 코드에는 BFF 계층이 없었고 msw는 설치된 적도 없었어요. 지운 건 컴포넌트 안에 박아 둔 배열이었고, 같은 날 API 경로 형식과 응답 모양이 바뀌었습니다. 나흘 사이의 커밋 셋을 차례대로 적었습니다. · 루트 레이아웃에 'use client'가 붙어 있었다2026-03-14루트 레이아웃에 'use client'가 붙어 있었다 — 라이트하우스 점수를 보러 갔다가App Router로 만들었다고 믿었던 프로젝트의 루트 레이아웃에 use client가 붙어 있었습니다. 그 한 줄 때문에 트리 전체가 클라이언트 컴포넌트였고, next/head는 무동작이었으며, QueryClient는 모듈 최상단에서 만들어지고 있었어요. 점수를 올리러 갔다가 경계를 다시 그은 기록입니다.