this repo has no description
at v1.0.5 5.4 kB view raw
1/* eslint-disable no-console */ 2import * as esbuild from "esbuild"; 3import copyStaticFiles from "esbuild-copy-static-files"; 4 5import path from "path"; 6import fs from "fs"; 7 8const config = { 9 injector: "packages/injector/src/index.ts", 10 "node-preload": "packages/node-preload/src/index.ts", 11 "web-preload": "packages/web-preload/src/index.ts" 12}; 13 14const prod = process.env.NODE_ENV === "production"; 15const watch = process.argv.includes("--watch"); 16 17const external = [ 18 "electron", 19 "fs", 20 "path", 21 "module", 22 "events", 23 "original-fs", // wtf asar? 24 25 // Silence an esbuild warning 26 "./node-preload.js" 27]; 28 29let lastMessages = new Set(); 30/** @type {import("esbuild").Plugin} */ 31const deduplicatedLogging = { 32 name: "deduplicated-logging", 33 setup(build) { 34 build.onStart(() => { 35 lastMessages.clear(); 36 }); 37 38 build.onEnd(async (result) => { 39 const formatted = await Promise.all([ 40 esbuild.formatMessages(result.warnings, { 41 kind: "warning", 42 color: true 43 }), 44 esbuild.formatMessages(result.errors, { kind: "error", color: true }) 45 ]).then((a) => a.flat()); 46 47 // console.log(formatted); 48 for (const message of formatted) { 49 if (lastMessages.has(message)) continue; 50 lastMessages.add(message); 51 console.log(message.trim()); 52 } 53 }); 54 } 55}; 56 57const timeFormatter = new Intl.DateTimeFormat(undefined, { 58 hour: "numeric", 59 minute: "numeric", 60 second: "numeric", 61 hour12: false 62}); 63/** @type {import("esbuild").Plugin} */ 64const taggedBuildLog = (tag) => ({ 65 name: "build-log", 66 setup(build) { 67 build.onEnd((result) => { 68 console.log( 69 `[${timeFormatter.format(new Date())}] [${tag}] build finished` 70 ); 71 }); 72 } 73}); 74 75async function build(name, entry) { 76 const outfile = path.join("./dist", name + ".js"); 77 78 const dropLabels = []; 79 if (name !== "injector") dropLabels.push("injector"); 80 if (name !== "node-preload") dropLabels.push("nodePreload"); 81 if (name !== "web-preload") dropLabels.push("webPreload"); 82 83 const define = { 84 MOONLIGHT_ENV: `"${name}"`, 85 MOONLIGHT_PROD: prod.toString() 86 }; 87 88 for (const iterName of Object.keys(config)) { 89 const snake = iterName.replace(/-/g, "_").toUpperCase(); 90 define[`MOONLIGHT_${snake}`] = (name === iterName).toString(); 91 } 92 93 const nodeDependencies = ["glob"]; 94 const ignoredExternal = name === "web-preload" ? nodeDependencies : []; 95 96 /** @type {import("esbuild").BuildOptions} */ 97 const esbuildConfig = { 98 entryPoints: [entry], 99 outfile, 100 101 format: "cjs", 102 platform: name === "web-preload" ? "browser" : "node", 103 104 treeShaking: true, 105 bundle: true, 106 minify: prod, 107 sourcemap: "inline", 108 109 external: [...ignoredExternal, ...external], 110 111 define, 112 dropLabels, 113 114 logLevel: "silent", 115 plugins: [deduplicatedLogging, taggedBuildLog(name)] 116 }; 117 118 if (watch) { 119 const ctx = await esbuild.context(esbuildConfig); 120 await ctx.watch(); 121 } else { 122 await esbuild.build(esbuildConfig); 123 } 124} 125 126async function buildExt(ext, side, copyManifest, fileExt) { 127 const outdir = path.join("./dist", "core-extensions", ext); 128 if (!fs.existsSync(outdir)) { 129 fs.mkdirSync(outdir, { recursive: true }); 130 } 131 132 const entryPoints = [ 133 `packages/core-extensions/src/${ext}/${side}.${fileExt}` 134 ]; 135 136 const wpModulesDir = `packages/core-extensions/src/${ext}/webpackModules`; 137 if (fs.existsSync(wpModulesDir) && side === "index") { 138 const wpModules = fs.readdirSync(wpModulesDir); 139 for (const wpModule of wpModules) { 140 entryPoints.push( 141 `packages/core-extensions/src/${ext}/webpackModules/${wpModule}` 142 ); 143 } 144 } 145 146 const wpImportPlugin = { 147 name: "webpackImports", 148 setup(build) { 149 build.onResolve({ filter: /^@moonlight-mod\/wp\// }, (args) => { 150 const wpModule = args.path.replace(/^@moonlight-mod\/wp\//, ""); 151 return { 152 path: wpModule, 153 external: true 154 }; 155 }); 156 } 157 }; 158 159 const esbuildConfig = { 160 entryPoints, 161 outdir, 162 163 format: "cjs", 164 platform: "node", 165 166 treeShaking: true, 167 bundle: true, 168 sourcemap: prod ? false : "inline", 169 170 external, 171 172 logOverride: { 173 "commonjs-variable-in-esm": "verbose" 174 }, 175 logLevel: "silent", 176 plugins: [ 177 ...(copyManifest 178 ? [ 179 copyStaticFiles({ 180 src: `./packages/core-extensions/src/${ext}/manifest.json`, 181 dest: `./dist/core-extensions/${ext}/manifest.json` 182 }) 183 ] 184 : []), 185 wpImportPlugin, 186 deduplicatedLogging, 187 taggedBuildLog(`ext/${ext}`) 188 ] 189 }; 190 191 if (watch) { 192 const ctx = await esbuild.context(esbuildConfig); 193 await ctx.watch(); 194 } else { 195 await esbuild.build(esbuildConfig); 196 } 197} 198 199const promises = []; 200 201for (const [name, entry] of Object.entries(config)) { 202 promises.push(build(name, entry)); 203} 204 205const coreExtensions = fs.readdirSync("./packages/core-extensions/src"); 206for (const ext of coreExtensions) { 207 let copiedManifest = false; 208 209 for (const fileExt of ["ts", "tsx"]) { 210 for (const type of ["index", "node", "host"]) { 211 if ( 212 fs.existsSync( 213 `./packages/core-extensions/src/${ext}/${type}.${fileExt}` 214 ) 215 ) { 216 promises.push(buildExt(ext, type, !copiedManifest, fileExt)); 217 copiedManifest = true; 218 } 219 } 220 } 221} 222 223await Promise.all(promises);