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