// 빌드 후 실행: 라우트별 완성 HTML(
+ 본문)을 dist 에 생성하는 사전 렌더링(SSG) 스크립트 import fs from 'fs'; import path from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import { DEFAULT_PATH } from '../src/config.js'; import { getPrerenderPaths } from './routes.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.resolve(__dirname, '..'); const distDir = path.join(root, 'dist'); const ssrEntry = path.join(root, 'dist-ssr', 'entry-server.js'); const HEAD_PLACEHOLDER = ''; const HTML_PLACEHOLDER = ''; const template = fs.readFileSync(path.join(distDir, 'index.html'), 'utf-8'); if (!template.includes(HEAD_PLACEHOLDER) || !template.includes(HTML_PLACEHOLDER)) { throw new Error('dist/index.html 에서 / 자리표시자를 찾지 못했습니다.'); } // Cloudflare Workers (_worker.js) 생성용으로 원본 템플릿 보존 fs.writeFileSync(path.join(distDir, '_template.html'), template, 'utf-8'); const { render } = await import(pathToFileURL(ssrEntry).href); const writeFile = (file, content) => { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, content, 'utf-8'); }; // url -> 출력 파일 경로 const popularPaths = [ DEFAULT_PATH, '/incheon/yeonsu-gu/songdo-dong/middle/math', '/daegu/suseong-gu/hwanggeum-dong/middle/math', '/daegu/suseong-gu/hwanggeum-dong/high/korean', '/seoul/gangnam-gu/daechi-dong/high/math', '/gyeonggi/seongnam-si-bundang-gu/sunae-dong/middle/english', '/busan/haeundae-gu/u-dong/middle/english' ]; const allLandingPaths = Array.from(new Set([...popularPaths, ...getPrerenderPaths()])); const targets = [ { url: '/', file: path.join(distDir, 'index.html'), kind: 'home' }, // 메인 홈 화면 (지역·학년·과목 허브) { url: '/regions', file: path.join(distDir, 'regions', 'index.html'), kind: 'page' }, { url: '/admin', file: path.join(distDir, 'admin', 'index.html'), kind: 'noindex' }, { url: '/__not-found__', file: path.join(distDir, '404.html'), kind: 'noindex' }, ...allLandingPaths.map((p) => ({ url: p, file: path.join(distDir, ...p.split('/').filter(Boolean), 'index.html'), kind: 'landing' })) ]; const problems = []; let count = 0; for (const t of targets) { const { html, head, routeName } = await render(t.url); let out = template; if (head) { out = out.replace(/