Vite로 여러 페이지 관리하는 웹사이트 만들기

HTML, Tailwind CSS, JavaScript를 배웠다면 이제 여러 페이지짜리 웹사이트를 만들어볼 차례입니다. 그런데 페이지가 2~3개만 되어도 귀찮은 일이 생깁니다. 사이드바 메뉴가 모든 파일에 복사-붙여넣기 되어 있으니까, 메뉴 하나 고치려면 파일을 전부 열어서 똑같이 수정해야 합니다. 파일이 늘어나면 실수도 따라 늘어나고요.
이 글에서는 Vite로 관리자 페이지를 만듭니다. 3개 페이지가 사이드바 하나를 공유하고, Tailwind CSS도 CDN 대신 Vite로 빌드되게 설정합니다. 다 만들고 나면 사이드바 코드는 딱 한 곳에만 있고, 거기서 메뉴를 고치면 모든 페이지에 반영됩니다.
시작하기 전에
따라 하려면 다음이 필요합니다.
- HTML, CSS, JavaScript 기본 문법
- Tailwind CSS 유틸리티 클래스 사용 경험
- Node.js 18 이상
- VS Code 같은 코드 에디터
- 예상 시간: 약 40분
먼저 Node.js가 설치되어 있는지 확인합니다. 터미널을 열고 이 명령어를 입력합니다.
node -v
v18.0.0 이상이 출력되면 됩니다. 버전 정보가 나타나지 않으면 Node.js 공식 사이트에서 LTS 버전을 다운로드하여 설치합니다.
1단계: Vite가 뭔지 이해하기 (5분)
코드를 작성하기 전에, Vite가 뭔지부터 짚고 넘어갑니다.
HTML 파일을 브라우저에서 여는 것과 뭐가 다를까?
지금까지는 HTML 파일을 만들고 브라우저에서 직접 열어서 결과를 확인했을 겁니다. 파일 탐색기에서 index.html을 더블클릭하면 브라우저가 열리죠. 간단하긴 한데, 프로젝트가 커지면 이런 불편이 생깁니다.
- CSS를 고칠 때마다 브라우저에서 새로고침을 눌러야 합니다
- Tailwind CSS를 CDN으로 불러오면 안 쓰는 스타일까지 전부 딸려와서 파일이 큽니다
- JavaScript 파일이 여러 개면 불러오는 순서를 직접 맞춰야 합니다
- 여러 페이지에서 공통 코드를 재사용하기 어렵습니다
Vite는 뭘 해주는가
Vite는 개발 서버와 빌드 도구를 결합한 도구입니다.
개발할 때 (dev 모드): 코드를 수정하면 브라우저가 알아서 새로고침됩니다. 저장하는 순간 화면이 바뀌니까, F5를 누를 일이 없어집니다.
배포할 때 (build 모드): HTML, CSS, JavaScript를 하나로 합치고, 안 쓰는 코드를 지우고, 파일 크기를 줄여줍니다. CDN으로 Tailwind를 불러오면 300KB가 넘는데, Vite로 빌드하면 실제 쓴 클래스만 남아서 10KB 이하가 됩니다.
정리하면 이렇습니다.
| 파일 직접 열기 | Vite 사용 | |
|---|---|---|
| 코드 수정 후 | 브라우저에서 새로고침 | 자동으로 화면 갱신 |
| Tailwind CSS | CDN으로 전체 로드 (300KB+) | 사용한 것만 포함 (10KB 이하) |
| JavaScript 파일 관리 | <script> 순서 직접 관리 | import/export로 자동 관리 |
| 배포용 파일 | 원본 그대로 | 최적화된 파일 생성 |
"빌드한다"는 게 뭔가
"빌드"라는 말이 좀 어렵게 들릴 수 있는데, 별거 아닙니다. 개발용 코드를 배포용 코드로 바꾸는 과정입니다.
개발할 때는 파일을 여러 개로 나눠서 작업하는 게 편합니다. 사이드바는 sidebar.js, 스타일은 style.css, 페이지별 로직은 각각 따로. 그런데 실제 웹사이트에 올릴 때는 파일이 적을수록 빨리 로딩됩니다.
빌드하면 이런 일이 일어납니다.
- 여러 JavaScript 파일을 하나로 합칩니다
- CSS에서 실제 쓴 클래스만 남기고 나머지를 지웁니다
- 코드의 공백과 줄바꿈을 없애서 파일 크기를 줄입니다
- 결과물을
dist/폴더에 넣습니다
이 dist/ 폴더를 웹 서버에 올리면 사이트가 공개됩니다. 개발할 때 쓴 원본 파일은 올리지 않습니다.
다음 그림은 빌드 과정을 한눈에 정리한 것입니다.

왼쪽의 개발 파일들이 빌드를 거치면 오른쪽의 dist/ 폴더에 최적화된 파일로 변환됩니다. 특히 Tailwind CSS는 300KB 이상에서 10KB 이하로 줄어듭니다. JavaScript 파일들도 하나로 합쳐지고 압축됩니다.
확인하기: 여기까지 이해되었으면 다음으로 넘어갑니다. Vite는 "개발할 때 편하게, 배포할 때 가볍게" 해주는 도구입니다. 이것만 기억하면 됩니다.
2단계: Vite 프로젝트 만들기 (5분)
터미널을 열고 프로젝트를 만들 폴더로 이동합니다.
npm create vite@latest my-admin -- --template vanilla
my-admin이라는 폴더에 Vite 프로젝트가 만들어집니다. --template vanilla는 React나 Vue 같은 프레임워크 없이 순수 HTML/CSS/JavaScript로 시작하겠다는 뜻입니다. 지금까지 배운 것만으로 충분합니다.
프로젝트 폴더로 들어가서 필요한 패키지를 설치합니다.
cd my-admin npm install
npm install을 하면 필요한 도구들이 다운로드됩니다. node_modules 폴더가 생기는데, 이 안은 건드릴 일이 없습니다.
개발 서버를 띄워봅니다.
npm run dev
터미널에 이와 비슷한 메시지가 뜹니다.
VITE v6.x.x ready in xxx ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help
브라우저에서 http://localhost:5173/을 열어봅니다.
확인하기: Vite 로고와 함께 "Hello Vite!" 같은 기본 페이지가 보이면 성공입니다. Ctrl + C를 누르면 서버가 꺼집니다.
3단계: 프로젝트 구조 정리하기 (5분)
Vite가 만들어준 기본 파일들을 정리합니다. 현재 폴더 구조는 이렇습니다.
my-admin/ ├── index.html ├── package.json ├── node_modules/ ├── public/ │ └── vite.svg ├── counter.js ├── javascript.svg ├── main.js └── style.css
counter.js, javascript.svg는 Vite가 만든 예제 파일이라 필요 없습니다. 지웁니다.
rm counter.js javascript.svg public/vite.svg
style.css와 main.js의 내용도 전부 지웁니다.
main.js는 빈 파일이 아니라, 다음 한 줄만 남겨둡니다.
import './style.css'
JavaScript에서 CSS를 불러오는 방식이 다소 생소하게 느껴질 수 있습니다. 원래 HTML에서 <link> 태그로 CSS를 불러왔으니까요. Vite에서는 이렇게 JS가 CSS를 가져와야 빌드할 때 최적화할 수 있습니다.
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> </head> <body> <h1>관리자 페이지</h1> <script type="module" src="/main.js"></script> </body> </html>
여기서 <script type="module">을 눈여겨봅니다. type="module"이 붙으면 JavaScript에서 import/export 문법을 쓸 수 있게 됩니다. Vite가 바로 이 모듈 시스템 위에서 돌아갑니다.
확인하기: npm run dev를 실행하고 브라우저를 열면 "관리자 페이지"라는 텍스트만 보여야 합니다.
4단계: Tailwind CSS 설치하기 (5분)
지금까지 Tailwind CSS를 CDN 방식으로 썼을 겁니다.
<!-- CDN 방식 - 이제 이렇게 안 합니다 --> <script src="https://cdn.tailwindcss.com"></script>
CDN 방식은 편하긴 한데, Tailwind 스타일을 통째로 불러옵니다. Vite에 Tailwind를 설치하면 실제 쓴 클래스만 CSS에 들어갑니다.
개발 서버를 Ctrl + C로 끄고, Tailwind CSS와 Vite 플러그인을 설치합니다.
npm install -D tailwindcss @tailwindcss/vite
-D는 "개발용으로만 설치"한다는 뜻입니다. Tailwind는 빌드 과정에서만 필요하고, 최종 결과물에는 변환된 CSS만 들어갑니다.
프로젝트 루트에 vite.config.js 파일을 새로 만듭니다.
import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ tailwindcss(), ], })
Vite에게 "Tailwind CSS 플러그인을 쓰겠다"고 알려주는 설정 파일입니다.
style.css를 열고 다음 한 줄을 넣습니다.
@import "tailwindcss";
이 한 줄이 CDN의 <script> 태그를 대신합니다. Tailwind의 모든 유틸리티 클래스를 쓸 수 있게 되죠.
잘 되는지 확인해봅니다. index.html의 <h1> 태그에 Tailwind 클래스를 추가합니다.
<body class="bg-gray-100"> <h1 class="text-3xl font-bold text-blue-600 p-8">관리자 페이지</h1> <script type="module" src="/main.js"></script> </body>
다시 npm run dev로 서버를 띄웁니다.
확인하기: 회색 배경에 파란색 굵은 글씨로 "관리자 페이지"가 보이면 Tailwind가 잘 붙은 겁니다.
5단계: 여러 페이지 만들기 (5분)
Vite에서 여러 페이지를 만드는 건 간단합니다. HTML 파일을 추가하면 끝입니다.
관리자 페이지용 폴더를 만듭니다.
mkdir pages
pages/dashboard.html 파일을 만들고 다음 내용을 작성합니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>대시보드</title> </head> <body class="bg-gray-100"> <div class="flex h-screen"> <aside class="w-64 bg-white border-r p-6"> <h2 class="text-xl font-bold mb-6">관리자</h2> <nav class="flex flex-col gap-2"> <a href="/pages/dashboard.html" class="block py-2 px-4 bg-blue-100 text-blue-700 rounded font-medium">대시보드</a> <a href="/pages/category.html" class="block py-2 px-4 hover:bg-gray-100 rounded">카테고리 관리</a> <a href="/pages/song.html" class="block py-2 px-4 hover:bg-gray-100 rounded">노래 관리</a> </nav> </aside> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">대시보드</h1> <p class="text-gray-600">관리자 페이지에 오신 것을 환영합니다.</p> </main> </div> <script type="module" src="/main.js"></script> </body> </html>
pages/category.html 파일을 만듭니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>카테고리 관리</title> </head> <body class="bg-gray-100"> <div class="flex h-screen"> <aside class="w-64 bg-white border-r p-6"> <h2 class="text-xl font-bold mb-6">관리자</h2> <nav class="flex flex-col gap-2"> <a href="/pages/dashboard.html" class="block py-2 px-4 hover:bg-gray-100 rounded">대시보드</a> <a href="/pages/category.html" class="block py-2 px-4 bg-blue-100 text-blue-700 rounded font-medium">카테고리 관리</a> <a href="/pages/song.html" class="block py-2 px-4 hover:bg-gray-100 rounded">노래 관리</a> </nav> </aside> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">카테고리 관리</h1> <p class="text-gray-600">카테고리를 관리하는 페이지입니다.</p> </main> </div> <script type="module" src="/main.js"></script> </body> </html>
pages/song.html 파일을 만듭니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>노래 관리</title> </head> <body class="bg-gray-100"> <div class="flex h-screen"> <aside class="w-64 bg-white border-r p-6"> <h2 class="text-xl font-bold mb-6">관리자</h2> <nav class="flex flex-col gap-2"> <a href="/pages/dashboard.html" class="block py-2 px-4 hover:bg-gray-100 rounded">대시보드</a> <a href="/pages/category.html" class="block py-2 px-4 hover:bg-gray-100 rounded">카테고리 관리</a> <a href="/pages/song.html" class="block py-2 px-4 bg-blue-100 text-blue-700 rounded font-medium">노래 관리</a> </nav> </aside> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">노래 관리</h1> <p class="text-gray-600">노래를 관리하는 페이지입니다.</p> </main> </div> <script type="module" src="/main.js"></script> </body> </html>
브라우저에서 http://localhost:5173/pages/dashboard.html을 열어봅니다. 사이드바 링크를 클릭하면 페이지가 바뀝니다.
그런데 여기서 문제가 있습니다. 사이드바 코드가 3개 파일에 똑같이 복사되어 있습니다. 메뉴를 하나 추가하려면 3개 파일을 다 열어서 고쳐야 합니다. 10개면 10곳입니다. 코드 리뷰에서 흔히 지적되는 "코드 중복" 문제가 바로 이것입니다.
확인하기: 3개 페이지가 다 열리고, 사이드바 링크로 이동이 되면 성공입니다. 사이드바 중복 문제는 다음 단계에서 해결합니다.
다음 그림은 지금 상태(복사-붙여넣기)와 다음 단계에서 만들 구조(모듈 분리)를 비교한 것입니다.

왼쪽은 지금 상태입니다. 사이드바 코드 30줄이 3개 파일에 그대로 복사되어 있어서, 메뉴를 하나 추가하려면 3곳을 다 수정해야 합니다. 오른쪽은 다음 단계에서 만들 구조입니다. 사이드바 코드가 sidebar.js 한 곳에만 있고, 각 페이지가 import로 가져다 씁니다. 수정할 곳이 1곳이면 끝입니다.
6단계: 사이드바를 JavaScript로 분리하기 (10분)
이 글에서 가장 중요한 단계입니다. 반복되는 사이드바를 한 곳에서 관리하게 만듭니다.
사이드바 생성 함수 만들기
components/ 폴더를 만들고 sidebar.js 파일을 생성합니다.
mkdir components
components/sidebar.js 파일을 만들고 다음 내용을 작성합니다.
const menuItems = [ { title: '대시보드', href: '/pages/dashboard.html' }, { title: '카테고리 관리', href: '/pages/category.html' }, { title: '노래 관리', href: '/pages/song.html' }, ] export function createSidebar() { const currentPath = window.location.pathname const aside = document.createElement('aside') aside.className = 'w-64 bg-white border-r p-6 flex-shrink-0' const title = document.createElement('h2') title.className = 'text-xl font-bold mb-6' title.textContent = '관리자' aside.appendChild(title) const nav = document.createElement('nav') nav.className = 'flex flex-col gap-2' menuItems.forEach(item => { const a = document.createElement('a') a.href = item.href a.textContent = item.title const isActive = currentPath === item.href if (isActive) { a.className = 'block py-2 px-4 bg-blue-100 text-blue-700 rounded font-medium' } else { a.className = 'block py-2 px-4 hover:bg-gray-100 rounded' } nav.appendChild(a) }) aside.appendChild(nav) return aside }
코드가 좀 길어 보이는데, 핵심만 짚어봅니다.
menuItems 배열: 메뉴 항목이 데이터로 정의되어 있습니다. 메뉴를 추가하고 싶으면 여기에 객체 하나만 더 넣으면 됩니다. HTML 3곳을 고칠 필요가 없어지는 거죠.
export function: export가 붙으면 다른 파일에서 이 함수를 import해서 쓸 수 있습니다.
window.location.pathname: 지금 어떤 페이지에 있는지 경로를 알려줍니다. /pages/dashboard.html에 있으면 대시보드 메뉴만 파란색으로 바뀌죠. 각 페이지에서 "나는 대시보드야"라고 따로 알려줄 필요가 없습니다.
document.createElement: HTML 태그를 JavaScript로 만드는 방법입니다. <aside>, <nav>, <a> 같은 태그를 코드로 만들고, appendChild로 붙입니다.
HTML 파일에서 사이드바 코드 제거하기
이제 3개의 HTML 파일에서 사이드바 코드를 지우고 JavaScript가 대신 넣어주도록 합니다.
pages/dashboard.html을 다음으로 수정합니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>대시보드</title> </head> <body class="bg-gray-100"> <div id="app" class="flex h-screen"> <!-- 사이드바는 JavaScript가 자동으로 넣어줍니다 --> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">대시보드</h1> <p class="text-gray-600">관리자 페이지에 오신 것을 환영합니다.</p> </main> </div> <script type="module" src="/pages/dashboard.js"></script> </body> </html>
달라진 점이 두 군데 있습니다.
<aside>태그가 통째로 사라졌습니다. 사이드바는 HTML에 안 씁니다.<script>가main.js대신dashboard.js를 불러옵니다. 각 페이지가 자기만의 JS 파일을 갖게 됩니다.
같은 방식으로 pages/category.html을 수정합니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>카테고리 관리</title> </head> <body class="bg-gray-100"> <div id="app" class="flex h-screen"> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">카테고리 관리</h1> <p class="text-gray-600">카테고리를 관리하는 페이지입니다.</p> </main> </div> <script type="module" src="/pages/category.js"></script> </body> </html>
pages/song.html도 수정합니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>노래 관리</title> </head> <body class="bg-gray-100"> <div id="app" class="flex h-screen"> <main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">노래 관리</h1> <p class="text-gray-600">노래를 관리하는 페이지입니다.</p> </main> </div> <script type="module" src="/pages/song.js"></script> </body> </html>
3개 파일이 비슷비슷하지만, 사이드바 코드는 어디에도 없습니다. <title>, <h1>, <p>, <script>만 페이지마다 다릅니다.
페이지별 JavaScript 파일 만들기
이제 각 페이지의 JavaScript 파일을 만들 차례입니다. 사이드바를 불러와서 페이지에 넣어주는 역할을 합니다.
pages/dashboard.js 파일을 만듭니다.
import '../style.css' import { createSidebar } from '../components/sidebar.js' const app = document.getElementById('app') app.insertBefore(createSidebar(), app.firstChild)
단 4줄입니다.
import '../style.css'— Tailwind CSS를 불러옵니다import { createSidebar } from '../components/sidebar.js'— 아까 만든 사이드바 함수를 가져옵니다document.getElementById('app')— HTML에서id="app"인 요소를 찾습니다app.insertBefore(createSidebar(), app.firstChild)— 사이드바를<main>앞에 끼워넣습니다
pages/category.js 파일을 만듭니다. 내용이 같습니다.
import '../style.css' import { createSidebar } from '../components/sidebar.js' const app = document.getElementById('app') app.insertBefore(createSidebar(), app.firstChild)
pages/song.js 파일도 만듭니다.
import '../style.css' import { createSidebar } from '../components/sidebar.js' const app = document.getElementById('app') app.insertBefore(createSidebar(), app.firstChild)
"이것도 내용이 똑같은데 또 반복 아닌가?" 싶을 수 있습니다. 맞습니다. 지금은요. 하지만 각 페이지에 기능이 붙으면 달라집니다. 카테고리 페이지에는 카테고리 CRUD 로직이, 노래 페이지에는 노래 관리 로직이 추가될 겁니다. 지금은 사이드바만 불러오고 있지만, 페이지별로 코드가 달라질 자리가 마련된 셈입니다.
지금까지 만든 프로젝트 구조입니다.
my-admin/ ├── index.html ├── main.js ├── style.css ├── vite.config.js ├── package.json ├── components/ │ └── sidebar.js ← 사이드바 코드가 여기 한 곳에만 있음 └── pages/ ├── dashboard.html ├── dashboard.js ├── category.html ├── category.js ├── song.html └── song.js
다음 그림은 각 파일 사이의 import 관계를 보여줍니다.

HTML 파일은 자기 페이지의 JS 파일만 로드합니다. JS 파일이 공통 모듈인 style.css와 sidebar.js를 import합니다. 이 구조 덕분에 사이드바를 수정하면 모든 페이지에 자동으로 반영됩니다.
확인하기: http://localhost:5173/pages/dashboard.html을 열었을 때 사이드바가 나오고, 메뉴를 클릭하면 페이지가 전환되고, 현재 페이지 메뉴가 파란색이면 성공입니다.
7단계: 사이드바 수정이 모든 페이지에 반영되는지 확인하기 (3분)
분리한 보람이 있는지 직접 확인해봅니다.
components/sidebar.js를 열고 menuItems에 항목을 하나 추가합니다.
const menuItems = [ { title: '대시보드', href: '/pages/dashboard.html' }, { title: '카테고리 관리', href: '/pages/category.html' }, { title: '노래 관리', href: '/pages/song.html' }, { title: '노래 신청 관리', href: '/pages/request.html' }, // 추가 ]
저장하고 브라우저를 봅니다. 대시보드, 카테고리, 노래 관리 페이지 셋 다 사이드바에 "노래 신청 관리"가 생겨 있습니다. 파일 하나만 건드렸는데 전부 바뀌었습니다.
전에는 HTML 3개를 열어서 같은 <a> 태그를 3번 추가해야 했습니다. 10개면 10번. 이제는 sidebar.js 한 곳이면 끝입니다.
확인했으면 추가한 항목은 지워도 되고, 그냥 둬도 됩니다.
확인하기: sidebar.js를 고쳤을 때 모든 페이지 사이드바가 같이 바뀌는 걸 확인했으면 이 단계는 끝입니다.
8단계: Vite 빌드 설정하기 (5분)
개발 모드에서는 Vite가 HTML 파일을 알아서 찾아주지만, 빌드할 때는 어떤 파일을 포함할지 직접 알려줘야 합니다.
vite.config.js를 다음으로 수정합니다.
import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' import { resolve } from 'path' export default defineConfig({ plugins: [ tailwindcss(), ], build: { rollupOptions: { input: { main: resolve(__dirname, 'index.html'), dashboard: resolve(__dirname, 'pages/dashboard.html'), category: resolve(__dirname, 'pages/category.html'), song: resolve(__dirname, 'pages/song.html'), }, }, }, })
build.rollupOptions.input에 HTML 파일을 하나씩 등록합니다. 여기 안 넣은 파일은 빌드에서 빠집니다.
빌드를 돌려봅니다.
npm run build
dist/ 폴더가 생기고, 안에 빌드된 파일이 들어 있습니다.
dist/ ├── index.html ├── pages/ │ ├── dashboard.html │ ├── category.html │ └── song.html └── assets/ ├── dashboard-xxxxx.js ├── category-xxxxx.js ├── song-xxxxx.js └── dashboard-xxxxx.css
assets/ 안의 파일명에 xxxxx 같은 문자가 붙어 있는데, Vite가 파일 내용을 기반으로 만든 해시값입니다. 코드가 바뀌면 파일명도 바뀌기 때문에, 브라우저가 예전 버전을 캐시해서 안 바뀌는 문제를 막아줍니다.
빌드 결과를 미리 확인해봅니다.
npm run preview
http://localhost:4173/pages/dashboard.html을 열어서 개발 모드와 똑같이 동작하는지 봅니다.
확인하기: npm run build가 오류 없이 끝나고, npm run preview에서 사이트가 정상 동작하면 됩니다.
9단계: 카테고리 관리 기능 추가하기 (10분)
이제 빈 페이지에 실제 기능을 붙여봅니다. 카테고리 페이지에 추가/삭제 기능을 만듭니다.
pages/category.html의 <main> 부분을 수정합니다.
<main class="flex-1 p-8"> <h1 class="text-2xl font-bold mb-4">카테고리 관리</h1> <div class="flex gap-2 mb-6"> <input type="text" id="categoryInput" placeholder="카테고리 이름" class="border rounded px-4 py-2 flex-1" /> <button id="addBtn" class="bg-blue-500 text-white px-6 py-2 rounded hover:bg-blue-600" > 추가 </button> </div> <ul id="categoryList" class="space-y-2"></ul> </main>
pages/category.js를 다음으로 수정합니다.
import '../style.css' import { createSidebar } from '../components/sidebar.js' const app = document.getElementById('app') app.insertBefore(createSidebar(), app.firstChild) // --- 카테고리 관리 로직 --- const input = document.getElementById('categoryInput') const addBtn = document.getElementById('addBtn') const list = document.getElementById('categoryList') // LocalStorage에서 데이터 불러오기 let categories = JSON.parse(localStorage.getItem('categories')) || [] function save() { localStorage.setItem('categories', JSON.stringify(categories)) } function render() { list.innerHTML = '' categories.forEach((name, index) => { const li = document.createElement('li') li.className = 'flex items-center justify-between bg-white p-4 rounded border' const span = document.createElement('span') span.textContent = name const deleteBtn = document.createElement('button') deleteBtn.textContent = '삭제' deleteBtn.className = 'text-red-500 hover:text-red-700' deleteBtn.addEventListener('click', () => { if (confirm(`"${name}" 카테고리를 삭제하시겠습니까?`)) { categories.splice(index, 1) save() render() } }) li.appendChild(span) li.appendChild(deleteBtn) list.appendChild(li) }) } addBtn.addEventListener('click', () => { const name = input.value.trim() if (!name) { alert('카테고리 이름을 입력해주세요.') return } categories.push(name) save() render() input.value = '' }) input.addEventListener('keydown', (e) => { if (e.key === 'Enter') addBtn.click() }) render()
앞쪽 4줄은 다른 페이지와 같습니다. CSS 불러오고 사이드바 넣고. 그 밑부터가 카테고리 페이지에만 있는 로직입니다.
페이지별 JS 파일이 왜 필요한지 이제 이해가 될 겁니다. 공통 코드(CSS, 사이드바)는 같은데, 페이지마다 기능이 다르니까요. 사이드바는 components/sidebar.js가 담당하고, 카테고리 로직은 pages/category.js가 담당합니다.
확인하기: 카테고리 이름을 입력하고 추가를 누르면 목록에 나타나야 합니다. 삭제를 누르면 확인 절차를 거쳐 데이터가 삭제됩니다. 새로고침해도 데이터가 남아 있으면 성공입니다.
프로젝트 최종 구조
my-admin/ ├── index.html ← 메인 페이지 ├── main.js ← 메인 페이지 JS ├── style.css ← Tailwind CSS 진입점 ├── vite.config.js ← Vite + Tailwind 설정 ├── package.json ├── components/ │ └── sidebar.js ← 사이드바 (한 곳에서 관리) └── pages/ ├── dashboard.html ← 대시보드 페이지 ├── dashboard.js ├── category.html ← 카테고리 관리 페이지 ├── category.js ← 카테고리 CRUD 로직 포함 ├── song.html ← 노래 관리 페이지 └── song.js
기억할 점은 세 가지입니다.
- 공통 요소는
components/에 둡니다. 사이드바뿐 아니라 모달이나 알림 같은 공통 UI도 여기에 만들면 됩니다. - 각 페이지는 HTML + JS 한 쌍입니다. HTML은 화면 뼈대, JS는 공통 요소를 붙이고 페이지 고유 로직을 담당합니다.
- CSS는
style.css하나면 됩니다. Tailwind를 쓰면 클래스로 스타일링하니까 CSS 파일을 여러 개 만들 필요가 없습니다.
마무리
이 글에서 한 것들을 정리합니다.
- Vite 프로젝트를 처음부터 만들었습니다
- CDN 대신 Vite 플러그인으로 Tailwind CSS를 연결했습니다
- 3개 페이지를 만들고 서로 이동하게 했습니다
- 사이드바를 JS 모듈로 분리해서 코드 중복을 없앴습니다
- 카테고리 추가/삭제 + LocalStorage 저장까지 구현했습니다
npm run build로 배포용 파일을 뽑아봤습니다
핵심은 반복되는 코드를 한 곳에서 관리하는 것입니다. 사이드바가 3곳에 복사되어 있으면 고칠 때 3곳을 다 열어야 합니다. 모듈로 분리하면 1곳이면 끝입니다. 페이지가 늘어날수록 이 차이가 커집니다.
직접 해보면 좋은 것들:
- 노래 관리 페이지(
song.js)에 노래 추가/삭제 기능 붙이기 - 사이드바에 아이콘 넣어보기
- 모달을
components/modal.js로 분리해보기
문제 해결
npm run dev 할 때 포트가 이미 사용 중이라고 나옵니다
다른 프로그램이 5173 포트를 쓰고 있는 겁니다. Vite가 자동으로 비어 있는 다른 포트(5174 등)를 찾아주므로, 터미널에 표시된 주소를 그대로 사용하면 됩니다.
Tailwind CSS 클래스가 적용되지 않습니다
세 군데를 확인합니다.
style.css에@import "tailwindcss";가 있는지- 각 페이지 JS 파일에
import '../style.css'가 있는지 vite.config.js에tailwindcss()플러그인이 들어 있는지
페이지 이동할 때 404가 뜹니다
링크 경로를 확인합니다. /pages/dashboard.html처럼 프로젝트 루트 기준의 절대 경로를 써야 합니다. ./dashboard.html처럼 상대 경로를 쓰면 현재 위치에 따라 경로가 달라져서 깨질 수 있습니다.
npm run build 했는데 페이지가 안 열립니다
vite.config.js의 rollupOptions.input에 해당 HTML 파일을 넣었는지 확인합니다. 여기 안 넣은 파일은 빌드에 포함되지 않습니다.



댓글
댓글을 작성하려면 이 필요합니다.