From dcb0408e31319529cc6a567f0691bcb5863ce8f2 Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Wed, 22 May 2024 19:41:00 +0800 Subject: [PATCH] feat(metro): lazify destructures --- src/core/plugins/quickInstall/forumPost.tsx | 5 +++-- src/core/plugins/quickInstall/url.tsx | 9 +++++---- src/core/ui/components/AddonPage.tsx | 5 +++-- src/core/ui/components/Card.tsx | 7 ++++--- src/core/ui/settings/pages/Developer.tsx | 7 ++++--- src/lib/managers/themes.ts | 7 +++---- src/lib/ui/components/ContextMenu.tsx | 5 +++-- src/lib/ui/safeMode.tsx | 5 +++-- src/lib/ui/styles.ts | 5 +++-- src/lib/ui/toasts.ts | 5 +++-- src/lib/utils/lazy.ts | 19 +++++++++++++++++++ src/metro/modules.ts | 2 ++ src/metro/proxy.ts | 3 --- 13 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/core/plugins/quickInstall/forumPost.tsx b/src/core/plugins/quickInstall/forumPost.tsx index b0d165f..026d88f 100644 --- a/src/core/plugins/quickInstall/forumPost.tsx +++ b/src/core/plugins/quickInstall/forumPost.tsx @@ -6,7 +6,8 @@ import { useProxy } from "@lib/api/storage"; import { installPlugin, plugins, removePlugin } from "@lib/managers/plugins"; import { installTheme, removeTheme, themes } from "@lib/managers/themes"; import { DISCORD_SERVER_ID, HTTP_REGEX_MULTI, PLUGINS_CHANNEL_ID, PROXY_PREFIX, THEMES_CHANNEL_ID } from "@lib/utils/constants"; -import { findByPropsProxy } from "@metro/utils"; +import { lazyDestructure } from "@lib/utils/lazy"; +import { findByProps, findByPropsProxy } from "@metro/utils"; import { ErrorBoundary } from "@ui/components"; import { Button } from "@ui/components/discord/Redesign"; import { showToast } from "@ui/toasts"; @@ -15,7 +16,7 @@ type PostType = "Plugin" | "Theme"; // const ForumPostLongPressActionSheet = findByNameProxy("ForumPostLongPressActionSheet", false); // const { ActionSheetRow } = findByPropsProxy("ActionSheetRow"); -const { useFirstForumPostMessage } = findByPropsProxy("useFirstForumPostMessage"); +const { useFirstForumPostMessage } = lazyDestructure(() => findByProps("useFirstForumPostMessage")); const forumReactions = findByPropsProxy("MostCommonForumPostReaction"); const postMap = { diff --git a/src/core/plugins/quickInstall/url.tsx b/src/core/plugins/quickInstall/url.tsx index b1a48c4..1f97fd4 100644 --- a/src/core/plugins/quickInstall/url.tsx +++ b/src/core/plugins/quickInstall/url.tsx @@ -5,18 +5,19 @@ import { after, instead } from "@lib/api/patcher"; import { installPlugin } from "@lib/managers/plugins"; import { installTheme } from "@lib/managers/themes"; import { PROXY_PREFIX, THEMES_CHANNEL_ID } from "@lib/utils/constants"; +import { lazyDestructure } from "@lib/utils/lazy"; import { channels, url } from "@metro/common"; import { byMutableProp } from "@metro/filters"; import { findExports } from "@metro/finders"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps, findByPropsProxy } from "@metro/utils"; import { showConfirmationAlert } from "@ui/alerts"; import { showToast } from "@ui/toasts"; const showSimpleActionSheet = findExports(byMutableProp("showSimpleActionSheet")); const handleClick = findByPropsProxy("handleClick"); -const { openURL } = url; -const { getChannelId } = channels; -const { getChannel } = findByPropsProxy("getChannel"); +const { openURL } = lazyDestructure(() => url); +const { getChannelId } = lazyDestructure(() => channels); +const { getChannel } = lazyDestructure(() => findByProps("getChannel")); function typeFromUrl(url: string) { if (url.startsWith(PROXY_PREFIX)) { diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index 8bd2546..b55c0d0 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -4,8 +4,9 @@ import { getAssetIDByName } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; import { settings } from "@lib/settings"; import { HTTP_REGEX_MULTI } from "@lib/utils/constants"; +import { lazyDestructure } from "@lib/utils/lazy"; import { clipboard } from "@metro/common"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps, findByPropsProxy } from "@metro/utils"; import { showInputAlert } from "@ui/alerts"; import { ErrorBoundary, Search } from "@ui/components"; import { HelpMessage } from "@ui/components/discord"; @@ -44,7 +45,7 @@ function getItemsByQuery["items"][string]>(ite } const reanimated = findByPropsProxy("useSharedValue"); -const { FloatingActionButton } = findByPropsProxy("FloatingActionButton"); +const { FloatingActionButton } = lazyDestructure(() => findByProps("FloatingActionButton")); export default function AddonPage({ floatingButtonText, fetchFunction, items, safeModeMessage, safeModeExtras, card: CardComponent, isRemoveMode, headerComponent, onFABPress }: AddonPageProps) { useProxy(items); diff --git a/src/core/ui/components/Card.tsx b/src/core/ui/components/Card.tsx index 5394ac5..4b2bba8 100644 --- a/src/core/ui/components/Card.tsx +++ b/src/core/ui/components/Card.tsx @@ -1,14 +1,15 @@ import { getAssetIDByName } from "@lib/api/assets"; +import { lazyDestructure } from "@lib/utils/lazy"; import { ReactNative as RN } from "@metro/common"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps } from "@metro/utils"; import { semanticColors } from "@ui/color"; import { FormRow } from "@ui/components/discord/Forms"; import { FormCheckbox, FormSwitch, IconButton } from "@ui/components/discord/Redesign"; import { createStyles, TextStyleSheet } from "@ui/styles"; import { ImageBackground, View } from "react-native"; -const { hideActionSheet } = findByPropsProxy("openLazy", "hideActionSheet"); -const { showSimpleActionSheet } = findByPropsProxy("showSimpleActionSheet"); +const { hideActionSheet } = lazyDestructure(() => findByProps("openLazy", "hideActionSheet")); +const { showSimpleActionSheet } = lazyDestructure(() => findByProps("showSimpleActionSheet")); // TODO: These styles work weirdly. iOS has cramped text, Android with low DPI probably does too. Fix? const useStyles = createStyles({ diff --git a/src/core/ui/settings/pages/Developer.tsx b/src/core/ui/settings/pages/Developer.tsx index 8f9e8d1..6bf907b 100644 --- a/src/core/ui/settings/pages/Developer.tsx +++ b/src/core/ui/settings/pages/Developer.tsx @@ -6,8 +6,9 @@ import { getReactDevToolsProp, getReactDevToolsVersion, isLoaderConfigSupported, import { useProxy } from "@lib/api/storage"; import { connectToDebugger } from "@lib/debug"; import { loaderConfig, settings } from "@lib/settings"; +import { lazyDestructure } from "@lib/utils/lazy"; import { NavigationNative } from "@metro/common"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps } from "@metro/utils"; import { semanticColors } from "@ui/color"; import { ErrorBoundary } from "@ui/components"; import { FormText } from "@ui/components/discord/Forms"; @@ -15,8 +16,8 @@ import { Button, Stack, TableRow, TableRowGroup, TableSwitchRow, TextInput } fro import { createStyles, TextStyleSheet } from "@ui/styles"; import { ScrollView, StyleSheet } from "react-native"; -const { hideActionSheet } = findByPropsProxy("openLazy", "hideActionSheet"); -const { showSimpleActionSheet } = findByPropsProxy("showSimpleActionSheet"); +const { hideActionSheet } = lazyDestructure(() => findByProps("openLazy", "hideActionSheet")); +const { showSimpleActionSheet } = lazyDestructure(() => findByProps("showSimpleActionSheet")); const RDT_EMBED_LINK = "https://raw.githubusercontent.com/amsyarasyiq/rdt-embedder/main/dist.js"; diff --git a/src/lib/managers/themes.ts b/src/lib/managers/themes.ts index 9047e80..a9635c0 100644 --- a/src/lib/managers/themes.ts +++ b/src/lib/managers/themes.ts @@ -8,11 +8,12 @@ import { ThemeManager } from "@lib/api/native/modules"; import { after, before, instead } from "@lib/api/patcher"; import { awaitSyncWrapper, createFileBackend, createMMKVBackend, createStorage, wrapSync } from "@lib/api/storage"; import { findInReactTree, safeFetch } from "@lib/utils"; +import { lazyDestructure } from "@lib/utils/lazy"; import { Author } from "@lib/utils/types"; import { chroma } from "@metro/common"; import { byMutableProp } from "@metro/filters"; import { findExports } from "@metro/finders"; -import { findByNameProxy, findByPropsProxy, findByStoreNameProxy } from "@metro/utils"; +import { findByNameProxy, findByProps, findByPropsProxy, findByStoreNameProxy } from "@metro/utils"; import { ImageBackground, Platform, processColor } from "react-native"; export interface ThemeData { @@ -76,9 +77,7 @@ async function writeTheme(theme: Theme | {}) { */ export function patchChatBackground() { const MessagesWrapperConnected = findByNameProxy("MessagesWrapperConnected", false); - if (!MessagesWrapperConnected) return; - const { MessagesWrapper } = findByPropsProxy("MessagesWrapper"); - if (!MessagesWrapper) return; + const { MessagesWrapper } = lazyDestructure(() => findByProps("MessagesWrapper")); const patches = [ after("default", MessagesWrapperConnected, (_, ret) => enabled ? React.createElement(ImageBackground, { diff --git a/src/lib/ui/components/ContextMenu.tsx b/src/lib/ui/components/ContextMenu.tsx index c27f985..09c98a0 100644 --- a/src/lib/ui/components/ContextMenu.tsx +++ b/src/lib/ui/components/ContextMenu.tsx @@ -1,9 +1,10 @@ import { instead } from "@lib/api/patcher"; +import { lazyDestructure } from "@lib/utils/lazy"; import { OptionalKeys } from "@lib/utils/types"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps } from "@metro/utils"; import { AccessibilityInfo, Platform, View } from "react-native"; -const { ContextMenu: _ContextMenu } = findByPropsProxy("ContextMenu"); +const { ContextMenu: _ContextMenu } = lazyDestructure(() => findByProps("ContextMenu")); type ContextMenuItem = { label: string, diff --git a/src/lib/ui/safeMode.tsx b/src/lib/ui/safeMode.tsx index 901db51..0a503af 100644 --- a/src/lib/ui/safeMode.tsx +++ b/src/lib/ui/safeMode.tsx @@ -3,8 +3,9 @@ import { DeviceManager } from "@lib/api/native/modules"; import { after } from "@lib/api/patcher"; import { toggleSafeMode } from "@lib/debug"; import { settings } from "@lib/settings"; +import { lazyDestructure } from "@lib/utils/lazy"; import { ButtonColors } from "@lib/utils/types"; -import { findByNameProxy, findByPropsProxy } from "@metro/utils"; +import { findByNameProxy, findByProps } from "@metro/utils"; import { semanticColors } from "@ui/color"; import { Codeblock, ErrorBoundary as _ErrorBoundary } from "@ui/components"; import { Button, SafeAreaView } from "@ui/components/discord"; @@ -14,7 +15,7 @@ import { Text, View } from "react-native"; const ErrorBoundary = findByNameProxy("ErrorBoundary"); // Let's just pray they have this. -const { BadgableTabBar } = findByPropsProxy("BadgableTabBar"); +const { BadgableTabBar } = lazyDestructure(() => findByProps("BadgableTabBar")); const styles = createThemedStyleSheet({ container: { diff --git a/src/lib/ui/styles.ts b/src/lib/ui/styles.ts index b66b53f..7dd9b7b 100644 --- a/src/lib/ui/styles.ts +++ b/src/lib/ui/styles.ts @@ -1,4 +1,5 @@ -import { findByPropsProxy } from "@metro/utils"; +import { lazyDestructure } from "@lib/utils/lazy"; +import { findByProps } from "@metro/utils"; import { isSemanticColor, resolveSemanticColor } from "@ui/color"; import { CompatfulRedesign } from "@ui/components/discord/Redesign"; import { DiscordTextStyles } from "@ui/types"; @@ -6,7 +7,7 @@ import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from "react-native"; type NamedStyles = { [P in keyof T]: ViewStyle | TextStyle | ImageStyle }; -export const { TextStyleSheet } = findByPropsProxy("TextStyleSheet") as unknown as { +export const { TextStyleSheet } = lazyDestructure(() => findByProps("TextStyleSheet")) as unknown as { TextStyleSheet: { [key in DiscordTextStyles]: TextStyle; }; }; diff --git a/src/lib/ui/toasts.ts b/src/lib/ui/toasts.ts index 232b7cf..9f74cf0 100644 --- a/src/lib/ui/toasts.ts +++ b/src/lib/ui/toasts.ts @@ -1,10 +1,11 @@ import { Strings } from "@core/i18n"; import { getAssetIDByName } from "@lib/api/assets"; +import { lazyDestructure } from "@lib/utils/lazy"; import { toasts } from "@metro/common"; -import { findByPropsProxy } from "@metro/utils"; +import { findByProps } from "@metro/utils"; import { Platform } from "react-native"; -const { uuid4 } = findByPropsProxy("uuid4"); +const { uuid4 } = lazyDestructure(() => findByProps("uuid4")); export const showToast = (content: string, asset?: number) => toasts.open({ // ? In build 182205/44707, Discord changed their toasts, source is no longer used, rather icon, and a key is needed. diff --git a/src/lib/utils/lazy.ts b/src/lib/utils/lazy.ts index fe6852b..96f3e11 100644 --- a/src/lib/utils/lazy.ts +++ b/src/lib/utils/lazy.ts @@ -43,3 +43,22 @@ export function proxyLazy(factory: () => T, asFunction = true): T { return new Proxy(dummy, lazyHandler) as any; } + +export function lazyDestructure>(factory: () => T, asFunction = false): T { + const proxiedObject = proxyLazy(factory, asFunction); + + return new Proxy({}, { + get(_, property) { + if (property === Symbol.iterator) { + return function* () { + yield proxiedObject; + yield new Proxy({}, { + get: (_, p) => proxyLazy(() => proxiedObject[p]) + }); + throw new Error("This is not a real iterator, this is likely used incorrectly"); + }; + } + return proxyLazy(() => proxiedObject[property]); + } + }) as T; +} diff --git a/src/metro/modules.ts b/src/metro/modules.ts index 26a8c04..37e3019 100644 --- a/src/metro/modules.ts +++ b/src/metro/modules.ts @@ -174,7 +174,9 @@ export function requireModule(id: Metro.ModuleID) { let moduleExports; try { + const forced = !metroModules[id]?.isInitialized; moduleExports = metroRequire(id); + forced && console.log("Force inited", id, moduleExports); } catch { blacklistModule(String(id)); moduleExports = undefined; diff --git a/src/metro/proxy.ts b/src/metro/proxy.ts index 5a89656..51e22dc 100644 --- a/src/metro/proxy.ts +++ b/src/metro/proxy.ts @@ -5,9 +5,6 @@ import { filterExports, findExports } from "./finders"; import { requireModule, subscribeModule } from "./modules"; import type { FilterFn } from "./types"; -// TODO: "Find info" sounds too meh -const findInfoSym = Symbol.for("bunny.metro.findInfo"); - const proxyInfoMap = new WeakMap<{}, FindProxyInfo>(); interface FindProxyInfo {