UNPKG

sapi-kit

Version:

A development toolkit for Minecraft Bedrock Edition Script API

131 lines (130 loc) 4.58 kB
//这是构建脚本 npm run build import commonjs from "@rollup/plugin-commonjs"; import resolve from "@rollup/plugin-node-resolve"; import chalk from "chalk"; import { exec, execSync } from "child_process"; import { existsSync } from "fs"; import { rm } from "fs/promises"; import path from "path"; import { rollup } from "rollup"; import { setTimeout } from "timers/promises"; import { copy2Game } from "./copy.js"; import { formatTime, loadConfig } from "./func.js"; const inputDir = "./cache/"; const entryFile = path.join(inputDir, "/main.js"); const outputDir = "scripts"; //build主函数 export async function runBuild(isBuilding, isClearCache = true) { isBuilding.value = true; const startTime = Date.now(); console.log(`${formatTime()} ${chalk.cyanBright("构建开始")} 🚀`); try { const config = await loadConfig(); console.log(`${formatTime()} ${chalk.blue("[TS]")} 编译 TypeScript...`); await compileTS(config.useNpx ?? false); console.log(`${formatTime()} ${chalk.greenBright("[TS]")} 编译完成`); if (config.shouldClearOutput && existsSync(outputDir)) { console.log(`${formatTime()} ${chalk.yellow("[清理]")} 删除scripts目录...`); await safeDelete(outputDir, 4); } console.log(`${formatTime()} ${chalk.blue("[Rollup]")} 开始打包...`); const bundle = await rollup({ input: entryFile, plugins: [ resolve(), commonjs({ include: /node_modules/, }), ], external: /^@minecraft.+/, onwarn(warning, warn) { if (warning.code === "CIRCULAR_DEPENDENCY") return; warn(warning); }, }); await bundle.write({ dir: outputDir, format: "es", preserveModules: true, preserveModulesRoot: inputDir, }); await bundle.close(); console.log(`${formatTime()} ${chalk.greenBright("[Rollup]")} 打包完成 ✔️`); //拷贝到游戏目录 if (config.shouldCopyToGame) await copy2Game(); const totalTime = ((Date.now() - startTime) / 1000).toFixed(2); console.log(`${formatTime()} ${chalk.greenBright("构建完成")} 🎉 用时 ${chalk.bold(`${totalTime}s`)}`); } catch (err) { console.error(`${formatTime()} ${chalk.redBright("构建失败 ❌")}`); if (!(err instanceof TSCError)) { console.error(chalk.red(err.stack || err.message)); } } if (isClearCache) { clearCache(); } isBuilding.value = false; } class TSCError extends Error { constructor(message, option) { super(message, option); } } function checkTscAvailable() { try { execSync("tsc --version", { stdio: "ignore" }); return true; } catch { return false; } } function compileTS(usenpx) { return new Promise((resolve, reject) => { const cmd = exec(usenpx ? "npx tsc" : "tsc"); cmd.stdout?.on("data", (data) => process.stdout.write(data)); cmd.stderr?.on("data", (data) => process.stderr.write(data)); cmd.on("exit", (code) => { if (code === 0) resolve(1); else reject(new TSCError(`tsc exited with code ${code}`)); }); }); } async function safeDelete(dir, retries = 10, delayMs = 300) { for (let i = 0; i < retries; i++) { try { if (existsSync(dir)) { await rm(dir, { recursive: true, force: true }); } return; } catch (e) { if (i === retries - 1) throw e; if (e.code === "EBUSY" || e.code === "EPERM" || e.code === "ENOTEMPTY") { console.warn(`${formatTime()} ${chalk.gray(`文件被占用,重试第 ${i + 1} 次...`)}`); await setTimeout(delayMs); } else { throw e; } } } } export async function clearCache() { console.log(`${formatTime()} ${chalk.yellow("[清理]")} 清理缓存目录...`); return safeDelete(inputDir, 3); } export async function buildMain(isBuilding, isClearCache = true) { await clearCache(); // 启动构建 if (!checkTscAvailable()) { throw new Error("TypeScript未安装或环境变量错误,请使用npm i -g typescript安装"); } runBuild(isBuilding, isClearCache); }