Make Webpack finds not need to re-search
This commit is contained in:
parent
886071af4d
commit
4a89fadedd
|
@ -471,26 +471,19 @@ async function runtime(token: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must evaluate the len outside of the loop, as the array will be modified by the find methods called inside of it
|
const WEBPACK_SEARCH_HISTORY_WITH_FILTER_NAME_PROP = ["find", "findComponent", "waitFor"];
|
||||||
// This will avoid an infinite loop
|
|
||||||
const len = Vencord.Webpack.webpackSearchHistory.length;
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
const [searchType, args] = Vencord.Webpack.webpackSearchHistory[i];
|
|
||||||
|
|
||||||
let method = searchType as string;
|
// eslint-disable-next-line prefer-const
|
||||||
if (searchType === "waitFor") method = "cacheFind";
|
for (let [searchType, args] of Vencord.Webpack.webpackSearchHistory) {
|
||||||
|
args = [...args];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result: any;
|
let result = null as any;
|
||||||
|
|
||||||
if (method === "webpackDependantLazy" || method === "webpackDependantLazyComponent") {
|
if (searchType === "webpackDependantLazy" || searchType === "webpackDependantLazyComponent") {
|
||||||
const [factory] = args;
|
const [factory] = args;
|
||||||
result = factory();
|
result = factory();
|
||||||
|
} else if (searchType === "extractAndLoadChunks") {
|
||||||
if (result != null && "$$vencordGetter" in result) {
|
|
||||||
result = result.$$vencordGetter();
|
|
||||||
}
|
|
||||||
} else if (method === "extractAndLoadChunks") {
|
|
||||||
const [code, matcher] = args;
|
const [code, matcher] = args;
|
||||||
|
|
||||||
const module = Vencord.Webpack.findModuleFactory(...code);
|
const module = Vencord.Webpack.findModuleFactory(...code);
|
||||||
|
@ -498,14 +491,20 @@ async function runtime(token: string) {
|
||||||
result = module.toString().match(Vencord.Util.canonicalizeMatch(matcher));
|
result = module.toString().match(Vencord.Util.canonicalizeMatch(matcher));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = Vencord.Webpack[method](...args);
|
result = args.shift();
|
||||||
|
|
||||||
// If the result is our Proxy or ComponentWrapper, this means the search failed
|
if (result != null) {
|
||||||
if (
|
if (result.$$vencordCallbackCalled != null && !result.$$vencordCallbackCalled()) {
|
||||||
result != null &&
|
result = null;
|
||||||
(result[Vencord.Util.proxyInnerGet] != null || "$$vencordGetter" in result)
|
}
|
||||||
) {
|
|
||||||
result = undefined;
|
if (result[Vencord.Util.proxyInnerGet] != null) {
|
||||||
|
result = result[Vencord.Util.proxyInnerValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.$$vencordInner != null) {
|
||||||
|
result = result.$$vencordInner();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,28 +516,27 @@ async function runtime(token: string) {
|
||||||
|
|
||||||
let filterName = "";
|
let filterName = "";
|
||||||
let parsedArgs = args;
|
let parsedArgs = args;
|
||||||
if ("$$vencordProps" in args[0]) {
|
|
||||||
if (
|
if (args[0].$$vencordProps != null) {
|
||||||
searchType === "find" ||
|
if (WEBPACK_SEARCH_HISTORY_WITH_FILTER_NAME_PROP.includes(searchType)) {
|
||||||
searchType === "findComponent" ||
|
filterName = args[0].$$vencordProps.shift();
|
||||||
searchType === "waitFor"
|
|
||||||
) {
|
|
||||||
filterName = args[0].$$vencordProps[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedArgs = args[0].$$vencordProps.slice(1);
|
parsedArgs = args[0].$$vencordProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if parsedArgs is the same as args, it means vencordProps of the filter was not available (like in normal filter functions),
|
||||||
|
// so log the filter function instead
|
||||||
if (
|
if (
|
||||||
parsedArgs === args && searchType === "waitFor" ||
|
parsedArgs === args && (searchType === "waitFor" ||
|
||||||
searchType === "find" ||
|
searchType === "find" ||
|
||||||
searchType === "findComponent" ||
|
searchType === "findComponent" ||
|
||||||
searchType === "webpackDependantLazy" ||
|
searchType === "webpackDependantLazy" ||
|
||||||
searchType === "webpackDependantLazyComponent"
|
searchType === "webpackDependantLazyComponent")
|
||||||
) {
|
) {
|
||||||
logMessage += `(${parsedArgs[0].toString().slice(0, 147)}...)`;
|
logMessage += `(${args[0].toString().slice(0, 147)}...)`;
|
||||||
} else if (searchType === "extractAndLoadChunks") {
|
} else if (searchType === "extractAndLoadChunks") {
|
||||||
logMessage += `([${parsedArgs[0].map((arg: any) => `"${arg}"`).join(", ")}], ${parsedArgs[1].toString()})`;
|
logMessage += `([${args[0].map((arg: any) => `"${arg}"`).join(", ")}], ${args[1].toString()})`;
|
||||||
} else {
|
} else {
|
||||||
logMessage += `(${filterName.length ? `${filterName}(` : ""}${parsedArgs.map(arg => `"${arg}"`).join(", ")})${filterName.length ? ")" : ""}`;
|
logMessage += `(${filterName.length ? `${filterName}(` : ""}${parsedArgs.map(arg => `"${arg}"`).join(", ")})${filterName.length ? ")" : ""}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,18 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function makeLazy<T>(factory: () => T, attempts = 5): () => T {
|
export function makeLazy<T>(factory: () => T, attempts = 5, { isIndirect = false }: { isIndirect?: boolean; } = {}): () => T {
|
||||||
let tries = 0;
|
let tries = 0;
|
||||||
let cache: T;
|
let cache: T;
|
||||||
|
|
||||||
const getter = () => {
|
const getter = () => {
|
||||||
if (!cache && attempts > tries) {
|
if (!cache && attempts > tries) {
|
||||||
cache = factory();
|
cache = factory();
|
||||||
if (!cache && attempts === ++tries) {
|
if (!cache && attempts === ++tries && !isIndirect) {
|
||||||
console.error(`Lazy factory failed:\n\n${factory}`);
|
console.error(`Lazy factory failed:\n\n${factory}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,8 +49,8 @@ const handler: ProxyHandler<any> = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const proxyLazyGet = Symbol.for("vencord.lazy.get");
|
export const proxyLazyGet = Symbol.for("vencord.lazy.get");
|
||||||
const proxyLazyCache = Symbol.for("vencord.lazy.cached");
|
export const proxyLazyCache = Symbol.for("vencord.lazy.cached");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the result of factory in a Proxy you can consume as if it wasn't lazy.
|
* Wraps the result of factory in a Proxy you can consume as if it wasn't lazy.
|
||||||
|
@ -59,7 +60,7 @@ const proxyLazyCache = Symbol.for("vencord.lazy.cached");
|
||||||
* @returns Result of factory function
|
* @returns Result of factory function
|
||||||
*/
|
*/
|
||||||
export function proxyLazy<T = any>(factory: () => T, attempts = 5, isChild = false): T {
|
export function proxyLazy<T = any>(factory: () => T, attempts = 5, isChild = false): T {
|
||||||
const get = makeLazy(factory, attempts) as any;
|
const get = makeLazy(factory, attempts, { isIndirect: true }) as any;
|
||||||
|
|
||||||
let isSameTick = true;
|
let isSameTick = true;
|
||||||
if (!isChild) setTimeout(() => isSameTick = false, 0);
|
if (!isChild) setTimeout(() => isSameTick = false, 0);
|
||||||
|
@ -84,6 +85,9 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, isChild = fal
|
||||||
return new Proxy(proxyDummy, {
|
return new Proxy(proxyDummy, {
|
||||||
...handler,
|
...handler,
|
||||||
get(target, p, receiver) {
|
get(target, p, receiver) {
|
||||||
|
if (p === proxyLazyGet) return target[proxyLazyGet];
|
||||||
|
if (p === proxyLazyCache) return target[proxyLazyCache];
|
||||||
|
|
||||||
// If we're still in the same tick, it means the lazy was immediately used.
|
// If we're still in the same tick, it means the lazy was immediately used.
|
||||||
// thus, we lazy proxy the get access to make things like destructuring work as expected
|
// thus, we lazy proxy the get access to make things like destructuring work as expected
|
||||||
// meow here will also be a lazy
|
// meow here will also be a lazy
|
||||||
|
|
|
@ -4,12 +4,8 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentType } from "react";
|
|
||||||
|
|
||||||
import { makeLazy } from "./lazy";
|
import { makeLazy } from "./lazy";
|
||||||
|
|
||||||
export const NoopComponent = () => null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lazy component. The factory method is called on first render.
|
* A lazy component. The factory method is called on first render.
|
||||||
* @param factory Function returning a component
|
* @param factory Function returning a component
|
||||||
|
@ -17,25 +13,31 @@ export const NoopComponent = () => null;
|
||||||
* @returns Result of factory function
|
* @returns Result of factory function
|
||||||
*/
|
*/
|
||||||
export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>, attempts = 5) {
|
export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>, attempts = 5) {
|
||||||
const get = makeLazy(factory, attempts);
|
const get = makeLazy(factory, attempts, { isIndirect: true });
|
||||||
|
|
||||||
|
let InnerComponent = null as React.ComponentType<T> | null;
|
||||||
|
|
||||||
|
let lazyFailedLogged = false;
|
||||||
const LazyComponent = (props: T) => {
|
const LazyComponent = (props: T) => {
|
||||||
let Component = (() => {
|
|
||||||
console.error(`LazyComponent factory failed:\n\n${factory}`);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}) as React.ComponentType<T>;
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!get.$$vencordLazyFailed()) {
|
if (!get.$$vencordLazyFailed()) {
|
||||||
const result = get();
|
const ResultComponent = get();
|
||||||
if (result != null) Component = result;
|
if (ResultComponent != null) {
|
||||||
|
InnerComponent = ResultComponent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Component {...props} />;
|
if (InnerComponent === null && !lazyFailedLogged) {
|
||||||
|
// @ts-ignore
|
||||||
|
if (get.$$vencordLazyFailed()) {
|
||||||
|
lazyFailedLogged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`LazyComponent factory failed:\n\n${factory}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InnerComponent && <InnerComponent {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
LazyComponent.$$vencordGetter = get;
|
return LazyComponent as React.ComponentType<T>;
|
||||||
|
|
||||||
return LazyComponent as ComponentType<T>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import { checkIntersecting } from "./misc";
|
||||||
|
|
||||||
export * from "./lazyReact";
|
export * from "./lazyReact";
|
||||||
|
|
||||||
|
export const NoopComponent = () => null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an element is on screen
|
* Check if an element is on screen
|
||||||
* @param intersectOnly If `true`, will only update the state when the element comes into view
|
* @param intersectOnly If `true`, will only update the state when the element comes into view
|
||||||
|
|
|
@ -133,7 +133,22 @@ export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect
|
||||||
if (typeof callback !== "function")
|
if (typeof callback !== "function")
|
||||||
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
||||||
|
|
||||||
if (IS_DEV && !isIndirect) webpackSearchHistory.push(["waitFor", [filter]]);
|
if (IS_DEV && !isIndirect) {
|
||||||
|
const originalCallback = callback;
|
||||||
|
|
||||||
|
let callbackCalled = false;
|
||||||
|
callback = function () {
|
||||||
|
callbackCalled = true;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
originalCallback(...arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
callback.$$vencordCallbackCalled = () => callbackCalled;
|
||||||
|
|
||||||
|
webpackSearchHistory.push(["waitFor", [callback, filter]]);
|
||||||
|
}
|
||||||
|
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
const existing = cacheFind(filter);
|
const existing = cacheFind(filter);
|
||||||
|
@ -165,11 +180,13 @@ export function find<T = any>(filter: FilterFn, callback: (mod: any) => any = m
|
||||||
if (typeof callback !== "function")
|
if (typeof callback !== "function")
|
||||||
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
||||||
|
|
||||||
if (IS_DEV && !isIndirect) webpackSearchHistory.push(["find", [filter]]);
|
|
||||||
|
|
||||||
const [proxy, setInnerValue] = proxyInner<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find.");
|
const [proxy, setInnerValue] = proxyInner<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find.");
|
||||||
waitFor(filter, mod => setInnerValue(callback(mod)), { isIndirect: true });
|
waitFor(filter, mod => setInnerValue(callback(mod)), { isIndirect: true });
|
||||||
|
|
||||||
|
if (IS_DEV && !isIndirect) {
|
||||||
|
webpackSearchHistory.push(["find", [proxy, filter]]);
|
||||||
|
}
|
||||||
|
|
||||||
if (proxy[proxyInnerValue] != null) return proxy[proxyInnerValue] as T;
|
if (proxy[proxyInnerValue] != null) return proxy[proxyInnerValue] as T;
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
|
@ -187,9 +204,7 @@ export function findComponent<T extends object = any>(filter: FilterFn, parse: (
|
||||||
if (typeof parse !== "function")
|
if (typeof parse !== "function")
|
||||||
throw new Error("Invalid component parse. Expected a function got " + typeof parse);
|
throw new Error("Invalid component parse. Expected a function got " + typeof parse);
|
||||||
|
|
||||||
if (IS_DEV && !isIndirect) webpackSearchHistory.push(["findComponent", [filter]]);
|
let InnerComponent = null as React.ComponentType<T> | null;
|
||||||
|
|
||||||
let InnerComponent = null as null | React.ComponentType<T>;
|
|
||||||
|
|
||||||
let findFailedLogged = false;
|
let findFailedLogged = false;
|
||||||
const WrapperComponent = (props: T) => {
|
const WrapperComponent = (props: T) => {
|
||||||
|
@ -201,14 +216,20 @@ export function findComponent<T extends object = any>(filter: FilterFn, parse: (
|
||||||
return InnerComponent && <InnerComponent {...props} />;
|
return InnerComponent && <InnerComponent {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
WrapperComponent.$$vencordGetter = () => InnerComponent;
|
|
||||||
|
|
||||||
waitFor(filter, (v: any) => {
|
waitFor(filter, (v: any) => {
|
||||||
const parsedComponent = parse(v);
|
const parsedComponent = parse(v);
|
||||||
InnerComponent = parsedComponent;
|
InnerComponent = parsedComponent;
|
||||||
Object.assign(InnerComponent, parsedComponent);
|
Object.assign(InnerComponent, parsedComponent);
|
||||||
}, { isIndirect: true });
|
}, { isIndirect: true });
|
||||||
|
|
||||||
|
if (IS_DEV) {
|
||||||
|
WrapperComponent.$$vencordInner = () => InnerComponent;
|
||||||
|
|
||||||
|
if (!isIndirect) {
|
||||||
|
webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (InnerComponent !== null) return InnerComponent;
|
if (InnerComponent !== null) return InnerComponent;
|
||||||
|
|
||||||
return WrapperComponent;
|
return WrapperComponent;
|
||||||
|
@ -230,9 +251,7 @@ export function findExportedComponent<T extends object = any>(...props: string[]
|
||||||
|
|
||||||
const filter = filters.byProps(...newProps);
|
const filter = filters.byProps(...newProps);
|
||||||
|
|
||||||
if (IS_DEV) webpackSearchHistory.push(["findExportedComponent", props]);
|
let InnerComponent = null as React.ComponentType<T> | null;
|
||||||
|
|
||||||
let InnerComponent = null as null | React.ComponentType<T>;
|
|
||||||
|
|
||||||
let findFailedLogged = false;
|
let findFailedLogged = false;
|
||||||
const WrapperComponent = (props: T) => {
|
const WrapperComponent = (props: T) => {
|
||||||
|
@ -244,7 +263,6 @@ export function findExportedComponent<T extends object = any>(...props: string[]
|
||||||
return InnerComponent && <InnerComponent {...props} />;
|
return InnerComponent && <InnerComponent {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
WrapperComponent.$$vencordGetter = () => InnerComponent;
|
|
||||||
|
|
||||||
waitFor(filter, (v: any) => {
|
waitFor(filter, (v: any) => {
|
||||||
const parsedComponent = parse(v[newProps[0]]);
|
const parsedComponent = parse(v[newProps[0]]);
|
||||||
|
@ -252,6 +270,11 @@ export function findExportedComponent<T extends object = any>(...props: string[]
|
||||||
Object.assign(InnerComponent, parsedComponent);
|
Object.assign(InnerComponent, parsedComponent);
|
||||||
}, { isIndirect: true });
|
}, { isIndirect: true });
|
||||||
|
|
||||||
|
if (IS_DEV) {
|
||||||
|
WrapperComponent.$$vencordInner = () => InnerComponent;
|
||||||
|
webpackSearchHistory.push(["findExportedComponent", [WrapperComponent, ...props]]);
|
||||||
|
}
|
||||||
|
|
||||||
if (InnerComponent !== null) return InnerComponent;
|
if (InnerComponent !== null) return InnerComponent;
|
||||||
|
|
||||||
return WrapperComponent as React.ComponentType<T>;
|
return WrapperComponent as React.ComponentType<T>;
|
||||||
|
@ -271,9 +294,13 @@ export function findComponentByCode<T extends object = any>(...code: string[] |
|
||||||
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => React.ComponentType<T>;
|
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => React.ComponentType<T>;
|
||||||
const newCode = code as string[];
|
const newCode = code as string[];
|
||||||
|
|
||||||
if (IS_DEV) webpackSearchHistory.push(["findComponentByCode", code]);
|
const ComponentResult = findComponent<T>(filters.componentByCode(...newCode), parse, { isIndirect: true });
|
||||||
|
|
||||||
return findComponent<T>(filters.componentByCode(...newCode), parse, { isIndirect: true });
|
if (IS_DEV) {
|
||||||
|
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...code]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComponentResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -282,9 +309,13 @@ export function findComponentByCode<T extends object = any>(...code: string[] |
|
||||||
* @param props A list of props to search the exports for
|
* @param props A list of props to search the exports for
|
||||||
*/
|
*/
|
||||||
export function findByProps<T = any>(...props: string[]) {
|
export function findByProps<T = any>(...props: string[]) {
|
||||||
if (IS_DEV) webpackSearchHistory.push(["findByProps", props]);
|
const result = find<T>(filters.byProps(...props), m => m, { isIndirect: true });
|
||||||
|
|
||||||
return find<T>(filters.byProps(...props), m => m, { isIndirect: true });
|
if (IS_DEV) {
|
||||||
|
webpackSearchHistory.push(["findByProps", [result, ...props]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -293,9 +324,13 @@ export function findByProps<T = any>(...props: string[]) {
|
||||||
* @param code A list of code to search each export for
|
* @param code A list of code to search each export for
|
||||||
*/
|
*/
|
||||||
export function findByCode<T = any>(...code: string[]) {
|
export function findByCode<T = any>(...code: string[]) {
|
||||||
if (IS_DEV) webpackSearchHistory.push(["findByCode", code]);
|
const result = find<T>(filters.byCode(...code), m => m, { isIndirect: true });
|
||||||
|
|
||||||
return find<T>(filters.byCode(...code), m => m, { isIndirect: true });
|
if (IS_DEV) {
|
||||||
|
webpackSearchHistory.push(["findByCode", [result, ...code]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,9 +339,13 @@ export function findByCode<T = any>(...code: string[]) {
|
||||||
* @param name The store name
|
* @param name The store name
|
||||||
*/
|
*/
|
||||||
export function findStore<T = any>(name: string) {
|
export function findStore<T = any>(name: string) {
|
||||||
if (IS_DEV) webpackSearchHistory.push(["findStore", [name]]);
|
const result = find<T>(filters.byStoreName(name), m => m, { isIndirect: true });
|
||||||
|
|
||||||
return find<T>(filters.byStoreName(name), m => m, { isIndirect: true });
|
if (IS_DEV) {
|
||||||
|
webpackSearchHistory.push(["findStore", [result, name]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue