찾아보고 고민해본 결과 총 3가지 방식으로 이미지 업로드 기능을 구현가능해 보인다.
1. Delayed image upload
2. 임시 이미지 업로드
3. 이미지 업로드 후 스케줄링 기반 정리
해당 글에서는 delayed image upload에 대해서 작성한다.
구현 방식에는 정답이 없으므로 장단점을 고려해 선택하는 것을 추천합니다.
해당 코드에서는 서버로 업로드 될 이미지를 담는 pendingImages와BASE64로 된 이미지 출력을 메인으로 보면 된다.
또한, 이후 BASE64에서 치환할 file을 트래킹하기 위해 data-index에는 pendingImages의 인덱스도 같이 저장한다.
const pendingImages = []; // 서버 업로드 예정 이미지 저장
const previewContainer = document.getElementById('preview');
const input = document.getElementById('imageInput');
input.addEventListener('change', (e) => {
const files = Array.from(e.target.files);
files.forEach((file) => {
// 1) pendingImages 배열에 저장
const index = pendingImages.length;
pendingImages.push(file);
// 2) FileReader로 Base64 변환
const reader = new FileReader();
reader.onload = function(event) {
// 3) 이미지 요소 생성 및 미리보기
const img = document.createElement('img');
img.src = event.target.result; // Base64
// BASE64에서 치환할 file을 트래킹하기 위한 index 저장
img.setAttribute('data-index', index);
previewContainer.appendChild(img);
};
reader.readAsDataURL(file);
});
});
해당 코드에서는 pendingImages에 쌓인 이미지들을 서버에 저장하고,
반환받은 URL로 HTML에 치환하여 게시글을 저장하는 방식이다.
(간결한 코드를 위해 따로 예외처리는 되어있지 않습니다.)
// 게시글 제출 시 서버 업로드 + BASE64 → URL 치환
submitBtn.addEventListener('click', async () => {
// 1) FormData로 서버 업로드
const formData = new FormData();
pendingImages.forEach(file => formData.append('files', file));
// 서버에 이미지 업로드 (예: /api/upload-images)
const res = await fetch('/api/upload-images', {
method: 'POST',
body: formData
});
const uploadedUrls = await res.json(); // ["image_url_1.png", "image_url_2.png", ...]
// 2) Base64 → 서버 URL 치환
const imgs = previewContainer.querySelectorAll('img');
imgs.forEach(img => {
const index = parseInt(img.getAttribute('data-index'));
img.src = uploadedUrls[index];
});
// 3) 게시글 내용 생성 (HTML 포함)
const title = document.getElementById('title').value;
const contentHTML = previewContainer.innerHTML;
// 4) 게시글 서버 전송
await fetch('/api/post', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title,
content: contentHTML
})
});
alert('게시글 작성 완료!');
});