From 8de1ca86a941dfb55067a665dcbe888ad72dc474 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 29 May 2024 23:42:14 -0300 Subject: [PATCH 1/4] I only understood today the reason for the Object.assign --- src/plugins/moreUserTags/index.tsx | 17 +++++----- src/utils/lazy.ts | 1 + src/utils/lazyReact.tsx | 8 +---- src/utils/proxyInner.ts | 1 + src/webpack/webpack.tsx | 52 ++++++++---------------------- 5 files changed, 25 insertions(+), 54 deletions(-) diff --git a/src/plugins/moreUserTags/index.tsx b/src/plugins/moreUserTags/index.tsx index 869319097..6e1493d05 100644 --- a/src/plugins/moreUserTags/index.tsx +++ b/src/plugins/moreUserTags/index.tsx @@ -56,8 +56,7 @@ const PermissionUtil = findByProps("computePermissions", "canEveryoneRole") as { computePermissions({ ...args }): bigint; }; -const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP,") as React.ComponentType<{ type?: number, className?: string, useRemSizes?: boolean; }>; -const { BotTagTypes } = findByProps("BotTagTypes"); +const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP,") as React.ComponentType<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record; }; const isWebhook = (message: Message, user: User) => !!message?.webhookId && user.isNonUserBot(); @@ -123,7 +122,7 @@ function SettingsComponent(props: { setValue(v: any): void; }) { onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} > - {t.displayName} Tag + {t.displayName} Tag )} @@ -303,7 +302,7 @@ export default definePlugin({ return obj; }, - isOPTag: (tag: number) => tag === BotTagTypes.ORIGINAL_POSTER || tags.some(t => tag === BotTagTypes[`${t.name}-OP`]), + isOPTag: (tag: number) => tag === Tag.Types.ORIGINAL_POSTER || tags.some(t => tag === Tag.Types[`${t.name}-OP`]), getTagText(passedTagName: string, strings: Record) { if (!passedTagName) return strings.APP_TAG; @@ -336,9 +335,9 @@ export default definePlugin({ if (!user) return null; if (location === "chat" && user.id === "1") - return BotTagTypes.OFFICIAL; + return Tag.Types.OFFICIAL; if (user.isClyde()) - return BotTagTypes.AI; + return Tag.Types.AI; let type = typeof origType === "number" ? origType : null; @@ -366,11 +365,11 @@ export default definePlugin({ (tag.condition?.(message!, user, channel)) ) { if (channel.isForumPost() && channel.ownerId === user.id) - type = BotTagTypes[`${tag.name}-OP`]; + type = Tag.Types[`${tag.name}-OP`]; else if (user.bot && !isWebhook(message!, user) && !settings.dontShowBotTag) - type = BotTagTypes[`${tag.name}-BOT`]; + type = Tag.Types[`${tag.name}-BOT`]; else - type = BotTagTypes[tag.name]; + type = Tag.Types[tag.name]; break; } } diff --git a/src/utils/lazy.ts b/src/utils/lazy.ts index 842c64d18..14349379f 100644 --- a/src/utils/lazy.ts +++ b/src/utils/lazy.ts @@ -71,6 +71,7 @@ const handler: ProxyHandler = { /** * Wraps the result of factory in a Proxy you can consume as if it wasn't lazy. * On first property access, the factory is evaluated. + * * @param factory Factory returning the result * @param attempts How many times to try to evaluate the factory before giving up * @returns Result of factory function diff --git a/src/utils/lazyReact.tsx b/src/utils/lazyReact.tsx index 74c7832d2..3a8a9ebc0 100644 --- a/src/utils/lazyReact.tsx +++ b/src/utils/lazyReact.tsx @@ -9,13 +9,6 @@ import { makeLazy } from "./lazy"; /** * A lazy component. The factory method is called on first render. * - * IMPORTANT: You cannot access properties set on the lazy component using this method. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = LazyComponent(...); - * console.log(Component.Types); // This will not work - * ```` * @param factory Function returning a component * @param attempts How many times to try to get the component before giving up * @returns Result of factory function @@ -31,6 +24,7 @@ export function LazyComponent(factory: () => React.Compo const ResultComponent = get(); if (ResultComponent != null) { InnerComponent = ResultComponent; + Object.assign(LazyComponent, ResultComponent); } } diff --git a/src/utils/proxyInner.ts b/src/utils/proxyInner.ts index ff68c724f..e52bc970d 100644 --- a/src/utils/proxyInner.ts +++ b/src/utils/proxyInner.ts @@ -46,6 +46,7 @@ const handler: ProxyHandler = { /** * A proxy which has an inner value that can be set later. * When a property is accessed, the proxy looks for the property value in its inner value, and errors if it's not set. + * * @param err The error message to throw when the inner value is not set * @param primitiveErr The error message to throw when the inner value is a primitive * @returns A proxy which will act like the inner value when accessed diff --git a/src/webpack/webpack.tsx b/src/webpack/webpack.tsx index 60eb24300..ca5c7a0eb 100644 --- a/src/webpack/webpack.tsx +++ b/src/webpack/webpack.tsx @@ -122,6 +122,7 @@ function printFilter(filter: FilterFn) { * then call the callback with the module as the first argument. * * If the module is already required, the callback will be called immediately. + * * @param filter A function that takes a module and returns a boolean * @param callback A function that takes the found module as its first argument */ @@ -165,6 +166,7 @@ export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect * The callback must return a value that will be used as the proxy inner value. * * If no callback is specified, the default callback will assign the proxy inner value to all the module. + * * @param filter A function that takes a module and returns a boolean * @param callback A function that takes the found module as its first argument and returns something to use as the proxy inner value. Useful if you want to use a value from the module, instead of all of it. Defaults to the module itself * @returns A proxy that has the callback return value as its true value, or the callback return value if the callback was called when the function was called @@ -190,13 +192,6 @@ export function find(filter: FilterFn, callback: (mod: any) => an /** * Find the first component that matches the filter. * - * IMPORTANT: You cannot access properties set on the found component using this method. You should instead try to obtain the property using a non component find instead. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = findComponent(...); - * console.log(Component.Types); // This will not work - * ```` * @param filter A function that takes a module and returns a boolean * @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 @@ -222,7 +217,7 @@ export function findComponent(filter: FilterFn, parse: ( waitFor(filter, (v: any) => { const parsedComponent = parse(v); InnerComponent = parsedComponent; - Object.assign(InnerComponent, parsedComponent); + Object.assign(WrapperComponent, parsedComponent); }, { isIndirect: true }); if (IS_DEV) { @@ -241,13 +236,6 @@ export function findComponent(filter: FilterFn, parse: ( /** * Find the first component that is exported by the first prop name. * - * IMPORTANT: You cannot access properties set on the found component using this method. You should instead try to obtain the property using a non component find instead. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = findExportedComponent(...); - * console.log(Component.Types); // This will not work - * ```` * @example findExportedComponent("FriendRow") * @example findExportedComponent("FriendRow", "Friend", FriendRow => React.memo(FriendRow)) * @@ -277,7 +265,7 @@ export function findExportedComponent(...props: string[] waitFor(filter, (v: any) => { const parsedComponent = parse(v[newProps[0]]); InnerComponent = parsedComponent; - Object.assign(InnerComponent, parsedComponent); + Object.assign(WrapperComponent, parsedComponent); }, { isIndirect: true }); if (IS_DEV) { @@ -293,13 +281,6 @@ export function findExportedComponent(...props: string[] /** * Find the first component in a default export that includes all the given code. * - * IMPORTANT: You cannot access properties set on the found component using this method. You should instead try to obtain the property using a non component find instead. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = findComponentByCode(...); - * console.log(Component.Types); // This will not work - * ```` * @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR") * @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)", ColorPicker => React.memo(ColorPicker)) * @@ -367,6 +348,7 @@ export function findStore(name: string) { /** * Find the first already required module that matches the filter. + * * @param filter A function that takes a module and returns a boolean * @returns The found module or null */ @@ -414,6 +396,7 @@ export function cacheFindAll(filter: FilterFn) { /** * Same as {@link cacheFind} but in bulk. + * * @param filterFns Array of filters. Please note that this array will be modified in place, so if you still * need it afterwards, pass a copy. * @returns Array of results in the same order as the passed filters @@ -520,6 +503,7 @@ export function findModuleFactory(...code: string[]) { * * Wraps the result of factory in a Proxy you can consume as if it wasn't lazy. * On first property access, the factory is evaluated. + * * @param factory Factory returning the result * @param attempts How many times to try to evaluate the factory before giving up * @returns Result of factory function @@ -535,13 +519,6 @@ export function webpackDependantLazy(factory: () => T, attempts?: * * A lazy component. The factory method is called on first render. * - * IMPORTANT: You cannot access properties set on the lazy component using this method. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = webpackDependantLazyComponent(...); - * console.log(Component.Types); // This will not work - * ```` * @param factory Function returning a Component * @param attempts How many times to try to get the component before giving up * @returns Result of factory function @@ -566,6 +543,7 @@ function deprecatedRedirect any>(oldMethod: string * * Wraps the result of factory in a Proxy you can consume as if it wasn't lazy. * On first property access, the factory is evaluated. + * * @param factory Factory returning the result * @param attempts How many times to try to evaluate the factory before giving up * @returns Result of factory function @@ -579,13 +557,6 @@ export const proxyLazyWebpack = deprecatedRedirect("proxyLazyWebpack", "webpackD * * A lazy component. The factory method is called on first render. * - * IMPORTANT: You cannot access properties set on the lazy component using this method. - * - * Example of how you cannot access the properties set on the component: - * ``` - * const Component = LazyComponentWebpack(...); - * console.log(Component.Types); // This will not work - * ```` * @param factory Function returning a Component * @param attempts How many times to try to get the component before giving up * @returns Result of factory function @@ -651,6 +622,7 @@ export const findAll = deprecatedRedirect("findAll", "cacheFindAll", cacheFindAl * @deprecated Use {@link cacheFindBulk} instead * * Same as {@link cacheFind} but in bulk + * * @param filterFns Array of filters. Please note that this array will be modified in place, so if you still * need it afterwards, pass a copy. * @returns Array of results in the same order as the passed filters @@ -662,6 +634,7 @@ export const ChunkIdsRegex = /\("(.+?)"\)/g; /** * Extract and load chunks using their entry point. + * * @param code An array of all the code the module factory containing the lazy chunk loading must include * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory * @returns A promise that resolves when the chunks were loaded @@ -712,6 +685,7 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def * This is just a wrapper around {@link extractAndLoadChunks} to make our reporter test for your webpack finds. * * Extract and load chunks using their entry point. + * * @param code An array of all the code the module factory containing the lazy chunk loading must include * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory * @returns A function that returns a promise that resolves when the chunks were loaded, on first call @@ -724,7 +698,8 @@ export function extractAndLoadChunksLazy(code: string[], matcher = DefaultExtrac /** * Search modules by keyword. This searches the factory methods, - * meaning you can search all sorts of things, displayName, methodName, strings somewhere in the code, etc + * meaning you can search all sorts of things, methodName, strings somewhere in the code, etc. + * * @param filters One or more strings or regexes * @returns Mapping of found modules */ @@ -751,6 +726,7 @@ export function search(...filters: Array) { * to view a massive file. extract then returns the extracted module so you can jump to it. * As mentioned above, note that this extracted module is not actually used, * so putting breakpoints or similar will have no effect. + * * @param id The id of the module to extract */ export function extract(id: string | number) { From 892de53603a1af1bf9f4dbd331868f12fec2edc0 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 30 May 2024 00:51:23 -0300 Subject: [PATCH 2/4] Fix extractAndLoadChunks issue with 2 match groups; Improve testing of lazy extractAndLoadChunks --- scripts/generateReport.ts | 11 +++++------ src/webpack/webpack.ts | 37 ++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index 200aa3f83..d3068492f 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -343,7 +343,7 @@ async function runtime(token: string) { // True if resolved, false otherwise const chunksSearchPromises = [] as Array<() => boolean>; - const LazyChunkRegex = canonicalizeMatch(/(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\)))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g); + const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g); async function searchAndLoadLazyChunks(factoryCode: string) { const lazyChunks = factoryCode.matchAll(LazyChunkRegex); @@ -353,8 +353,7 @@ async function runtime(token: string) { // the chunk containing the component const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT"); - await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIdsArray, rawChunkIdsSingle, entryPoint]) => { - const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle; + await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => { const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Vencord.Webpack.ChunkIdsRegex)).map(m => m[1]) : []; if (chunkIds.length === 0) { @@ -525,14 +524,14 @@ async function runtime(token: string) { } else if (method === "extractAndLoadChunks") { const [code, matcher] = args; - const module = Vencord.Webpack.findModuleFactory(...code); - if (module) result = module.toString().match(canonicalizeMatch(matcher)); + result = await Vencord.Webpack.extractAndLoadChunks(code, matcher); + if (result === false) result = null; } else { // @ts-ignore result = Vencord.Webpack[method](...args); } - if (result == null || ("$$vencordInternal" in result && result.$$vencordInternal() == null)) throw "a rock at ben shapiro"; + if (result == null || (result.$$vencordInternal != null && result.$$vencordInternal() == null)) throw "a rock at ben shapiro"; } catch (e) { let logMessage = searchType; if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") logMessage += `(${args[0].toString().slice(0, 147)}...)`; diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index f2e6e58a8..9e0c0d000 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -402,14 +402,14 @@ export function findExportedComponentLazy(...props: stri }); } -export const DefaultExtractAndLoadChunksRegex = /(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\))|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/; -export const ChunkIdsRegex = /\("(.+?)"\)/g; +export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/; +export const ChunkIdsRegex = /\("([^"]+?)"\)/g; /** * Extract and load chunks using their entry point * @param code An array of all the code the module factory containing the lazy chunk loading must include - * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory - * @returns A promise that resolves when the chunks were loaded + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory + * @returns A promise that resolves with a boolean whether the chunks were loaded */ export async function extractAndLoadChunks(code: string[], matcher: RegExp = DefaultExtractAndLoadChunksRegex) { const module = findModuleFactory(...code); @@ -417,7 +417,11 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def const err = new Error("extractAndLoadChunks: Couldn't find module factory"); logger.warn(err, "Code:", code, "Matcher:", matcher); - return; + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return false; } const match = module.toString().match(canonicalizeMatch(matcher)); @@ -429,10 +433,10 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def if (IS_DEV && !devToolsOpen) throw err; - return; + return false; } - const [, rawChunkIdsArray, rawChunkIdsSingle, entryPointId] = match; + const [, rawChunkIds, entryPointId] = match; if (Number.isNaN(Number(entryPointId))) { const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number"); logger.warn(err, "Code:", code, "Matcher:", matcher); @@ -441,16 +445,27 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def if (IS_DEV && !devToolsOpen) throw err; - return; + return false; } - const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle; if (rawChunkIds) { const chunkIds = Array.from(rawChunkIds.matchAll(ChunkIdsRegex)).map((m: any) => m[1]); await Promise.all(chunkIds.map(id => wreq.e(id))); } + if (wreq.m[entryPointId] == null) { + const err = new Error("extractAndLoadChunks: Entry point is not loaded in the module factories, perhaps one of the chunks failed to load"); + logger.warn(err, "Code:", code, "Matcher:", matcher); + + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return false; + } + wreq(entryPointId); + return true; } /** @@ -458,8 +473,8 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def * * Extract and load chunks using their entry point * @param code An array of all the code the module factory containing the lazy chunk loading must include - * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory - * @returns A function that returns a promise that resolves when the chunks were loaded, on first call + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory + * @returns A function that returns a promise that resolves with a boolean whether the chunks were loaded, on first call */ export function extractAndLoadChunksLazy(code: string[], matcher = DefaultExtractAndLoadChunksRegex) { if (IS_DEV) lazyWebpackSearchHistory.push(["extractAndLoadChunks", [code, matcher]]); From 7816727e268463e9e08ec768ddf93666f7b50e6c Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 30 May 2024 01:02:25 -0300 Subject: [PATCH 3/4] Merge branch 'dev' into immediate-finds --- scripts/generateReport.ts | 16 +++++++--------- src/webpack/webpack.tsx | 33 ++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index 438ac1a24..ef733f874 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -341,7 +341,7 @@ async function runtime(token: string) { // True if resolved, false otherwise const chunksSearchPromises = [] as Array<() => boolean>; - const LazyChunkRegex = canonicalizeMatch(/(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\)))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g); + const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g); async function searchAndLoadLazyChunks(factoryCode: string) { const lazyChunks = factoryCode.matchAll(LazyChunkRegex); @@ -351,8 +351,7 @@ async function runtime(token: string) { // the chunk containing the component const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT"); - await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIdsArray, rawChunkIdsSingle, entryPoint]) => { - const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle; + await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => { const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Vencord.Webpack.ChunkIdsRegex)).map(m => m[1]) : []; if (chunkIds.length === 0) { @@ -503,8 +502,7 @@ async function runtime(token: string) { } } - // eslint-disable-next-line prefer-const - for (let [searchType, args] of Vencord.Webpack.webpackSearchHistory) { + await Promise.all(Vencord.Webpack.webpackSearchHistory.map(async ([searchType, args]) => { args = [...args]; try { @@ -520,9 +518,9 @@ async function runtime(token: string) { case "extractAndLoadChunks": { const [code, matcher] = args; - const module = Vencord.Webpack.findModuleFactory(...code); - if (module) { - result = module.toString().match(Vencord.Util.canonicalizeMatch(matcher)); + result = await Vencord.Webpack.extractAndLoadChunks(code, matcher); + if (result === false) { + result = null; } break; @@ -592,7 +590,7 @@ async function runtime(token: string) { console.log("[PUP_WEBPACK_FIND_FAIL]", logMessage); } - } + })); setTimeout(() => console.log("[PUPPETEER_TEST_DONE_SIGNAL]"), 1000); } catch (e) { diff --git a/src/webpack/webpack.tsx b/src/webpack/webpack.tsx index ca5c7a0eb..adf498997 100644 --- a/src/webpack/webpack.tsx +++ b/src/webpack/webpack.tsx @@ -629,15 +629,15 @@ export const findAll = deprecatedRedirect("findAll", "cacheFindAll", cacheFindAl */ export const findBulk = deprecatedRedirect("findBulk", "cacheFindBulk", cacheFindBulk); -export const DefaultExtractAndLoadChunksRegex = /(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\))|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/; -export const ChunkIdsRegex = /\("(.+?)"\)/g; +export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/; +export const ChunkIdsRegex = /\("([^"]+?)"\)/g; /** * Extract and load chunks using their entry point. * * @param code An array of all the code the module factory containing the lazy chunk loading must include - * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory - * @returns A promise that resolves when the chunks were loaded + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory + * @returns A promise that resolves with a boolean whether the chunks were loaded */ export async function extractAndLoadChunks(code: string[], matcher: RegExp = DefaultExtractAndLoadChunksRegex) { const module = findModuleFactory(...code); @@ -645,7 +645,11 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def const err = new Error("extractAndLoadChunks: Couldn't find module factory"); logger.warn(err, "Code:", code, "Matcher:", matcher); - return; + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return false; } const match = module.toString().match(canonicalizeMatch(matcher)); @@ -657,10 +661,10 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def if (IS_DEV && !devToolsOpen) throw err; - return; + return false; } - const [, rawChunkIdsArray, rawChunkIdsSingle, entryPointId] = match; + const [, rawChunkIds, entryPointId] = match; if (Number.isNaN(Number(entryPointId))) { const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number"); logger.warn(err, "Code:", code, "Matcher:", matcher); @@ -669,16 +673,27 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def if (IS_DEV && !devToolsOpen) throw err; - return; + return false; } - const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle; if (rawChunkIds) { const chunkIds = Array.from(rawChunkIds.matchAll(ChunkIdsRegex)).map((m: any) => m[1]); await Promise.all(chunkIds.map(id => wreq.e(id))); } + if (wreq.m[entryPointId] == null) { + const err = new Error("extractAndLoadChunks: Entry point is not loaded in the module factories, perhaps one of the chunks failed to load"); + logger.warn(err, "Code:", code, "Matcher:", matcher); + + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return false; + } + wreq(entryPointId); + return true; } /** From 99160638df0d6300a8c8683595fbc142f4eb5aaa Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 30 May 2024 01:04:44 -0300 Subject: [PATCH 4/4] sdfgdsfdsds --- src/webpack/webpack.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webpack/webpack.tsx b/src/webpack/webpack.tsx index adf498997..424182271 100644 --- a/src/webpack/webpack.tsx +++ b/src/webpack/webpack.tsx @@ -702,8 +702,8 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def * Extract and load chunks using their entry point. * * @param code An array of all the code the module factory containing the lazy chunk loading must include - * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory - * @returns A function that returns a promise that resolves when the chunks were loaded, on first call + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory + * @returns A function that returns a promise that resolves with a boolean whether the chunks were loaded, on first call */ export function extractAndLoadChunksLazy(code: string[], matcher = DefaultExtractAndLoadChunksRegex) { if (IS_DEV) webpackSearchHistory.push(["extractAndLoadChunks", [code, matcher]]);