Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322/* eslint-disable no-console */import * as esbuild from "esbuild";import copyStaticFiles from "esbuild-copy-static-files";
import path from "path";import fs from "fs";
const config = { injector: "packages/injector/src/index.ts", "node-preload": "packages/node-preload/src/index.ts", "web-preload": "packages/web-preload/src/index.ts"};
const prod = process.env.NODE_ENV === "production";const watch = process.argv.includes("--watch");const browser = process.argv.includes("--browser");const mv2 = process.argv.includes("--mv2");const clean = process.argv.includes("--clean");
const buildBranch = process.env.MOONLIGHT_BRANCH ?? "dev";const buildVersion = process.env.MOONLIGHT_VERSION ?? "dev";
const external = [ "electron", "fs", "path", "module", "discord", // mappings
// Silence an esbuild warning "./node-preload.js"];
let lastMessages = new Set();/** @type {import("esbuild").Plugin} */const deduplicatedLogging = { name: "deduplicated-logging", setup(build) { build.onStart(() => { lastMessages.clear(); });
build.onEnd(async (result) => { const formatted = await Promise.all([ esbuild.formatMessages(result.warnings, { kind: "warning", color: true }), esbuild.formatMessages(result.errors, { kind: "error", color: true }) ]).then((a) => a.flat());
// console.log(formatted); for (const message of formatted) { if (lastMessages.has(message)) continue; lastMessages.add(message); console.log(message.trim()); } }); }};
const timeFormatter = new Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "numeric", second: "numeric", hour12: false});/** @type {import("esbuild").Plugin} */const taggedBuildLog = (tag) => ({ name: "build-log", setup(build) { build.onEnd((result) => { console.log(`[${timeFormatter.format(new Date())}] [${tag}] build finished`); }); }});
async function build(name, entry) { let outfile = path.join("./dist", name + ".js"); const browserDir = mv2 ? "browser-mv2" : "browser"; if (name === "browser") outfile = path.join("./dist", browserDir, "index.js");
const dropLabels = []; const labels = { injector: ["injector"], nodePreload: ["node-preload"], webPreload: ["web-preload"], browser: ["browser"],
webTarget: ["web-preload", "browser"], nodeTarget: ["node-preload", "injector"] }; for (const [label, targets] of Object.entries(labels)) { if (!targets.includes(name)) { dropLabels.push(label); } }
const define = { MOONLIGHT_ENV: `"${name}"`, MOONLIGHT_PROD: prod.toString(), MOONLIGHT_BRANCH: `"${buildBranch}"`, MOONLIGHT_VERSION: `"${buildVersion}"` };
for (const iterName of ["injector", "node-preload", "web-preload", "browser"]) { const snake = iterName.replace(/-/g, "_").toUpperCase(); define[`MOONLIGHT_${snake}`] = (name === iterName).toString(); }
const nodeDependencies = ["glob"]; const ignoredExternal = name === "web-preload" ? nodeDependencies : [];
const plugins = [deduplicatedLogging, taggedBuildLog(name)]; if (name === "browser") { plugins.push( copyStaticFiles({ src: mv2 ? "./packages/browser/manifestv2.json" : "./packages/browser/manifest.json", dest: `./dist/${browserDir}/manifest.json` }) );
if (!mv2) { plugins.push( copyStaticFiles({ src: "./packages/browser/modifyResponseHeaders.json", dest: `./dist/${browserDir}/modifyResponseHeaders.json` }) ); plugins.push( copyStaticFiles({ src: "./packages/browser/blockLoading.json", dest: `./dist/${browserDir}/blockLoading.json` }) ); }
plugins.push( copyStaticFiles({ src: mv2 ? "./packages/browser/src/background-mv2.js" : "./packages/browser/src/background.js", dest: `./dist/${browserDir}/background.js` }) ); }
/** @type {import("esbuild").BuildOptions} */ const esbuildConfig = { entryPoints: [entry], outfile,
format: "iife", globalName: "module.exports",
platform: ["web-preload", "browser"].includes(name) ? "browser" : "node",
treeShaking: true, bundle: true, minify: prod, sourcemap: "inline",
external: [...ignoredExternal, ...external],
define, dropLabels,
logLevel: "silent", plugins,
// https://github.com/evanw/esbuild/issues/3944 footer: name === "web-preload" ? { js: `\n//# sourceURL=${name}.js` } : undefined };
if (name === "browser") { const coreExtensionsJson = {};
function readDir(dir) { const files = fs.readdirSync(dir); for (const file of files) { const filePath = dir + "/" + file; const normalizedPath = filePath.replace("./dist/core-extensions/", ""); if (fs.statSync(filePath).isDirectory()) { readDir(filePath); } else { coreExtensionsJson[normalizedPath] = fs.readFileSync(filePath, "utf8"); } } }
readDir("./dist/core-extensions");
esbuildConfig.banner = { js: `window._moonlight_coreExtensionsStr = ${JSON.stringify(JSON.stringify(coreExtensionsJson))};` }; }
if (watch) { const ctx = await esbuild.context(esbuildConfig); await ctx.watch(); } else { await esbuild.build(esbuildConfig); }}
async function buildExt(ext, side, fileExt) { const outdir = path.join("./dist", "core-extensions", ext); if (!fs.existsSync(outdir)) { fs.mkdirSync(outdir, { recursive: true }); }
const entryPoints = [`packages/core-extensions/src/${ext}/${side}.${fileExt}`];
const wpModulesDir = `packages/core-extensions/src/${ext}/webpackModules`; if (fs.existsSync(wpModulesDir) && side === "index") { const wpModules = fs.opendirSync(wpModulesDir); for await (const wpModule of wpModules) { if (wpModule.isFile()) { entryPoints.push(`packages/core-extensions/src/${ext}/webpackModules/${wpModule.name}`); } else { for (const fileExt of ["ts", "tsx"]) { const path = `packages/core-extensions/src/${ext}/webpackModules/${wpModule.name}/index.${fileExt}`; if (fs.existsSync(path)) { entryPoints.push({ in: path, out: `webpackModules/${wpModule.name}` }); } } } } }
const wpImportPlugin = { name: "webpackImports", setup(build) { build.onResolve({ filter: /^@moonlight-mod\/wp\// }, (args) => { const wpModule = args.path.replace(/^@moonlight-mod\/wp\//, ""); return { path: wpModule, external: true }; }); } };
const styleInput = `packages/core-extensions/src/${ext}/style.css`; const styleOutput = `dist/core-extensions/${ext}/style.css`;
const esbuildConfig = { entryPoints, outdir,
format: "iife", globalName: "module.exports", platform: "node",
treeShaking: true, bundle: true, sourcemap: prod ? false : "inline",
external,
logOverride: { "commonjs-variable-in-esm": "verbose" }, logLevel: "silent", plugins: [ copyStaticFiles({ src: `./packages/core-extensions/src/${ext}/manifest.json`, dest: `./dist/core-extensions/${ext}/manifest.json` }), ...(fs.existsSync(styleInput) ? [ copyStaticFiles({ src: styleInput, dest: styleOutput }) ] : []), wpImportPlugin, deduplicatedLogging, taggedBuildLog(`ext/${ext}`) ] };
if (watch) { const ctx = await esbuild.context(esbuildConfig); await ctx.watch(); } else { await esbuild.build(esbuildConfig); }}
const promises = [];
if (clean) { fs.rmSync("./dist", { recursive: true, force: true });} else if (browser) { build("browser", "packages/browser/src/index.ts");} else { for (const [name, entry] of Object.entries(config)) { promises.push(build(name, entry)); }
const coreExtensions = fs.readdirSync("./packages/core-extensions/src"); for (const ext of coreExtensions) { for (const fileExt of ["ts", "tsx"]) { for (const type of ["index", "node", "host"]) { if (fs.existsSync(`./packages/core-extensions/src/${ext}/${type}.${fileExt}`)) { promises.push(buildExt(ext, type, fileExt)); } } } }}
await Promise.all(promises);