From 53dd86fa6e8cd8ad8832bf1fd53397a8527289a0 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Sun, 2 Jun 2024 18:46:03 -0300 Subject: [PATCH] Improve typings and other stuff --- src/debug/loadLazyChunks.ts | 20 +++++++++++--------- src/webpack/patchWebpack.ts | 24 ++++++++---------------- src/webpack/webpack.ts | 4 ++-- src/webpack/wreq.d.ts | 18 +++++++++++++++++- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/debug/loadLazyChunks.ts b/src/debug/loadLazyChunks.ts index f4f7f88b3..4aea9ff5d 100644 --- a/src/debug/loadLazyChunks.ts +++ b/src/debug/loadLazyChunks.ts @@ -8,6 +8,7 @@ import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; import * as Webpack from "@webpack"; import { wreq } from "@webpack"; +import { AnyModuleFactory, ModuleFactory } from "webpack"; const LazyChunkLoaderLogger = new Logger("LazyChunkLoader"); @@ -109,21 +110,22 @@ export async function loadLazyChunks() { }, 0); } - Webpack.factoryListeners.add(factory => { + function factoryListener(factory: AnyModuleFactory | ModuleFactory) { let isResolved = false; - searchAndLoadLazyChunks(String(factory)).then(() => isResolved = true); - - chunksSearchPromises.push(() => isResolved); - }); - - for (const factoryId in wreq.m) { - let isResolved = false; - searchAndLoadLazyChunks(String(wreq.m[factoryId])).then(() => isResolved = true); + searchAndLoadLazyChunks(String(factory)) + .then(() => isResolved = true) + .catch(() => isResolved = true); chunksSearchPromises.push(() => isResolved); } + Webpack.factoryListeners.add(factoryListener); + for (const factoryId in wreq.m) { + factoryListener(wreq.m[factoryId]); + } + await chunksSearchingDone; + Webpack.factoryListeners.delete(factoryListener); // Require deferred entry points for (const deferredRequire of deferredRequires) { diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index a17a2e5dd..7ac7cac00 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -12,15 +12,7 @@ import { PatchReplacement } from "@utils/types"; import { traceFunction } from "../debug/Tracer"; import { patches } from "../plugins"; -import { _initWebpack, factoryListeners, ModuleFactory, moduleListeners, subscriptions, WebpackRequire, wreq } from "."; - -type AnyWebpackRequire = Partial & Pick; - -type PatchedModuleFactory = ModuleFactory & { - $$vencordOriginal?: ModuleFactory; -}; - -type PatchedModuleFactories = Record; +import { _initWebpack, AnyModuleFactory, AnyWebpackRequire, factoryListeners, moduleListeners, PatchedModuleFactories, PatchedModuleFactory, subscriptions, WebpackRequire, wreq } from "."; const logger = new Logger("WebpackInterceptor", "#8caaee"); @@ -56,7 +48,7 @@ const define: Define = (target, p, attributes) => { define(Function.prototype, "O", { enumerable: false, - set(this: WebpackRequire, onChunksLoaded: WebpackRequire["O"]) { + set(this: AnyWebpackRequire, onChunksLoaded: AnyWebpackRequire["O"]) { define(this, "O", { value: onChunksLoaded }); const { stack } = new Error(); @@ -104,7 +96,7 @@ define(Function.prototype, "O", { const proxiedModuleFactories = new Proxy(this.m, moduleFactoriesHandler); /* If Discord ever decides to set module factories using the variable of the modules object directly, instead of wreq.m, switch the proxy to the prototype - Reflect.setPrototypeOf(moduleFactories, new Proxy(moduleFactories, moduleFactoriesHandler)); + define(this, "m", { value: Reflect.setPrototypeOf(this.m, new Proxy(this.m, moduleFactoriesHandler)) }); */ define(this, "m", { value: proxiedModuleFactories }); @@ -133,7 +125,7 @@ function defineModulesFactoryGetter(id: PropertyKey, factory: PatchedModuleFacto return (factory = patchFactory(id, factory)); }, - set(v: ModuleFactory) { + set(v: AnyModuleFactory) { if (factory.$$vencordOriginal != null) { factory.$$vencordOriginal = v; } else { @@ -153,7 +145,7 @@ function defineModulesFactoryGetter(id: PropertyKey, factory: PatchedModuleFacto * @param ignoreExistingInTarget Whether to ignore checking if the factory already exists in the moduleFactoriesTarget * @returns Whether the original factory was updated, or false if it doesn't exist in any Webpack instance */ -function updateExistingFactory(moduleFactoriesTarget: AnyWebpackRequire["m"], id: PropertyKey, newFactory: ModuleFactory, ignoreExistingInTarget: boolean = false) { +function updateExistingFactory(moduleFactoriesTarget: AnyWebpackRequire["m"], id: PropertyKey, newFactory: AnyModuleFactory, ignoreExistingInTarget: boolean = false) { let existingFactory: TypedPropertyDescriptor | undefined; for (const wreq of allWebpackInstances) { if (ignoreExistingInTarget && wreq.m === moduleFactoriesTarget) continue; @@ -228,7 +220,7 @@ const moduleFactoriesHandler: ProxyHandler = { * @param factory The original or patched module factory * @returns The wrapper for the patched module factory */ -function patchFactory(id: PropertyKey, factory: ModuleFactory) { +function patchFactory(id: PropertyKey, factory: AnyModuleFactory) { const originalFactory = factory; for (const factoryListener of factoryListeners) { @@ -347,7 +339,7 @@ function patchFactory(id: PropertyKey, factory: ModuleFactory) { // The patched factory wrapper, define it in an object to preserve the name after minification const patchedFactory: PatchedModuleFactory = { - PatchedFactory(...args: Parameters) { + PatchedFactory(...args: Parameters) { // Restore the original factory in all the module factories objects, // because we want to make sure the original factory is restored properly, no matter what is the Webpack instance for (const wreq of allWebpackInstances) { @@ -370,7 +362,7 @@ function patchFactory(id: PropertyKey, factory: ModuleFactory) { `id: ${String(id)}` + interpolateIfDefined`, WebpackInstance origin: ${webpackInstanceFileName}` + ")" ); - _initWebpack(require); + _initWebpack(require as WebpackRequire); } else if (IS_DEV) { logger.error("WebpackRequire was not initialized, running modules without patches instead."); } diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index f31855870..5d09c3b0f 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -22,7 +22,7 @@ import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; import { traceFunction } from "../debug/Tracer"; -import { ModuleExports, ModuleFactory, WebpackRequire } from "./wreq"; +import { AnyModuleFactory, ModuleExports, ModuleFactory, WebpackRequire } from "./wreq"; const logger = new Logger("Webpack"); @@ -72,7 +72,7 @@ export type CallbackFn = (module: ModuleExports, id: PropertyKey) => void; export const subscriptions = new Map(); export const moduleListeners = new Set(); -export const factoryListeners = new Set<(factory: ModuleFactory) => void>(); +export const factoryListeners = new Set<(factory: AnyModuleFactory) => void>(); export function _initWebpack(webpackRequire: WebpackRequire) { wreq = webpackRequire; diff --git a/src/webpack/wreq.d.ts b/src/webpack/wreq.d.ts index 6611680bd..c27ad3094 100644 --- a/src/webpack/wreq.d.ts +++ b/src/webpack/wreq.d.ts @@ -53,7 +53,7 @@ export type OnChunksLoaded = ((this: WebpackRequire, result: any, chunkIds: Prop j: (this: OnChunksLoaded, chunkId: PropertyKey) => boolean; }; -export type WebpackRequire = ((moduleId: PropertyKey) => Module) & { +export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & { /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ m: Record; /** The module cache, where all modules which have been WebpackRequire'd are stored */ @@ -182,3 +182,19 @@ export type WebpackRequire = ((moduleId: PropertyKey) => Module) & { /** Document baseURI or WebWorker location.href */ b: string; }; + +// Utility section for Vencord + +export type AnyWebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & Partial> & Pick & { + /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ + m: Record; +}; + +/** exports can be anything, however initially it is always an empty object */ +export type AnyModuleFactory = (this: ModuleExports, module: Module, exports: ModuleExports, require: AnyWebpackRequire) => void; + +export type PatchedModuleFactory = AnyModuleFactory & { + $$vencordOriginal?: AnyModuleFactory; +}; + +export type PatchedModuleFactories = Record;