Merge branch 'modules-proxy-patches' into immediate-finds-modules-proxy
This commit is contained in:
commit
05717d6bc3
|
@ -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) {
|
||||
|
|
|
@ -12,15 +12,7 @@ import { PatchReplacement } from "@utils/types";
|
|||
|
||||
import { traceFunction } from "../debug/Tracer";
|
||||
import { patches } from "../plugins";
|
||||
import { _initWebpack, factoryListeners, ModuleFactory, moduleListeners, waitForSubscriptions, 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, waitForSubscriptions, 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.");
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { AnyObject } from "@utils/types";
|
|||
|
||||
import { traceFunction } from "../debug/Tracer";
|
||||
import { GenericStore } from "./common";
|
||||
import { ModuleExports, ModuleFactory, WebpackRequire } from "./wreq";
|
||||
import { AnyModuleFactory, ModuleExports, ModuleFactory, WebpackRequire } from "./wreq";
|
||||
|
||||
const logger = new Logger("Webpack");
|
||||
|
||||
|
@ -90,7 +90,7 @@ export type ModCallbackFnWithId = (module: ModuleExports, id: PropertyKey) => vo
|
|||
|
||||
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
|
||||
export const moduleListeners = new Set<ModCallbackFnWithId>();
|
||||
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
18
src/webpack/wreq.d.ts
vendored
|
@ -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>;
|
||||
|
|
Loading…
Reference in a new issue