mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-10 01:46:23 +00:00
Lazy components are always functions
This commit is contained in:
parent
7eeaa32473
commit
126f2df811
8 changed files with 45 additions and 41 deletions
4
src/globals.d.ts
vendored
4
src/globals.d.ts
vendored
|
@ -19,6 +19,8 @@
|
|||
import { LoDashStatic } from "lodash";
|
||||
|
||||
declare global {
|
||||
type AnyRecord = Record<PropertyKey, any>;
|
||||
|
||||
/**
|
||||
* This exists only at build time, so references to it in patches should insert it
|
||||
* via String interpolation OR use different replacement code based on this
|
||||
|
@ -64,7 +66,7 @@ declare global {
|
|||
export var Vesktop: any;
|
||||
export var VesktopNative: any;
|
||||
|
||||
interface Window extends Record<PropertyKey, any> {
|
||||
interface Window extends AnyRecord {
|
||||
_: LoDashStatic;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const UserProfile = findComponentByCode("UserProfilePopoutWrapper: user cannot b
|
|||
const styles = findByProps("accountProfilePopoutWrapper");
|
||||
|
||||
let openAlternatePopout = false;
|
||||
let accountPanelRef: React.MutableRefObject<Record<PropertyKey, any> | null> = { current: null };
|
||||
let accountPanelRef: React.MutableRefObject<AnyRecord | null> = { current: null };
|
||||
|
||||
const AccountPanelContextMenu = ErrorBoundary.wrap(() => {
|
||||
const { prioritizeServerProfile } = settings.use(["prioritizeServerProfile"]);
|
||||
|
|
|
@ -17,7 +17,7 @@ const selectVoiceChannel = findProp("selectVoiceChannel", "selectChannel");
|
|||
const VoiceStateStore = findStore("VoiceStateStore");
|
||||
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||
|
||||
interface IconProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
interface IconProps extends React.ComponentPropsWithoutRef<"div"> {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
|
||||
import { makeLazy } from "./lazy";
|
||||
|
||||
export type LazyComponentType<T extends object = any> = React.ComponentType<T> & Record<PropertyKey, any>;
|
||||
|
||||
export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner");
|
||||
|
||||
export type LazyComponentType<P extends AnyRecord> = React.FunctionComponent<P> & AnyRecord & {
|
||||
[SYM_LAZY_COMPONENT_INNER]: () => LazyComponentType<P> | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A lazy component. The factory method is called on first render.
|
||||
*
|
||||
|
@ -17,15 +19,16 @@ export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner"
|
|||
* @param attempts How many times to try to get the component before giving up
|
||||
* @returns Result of factory function
|
||||
*/
|
||||
export function LazyComponent<T extends object = any>(factory: () => LazyComponentType<T>, attempts = 5, errMsg: string | (() => string) = `LazyComponent factory failed:\n${factory}`) {
|
||||
export function LazyComponent<P extends AnyRecord>(factory: () => any, attempts = 5, err: string | (() => string) = `LazyComponent factory failed:\n${factory}`): LazyComponentType<P> {
|
||||
const get = makeLazy(factory, attempts, { isIndirect: true });
|
||||
|
||||
let InnerComponent = null as LazyComponentType<T> | null;
|
||||
let InnerComponent = null as LazyComponentType<P> | null;
|
||||
|
||||
let lazyFailedLogged = false;
|
||||
const LazyComponent = (props: T) => {
|
||||
const LazyComponent: LazyComponentType<P> = function (props) {
|
||||
if (!get.$$vencordLazyFailed()) {
|
||||
const ResultComponent = get();
|
||||
|
||||
if (ResultComponent != null) {
|
||||
InnerComponent = ResultComponent;
|
||||
Object.assign(LazyComponent, ResultComponent);
|
||||
|
@ -37,7 +40,7 @@ export function LazyComponent<T extends object = any>(factory: () => LazyCompone
|
|||
lazyFailedLogged = true;
|
||||
}
|
||||
|
||||
console.error(typeof errMsg === "string" ? errMsg : errMsg());
|
||||
console.error(typeof err === "string" ? err : err());
|
||||
}
|
||||
|
||||
return InnerComponent && <InnerComponent {...props} />;
|
||||
|
@ -45,5 +48,5 @@ export function LazyComponent<T extends object = any>(factory: () => LazyCompone
|
|||
|
||||
LazyComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
|
||||
|
||||
return LazyComponent as LazyComponentType<T>;
|
||||
return LazyComponent;
|
||||
}
|
||||
|
|
|
@ -51,12 +51,13 @@ export type ModCallbackInfo = {
|
|||
factory: AnyModuleFactory;
|
||||
};
|
||||
|
||||
export type FactoryListernFn = (factory: AnyModuleFactory) => void;
|
||||
export type ModListenerFn = (module: ModuleExports, info: ModListenerInfo) => void;
|
||||
export type ModCallbackFn = ((module: ModuleExports, info: ModCallbackInfo) => void) & {
|
||||
$$vencordCallbackCalled?: () => boolean;
|
||||
};
|
||||
|
||||
export const factoryListeners = new Set<(factory: AnyModuleFactory) => void>();
|
||||
export const factoryListeners = new Set<FactoryListernFn>();
|
||||
export const moduleListeners = new Set<ModListenerFn>();
|
||||
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
|
||||
|
||||
|
@ -170,16 +171,14 @@ function printFilter(filter: FilterFn) {
|
|||
return String(filter);
|
||||
}
|
||||
|
||||
function wrapWebpackComponent<T extends object = any>(
|
||||
errMsg: string | (() => string)
|
||||
): [WrapperComponent: LazyComponentType<T>, setInnerComponent: (rawComponent: any, parsedComponent: LazyComponentType<T>) => void] {
|
||||
let InnerComponent = null as LazyComponentType<T> | null;
|
||||
function wrapWebpackComponent<P extends AnyRecord>(err: string | (() => string)): [WrapperComponent: LazyComponentType<P>, setInnerComponent: (rawComponent: any, parsedComponent: LazyComponentType<P>) => void] {
|
||||
let InnerComponent = null as LazyComponentType<P> | null;
|
||||
|
||||
let findFailedLogged = false;
|
||||
const WrapperComponent = (props: T) => {
|
||||
const WrapperComponent: LazyComponentType<P> = function (props) {
|
||||
if (InnerComponent === null && !findFailedLogged) {
|
||||
findFailedLogged = true;
|
||||
logger.error(typeof errMsg === "string" ? errMsg : errMsg());
|
||||
logger.error(typeof err === "string" ? err : err());
|
||||
}
|
||||
|
||||
return InnerComponent && <InnerComponent {...props} />;
|
||||
|
@ -187,7 +186,7 @@ function wrapWebpackComponent<T extends object = any>(
|
|||
|
||||
WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
|
||||
|
||||
function setInnerComponent(RawComponent: any, ParsedComponent: LazyComponentType<T>) {
|
||||
function setInnerComponent(RawComponent: any, ParsedComponent: LazyComponentType<P>) {
|
||||
InnerComponent = ParsedComponent;
|
||||
Object.assign(WrapperComponent, RawComponent);
|
||||
}
|
||||
|
@ -282,7 +281,7 @@ export function find<T = any>(filter: FilterFn, parse: (module: ModuleExports) =
|
|||
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
||||
* @returns The component if found, or a noop component
|
||||
*/
|
||||
export function findComponent<T extends object = any>(filter: FilterFn, parse: (component: ModuleExports) => LazyComponentType<T> = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
||||
export function findComponent<P extends AnyRecord>(filter: FilterFn, parse: (component: ModuleExports) => LazyComponentType<P> = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
||||
if (typeof filter !== "function") {
|
||||
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
||||
}
|
||||
|
@ -290,14 +289,14 @@ export function findComponent<T extends object = any>(filter: FilterFn, parse: (
|
|||
throw new Error("Invalid component parse. Expected a function got " + typeof parse);
|
||||
}
|
||||
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<P>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
|
||||
waitFor(filter, m => setInnerComponent(m, parse(m)), { isIndirect: true });
|
||||
|
||||
if (IS_REPORTER && !isIndirect) {
|
||||
webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]);
|
||||
}
|
||||
|
||||
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as LazyComponentType<T>;
|
||||
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]()!;
|
||||
|
||||
return WrapperComponent;
|
||||
}
|
||||
|
@ -312,20 +311,20 @@ export function findComponent<T extends object = any>(filter: FilterFn, parse: (
|
|||
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
||||
* @returns The component if found, or a noop component
|
||||
*/
|
||||
export function findExportedComponent<T extends object = any>(...props: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<T>]) {
|
||||
const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
|
||||
export function findExportedComponent<P extends AnyRecord>(...props: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<P>]) {
|
||||
const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: ModuleExports) => LazyComponentType<P>;
|
||||
const newProps = props as PropsFilter;
|
||||
|
||||
const filter = filters.byProps(...newProps);
|
||||
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<P>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
|
||||
waitFor(filter, m => setInnerComponent(m[newProps[0]], parse(m[newProps[0]])), { isIndirect: true });
|
||||
|
||||
if (IS_REPORTER) {
|
||||
webpackSearchHistory.push(["findExportedComponent", [WrapperComponent, ...newProps]]);
|
||||
}
|
||||
|
||||
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as LazyComponentType<T>;
|
||||
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]()!;
|
||||
|
||||
return WrapperComponent;
|
||||
}
|
||||
|
@ -340,11 +339,11 @@ export function findExportedComponent<T extends object = any>(...props: PropsFil
|
|||
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
||||
* @returns The component if found, or a noop component
|
||||
*/
|
||||
export function findComponentByCode<T extends object = any>(...code: CodeFilter | [...CodeFilter, (component: ModuleExports) => LazyComponentType<T>]) {
|
||||
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
|
||||
export function findComponentByCode<P extends AnyRecord>(...code: CodeFilter | [...CodeFilter, (component: ModuleExports) => LazyComponentType<P>]) {
|
||||
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: ModuleExports) => LazyComponentType<P>;
|
||||
const newCode = code as CodeFilter;
|
||||
|
||||
const ComponentResult = findComponent<T>(filters.componentByCode(...newCode), parse, { isIndirect: true });
|
||||
const ComponentResult = findComponent<P>(filters.componentByCode(...newCode), parse, { isIndirect: true });
|
||||
|
||||
if (IS_REPORTER) {
|
||||
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newCode]]);
|
||||
|
@ -363,11 +362,11 @@ export function findComponentByCode<T extends object = any>(...code: CodeFilter
|
|||
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
||||
* @returns The component if found, or a noop component
|
||||
*/
|
||||
export function findComponentByFields<T extends object = any>(...fields: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<T>]) {
|
||||
const parse = (typeof fields.at(-1) === "function" ? fields.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
|
||||
export function findComponentByFields<P extends AnyRecord>(...fields: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<P>]) {
|
||||
const parse = (typeof fields.at(-1) === "function" ? fields.pop() : m => m) as (component: ModuleExports) => LazyComponentType<P>;
|
||||
const newFields = fields as PropsFilter;
|
||||
|
||||
const ComponentResult = findComponent<T>(filters.componentByFields(...newFields), parse, { isIndirect: true });
|
||||
const ComponentResult = findComponent<P>(filters.componentByFields(...newFields), parse, { isIndirect: true });
|
||||
|
||||
if (IS_REPORTER) {
|
||||
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newFields]]);
|
||||
|
@ -497,14 +496,14 @@ export function mapMangledModule<S extends PropertyKey>(code: CodeFilterWithSing
|
|||
const mapperFilter = mappers[newName];
|
||||
|
||||
// Wrapper to select whether the parent factory filter or child mapper filter failed when the error is thrown
|
||||
const errorMsgWrapper = () => `Webpack mapMangledModule ${callbackCalled ? "mapper" : "factory"} filter matched no module. Filter: ${printFilter(callbackCalled ? mapperFilter : factoryFilter)}`;
|
||||
const errorWrapper = () => `Webpack mapMangledModule ${callbackCalled ? "mapper" : "factory"} filter matched no module. Filter: ${printFilter(callbackCalled ? mapperFilter : factoryFilter)}`;
|
||||
|
||||
if (mapperFilter.$$vencordIsComponentFilter) {
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorMsgWrapper);
|
||||
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorWrapper);
|
||||
mapping[newName] = WrapperComponent;
|
||||
wrapperComponentSetters[newName] = setInnerComponent;
|
||||
} else {
|
||||
const [proxy, setInnerValue] = proxyInner(errorMsgWrapper, "Webpack find with proxy called on a primitive value. This may happen if you are trying to destructure a mapMangledModule primitive value on top level.");
|
||||
const [proxy, setInnerValue] = proxyInner(errorWrapper, "Webpack find with proxy called on a primitive value. This may happen if you are trying to destructure a mapMangledModule primitive value on top level.");
|
||||
mapping[newName] = proxy;
|
||||
proxyInnerSetters[newName] = setInnerValue;
|
||||
}
|
||||
|
@ -604,12 +603,12 @@ export function webpackDependantLazy<T = any>(factory: () => T, attempts?: numbe
|
|||
* @param attempts How many times to try to get the component before giving up
|
||||
* @returns Result of factory function
|
||||
*/
|
||||
export function webpackDependantLazyComponent<T extends object = any>(factory: () => any, attempts?: number) {
|
||||
export function webpackDependantLazyComponent<P extends AnyRecord>(factory: () => any, attempts?: number) {
|
||||
if (IS_REPORTER) {
|
||||
webpackSearchHistory.push(["webpackDependantLazyComponent", [factory]]);
|
||||
}
|
||||
|
||||
return LazyComponent<T>(factory, attempts, `Webpack dependant LazyComponent factory failed:\n${factory}`);
|
||||
return LazyComponent<P>(factory, attempts, `Webpack dependant LazyComponent factory failed:\n${factory}`);
|
||||
}
|
||||
|
||||
export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/;
|
||||
|
|
4
src/webpack/common/types/menu.d.ts
vendored
4
src/webpack/common/types/menu.d.ts
vendored
|
@ -18,7 +18,7 @@
|
|||
|
||||
import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
|
||||
|
||||
type RC<C> = ComponentType<PropsWithChildren<C & Record<PropertyKey, any>>>;
|
||||
type RC<C> = ComponentType<PropsWithChildren<C & AnyRecord>>;
|
||||
|
||||
export interface Menu {
|
||||
Menu: RC<{
|
||||
|
@ -73,7 +73,7 @@ export interface Menu {
|
|||
renderValue?(value: number): string,
|
||||
}>;
|
||||
MenuSearchControl: RC<{
|
||||
query: string
|
||||
query: string;
|
||||
onChange(query: string): void;
|
||||
placeholder?: string;
|
||||
}>;
|
||||
|
|
2
src/webpack/common/types/utils.d.ts
vendored
2
src/webpack/common/types/utils.d.ts
vendored
|
@ -241,7 +241,7 @@ export interface Constants {
|
|||
|
||||
export type ActiveView = LiteralUnion<"emoji" | "gif" | "sticker" | "soundboard", string>;
|
||||
|
||||
export interface ExpressionPickerStoreState extends Record<PropertyKey, any> {
|
||||
export interface ExpressionPickerStoreState extends AnyRecord {
|
||||
activeView: ActiveView | null;
|
||||
lastActiveView: ActiveView | null;
|
||||
activeViewType: any | null;
|
||||
|
|
4
src/webpack/wreq.d.ts
vendored
4
src/webpack/wreq.d.ts
vendored
|
@ -72,7 +72,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
|
|||
// * });
|
||||
// * @returns fromObject
|
||||
// */
|
||||
// es: (this: WebpackRequire, fromObject: Record<PropertyKey, any>, toObject: Record<PropertyKey, any>) => Record<PropertyKey, any>;
|
||||
// es: (this: WebpackRequire, fromObject: AnyRecord, toObject: AnyRecord) => AnyRecord;
|
||||
/**
|
||||
* Creates an async module. A module that exports something that is a Promise, or requires an export from an async module.
|
||||
*
|
||||
|
@ -132,7 +132,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
|
|||
* }
|
||||
* // exports is now { exportName: someExportedValue } (but each value is actually a getter)
|
||||
*/
|
||||
d: (this: WebpackRequire, exports: Record<PropertyKey, any>, definiton: Record<PropertyKey, any>) => void;
|
||||
d: (this: WebpackRequire, exports: AnyRecord, definiton: AnyRecord) => void;
|
||||
/** The chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */
|
||||
f: ChunkHandlers;
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue