diff --git a/lib/react/src/index.ts b/lib/react/src/index.ts index 57b4849..c3930d9 100644 --- a/lib/react/src/index.ts +++ b/lib/react/src/index.ts @@ -30,7 +30,8 @@ const unsubRN = waitForModules( ReactNativeModuleId = id ReactNative = exports - require('./native/patches') + // @as-require + import('./native/patches') }, { cached: true, diff --git a/scripts/build.ts b/scripts/build.ts index 9c18a52..efb0df5 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -5,6 +5,7 @@ import { parse } from 'path' import { rolldown } from 'rolldown' import { importGlobPlugin } from 'rolldown/experimental' import pkg from '../package.json' +import asRequire from './plugins/as-require' import hermesSwcPlugin from './plugins/hermes-swc' import hermesCPlugin from './plugins/hermesc' import shimAliases from './plugins/shim-aliases' @@ -86,6 +87,7 @@ export default async function build(dev = Dev, log = true) { __BUILD_FLAG_LOG_PROMISE_REJECTIONS__: String(dev), }, plugins: [ + asRequire(), shimAliases(ShimsDir), importGlobPlugin(), hermesSwcPlugin(), diff --git a/scripts/plugins/as-require.ts b/scripts/plugins/as-require.ts new file mode 100644 index 0000000..6b8aea5 --- /dev/null +++ b/scripts/plugins/as-require.ts @@ -0,0 +1,76 @@ +import type { RolldownPlugin } from 'rolldown' + +/** + * Transforms `// @as-require` comments above supported import statements into `require` calls. + * + * Supported statements: + * - Static side-effect imports: `import 'module'` + * - Dynamic side-effect imports: `import('module')` and `await import('module')` + * - Dynamic imports with .then(): `import('module').then(mod => ...)` + */ +export default function asRequire() { + return { + name: 'as-require', + transform(code, id) { + if (!code.includes('// @as-require')) return null + + const asRequireRegex = + /(?:\s*\/\/\s*@as-require\s*[\r\n]+)([^\r\n]*)/g + + let hasChanged = false + const newCode = code.replace(asRequireRegex, (match, statement) => { + const trimmedStatement = statement.trim() + + // import('./mod').then(mod => mod.do()) -> ((mod => mod.do()))(require('./mod')) + const importThenRegex = + /^import\((['"])(.+?)\1\)\s*\.then\(([\s\S]+)\);?$/ + const thenMatch = trimmedStatement.match(importThenRegex) + if (thenMatch) { + hasChanged = true + const modulePath = `${thenMatch[1]}${thenMatch[2]}${thenMatch[1]}` + const callback = thenMatch[3].trim() + return `\n((${callback}))(require(${modulePath}));` + } + + // import './mod' -> require('./mod') + const staticSideEffectRegex = /^import\s+(['"])(.+?)\1;?$/ + const staticMatch = trimmedStatement.match( + staticSideEffectRegex, + ) + if (staticMatch) { + hasChanged = true + const modulePath = `${staticMatch[1]}${staticMatch[2]}${staticMatch[1]}` + return `\nrequire(${modulePath});` + } + + // import('./mod') -> require('./mod') + // await import('./mod') -> require('./mod') + const dynamicSideEffectRegex = + /^(?:await\s+)?import\((['"])(.+?)\1\);?$/ + const dynamicMatch = trimmedStatement.match( + dynamicSideEffectRegex, + ) + if (dynamicMatch) { + hasChanged = true + const modulePath = `${dynamicMatch[1]}${dynamicMatch[2]}${dynamicMatch[1]}` + return `\nrequire(${modulePath});` + } + + this.warn( + `[${this.pluginName}] Warning: Could not transform statement in ${id}:\n${statement}\n` + + `The line after the comment must be a side-effect import or a dynamic import with .then().`, + ) + + return match + }) + + if (hasChanged) + return { + code: newCode, + map: null, // Sourcemaps are broken by this transform + } + + return null + }, + } satisfies RolldownPlugin +} diff --git a/src/index.ts b/src/index.ts index a7d76b6..2e6c78a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ Object.defineProperty(globalThis, '__c', { delete globalThis.__c globalThis.__c = clear - require('./preinit') + // @as-require + import('./preinit') }, }) diff --git a/src/init.ts b/src/init.ts index fd93be1..6af55e1 100644 --- a/src/init.ts +++ b/src/init.ts @@ -9,12 +9,15 @@ const unsub = onRunApplication(() => { unsub() try { - require('./start') + // @as-require + import('./start') } catch (e) { onError(e) } }) // Run all init plugins -require('~/plugins/init') -require('@revenge-mod/plugins/init') +// @as-require +import '~/plugins/init' +// @as-require +import '@revenge-mod/plugins/init' diff --git a/src/plugins/start/developer-kit/index.ts b/src/plugins/start/developer-kit/index.ts index b977210..2b21cc6 100644 --- a/src/plugins/start/developer-kit/index.ts +++ b/src/plugins/start/developer-kit/index.ts @@ -40,7 +40,8 @@ registerPlugin<{ storage: Storage }>( api = api_ onSettingsModulesLoaded(() => { - require('./utils').register() + // @as-require + import('./utils').then(it => it.register()) }) if (api_.plugin.flags & PluginFlags.EnabledLate) diff --git a/src/plugins/start/settings/index.ts b/src/plugins/start/settings/index.ts index 3c8219d..50c7440 100644 --- a/src/plugins/start/settings/index.ts +++ b/src/plugins/start/settings/index.ts @@ -27,7 +27,8 @@ const pluginSettings = registerPlugin( { start() { onSettingsModulesLoaded(() => { - require('./register') + // @as-require + import('./register') }) waitForModuleWithImportedPath( diff --git a/src/preinit.ts b/src/preinit.ts index 3d4c110..3dcff95 100644 --- a/src/preinit.ts +++ b/src/preinit.ts @@ -13,30 +13,37 @@ const IndexModuleId = 0 onModuleFirstRequired(IndexModuleId, function onIndexRequired() { try { if (__BUILD_FLAG_LOG_PROMISE_REJECTIONS__) - require('./patches/log-promise-rejections') + // @as-require + import('./patches/log-promise-rejections') if (__DEV__) nativeLoggingHook(`\u001b[31m--- PREINIT STAGE ---\u001b[0m`, 1) // Initialize preinit libraries - require('@revenge-mod/react/preinit') - require('@revenge-mod/assets/preinit') - require('@revenge-mod/discord/preinit') + // @as-require + import('@revenge-mod/react/preinit') + // @as-require + import('@revenge-mod/assets/preinit') + // @as-require + import('@revenge-mod/discord/preinit') onModuleInitialized(IndexModuleId, function onIndexInitialized() { if (__DEV__) nativeLoggingHook(`\u001b[31m--- INIT STAGE ---\u001b[0m`, 1) try { - require('./init') + // @as-require + import('./init') } catch (e) { onError(e) } }) // Run all preinit plugins - require('~/plugins/preinit') - require('@revenge-mod/plugins/preinit') + // @as-require + import('~/plugins/preinit') + // @as-require + import('@revenge-mod/plugins/preinit') } catch (e) { onError(e) }