// /js/component-loader.js import { config } from './config.js'; /** * 공용 HTML 컴포넌트를 페이지의 특정 위치에 동적으로 로드합니다. * @param {string} componentName - 로드할 컴포넌트의 이름 (e.g., 'sidebar', 'navbar'). config.js의 components 객체에 정의된 키와 일치해야 합니다. * @param {string} containerSelector - 컴포넌트가 삽입될 DOM 요소의 CSS 선택자 (e.g., '#sidebar-container'). * @param {function(Document): void} [domProcessor=null] - DOM에 삽입하기 전에 로드된 HTML(Document)을 조작하는 선택적 함수. * (e.g., 역할 기반 메뉴 필터링) */ export async function loadComponent(componentName, containerSelector, domProcessor = null) { const container = document.querySelector(containerSelector); if (!container) { console.warn(`⚠️ 컴포넌트를 삽입할 컨테이너를 찾을 수 없습니다: ${containerSelector} (선택사항일 수 있음)`); return; } const componentPath = config.components[componentName]; if (!componentPath) { console.error(`🔴 설정 파일(config.js)에서 '${componentName}' 컴포넌트의 경로를 찾을 수 없습니다.`); container.innerHTML = `
${componentName} 로딩 실패
`; return; } try { const response = await fetch(componentPath); if (!response.ok) { throw new Error(`컴포넌트 파일을 불러올 수 없습니다: ${response.statusText}`); } const htmlText = await response.text(); if (domProcessor) { // 1. 텍스트를 가상 DOM으로 파싱 const parser = new DOMParser(); const doc = parser.parseFromString(htmlText, 'text/html'); // 2. DOM 프로세서(콜백)를 실행하여 DOM 조작 await domProcessor(doc); // 3. 조작된 HTML을 실제 DOM에 삽입 container.innerHTML = doc.body.innerHTML; } else { // DOM 조작이 필요 없는 경우, 바로 삽입 container.innerHTML = htmlText; } console.log(`✅ '${componentName}' 컴포넌트 로딩 완료: ${containerSelector}`); } catch (error) { console.error(`🔴 '${componentName}' 컴포넌트 로딩 실패:`, error); container.innerHTML = `${componentName} 로딩에 실패했습니다. 관리자에게 문의하세요.
`; } }