vd-plugins/scripts/build.mjs

202 lines
5.8 KiB
JavaScript
Raw Permalink Normal View History

2023-02-11 23:09:54 +08:00
import commonjs from "@rollup/plugin-commonjs";
import nodeResolve from "@rollup/plugin-node-resolve";
2023-02-13 00:48:48 +08:00
import { createHash } from "crypto";
2026-01-01 19:45:43 +01:00
import { readFile, readdir, writeFile, stat } from "fs/promises";
2023-02-13 00:18:39 +08:00
import { argv } from "process";
2023-02-13 22:22:21 +08:00
import { rollup, watch } from "rollup";
import swc from "@swc/core";
import esbuild from "rollup-plugin-esbuild";
2023-01-24 15:56:43 +00:00
2026-01-01 19:45:43 +01:00
// ═══════════════════════════════════════════════════════════════════════════════
// MAIN EXECUTION
// ═══════════════════════════════════════════════════════════════════════════════
const args = argv.slice(2);
console.clear();
2026-01-01 19:45:43 +01:00
// Parse arguments
const inputPlugins = args.filter((x) => !x.startsWith("-"));
const flags = args.map((x) => x.toLowerCase()).filter((x) => x.startsWith("-"));
const isWatch = flags.includes("--watch") || flags.includes("-w");
2026-01-01 19:45:43 +01:00
const isVerbose = flags.includes("--verbose") || flags.includes("-v");
const toBuild = inputPlugins.length ? inputPlugins : await readdir("./plugins");
2026-01-01 19:45:43 +01:00
console.log(`Found ${toBuild.length} plugin(s) to build`);
if (isWatch) {
console.log("Running in watch mode\n");
}
2026-01-01 19:45:43 +01:00
// Build statistics
let built = 0;
let failed = 0;
2026-01-01 19:45:43 +01:00
const startTime = Date.now();
2026-01-01 19:45:43 +01:00
// Build all plugins
for (const plugin of toBuild) {
2026-01-01 19:45:43 +01:00
if (plugin.endsWith(".ts")) continue;
const pluginStartTime = Date.now();
try {
2026-01-01 19:45:43 +01:00
console.log(`Building ${plugin}...`);
const result = await buildPlugin(plugin);
const buildTime = Date.now() - pluginStartTime;
console.log(`✓ ${plugin} (${buildTime}ms)`);
built++;
} catch (e) {
2026-01-01 19:45:43 +01:00
console.log(`✗ ${plugin}`);
if (isVerbose) {
console.error(e);
} else {
console.error(e.message);
}
failed++;
}
}
2026-01-01 19:45:43 +01:00
// Summary
const totalTime = Date.now() - startTime;
console.log(`\nBuild completed in ${totalTime}ms`);
console.log(`Success: ${built}, Failed: ${failed}\n`);
2026-01-01 19:45:43 +01:00
if (isWatch) {
console.log("Watching for changes... (Press Ctrl+C to exit)\n");
}
// ═══════════════════════════════════════════════════════════════════════════════
// BUILD FUNCTION
// ═══════════════════════════════════════════════════════════════════════════════
async function buildPlugin(plugin) {
2026-01-01 19:45:43 +01:00
if (plugin.endsWith(".ts")) return {};
const manifest = Object.assign(
JSON.parse(await readFile("./base_manifest.json")),
JSON.parse(await readFile(`./plugins/${plugin}/manifest.json`)),
);
const entry = "index.js";
const outPath = `./dist/${plugin}/${entry}`;
/** @type {import("rollup").RollupOptions} */
const options = {
input: `./plugins/${plugin}/${manifest.main}`,
output: {
file: outPath,
globals(id) {
if (id.startsWith("@vendetta"))
return id.substring(1).replace(/\//g, ".");
const map = {
react: "window.React",
"react-native": "vendetta.metro.common.ReactNative",
};
return map[id] || null;
},
format: "iife",
compact: true,
exports: "named",
inlineDynamicImports: true,
},
onwarn: (warning) => {
2026-01-01 19:45:43 +01:00
if (
![
"UNRESOLVED_IMPORT",
"MISSING_NAME_OPTION_FOR_IIFE_EXPORT",
"CIRCULAR_DEPENDENCY",
].includes(warning.code) &&
isVerbose
) {
console.warn(`${plugin}: ${warning.message}`);
}
},
plugins: [
nodeResolve({
resolveOnly: (id) => !["react", "react-native"].includes(id),
}),
commonjs(),
{
name: "swc",
transform(code, id) {
return swc.transform(code, {
filename: id,
jsc: {
parser: {
syntax: "typescript",
tsx: true,
},
externalHelpers: true,
},
env: {
targets: "defaults",
include: ["transform-classes", "transform-arrow-functions"],
},
});
},
},
esbuild({ minify: true }),
],
};
2026-01-01 19:45:43 +01:00
const applyHash = async () => {
const content = await readFile(outPath);
return Object.assign(manifest, {
hash: createHash("sha256").update(content).digest("hex"),
main: entry,
});
2026-01-01 19:45:43 +01:00
};
if (!isWatch) {
const bundle = await rollup(options);
await bundle.write(options.output);
await bundle.close();
await applyHash();
await writeFile(`./dist/${plugin}/manifest.json`, JSON.stringify(manifest));
2026-01-01 19:45:43 +01:00
const stats = await stat(outPath);
return { size: stats.size };
}
const watcher = watch(options);
return await new Promise((resolve, reject) => {
watcher.on("event", async (event) => {
switch (event.code) {
2026-01-01 19:45:43 +01:00
case "BUNDLE_START":
break;
case "BUNDLE_END": {
event.result.close();
await applyHash();
await writeFile(
`./dist/${plugin}/manifest.json`,
JSON.stringify(manifest),
);
2026-01-01 19:45:43 +01:00
console.log(`⚡ ${plugin} rebuilt (${event.duration}ms)`);
resolve({ size: 0 });
break;
}
case "ERROR":
case "FATAL":
2026-01-01 19:45:43 +01:00
console.error(`✗ ${plugin}`);
if (isVerbose) {
console.error(event.error);
} else {
console.error(event.error.message);
}
reject(event.error);
break;
}
});
});
2023-02-11 23:09:54 +08:00
}