import { transform } from '@swc/core' import { main } from 'bun' import chalk from 'chalk' import { type OutputChunk, type RolldownPlugin, rolldown } from 'rolldown' // If this file is being run directly, build the project if (main === import.meta.filename) build() export default async function build(dev = false, log = true) { const start = performance.now() const bundle = await rolldown({ input: 'src/index.ts', platform: 'neutral', treeshake: true, keepNames: true, moduleTypes: { '.webp': 'dataurl', }, define: { __BUILD_COMMIT__: JSON.stringify(''), __BUILD_ENV__: JSON.stringify(dev ? 'development' : 'production'), __BUILD_FLAG_INIT_DISABLE_PATCH_LOG_PROMISE_REJECTIONS__: String(!dev), }, plugins: [ swcPlugin(), hermesCPlugin({ flags: [ dev ? '-Og' : '-O', '-eager', '-finline', '-fno-static-require', '-Wno-direct-eval', '-Wno-undefined-variable', ], afterComplete() { if (log) console.debug(chalk.gray('\u{1F5CE} Bytecode compilation finished')) }, }), ], }) await bundle.write({ file: 'dist/revenge.js', format: 'iife', footer: '//# sourceURL=Revenge', inlineDynamicImports: true, }) if (log) console.info( chalk.greenBright( `\u{1F5CE} Compiled successfully! ${chalk.gray(`(took ${(performance.now() - start).toFixed(2)}ms)`)}`, ), ) } function swcPlugin() { return { name: 'swc', transform: { filter: { id: /\.[cm]?[jt]sx?$/, }, handler(code) { return transform(code, { jsc: { transform: { react: { runtime: 'automatic', }, }, parser: { syntax: 'typescript', tsx: true, }, }, env: { // https://github.com/discord/hermes/blob/main/doc/Features.md targets: 'fully supports es6', include: [ 'transform-block-scoping', 'transform-classes', 'transform-async-to-generator', 'transform-async-generator-functions', 'transform-named-capturing-groups-regex', ], exclude: [ 'transform-parameters', 'transform-template-literals', 'transform-exponentiation-operator', 'transform-nullish-coalescing-operator', 'transform-object-rest-spread', 'transform-optional-chaining', 'transform-logical-assignment-operators', ], }, }) }, }, } satisfies RolldownPlugin } function hermesCPlugin({ afterComplete, flags }: { flags?: string[]; afterComplete?: () => void } = {}) { const paths = { win32: 'hermesc.exe', darwin: 'darwin/hermesc', linux: 'linux/hermesc', } if (!(process.platform in paths)) throw new Error(`Unsupported platform: ${process.platform}`) const binPath = paths[process.platform as keyof typeof paths] return { name: 'hermesc', generateBundle(_, bundle) { const file = bundle['revenge.js'] as OutputChunk if (!file || !file.code) throw new Error('No code to compile') const cmd = Bun.spawnSync( [ `./node_modules/@unbound-mod/hermesc/${process.platform}/${binPath}`, '-emit-binary', ...(flags ?? []), ], { stdin: new Blob([file.code]), stdout: 'pipe', }, ) const buf = cmd.stdout if (!buf.length) throw new Error('No output from hermesc') this.emitFile({ type: 'asset', fileName: `${file.fileName.split('.')[0]!}.bundle`, source: buf, }) if (afterComplete) afterComplete() }, } satisfies RolldownPlugin }