Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(Webpack): Immediate finds using waitFor #2409

Open
wants to merge 141 commits into
base: dev
Choose a base branch
from
Open

Conversation

Nuckyz
Copy link
Collaborator

@Nuckyz Nuckyz commented May 3, 2024

Completely deprecates the lazy way that we currently do Webpack finds. Instead, now the default will be a unified way which is a combination of the plain cacheFind for already loaded modules, and usage of waitFor for when modules were not yet loaded.

The way this works is:

  • If you use the find methods in the top level, you will leverage the performance gain of using the waitFor alternative. By using waitFor, everytime a new module is loaded, Vencord will check if that module matches any of the finds requested, and if it does, it sets the result of that find to the module. This avoids having to iterate through the module cache for every find.

By using the waitFor alternative, the result of calling the find methods is a Proxy, which has a value inside which points to the module. When the module is found that value is set, and now the Proxy acts as the module found.

Trying to access a Proxy value before the module value is set will cause an error, which shows the filter that failed. This allows users to post better logs for us.

  • However, if you don't use in the top level, you will mostly likely just find the module using cacheFind, which does need to iterate through the module cache. But of course, if the module is not in the cache it will still register a waitFor, to find the module in case it is loaded later.

By having the unified way, we no longer need a lazy alternative of the methods, so the following changes to the API occurred:

  • Old find -> cacheFind
  • New find (wrapper around waitFor and cacheFind)
  • findLazy -> find (the wrapper)
  • findByProps, findByPropsLazy -> findByProps
  • findByCode, findByCodeLazy -> findByCode
  • findStore, findStoreLazy -> findStore
  • findComponent, findComponentLazy -> findComponent
  • findExportedComponent, findExportedComponentLazy -> findExportedComponent
  • findComponentByCode, findComponentByCodeLazy -> findComponentByCode

The following were changed for more appropriate names:

  • findAll -> cacheFindAll
  • findBulk -> cacheFindBulk

The following were changed for less weird names:

  • proxyLazyWebpack -> webpackDependantLazy
  • LazyComponentWebpack -> webpackDependantLazyComponent

The following were not changed:

  • findModuleId
  • findModuleFactory
  • ConsoleShortcuts preserved the same because it uses cacheFindAll and filters internally, so it doesn't rely on the way the old methods worked.

Additional:

  • Clean up proxyLazy and LazyComponent
  • Make reporter take advantage of the way the new finds work, so it no longer has to re-search everything
  • As stated before, better error for modules not found.

Warning

These are the files that the most changes were introduced: webpack.tsx, patchWebpack.ts, lazy.ts, lazyReact.tsx, proxyInner.ts, generateReport.ts and the commons in webpack
The rest is mainly just changing to use the new methods instead of the deprecated ones

Important

This change is fully backwards compatible for now, as the old methods were kept and just point to the new APIs now.
The plan is to remove them in the future.

@Nuckyz
Copy link
Collaborator Author

Nuckyz commented May 3, 2024

Documented the changes

@Nuckyz
Copy link
Collaborator Author

Nuckyz commented May 21, 2024

@CodiumAI-Agent /review

@Nuckyz
Copy link
Collaborator Author

Nuckyz commented May 21, 2024

@CodiumAI-Agent /improve

@CodiumAI-Agent
Copy link

PR Code Suggestions ✨

CategorySuggestion                                                                                                                                    Score
Best practice
Replace string literal exceptions with descriptive error messages or custom error types

Replace the string literal thrown in the exception with a more meaningful error message or
a custom error type. Throwing string literals can make error handling and debugging more
difficult.

scripts/generateReport.ts [512]

-throw "a rock at ben shapiro";
+throw new Error("Descriptive error message or custom error type");
 
Suggestion importance[1-10]: 10

Why: Throwing string literals is a bad practice as it makes error handling and debugging more difficult. Using a descriptive error message or custom error type improves code maintainability and clarity.

10
Replace non-null assertions with specific types or handle potential null values explicitly

Avoid using non-null assertions (as any) as they bypass TypeScript's type checking. If the
type is uncertain, consider using a more specific type or handling the undefined/null case
explicitly.

scripts/generateReport.ts [481]

-let result = null as any;
+let result: SpecificType | null = null;
 
Suggestion importance[1-10]: 8

Why: Avoiding non-null assertions improves type safety and helps prevent runtime errors. Using a specific type or handling null values explicitly makes the code more robust and maintainable.

8
Rename BlobMask to BlobMaskComponent to follow React naming conventions

The BlobMask variable is imported using findExportedComponent which suggests that it is a
React component. It is recommended to follow the React component naming convention by
capitalizing the first letter of the component name.

src/plugins/betterSessions/index.tsx [37]

-const BlobMask = findExportedComponent("BlobMask");
+const BlobMaskComponent = findExportedComponent("BlobMask");
 
Suggestion importance[1-10]: 8

Why: Following naming conventions is important for code readability and maintainability, especially in a collaborative environment. This suggestion aligns with best practices for React components.

8
Improve type safety and readability by using a more specific type for lastGuildId

Consider using a more specific type for lastGuildId instead of string | null. If
lastGuildId is expected to hold only certain types of strings (e.g., UUIDs, specific
identifiers), using a more specific type or a type alias could improve type safety and
code readability.

src/plugins/betterFolders/index.tsx [38]

-let lastGuildId = null as string | null;
+type GuildId = string; // Define this type according to your specific use case
+let lastGuildId: GuildId | null = null;
 
Suggestion importance[1-10]: 7

Why: The suggestion improves type safety and readability, which is beneficial for maintainability. However, it is not critical to the functionality of the code.

7
Improve the function name cacheFindAll to findAllWithCache for better clarity

Replace the cacheFindAll function with a more descriptive name that indicates its purpose
and functionality, especially if it involves caching mechanisms.

src/plugins/consoleShortcuts/index.ts [45]

-const matches = cacheFindAll(filterFactory(...filterProps));
+const matches = findAllWithCache(filterFactory(...filterProps));
 
Suggestion importance[1-10]: 6

Why: The suggestion enhances code clarity by providing a more descriptive function name, which helps in understanding the code better. However, it is a minor improvement and does not affect the functionality.

6
Rename setDecorationGridItem to setDecorationGridItemComponent to clarify its purpose

It is recommended to use a more descriptive name for the setDecorationGridItem function to
clarify that it is a setter function. This enhances code readability and maintainability.

src/plugins/decor/ui/components/index.ts [20]

-export const setDecorationGridItem = v => DecorationGridItem = v;
+export const setDecorationGridItemComponent = v => DecorationGridItem = v;
 
Suggestion importance[1-10]: 6

Why: The suggestion improves code readability by making the function's purpose clearer. This is a minor enhancement that aids in maintainability but does not impact the core functionality.

6
Performance
Replace eager loading methods with lazy loading equivalents to enhance performance

Replace the direct imports and usage of findByProps and findStore with their lazy
counterparts to avoid potential performance issues due to eager loading. This is
especially important in a plugin system where minimizing the initial load time can
significantly affect the overall performance.

src/plugins/implicitRelationships/index.ts [22-27]

-import { findByProps, findStore } from "@webpack";
-const UserAffinitiesStore = findStore("UserAffinitiesStore");
-const { FriendsSections } = findByProps("FriendsSections");
+import { findByPropsLazy, findStoreLazy } from "@webpack";
+const UserAffinitiesStore = findStoreLazy("UserAffinitiesStore");
+const { FriendsSections } = findByPropsLazy("FriendsSections");
 
Suggestion importance[1-10]: 9

Why: The suggestion correctly identifies a potential performance issue with eager loading and proposes a valid solution by using lazy loading methods. This change can significantly improve the initial load time of the plugin, which is crucial in a plugin system.

9
Use a lazy loading approach for findByProps to improve module loading efficiency

Replace the direct use of findByProps with a lazy or asynchronous variant to ensure that
the module is loaded only when necessary, which can help in reducing the initial load time
and potentially avoid runtime errors due to the module not being ready.

src/plugins/decor/ui/index.ts [11]

-export const DecorationModalStyles = findByProps("modalFooterShopButton");
+export const DecorationModalStyles = findByPropsLazy("modalFooterShopButton");
 
Suggestion importance[1-10]: 7

Why: The suggestion to use lazy loading can improve performance by reducing initial load time. However, the current use of findByProps may be intentional for immediate availability, so the impact might be minor.

7
Possible bug
Correct potential typo in the findComponentByCode function argument

Ensure that the string argument for findComponentByCode does not contain a trailing comma
unless it is intentional to match specific criteria. This could be a typo that might lead
to unexpected behavior or errors.

src/plugins/decor/ui/modals/CreateDecorationModal.tsx [20]

-const FileUpload = findComponentByCode("fileUploadInput,");
+const FileUpload = findComponentByCode("fileUploadInput");
 
Suggestion importance[1-10]: 9

Why: This suggestion addresses a potential typo that could lead to unexpected behavior or errors, making it a crucial fix for code correctness.

9
Possible issue
Add error handling for cacheFind to ensure stability

Consider handling the case where cacheFind returns null or an unexpected result to prevent
runtime errors. Implement error checking or default value assignment.

src/plugins/devCompanion.dev/index.tsx [207]

-results = cacheFind(filters.byProps(...parsedArgs));
+results = cacheFind(filters.byProps(...parsedArgs)) || [];
 
Suggestion importance[1-10]: 8

Why: Adding error handling for cacheFind enhances code stability by preventing runtime errors due to null or unexpected results, which is important for robust code.

8
Maintainability
Refactor nested if-else conditions into separate functions or a switch-case structure for better readability

Refactor the nested if-else conditions into separate functions or use a switch-case
structure to improve readability and maintainability.

scripts/generateReport.ts [483-509]

-if (searchType === "webpackDependantLazy" || searchType === "webpackDependantLazyComponent") {
-    const [factory] = args;
-    result = factory();
-} else if (searchType === "extractAndLoadChunks") {
-    const [code, matcher] = args;
-    const module = Vencord.Webpack.findModuleFactory(...code);
-    if (module) {
-        result = module.toString().match(Vencord.Util.canonicalizeMatch(matcher));
-    }
-} else {
-    const findResult = args.shift();
-    if (findResult != null) {
-        if (findResult.$$vencordCallbackCalled != null && findResult.$$vencordCallbackCalled()) {
-            result = findResult;
+switch (searchType) {
+    case "webpackDependantLazy":
+    case "webpackDependantLazyComponent":
+        const [factory] = args;
+        result = factory();
+        break;
+    case "extractAndLoadChunks":
+        const [code, matcher] = args;
+        const module = Vencord.Webpack.findModuleFactory(...code);
+        if (module) {
+            result = module.toString().match(Vencord.Util.canonicalizeMatch(matcher));
         }
-        if (findResult[Vencord.Util.proxyInnerGet] != null) {
-            result = findResult[Vencord.Util.proxyInnerValue];
+        break;
+    default:
+        const findResult = args.shift();
+        if (findResult != null) {
+            if (findResult.$$vencordCallbackCalled != null && findResult.$$vencordCallbackCalled()) {
+                result = findResult;
+            }
+            if (findResult[Vencord.Util.proxyInnerGet] != null) {
+                result = findResult[Vencord.Util.proxyInnerValue];
+            }
+            if (findResult.$$vencordInner != null) {
+                result = findResult.$$vencordInner();
+            }
         }
-        if (findResult.$$vencordInner != null) {
-            result = findResult.$$vencordInner();
-        }
-    }
+        break;
 }
 
Suggestion importance[1-10]: 7

Why: Refactoring nested if-else conditions into a switch-case structure improves readability and maintainability. It makes the code easier to understand and reduces the risk of errors.

7
Add fallback for findByProps to handle potential undefined properties safely

Replace the direct use of findByProps with a more specific method if available, or ensure
that the properties being accessed are correctly encapsulated within the method to prevent
accessing potentially undefined properties.

src/plugins/fakeNitro/index.tsx [40]

-const ProtoUtils = findByProps("BINARY_READ_OPTIONS");
+const ProtoUtils = findByProps("BINARY_READ_OPTIONS") || {};
 
Suggestion importance[1-10]: 7

Why: The suggestion improves maintainability by ensuring that the code handles potential undefined properties safely, though the current implementation might already be sufficient in many cases.

7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants