| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- "use strict";
- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.BuildService = void 0;
- const child_process_1 = require("child_process");
- const path_1 = __importDefault(require("path"));
- const fs_1 = __importDefault(require("fs"));
- const archiver_1 = __importDefault(require("archiver"));
- const configGenerator_1 = require("./configGenerator");
- const storageService_1 = require("./storageService");
- const TEMPLATE_DIR = path_1.default.resolve(__dirname, "../../../../templates/coloring");
- const BUILD_TIMEOUT_MS = 120_000; // 单次构建超时 120s
- class BuildService {
- db;
- storageDir;
- queue = [];
- running = false;
- constructor(db, storageDir) {
- this.db = db;
- this.storageDir = storageDir;
- }
- enqueue(buildId, creativeId, platforms, theme) {
- this.queue.push(() => this.build(buildId, creativeId, platforms, theme));
- if (!this.running) {
- this.processQueue();
- }
- }
- async processQueue() {
- this.running = true;
- while (this.queue.length > 0) {
- const task = this.queue.shift();
- try {
- await task();
- }
- catch (err) {
- console.error("[build] Queue task failed:", err);
- }
- }
- this.running = false;
- }
- async build(buildId, creativeId, platforms, theme) {
- const startTime = new Date().toISOString();
- try {
- // 更新状态 → building
- this.db
- .prepare("UPDATE builds SET status = 'building', started_at = ? WHERE id = ?")
- .run(startTime, buildId);
- // 1. 创建 symlink
- (0, configGenerator_1.createAssetsSymlink)(creativeId, this.storageDir);
- // 2. 生成 _ad_config_.ts
- const configContent = (0, configGenerator_1.generateAdConfig)({
- creativeId,
- theme,
- storageDir: this.storageDir,
- });
- const configPath = path_1.default.join(TEMPLATE_DIR, "src", "filler", "_ad_config_.ts");
- fs_1.default.writeFileSync(configPath, configContent, "utf-8");
- console.log(`[build] Generated _ad_config_.ts for creative ${creativeId}`);
- // 3. 构建输出目录
- const buildOutputDir = path_1.default.join(this.storageDir, "creatives", creativeId, "builds", buildId);
- (0, storageService_1.ensureDir)(buildOutputDir);
- // 4. 逐平台构建
- const results = [];
- for (const platform of platforms) {
- console.log(`[build] Building ${platform} for creative ${creativeId}...`);
- await this.runViteBuild(platform);
- await this.collectOutput(buildOutputDir, platform, results);
- }
- // 5. 复制预览产物(用第一个平台的输出即可,供真机扫码测试)
- const previewSrc = path_1.default.join(TEMPLATE_DIR, "dist", platforms[0], "index.html");
- const previewDir = path_1.default.join(this.storageDir, "previews");
- (0, storageService_1.ensureDir)(previewDir);
- const previewPath = path_1.default.join(previewDir, `${buildId}.html`);
- fs_1.default.copyFileSync(previewSrc, previewPath);
- console.log(`[build] Preview file: ${previewPath} (from ${platforms[0]})`);
- // 7. 打包 ZIP
- await this.createZip(buildOutputDir, results);
- // 6. 更新数据库
- const finishedAt = new Date().toISOString();
- this.db
- .prepare(`UPDATE builds SET status = 'completed', results = ?, finished_at = ? WHERE id = ?`)
- .run(JSON.stringify(results), finishedAt, buildId);
- // 更新创意状态
- this.db
- .prepare("UPDATE creatives SET status = 'built', updated_at = datetime('now') WHERE id = ?")
- .run(creativeId);
- console.log(`[build] Build ${buildId} completed: ${results.map((r) => r.platform).join(", ")}`);
- }
- catch (err) {
- console.error(`[build] Build ${buildId} failed:`, err.message);
- this.db
- .prepare("UPDATE builds SET status = 'failed', error_log = ? WHERE id = ?")
- .run(err.message || "Unknown error", buildId);
- this.db
- .prepare("UPDATE creatives SET status = 'assets_ready', updated_at = datetime('now') WHERE id = ?")
- .run(creativeId);
- }
- finally {
- // 清理临时文件
- (0, configGenerator_1.cleanupBuildArtifacts)();
- }
- }
- runViteBuild(platform) {
- return new Promise((resolve, reject) => {
- const cmd = `cd ${TEMPLATE_DIR} && AD_CONFIG_PATH=src/filler/_ad_config_.ts npx vite build --mode ${platform}`;
- console.log(`[build] Executing: ${cmd}`);
- (0, child_process_1.exec)(cmd, { timeout: BUILD_TIMEOUT_MS }, (error, stdout, stderr) => {
- if (stdout)
- console.log(`[vite:${platform}]`, stdout.slice(-500));
- if (stderr && !stderr.includes("vite"))
- console.error(`[vite:${platform}]`, stderr.slice(-500));
- if (error) {
- reject(new Error(`Vite build failed for ${platform}: ${error.message}`));
- }
- else {
- resolve();
- }
- });
- });
- }
- async collectOutput(buildOutputDir, platform, results) {
- const distPath = path_1.default.join(TEMPLATE_DIR, "dist", platform, "index.html");
- const destDir = path_1.default.join(buildOutputDir, platform);
- (0, storageService_1.ensureDir)(destDir);
- const destPath = path_1.default.join(destDir, "index.html");
- if (!fs_1.default.existsSync(distPath)) {
- throw new Error(`Build output not found for platform ${platform}: ${distPath}`);
- }
- fs_1.default.copyFileSync(distPath, destPath);
- const stat = fs_1.default.statSync(destPath);
- results.push({ platform, fileSize: stat.size });
- }
- createZip(buildOutputDir, results) {
- return new Promise((resolve, reject) => {
- const zipPath = path_1.default.join(buildOutputDir, "all.zip");
- const output = fs_1.default.createWriteStream(zipPath);
- const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
- output.on("close", resolve);
- archive.on("error", reject);
- archive.pipe(output);
- for (const r of results) {
- const filePath = path_1.default.join(buildOutputDir, r.platform, "index.html");
- if (fs_1.default.existsSync(filePath)) {
- archive.file(filePath, { name: `${r.platform}/index.html` });
- }
- }
- archive.finalize();
- });
- }
- }
- exports.BuildService = BuildService;
- //# sourceMappingURL=buildService.js.map
|