Skip to content

Commit

Permalink
Fix loading - inlined modules my behated
Browse files Browse the repository at this point in the history
  • Loading branch information
colin273 committed Jul 6, 2024
1 parent 1173064 commit 13b4ae5
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 106 deletions.
5 changes: 2 additions & 3 deletions src/renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
29 changes: 13 additions & 16 deletions src/renderer/managers/coremods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,17 @@ export async function stopAll(): Promise<void> {
await Promise.allSettled(Object.values(coremods).map((c) => c.stop?.()));
}

export function runPlaintextPatches(): Promise<void> {
return new Promise<void>((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);
}
27 changes: 11 additions & 16 deletions src/renderer/managers/ignition.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
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([
Expand Down Expand Up @@ -83,26 +81,23 @@ Load order:

export async function ignite(): Promise<void> {
// 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<void> {
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",
Expand Down
6 changes: 2 additions & 4 deletions src/renderer/modules/i18n.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
loadAllStrings(await RepluggedNative.i18n.getStrings());

locale = i18n._chosenLocale;

Expand Down
93 changes: 27 additions & 66 deletions src/renderer/modules/webpack/patch-load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(
(resolve) =>
(signalReady = () => {
ready = true;
resolve();
}),
);

/**
* @internal
* @hidden
*/
export let signalStart: () => void;

/**
* @internal
* @hidden
*/
export const waitForStart = new Promise<void>((resolve) => (signalStart = resolve));

const patchedModules = new Set<string>();

/**
Expand All @@ -53,8 +26,7 @@ const patchedModules = new Set<string>();
*/
export const sourceStrings: Record<number, string> = {};

async function patchChunk(chunk: WebpackChunk): Promise<void> {
await waitForStart;
function patchChunk(chunk: WebpackChunk): void {
const modules = chunk[1];
for (const id in modules) {
if (patchedModules.has(id)) continue;
Expand Down Expand Up @@ -85,8 +57,8 @@ async function patchChunk(chunk: WebpackChunk): Promise<void> {
function patchPush(webpackChunk: WebpackChunkGlobal): void {
let original = webpackChunk.push;

async function handlePush(chunk: WebpackChunk): Promise<unknown> {
await patchChunk(chunk);
function handlePush(chunk: WebpackChunk): unknown {
patchChunk(chunk);
return original.call(webpackChunk, chunk);
}

Expand Down Expand Up @@ -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<string, () => unknown>) => {
for (const prop in exports) {
if (
Expand All @@ -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,
});
}
}
2 changes: 1 addition & 1 deletion src/types/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type WebpackRawModules = Record<string | number, RawModule>;
export type WebpackRequire = ((e: number) => unknown) & {
c?: WebpackRawModules;
d: (module: unknown, exports: Record<string, () => unknown>) => void;
m: WebpackChunk;
m: WebpackChunk[1];
};

export type WebpackModule = (
Expand Down

0 comments on commit 13b4ae5

Please sign in to comment.