From 13b4ae55c5179a706108ad777d0f9a3301f6f43a Mon Sep 17 00:00:00 2001 From: colin273 Date: Fri, 5 Jul 2024 20:31:15 -0400 Subject: [PATCH] Fix loading - inlined modules my behated --- src/renderer/index.ts | 5 +- src/renderer/managers/coremods.ts | 29 +++---- src/renderer/managers/ignition.ts | 27 +++---- src/renderer/modules/i18n.ts | 6 +- src/renderer/modules/webpack/patch-load.ts | 93 +++++++--------------- src/types/webpack.ts | 2 +- 6 files changed, 56 insertions(+), 106 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index ccce42626..809cee494 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -8,8 +8,7 @@ type DiscordSplashWindow = Window & { // Splash screen if ((window as DiscordSplashWindow).DiscordSplash) { - await replugged.ignition.startSplash(); + void replugged.ignition.startSplash(); } else { - await replugged.plugins.loadAll(); - await replugged.ignition.ignite(); + void replugged.ignition.ignite(); } diff --git a/src/renderer/managers/coremods.ts b/src/renderer/managers/coremods.ts index 6bd1c2cf7..e975c24ab 100644 --- a/src/renderer/managers/coremods.ts +++ b/src/renderer/managers/coremods.ts @@ -77,20 +77,17 @@ export async function stopAll(): Promise { await Promise.allSettled(Object.values(coremods).map((c) => c.stop?.())); } -export function runPlaintextPatches(): Promise { - return new Promise((res) => { - [ - experimentsPlaintext, - notrackPlaintext, - noDevtoolsWarningPlaintext, - messagePopover, - notices, - contextMenu, - languagePlaintext, - commandsPlaintext, - settingsPlaintext, - badgesPlaintext, - ].forEach(patchPlaintext); - res(); - }); +export function runPlaintextPatches(): void { + [ + experimentsPlaintext, + notrackPlaintext, + noDevtoolsWarningPlaintext, + messagePopover, + notices, + contextMenu, + languagePlaintext, + commandsPlaintext, + settingsPlaintext, + badgesPlaintext, + ].forEach(patchPlaintext); } diff --git a/src/renderer/managers/ignition.ts b/src/renderer/managers/ignition.ts index 1847fb348..cb6721cb7 100644 --- a/src/renderer/managers/ignition.ts +++ b/src/renderer/managers/ignition.ts @@ -1,22 +1,20 @@ -import { signalStart, waitForReady } from "../modules/webpack/patch-load"; import { error, log } from "../modules/logger"; - import { ready as commonReady } from "@common"; import { ready as componentsReady } from "../modules/components"; -import * as i18n from "../modules/i18n"; import * as coremods from "./coremods"; import * as plugins from "./plugins"; import * as themes from "./themes"; import * as quickCSS from "./quick-css"; import { loadStyleSheet } from "../util"; import { startAutoUpdateChecking } from "./updater"; +import { interceptChunksGlobal } from "../modules/webpack/patch-load"; export async function start(): Promise { log("Ignition", "Start", void 0, "Igniting Replugged..."); const startTime = performance.now(); loadStyleSheet("replugged://renderer.css"); - i18n.load(); + await import("../modules/i18n").then((i18n) => i18n.load()); let started = false; await Promise.race([ @@ -83,26 +81,23 @@ Load order: export async function ignite(): Promise { // This is the function that will be called when loading the window. - // Plaintext patches are executed before Discord's preload. - await coremods.runPlaintextPatches(); + // Plaintext patches must run first. + interceptChunksGlobal(); + coremods.runPlaintextPatches(); await plugins.loadAll(); await plugins.runPlaintextPatches(); - // These next things will happen after Discord's preload is called. - // We schedule them here, but they cannot block the ignite function from returning. - (async () => { - await waitForReady; - signalStart(); - await commonReady(); - await componentsReady(); - await start(); - })(); + // At this point, Discord's code should run. + // Wait for the designated common modules to load before continuing. + await Promise.all([commonReady(), componentsReady()]); + await start(); } export async function startSplash(): Promise { log("Ignition", "Start", void 0, "Igniting Replugged Splash Screen..."); const startTime = performance.now(); - await themes.loadMissing().then(themes.loadAllSplash); + await themes.loadMissing(); + themes.loadAllSplash(); log( "Ignition", diff --git a/src/renderer/modules/i18n.ts b/src/renderer/modules/i18n.ts index 9e0656a74..88297050b 100644 --- a/src/renderer/modules/i18n.ts +++ b/src/renderer/modules/i18n.ts @@ -1,13 +1,11 @@ import { i18n } from "@common"; import type { RepluggedTranslations } from "../../types"; -const strings = await RepluggedNative.i18n.getStrings(); - export let locale: string | undefined; export const messages = new Map(); -export function load(): void { - loadAllStrings(strings); +export async function load(): Promise { + loadAllStrings(await RepluggedNative.i18n.getStrings()); locale = i18n._chosenLocale; diff --git a/src/renderer/modules/webpack/patch-load.ts b/src/renderer/modules/webpack/patch-load.ts index fda81026e..e2d0faecf 100644 --- a/src/renderer/modules/webpack/patch-load.ts +++ b/src/renderer/modules/webpack/patch-load.ts @@ -17,33 +17,6 @@ import { patchModuleSource } from "./plaintext-patch"; export let wpRequire: WebpackRequire | undefined; export let webpackChunks: WebpackRawModules | undefined; -let signalReady: () => void; -let ready = false; - -/** - * @internal - * @hidden - */ -export const waitForReady = new Promise( - (resolve) => - (signalReady = () => { - ready = true; - resolve(); - }), -); - -/** - * @internal - * @hidden - */ -export let signalStart: () => void; - -/** - * @internal - * @hidden - */ -export const waitForStart = new Promise((resolve) => (signalStart = resolve)); - const patchedModules = new Set(); /** @@ -53,8 +26,7 @@ const patchedModules = new Set(); */ export const sourceStrings: Record = {}; -async function patchChunk(chunk: WebpackChunk): Promise { - await waitForStart; +function patchChunk(chunk: WebpackChunk): void { const modules = chunk[1]; for (const id in modules) { if (patchedModules.has(id)) continue; @@ -85,8 +57,8 @@ async function patchChunk(chunk: WebpackChunk): Promise { function patchPush(webpackChunk: WebpackChunkGlobal): void { let original = webpackChunk.push; - async function handlePush(chunk: WebpackChunk): Promise { - await patchChunk(chunk); + function handlePush(chunk: WebpackChunk): unknown { + patchChunk(chunk); return original.call(webpackChunk, chunk); } @@ -114,6 +86,9 @@ function loadWebpackModules(chunksGlobal: WebpackChunkGlobal): void { if (wpRequire.c && !webpackChunks) webpackChunks = wpRequire.c; if (r) { + // The first batch of modules are added inline via r.m rather than being pushed + patchChunk([[], r.m]); + r.d = (module: unknown, exports: Record unknown>) => { for (const prop in exports) { if ( @@ -136,46 +111,32 @@ function loadWebpackModules(chunksGlobal: WebpackChunkGlobal): void { // Patch previously loaded chunks if (Array.isArray(chunksGlobal)) { for (const loadedChunk of chunksGlobal) { - void patchChunk(loadedChunk); + patchChunk(loadedChunk); } } patchPush(chunksGlobal); - signalReady(); - - // There is some kind of race condition where chunks are not patched ever, so this should make sure everything gets patched - // This is a temporary workaround that should be removed once we figure out the real cause - setInterval(() => { - if (Array.isArray(chunksGlobal)) { - for (const loadedChunk of chunksGlobal) { - void patchChunk(loadedChunk); - } - } - }, 1000); } // Intercept the webpack chunk global as soon as Discord creates it - -// Because using a timer is bad, thanks Ven -// https://github.com/Vendicated/Vencord/blob/ef353f1d66dbf1d14e528830d267aac518ed1beb/src/webpack/patchWebpack.ts -let webpackChunk: WebpackChunkGlobal | undefined; - -if (window.webpackChunkdiscord_app) { - webpackChunk = window.webpackChunkdiscord_app; - loadWebpackModules(webpackChunk!); -} else { - Object.defineProperty(window, "webpackChunkdiscord_app", { - get: () => webpackChunk, - set: (v) => { - // Only modify if the global has actually changed - // We don't need to check if push is the special webpack push, - // because webpack will go over the previously loaded modules - // when it sets the custom push method. - if (v !== webpackChunk && !ready) { - loadWebpackModules(v); - } - webpackChunk = v; - }, - configurable: true, - }); +export function interceptChunksGlobal(): void { + if (window.webpackChunkdiscord_app) { + loadWebpackModules(window.webpackChunkdiscord_app); + } else { + let webpackChunk: WebpackChunkGlobal | undefined; + Object.defineProperty(window, "webpackChunkdiscord_app", { + get: () => webpackChunk, + set: (v) => { + // Only modify if the global has actually changed + // We don't need to check if push is the special webpack push, + // because webpack will go over the previously loaded modules + // when it sets the custom push method. + if (v !== webpackChunk) { + loadWebpackModules(v); + } + webpackChunk = v; + }, + configurable: true, + }); + } } diff --git a/src/types/webpack.ts b/src/types/webpack.ts index 16974fbed..ee50e8d0e 100644 --- a/src/types/webpack.ts +++ b/src/types/webpack.ts @@ -20,7 +20,7 @@ export type WebpackRawModules = Record; export type WebpackRequire = ((e: number) => unknown) & { c?: WebpackRawModules; d: (module: unknown, exports: Record unknown>) => void; - m: WebpackChunk; + m: WebpackChunk[1]; }; export type WebpackModule = (