"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.startPreview = startPreview; exports.updatePreviewConfig = updatePreviewConfig; exports.stopPreview = stopPreview; exports.getPreviewStatus = getPreviewStatus; const child_process_1 = require("child_process"); const child_process_2 = require("child_process"); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const http_1 = __importDefault(require("http")); const configGenerator_1 = require("./configGenerator"); const TEMPLATE_DIR = path_1.default.resolve(__dirname, "../../../../templates/coloring"); const PREVIEW_PORT = 5199; let viteProcess = null; let currentCreativeId = null; /** * 等待 HTTP 服务就绪 */ function waitForReady(url, maxRetries = 15) { return new Promise((resolve, reject) => { let tries = 0; function check() { http_1.default.get(url, (res) => { if (res.statusCode === 200) resolve(); else retry(); }).on("error", retry); } function retry() { if (++tries >= maxRetries) { reject(new Error(`Preview server did not start within ${maxRetries}s`)); return; } setTimeout(check, 1000); } check(); }); } /** * 启动实时预览。等待 Vite dev server 就绪后才返回。 */ async function startPreview(creativeId, theme, storageDir) { // 1. 停止旧的预览(如果有) stopPreview(); // 2. 创建 symlink (0, configGenerator_1.createAssetsSymlink)(creativeId, storageDir); // 3. 生成配置 const configContent = (0, configGenerator_1.generateAdConfig)({ creativeId, theme, storageDir }); const configPath = path_1.default.join(TEMPLATE_DIR, "src", "filler", "_ad_config_.ts"); fs_1.default.writeFileSync(configPath, configContent, "utf-8"); // 4. 启动 Vite dev server console.log(`[preview] Starting Vite dev server on port ${PREVIEW_PORT}...`); viteProcess = (0, child_process_1.spawn)("npx", ["vite", "--port", String(PREVIEW_PORT), "--strictPort"], { cwd: TEMPLATE_DIR, env: { ...process.env, AD_CONFIG_PATH: "src/filler/_ad_config_.ts" }, stdio: ["ignore", "pipe", "pipe"], }); viteProcess.stdout?.on("data", (data) => { console.log(`[preview:vite] ${data.toString().trim()}`); }); viteProcess.stderr?.on("data", (data) => { console.log(`[preview:vite] ${data.toString().trim()}`); }); viteProcess.on("exit", (code) => { console.log(`[preview] Vite dev server exited (code ${code})`); viteProcess = null; currentCreativeId = null; }); currentCreativeId = creativeId; // 5. 等待 Vite 就绪 console.log("[preview] Waiting for Vite to be ready..."); await waitForReady(`http://localhost:${PREVIEW_PORT}`); console.log("[preview] Vite is ready."); return { url: `http://localhost:${PREVIEW_PORT}` }; } /** * 更新预览配置(主题变更时调用)。Vite HMR 会自动检测并刷新页面。 */ function updatePreviewConfig(creativeId, theme, storageDir) { if (currentCreativeId !== creativeId) return; const configContent = (0, configGenerator_1.generateAdConfig)({ creativeId, theme, storageDir }); const configPath = path_1.default.join(TEMPLATE_DIR, "src", "filler", "_ad_config_.ts"); fs_1.default.writeFileSync(configPath, configContent, "utf-8"); console.log(`[preview] Config updated for creative ${creativeId}`); } /** * 停止预览 */ function stopPreview() { if (viteProcess) { console.log("[preview] Stopping Vite dev server..."); try { viteProcess.kill("SIGTERM"); } catch { // ignore } viteProcess = null; } currentCreativeId = null; // 确保端口释放 try { (0, child_process_2.execSync)(`lsof -ti :${PREVIEW_PORT} | xargs kill -9 2>/dev/null`, { stdio: "ignore" }); } catch { } } function getPreviewStatus() { return { active: viteProcess !== null && currentCreativeId !== null, creativeId: currentCreativeId, url: currentCreativeId ? `http://localhost:${PREVIEW_PORT}` : null, }; } //# sourceMappingURL=previewService.js.map