GitHub Pages는 사용자 또는 조직 페이지(예: username.github.io)와 달리 프로젝트 페이지(예: username.github.io/[YOUR_REPOSITORY_NAME]/)의 경우 저장소 이름을 포함하는 서브 경로에서 사이트를 호스팅합니다. 이때 웹사이트 내의 이미지, CSS, JavaScript 파일 등의 자산(Asset) 경로가 절대 경로(예: /assets/image.png)로 지정되어 있으면, 브라우저는 이를 username.github.io/assets/image.png에서 찾으려 시도하여 404 Not Found 오류를 발생시키고 결국 페이지가 깨져 보이게 됩니다. 이 가이드는 Next.js와 같은 특정 프레임워크의 basePath 설정이 아닌, 일반적인 정적 HTML/CSS/JavaScript 사이트 또는 범용 빌드 도구(Vite, Webpack 등)를 사용하는 프로젝트에서 이 문제를 해결하는 방법을 제시합니다.
문제의 원인: GitHub Pages의 URL 구조
GitHub Pages는 두 가지 유형의 URL로 사이트를 제공합니다.
- 사용자/조직 페이지:
https://username.github.io또는https://orgname.github.io - 프로젝트 페이지:
https://username.github.io/[YOUR_REPOSITORY_NAME]/또는https://orgname.github.io/[YOUR_REPOSITORY_NAME]/
대부분의 경우 프로젝트 페이지로 배포하게 되는데, 이때 [YOUR_REPOSITORY_NAME] 부분이 URL의 서브 경로로 포함됩니다. 만약 HTML, CSS, JavaScript 파일 내에서 자산 경로를 /css/style.css나 /images/logo.png와 같이 루트를 기준으로 하는 절대 경로로 지정하면, 브라우저는 이를 https://username.github.io/css/style.css에서 찾으려고 합니다. 하지만 실제 파일은 https://username.github.io/[YOUR_REPOSITORY_NAME]/css/style.css에 있으므로 경로를 찾지 못하게 됩니다.
해결 방법 1: HTML <base> 태그 사용
HTML <base> 태그는 문서 내의 모든 상대 URL에 대한 기준 URL을 지정합니다. <head> 태그 안에 이 태그를 추가하여 GitHub Pages 저장소 이름을 기준으로 설정하면, 모든 상대 경로가 올바르게 해석됩니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>내 정적 사이트</title>
<!-- GitHub Pages 저장소 이름을 기준으로 <base> href 설정 -->
<!-- 예: 저장소 이름이 'my-blog'라면 href="/my-blog/" -->
<base href="/[YOUR_REPOSITORY_NAME]/">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>환영합니다!</h1>
<img src="images/logo.png" alt="로고">
<p>이것은 정적 사이트입니다.</p>
<script src="js/main.js"></script>
</body>
</html>
장점: 한 번의 설정으로 모든 상대 경로에 적용됩니다. 내부 링크(예: <a href="about.html">)에도 영향을 미쳐 /[YOUR_REPOSITORY_NAME]/about.html로 연결됩니다.
주의사항: SPA(Single Page Application)나 클라이언트 측 라우팅을 사용하는 복잡한 사이트에서는 <base> 태그가 예상치 못한 동작을 유발할 수 있으므로 주의해야 합니다. 일반적인 정적 사이트에는 유용합니다.
해결 방법 2: 모든 자산 경로를 상대 경로로 지정
가장 확실하고 안전한 방법은 모든 자산 경로를 현재 HTML 파일 또는 CSS 파일의 위치를 기준으로 하는 상대 경로로 지정하는 것입니다. 이는 <base> 태그의 영향을 받지 않고, 빌드 도구 설정 없이도 작동합니다.
HTML 파일 (index.html)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>내 정적 사이트</title>
<!-- CSS 파일은 현재 HTML 파일 기준 상대 경로 -->
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<h1>환영합니다!</h1>
<!-- 이미지 파일은 현재 HTML 파일 기준 상대 경로 -->
<img src="./images/logo.png" alt="로고">
<p>이것은 정적 사이트입니다.</p>
<!-- JS 파일도 현재 HTML 파일 기준 상대 경로 -->
<script src="./js/main.js"></script>
</body>
</html>
CSS 파일 (css/style.css)
/* background-image도 CSS 파일 기준 상대 경로 */
body {
background-image: url('../images/background.png'); /* css 폴더에서 상위로 이동 후 images 폴더 */
font-family: Arial, sans-serif;
}
h1 {
color: #333;
}
장점: 가장 견고하며, 어떤 환경에서도 경로 문제가 발생할 가능성이 낮습니다. 빌드 도구 설정이 필요 없습니다. 주의사항: 파일 구조가 복잡해지면 경로를 일일이 관리하기 번거로울 수 있습니다.
해결 방법 3: 빌드 도구의 base 또는 publicPath 옵션 활용
Vite, Webpack, Parcel 등 모듈 번들러나 빌드 도구를 사용하여 정적 사이트를 생성하는 경우, 해당 도구의 설정에서 base 또는 publicPath 옵션을 지정하여 모든 자산 경로에 저장소 이름을 자동으로 붙일 수 있습니다. 이는 빌드 시점에 경로를 수정해주므로, 수동으로 경로를 변경할 필요가 없습니다.
Vite 프로젝트 예시 (vite.config.ts)
import { defineConfig } from 'vite';
export default defineConfig({
// GitHub Pages에 배포할 저장소 이름을 base 경로로 설정
// 예: https://username.github.io/my-blog/ 일 경우 '/my-blog/'
base: '/[YOUR_REPOSITORY_NAME]/',
build: {
outDir: 'dist', // 빌드 결과물이 저장될 디렉토리
},
});
Webpack 프로젝트 예시 (webpack.config.js)
const path = require('path');
module.exports = {
// ... (다른 설정)
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
// GitHub Pages에 배포할 저장소 이름을 publicPath로 설정
// 예: https://username.github.io/my-blog/ 일 경우 '/my-blog/'
publicPath: '/[YOUR_REPOSITORY_NAME]/',
},
// ... (다른 설정)
};
장점: 빌드 도구가 자동으로 모든 자산 경로를 처리하므로 개발자가 직접 경로를 수정할 필요가 없습니다. 대규모 프로젝트에 적합합니다. 주의사항: 사용하는 빌드 도구에 따라 설정 방법이 다르므로, 해당 도구의 공식 문서를 참고하여 정확한 옵션과 값을 확인해야 합니다.
흔히 하는 실수 및 주의사항
- 로컬 환경과의 차이: 로컬에서
index.html을 직접 열거나http-server등으로 서빙할 때는/[YOUR_REPOSITORY_NAME]/와 같은 서브 경로가 없으므로 경로 문제가 발생하지 않을 수 있습니다. 반드시 배포된 GitHub Pages URL에서 최종 확인해야 합니다. - 잘못된
[YOUR_REPOSITORY_NAME]: 저장소 이름을 정확히 입력해야 합니다. 대소문자를 구분하며, 오타가 있으면 경로가 깨집니다. base태그와 내부 링크:<base>태그는 페이지 내의 모든 상대 URL에 영향을 미치므로, 내부 페이지 링크(<a>)가 예상과 다르게 동작할 수 있습니다. 예를 들어<a href="posts/1.html">은/[YOUR_REPOSITORY_NAME]/posts/1.html로 연결됩니다.- 환경 변수 활용: 만약 여러 환경(개발, 프로덕션, GitHub Pages)에 따라
base경로가 달라져야 한다면, 환경 변수를 활용하여 빌드 시점에 동적으로 경로를 설정하는 방법을 고려해볼 수 있습니다. 이는 프로젝트의 복잡성에 따라 달라질 수 있으니 확인이 필요합니다.