Improve typings and other stuff

This commit is contained in:
Nuckyz 2024-06-02 18:46:03 -03:00
parent 066ce07512
commit 53dd86fa6e
No known key found for this signature in database
GPG key ID: 440BF8296E1C4AD9
4 changed files with 38 additions and 28 deletions

View file

@ -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) {

View file

@ -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<WebpackRequire> & Pick<WebpackRequire, "m">;
type PatchedModuleFactory = ModuleFactory & {
$$vencordOriginal?: ModuleFactory;
};
type PatchedModuleFactories = Record<PropertyKey, PatchedModuleFactory>;
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<PatchedModuleFactory> | undefined;
for (const wreq of allWebpackInstances) {
if (ignoreExistingInTarget && wreq.m === moduleFactoriesTarget) continue;
@ -228,7 +220,7 @@ const moduleFactoriesHandler: ProxyHandler<PatchedModuleFactories> = {
* @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<ModuleFactory>) {
PatchedFactory(...args: Parameters<AnyModuleFactory>) {
// 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.");
}

View file

@ -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<FilterFn, CallbackFn>();
export const moduleListeners = new Set<CallbackFn>();
export const factoryListeners = new Set<(factory: ModuleFactory) => void>();
export const factoryListeners = new Set<(factory: AnyModuleFactory) => void>();
export function _initWebpack(webpackRequire: WebpackRequire) {
wreq = webpackRequire;

18
src/webpack/wreq.d.ts vendored
View file

@ -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<PropertyKey, ModuleFactory>;
/** 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<Omit<WebpackRequire, "m" | "O">> & Pick<WebpackRequire, "O"> & {
/** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */
m: Record<PropertyKey, AnyModuleFactory>;
};
/** 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<PropertyKey, PatchedModuleFactory>;