Add webpack find testing (#2016)
Co-authored-by: V <vendicated@riseup.net> Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
parent
3e8e106be7
commit
534565db25
2
.github/workflows/reportBrokenPlugins.yml
vendored
2
.github/workflows/reportBrokenPlugins.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
||||||
sudo apt-get install -y chromium-browser
|
sudo apt-get install -y chromium-browser
|
||||||
|
|
||||||
- name: Build web
|
- name: Build web
|
||||||
run: pnpm buildWeb --standalone
|
run: pnpm buildWeb --standalone --dev
|
||||||
|
|
||||||
- name: Create Report
|
- name: Create Report
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
|
@ -21,11 +21,11 @@ import esbuild from "esbuild";
|
||||||
import { readdir } from "fs/promises";
|
import { readdir } from "fs/promises";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
import { BUILD_TIMESTAMP, commonOpts, existsAsync, globPlugins, isStandalone, updaterDisabled, VERSION, watch } from "./common.mjs";
|
import { BUILD_TIMESTAMP, commonOpts, existsAsync, globPlugins, isDev, isStandalone, updaterDisabled, VERSION, watch } from "./common.mjs";
|
||||||
|
|
||||||
const defines = {
|
const defines = {
|
||||||
IS_STANDALONE: isStandalone,
|
IS_STANDALONE: isStandalone,
|
||||||
IS_DEV: JSON.stringify(watch),
|
IS_DEV: JSON.stringify(isDev),
|
||||||
IS_UPDATER_DISABLED: updaterDisabled,
|
IS_UPDATER_DISABLED: updaterDisabled,
|
||||||
IS_WEB: false,
|
IS_WEB: false,
|
||||||
IS_EXTENSION: false,
|
IS_EXTENSION: false,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { appendFile, mkdir, readdir, readFile, rm, writeFile } from "fs/promises
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import Zip from "zip-local";
|
import Zip from "zip-local";
|
||||||
|
|
||||||
import { BUILD_TIMESTAMP, commonOpts, globPlugins, VERSION, watch } from "./common.mjs";
|
import { BUILD_TIMESTAMP, commonOpts, globPlugins, isDev, VERSION } from "./common.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {esbuild.BuildOptions}
|
* @type {esbuild.BuildOptions}
|
||||||
|
@ -43,7 +43,7 @@ const commonOptions = {
|
||||||
IS_WEB: "true",
|
IS_WEB: "true",
|
||||||
IS_EXTENSION: "false",
|
IS_EXTENSION: "false",
|
||||||
IS_STANDALONE: "true",
|
IS_STANDALONE: "true",
|
||||||
IS_DEV: JSON.stringify(watch),
|
IS_DEV: JSON.stringify(isDev),
|
||||||
IS_DISCORD_DESKTOP: "false",
|
IS_DISCORD_DESKTOP: "false",
|
||||||
IS_VESKTOP: "false",
|
IS_VESKTOP: "false",
|
||||||
IS_UPDATER_DISABLED: "true",
|
IS_UPDATER_DISABLED: "true",
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const VERSION = PackageJSON.version;
|
||||||
// https://reproducible-builds.org/docs/source-date-epoch/
|
// https://reproducible-builds.org/docs/source-date-epoch/
|
||||||
export const BUILD_TIMESTAMP = Number(process.env.SOURCE_DATE_EPOCH) || Date.now();
|
export const BUILD_TIMESTAMP = Number(process.env.SOURCE_DATE_EPOCH) || Date.now();
|
||||||
export const watch = process.argv.includes("--watch");
|
export const watch = process.argv.includes("--watch");
|
||||||
|
export const isDev = watch || process.argv.includes("--dev");
|
||||||
export const isStandalone = JSON.stringify(process.argv.includes("--standalone"));
|
export const isStandalone = JSON.stringify(process.argv.includes("--standalone"));
|
||||||
export const updaterDisabled = JSON.stringify(process.argv.includes("--disable-updater"));
|
export const updaterDisabled = JSON.stringify(process.argv.includes("--disable-updater"));
|
||||||
export const gitHash = process.env.VENCORD_HASH || execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
|
export const gitHash = process.env.VENCORD_HASH || execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
|
||||||
|
|
|
@ -34,7 +34,7 @@ for (const variable of ["DISCORD_TOKEN", "CHROMIUM_BIN"]) {
|
||||||
const CANARY = process.env.USE_CANARY === "true";
|
const CANARY = process.env.USE_CANARY === "true";
|
||||||
|
|
||||||
const browser = await pup.launch({
|
const browser = await pup.launch({
|
||||||
headless: true,
|
headless: "new",
|
||||||
executablePath: process.env.CHROMIUM_BIN
|
executablePath: process.env.CHROMIUM_BIN
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -58,14 +58,16 @@ const report = {
|
||||||
plugin: string;
|
plugin: string;
|
||||||
error: string;
|
error: string;
|
||||||
}[],
|
}[],
|
||||||
otherErrors: [] as string[]
|
otherErrors: [] as string[],
|
||||||
|
badWebpackFinds: [] as string[]
|
||||||
};
|
};
|
||||||
|
|
||||||
const IGNORED_DISCORD_ERRORS = [
|
const IGNORED_DISCORD_ERRORS = [
|
||||||
"KeybindStore: Looking for callback action",
|
"KeybindStore: Looking for callback action",
|
||||||
"Unable to process domain list delta: Client revision number is null",
|
"Unable to process domain list delta: Client revision number is null",
|
||||||
"Downloading the full bad domains file",
|
"Downloading the full bad domains file",
|
||||||
/\[GatewaySocket\].{0,110}Cannot access '/
|
/\[GatewaySocket\].{0,110}Cannot access '/,
|
||||||
|
"search for 'name' in undefined"
|
||||||
] as Array<string | RegExp>;
|
] as Array<string | RegExp>;
|
||||||
|
|
||||||
function toCodeBlock(s: string) {
|
function toCodeBlock(s: string) {
|
||||||
|
@ -74,7 +76,10 @@ function toCodeBlock(s: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function printReport() {
|
async function printReport() {
|
||||||
|
console.log();
|
||||||
|
|
||||||
console.log("# Vencord Report" + (CANARY ? " (Canary)" : ""));
|
console.log("# Vencord Report" + (CANARY ? " (Canary)" : ""));
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
||||||
console.log("## Bad Patches");
|
console.log("## Bad Patches");
|
||||||
|
@ -87,12 +92,19 @@ async function printReport() {
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
||||||
|
console.log("## Bad Webpack Finds");
|
||||||
|
report.badWebpackFinds.forEach(p => console.log("- " + p));
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
console.log("## Bad Starts");
|
console.log("## Bad Starts");
|
||||||
report.badStarts.forEach(p => {
|
report.badStarts.forEach(p => {
|
||||||
console.log(`- ${p.plugin}`);
|
console.log(`- ${p.plugin}`);
|
||||||
console.log(` - Error: ${toCodeBlock(p.error)}`);
|
console.log(` - Error: ${toCodeBlock(p.error)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
report.otherErrors = report.otherErrors.filter(e => !IGNORED_DISCORD_ERRORS.some(regex => e.match(regex)));
|
report.otherErrors = report.otherErrors.filter(e => !IGNORED_DISCORD_ERRORS.some(regex => e.match(regex)));
|
||||||
|
|
||||||
console.log("## Discord Errors");
|
console.log("## Discord Errors");
|
||||||
|
@ -100,8 +112,9 @@ async function printReport() {
|
||||||
console.log(`- ${toCodeBlock(e)}`);
|
console.log(`- ${toCodeBlock(e)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
if (process.env.DISCORD_WEBHOOK) {
|
if (process.env.DISCORD_WEBHOOK) {
|
||||||
// this code was written almost entirely by Copilot xD
|
|
||||||
await fetch(process.env.DISCORD_WEBHOOK, {
|
await fetch(process.env.DISCORD_WEBHOOK, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -110,7 +123,7 @@ async function printReport() {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
description: "Here's the latest Vencord Report!",
|
description: "Here's the latest Vencord Report!",
|
||||||
username: "Vencord Reporter" + (CANARY ? " (Canary)" : ""),
|
username: "Vencord Reporter" + (CANARY ? " (Canary)" : ""),
|
||||||
avatar_url: "https://cdn.discordapp.com/icons/1015060230222131221/f0204a918c6c9c9a43195997e97d8adf.webp",
|
avatar_url: "https://cdn.discordapp.com/icons/1015060230222131221/6101cff21e241cebb60c4a01563d0c01.webp?size=512",
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
title: "Bad Patches",
|
title: "Bad Patches",
|
||||||
|
@ -125,6 +138,11 @@ async function printReport() {
|
||||||
}).join("\n\n") || "None",
|
}).join("\n\n") || "None",
|
||||||
color: report.badPatches.length ? 0xff0000 : 0x00ff00
|
color: report.badPatches.length ? 0xff0000 : 0x00ff00
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Bad Webpack Finds",
|
||||||
|
description: report.badWebpackFinds.map(toCodeBlock).join("\n") || "None",
|
||||||
|
color: report.badWebpackFinds.length ? 0xff0000 : 0x00ff00
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Bad Starts",
|
title: "Bad Starts",
|
||||||
description: report.badStarts.map(p => {
|
description: report.badStarts.map(p => {
|
||||||
|
@ -153,29 +171,35 @@ async function printReport() {
|
||||||
|
|
||||||
page.on("console", async e => {
|
page.on("console", async e => {
|
||||||
const level = e.type();
|
const level = e.type();
|
||||||
const args = e.args();
|
const rawArgs = e.args();
|
||||||
|
|
||||||
const firstArg = (await args[0]?.jsonValue());
|
const firstArg = await rawArgs[0]?.jsonValue();
|
||||||
if (firstArg === "PUPPETEER_TEST_DONE_SIGNAL") {
|
if (firstArg === "[PUPPETEER_TEST_DONE_SIGNAL]") {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
await printReport();
|
await printReport();
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const isVencord = (await args[0]?.jsonValue()) === "[Vencord]";
|
const isVencord = firstArg === "[Vencord]";
|
||||||
const isDebug = (await args[0]?.jsonValue()) === "[PUP_DEBUG]";
|
const isDebug = firstArg === "[PUP_DEBUG]";
|
||||||
|
const isWebpackFindFail = firstArg === "[PUP_WEBPACK_FIND_FAIL]";
|
||||||
|
|
||||||
|
if (isWebpackFindFail) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
report.badWebpackFinds.push(await rawArgs[1].jsonValue() as string);
|
||||||
|
}
|
||||||
|
|
||||||
if (isVencord) {
|
if (isVencord) {
|
||||||
// make ci fail
|
const args = await Promise.all(e.args().map(a => a.jsonValue()));
|
||||||
process.exitCode = 1;
|
|
||||||
|
|
||||||
const jsonArgs = await Promise.all(args.map(a => a.jsonValue()));
|
const [, tag, message] = args as Array<string>;
|
||||||
const [, tag, message] = jsonArgs;
|
const cause = await maybeGetError(e.args()[3]);
|
||||||
const cause = await maybeGetError(args[3]);
|
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "WebpackInterceptor:":
|
case "WebpackInterceptor:":
|
||||||
const [, plugin, type, id, regex] = (message as string).match(/Patch by (.+?) (had no effect|errored|found no module) \(Module id is (.+?)\): (.+)/)!;
|
process.exitCode = 1;
|
||||||
|
|
||||||
|
const [, plugin, type, id, regex] = message.match(/Patch by (.+?) (had no effect|errored|found no module) \(Module id is (.+?)\): (.+)/)!;
|
||||||
report.badPatches.push({
|
report.badPatches.push({
|
||||||
plugin,
|
plugin,
|
||||||
type,
|
type,
|
||||||
|
@ -183,17 +207,26 @@ page.on("console", async e => {
|
||||||
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
|
match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
|
||||||
error: cause
|
error: cause
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "PluginManager:":
|
case "PluginManager:":
|
||||||
const [, name] = (message as string).match(/Failed to start (.+)/)!;
|
const failedToStartMatch = message.match(/Failed to start (.+)/);
|
||||||
|
if (!failedToStartMatch) break;
|
||||||
|
|
||||||
|
process.exitCode = 1;
|
||||||
|
|
||||||
|
const [, name] = failedToStartMatch;
|
||||||
report.badStarts.push({
|
report.badStarts.push({
|
||||||
plugin: name,
|
plugin: name,
|
||||||
error: cause
|
error: cause
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (isDebug) {
|
}
|
||||||
console.error(e.text());
|
|
||||||
|
if (isDebug) {
|
||||||
|
console.log(e.text());
|
||||||
} else if (level === "error") {
|
} else if (level === "error") {
|
||||||
const text = await Promise.all(
|
const text = await Promise.all(
|
||||||
e.args().map(async a => {
|
e.args().map(async a => {
|
||||||
|
@ -206,8 +239,8 @@ page.on("console", async e => {
|
||||||
).then(a => a.join(" ").trim());
|
).then(a => a.join(" ").trim());
|
||||||
|
|
||||||
|
|
||||||
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of")) {
|
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of") && !text.includes("found no module Filter:")) {
|
||||||
console.error("Got unexpected error", text);
|
console.error("[Unexpected Error]", text);
|
||||||
report.otherErrors.push(text);
|
report.otherErrors.push(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,17 +252,16 @@ page.on("pageerror", e => console.error("[Page Error]", e));
|
||||||
await page.setBypassCSP(true);
|
await page.setBypassCSP(true);
|
||||||
|
|
||||||
function runTime(token: string) {
|
function runTime(token: string) {
|
||||||
console.error("[PUP_DEBUG]", "Starting test...");
|
console.log("[PUP_DEBUG]", "Starting test...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// spoof languages to not be suspicious
|
// Spoof languages to not be suspicious
|
||||||
Object.defineProperty(navigator, "languages", {
|
Object.defineProperty(navigator, "languages", {
|
||||||
get: function () {
|
get: function () {
|
||||||
return ["en-US", "en"];
|
return ["en-US", "en"];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Monkey patch Logger to not log with custom css
|
// Monkey patch Logger to not log with custom css
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
Vencord.Util.Logger.prototype._log = function (level, levelColor, args) {
|
Vencord.Util.Logger.prototype._log = function (level, levelColor, args) {
|
||||||
|
@ -237,7 +269,7 @@ function runTime(token: string) {
|
||||||
console[level]("[Vencord]", this.name + ":", ...args);
|
console[level]("[Vencord]", this.name + ":", ...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
// force enable all plugins and patches
|
// Force enable all plugins and patches
|
||||||
Vencord.Plugins.patches.length = 0;
|
Vencord.Plugins.patches.length = 0;
|
||||||
Object.values(Vencord.Plugins.plugins).forEach(p => {
|
Object.values(Vencord.Plugins.plugins).forEach(p => {
|
||||||
// Needs native server to run
|
// Needs native server to run
|
||||||
|
@ -247,8 +279,14 @@ function runTime(token: string) {
|
||||||
p.patches?.forEach(patch => {
|
p.patches?.forEach(patch => {
|
||||||
patch.plugin = p.name;
|
patch.plugin = p.name;
|
||||||
delete patch.predicate;
|
delete patch.predicate;
|
||||||
|
|
||||||
if (!Array.isArray(patch.replacement))
|
if (!Array.isArray(patch.replacement))
|
||||||
patch.replacement = [patch.replacement];
|
patch.replacement = [patch.replacement];
|
||||||
|
|
||||||
|
patch.replacement.forEach(r => {
|
||||||
|
delete r.predicate;
|
||||||
|
});
|
||||||
|
|
||||||
Vencord.Plugins.patches.push(patch);
|
Vencord.Plugins.patches.push(patch);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -256,41 +294,141 @@ function runTime(token: string) {
|
||||||
Vencord.Webpack.waitFor(
|
Vencord.Webpack.waitFor(
|
||||||
"loginToken",
|
"loginToken",
|
||||||
m => {
|
m => {
|
||||||
console.error("[PUP_DEBUG]", "Logging in with token...");
|
console.log("[PUP_DEBUG]", "Logging in with token...");
|
||||||
m.loginToken(token);
|
m.loginToken(token);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// force load all chunks
|
// Force load all chunks
|
||||||
Vencord.Webpack.onceReady.then(() => setTimeout(async () => {
|
Vencord.Webpack.onceReady.then(() => setTimeout(async () => {
|
||||||
console.error("[PUP_DEBUG]", "Webpack is ready!");
|
console.log("[PUP_DEBUG]", "Webpack is ready!");
|
||||||
|
|
||||||
const { wreq } = Vencord.Webpack;
|
const { wreq } = Vencord.Webpack;
|
||||||
|
|
||||||
console.error("[PUP_DEBUG]", "Loading all chunks...");
|
console.log("[PUP_DEBUG]", "Loading all chunks...");
|
||||||
const ids = Function("return" + wreq.u.toString().match(/(?<=\()\{.+?\}/s)![0])();
|
|
||||||
for (const id in ids) {
|
let chunks = null as Record<number, string[]> | null;
|
||||||
|
const sym = Symbol("Vencord.chunksExtract");
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, sym, {
|
||||||
|
get() {
|
||||||
|
chunks = this;
|
||||||
|
},
|
||||||
|
set() { },
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await (wreq as any).el(sym);
|
||||||
|
delete Object.prototype[sym];
|
||||||
|
|
||||||
|
const validChunksEntryPoints = [] as string[];
|
||||||
|
const validChunks = [] as string[];
|
||||||
|
const invalidChunks = [] as string[];
|
||||||
|
|
||||||
|
if (!chunks) throw new Error("Failed to get chunks");
|
||||||
|
|
||||||
|
chunksLoop:
|
||||||
|
for (const entryPoint in chunks) {
|
||||||
|
const chunkIds = chunks[entryPoint];
|
||||||
|
|
||||||
|
for (const id of chunkIds) {
|
||||||
|
if (!wreq.u(id)) continue;
|
||||||
|
|
||||||
|
const isWasm = await fetch(wreq.p + wreq.u(id))
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(t => t.includes(".module.wasm") || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
|
||||||
|
|
||||||
|
await new Promise(r => setTimeout(r, 150));
|
||||||
|
|
||||||
|
if (isWasm) {
|
||||||
|
invalidChunks.push(id);
|
||||||
|
continue chunksLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
validChunks.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
validChunksEntryPoints.push(entryPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entryPoint of validChunksEntryPoints) {
|
||||||
|
try {
|
||||||
|
// Loads all chunks required for an entry point
|
||||||
|
await (wreq as any).el(entryPoint);
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
const allChunks = Function("return " + (wreq.u.toString().match(/(?<=\()\{.+?\}/s)?.[0] ?? "null"))() as Record<string | number, string[]> | null;
|
||||||
|
if (!allChunks) throw new Error("Failed to get all chunks");
|
||||||
|
const chunksLeft = Object.keys(allChunks).filter(id => {
|
||||||
|
return !(validChunks.includes(id) || invalidChunks.includes(id));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const id of chunksLeft) {
|
||||||
const isWasm = await fetch(wreq.p + wreq.u(id))
|
const isWasm = await fetch(wreq.p + wreq.u(id))
|
||||||
.then(r => r.text())
|
.then(r => r.text())
|
||||||
.then(t => t.includes(".module.wasm") || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
|
.then(t => t.includes(".module.wasm") || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
|
||||||
|
|
||||||
if (!isWasm)
|
// Loads a chunk
|
||||||
await wreq.e(id as any);
|
if (!isWasm) await wreq.e(id as any);
|
||||||
|
|
||||||
await new Promise(r => setTimeout(r, 150));
|
await new Promise(r => setTimeout(r, 150));
|
||||||
}
|
}
|
||||||
console.error("[PUP_DEBUG]", "Finished loading chunks!");
|
|
||||||
|
// Make sure every chunk has finished loading
|
||||||
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
|
|
||||||
|
for (const entryPoint of validChunksEntryPoints) {
|
||||||
|
try {
|
||||||
|
if (wreq.m[entryPoint]) wreq(entryPoint as any);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[PUP_DEBUG]", "Finished loading all chunks!");
|
||||||
|
|
||||||
for (const patch of Vencord.Plugins.patches) {
|
for (const patch of Vencord.Plugins.patches) {
|
||||||
if (!patch.all) {
|
if (!patch.all) {
|
||||||
new Vencord.Util.Logger("WebpackInterceptor").warn(`Patch by ${patch.plugin} found no module (Module id is -): ${patch.find}`);
|
new Vencord.Util.Logger("WebpackInterceptor").warn(`Patch by ${patch.plugin} found no module (Module id is -): ${patch.find}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(() => console.log("PUPPETEER_TEST_DONE_SIGNAL"), 1000);
|
|
||||||
|
for (const [searchType, args] of Vencord.Webpack.lazyWebpackSearchHistory) {
|
||||||
|
let method = searchType;
|
||||||
|
|
||||||
|
if (searchType === "findComponent") method = "find";
|
||||||
|
if (searchType === "findExportedComponent") method = "findByProps";
|
||||||
|
if (searchType === "waitFor" || searchType === "waitForComponent" || searchType === "waitForStore") {
|
||||||
|
if (typeof args[0] === "string") method = "findByProps";
|
||||||
|
else method = "find";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result: any;
|
||||||
|
|
||||||
|
if (method === "proxyLazyWebpack" || method === "LazyComponentWebpack") {
|
||||||
|
const [factory] = args;
|
||||||
|
result = factory();
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
result = Vencord.Webpack[method](...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null || ("$$get" in result && result.$$get() == 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)}...)`;
|
||||||
|
else logMessage += `(${args.map(arg => `"${arg}"`).join(", ")})`;
|
||||||
|
|
||||||
|
console.log("[PUP_WEBPACK_FIND_FAIL]", logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => console.log("[PUPPETEER_TEST_DONE_SIGNAL]"), 1000);
|
||||||
}, 1000));
|
}, 1000));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[PUP_DEBUG]", "A fatal error occurred");
|
console.log("[PUP_DEBUG]", "A fatal error occurred:", e);
|
||||||
console.error("[PUP_DEBUG]", e);
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,9 @@ import { definePluginSettings, Settings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||||
import { getCurrentGuild } from "@utils/discord";
|
import { getCurrentGuild } from "@utils/discord";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
import { findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
||||||
import { ChannelStore, EmojiStore, FluxDispatcher, lodash, Parser, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
import { ChannelStore, EmojiStore, FluxDispatcher, lodash, Parser, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||||
import type { Message } from "discord-types/general";
|
import type { Message } from "discord-types/general";
|
||||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||||
|
@ -48,9 +47,9 @@ function searchProtoClassField(localName: string, protoClass: any) {
|
||||||
return fieldGetter?.();
|
return fieldGetter?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
const PreloadedUserSettingsActionCreators = proxyLazy(() => UserSettingsActionCreators.PreloadedUserSettingsActionCreators);
|
const PreloadedUserSettingsActionCreators = proxyLazyWebpack(() => UserSettingsActionCreators.PreloadedUserSettingsActionCreators);
|
||||||
const AppearanceSettingsActionCreators = proxyLazy(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
const AppearanceSettingsActionCreators = proxyLazyWebpack(() => searchProtoClassField("appearance", PreloadedUserSettingsActionCreators.ProtoClass));
|
||||||
const ClientThemeSettingsActionsCreators = proxyLazy(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
const ClientThemeSettingsActionsCreators = proxyLazyWebpack(() => searchProtoClassField("clientThemeSettings", AppearanceSettingsActionCreators));
|
||||||
|
|
||||||
const USE_EXTERNAL_EMOJIS = 1n << 18n;
|
const USE_EXTERNAL_EMOJIS = 1n << 18n;
|
||||||
const USE_EXTERNAL_STICKERS = 1n << 37n;
|
const USE_EXTERNAL_STICKERS = 1n << 37n;
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import ExpandableHeader from "@components/ExpandableHeader";
|
import ExpandableHeader from "@components/ExpandableHeader";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { filters, findBulk } from "@webpack";
|
import { filters, findBulk, proxyLazyWebpack } from "@webpack";
|
||||||
import { i18n, PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
|
import { i18n, PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
|
||||||
import type { Guild, GuildMember } from "discord-types/general";
|
import type { Guild, GuildMember } from "discord-types/general";
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ interface UserPermission {
|
||||||
|
|
||||||
type UserPermissions = Array<UserPermission>;
|
type UserPermissions = Array<UserPermission>;
|
||||||
|
|
||||||
const Classes = proxyLazy(() => {
|
const Classes = proxyLazyWebpack(() => {
|
||||||
const modules = findBulk(
|
const modules = findBulk(
|
||||||
filters.byProps("roles", "rolePill", "rolePillBorder"),
|
filters.byProps("roles", "rolePill", "rolePillBorder"),
|
||||||
filters.byProps("roleCircle", "dotBorderBase", "dotBorderColor"),
|
filters.byProps("roleCircle", "dotBorderBase", "dotBorderColor"),
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
import { findByProps, proxyLazyWebpack } from "@webpack";
|
||||||
import { findByPropsLazy } from "@webpack";
|
|
||||||
import { Flux, FluxDispatcher } from "@webpack/common";
|
import { Flux, FluxDispatcher } from "@webpack/common";
|
||||||
|
|
||||||
export interface Track {
|
export interface Track {
|
||||||
|
@ -66,12 +65,12 @@ interface Device {
|
||||||
type Repeat = "off" | "track" | "context";
|
type Repeat = "off" | "track" | "context";
|
||||||
|
|
||||||
// Don't wanna run before Flux and Dispatcher are ready!
|
// Don't wanna run before Flux and Dispatcher are ready!
|
||||||
export const SpotifyStore = proxyLazy(() => {
|
export const SpotifyStore = proxyLazyWebpack(() => {
|
||||||
// For some reason ts hates extends Flux.Store
|
// For some reason ts hates extends Flux.Store
|
||||||
const { Store } = Flux;
|
const { Store } = Flux;
|
||||||
|
|
||||||
const SpotifySocket = findByPropsLazy("getActiveSocketAndDevice");
|
const SpotifySocket = findByProps("getActiveSocketAndDevice");
|
||||||
const SpotifyUtils = findByPropsLazy("SpotifyAPI");
|
const SpotifyUtils = findByProps("SpotifyAPI");
|
||||||
|
|
||||||
const API_BASE = "https://api.spotify.com/v1/me/player";
|
const API_BASE = "https://api.spotify.com/v1/me/player";
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,13 @@
|
||||||
import { definePluginSettings, Settings } from "@api/Settings";
|
import { definePluginSettings, Settings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { LazyComponent } from "@utils/react";
|
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { find, findStoreLazy } from "@webpack";
|
import { find, findStoreLazy, LazyComponentWebpack } from "@webpack";
|
||||||
import { ChannelStore, GuildMemberStore, i18n, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
import { ChannelStore, GuildMemberStore, i18n, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
||||||
|
|
||||||
import { buildSeveralUsers } from "../typingTweaks";
|
import { buildSeveralUsers } from "../typingTweaks";
|
||||||
|
|
||||||
const ThreeDots = LazyComponent(() => {
|
const ThreeDots = LazyComponentWebpack(() => {
|
||||||
// This doesn't really need to explicitly find Dots' own module, but it's fine
|
// This doesn't really need to explicitly find Dots' own module, but it's fine
|
||||||
const res = find(m => m.Dots && !m.Menu);
|
const res = find(m => m.Dots && !m.Menu);
|
||||||
|
|
||||||
|
|
|
@ -22,15 +22,14 @@ import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { LazyComponent } from "@utils/react";
|
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { filters, find } from "@webpack";
|
import { filters, find, LazyComponentWebpack } from "@webpack";
|
||||||
import { Menu, Popout, useState } from "@webpack/common";
|
import { Menu, Popout, useState } from "@webpack/common";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
const HeaderBarIcon = LazyComponent(() => {
|
const HeaderBarIcon = LazyComponentWebpack(() => {
|
||||||
const filter = filters.byCode(".HEADER_BAR_BADGE");
|
const filter = filters.byCode(".HEADER_BAR_BADGE");
|
||||||
return find(m => m.Icon && filter(m.Icon)).Icon;
|
return find(m => m.Icon && filter(m.Icon))?.Icon;
|
||||||
});
|
});
|
||||||
|
|
||||||
function VencordPopout(onClose: () => void) {
|
function VencordPopout(onClose: () => void) {
|
||||||
|
|
|
@ -76,7 +76,7 @@ handler.getOwnPropertyDescriptor = (target, p) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the result of {@see makeLazy} in a Proxy you can consume as if it wasn't lazy.
|
* Wraps the result of {@link makeLazy} in a Proxy you can consume as if it wasn't lazy.
|
||||||
* On first property access, the lazy is evaluated
|
* On first property access, the lazy is evaluated
|
||||||
* @param factory lazy factory
|
* @param factory lazy factory
|
||||||
* @param attempts how many times to try to evaluate the lazy before giving up
|
* @param attempts how many times to try to evaluate the lazy before giving up
|
||||||
|
|
|
@ -16,8 +16,12 @@ const NoopComponent = () => null;
|
||||||
*/
|
*/
|
||||||
export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>, attempts = 5) {
|
export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>, attempts = 5) {
|
||||||
const get = makeLazy(factory, attempts);
|
const get = makeLazy(factory, attempts);
|
||||||
return (props: T) => {
|
const LazyComponent = (props: T) => {
|
||||||
const Component = get() ?? NoopComponent;
|
const Component = get() ?? NoopComponent;
|
||||||
return <Component {...props} />;
|
return <Component {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LazyComponent.$$get = get;
|
||||||
|
|
||||||
|
return LazyComponent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,11 @@
|
||||||
import { LazyComponent } from "@utils/react";
|
import { LazyComponent } from "@utils/react";
|
||||||
|
|
||||||
// eslint-disable-next-line path-alias/no-relative
|
// eslint-disable-next-line path-alias/no-relative
|
||||||
import { FilterFn, filters, waitFor } from "../webpack";
|
import { FilterFn, filters, lazyWebpackSearchHistory, waitFor } from "../webpack";
|
||||||
|
|
||||||
export function waitForComponent<T extends React.ComponentType<any> = React.ComponentType<any> & Record<string, any>>(name: string, filter: FilterFn | string | string[]): T {
|
export function waitForComponent<T extends React.ComponentType<any> = React.ComponentType<any> & Record<string, any>>(name: string, filter: FilterFn | string | string[]): T {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["waitForComponent", Array.isArray(filter) ? filter : [filter]]);
|
||||||
|
|
||||||
let myValue: T = function () {
|
let myValue: T = function () {
|
||||||
throw new Error(`Vencord could not find the ${name} Component`);
|
throw new Error(`Vencord could not find the ${name} Component`);
|
||||||
} as any;
|
} as any;
|
||||||
|
@ -30,11 +32,13 @@ export function waitForComponent<T extends React.ComponentType<any> = React.Comp
|
||||||
waitFor(filter, (v: any) => {
|
waitFor(filter, (v: any) => {
|
||||||
myValue = v;
|
myValue = v;
|
||||||
Object.assign(lazyComponent, v);
|
Object.assign(lazyComponent, v);
|
||||||
});
|
}, { isIndirect: true });
|
||||||
|
|
||||||
return lazyComponent;
|
return lazyComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function waitForStore(name: string, cb: (v: any) => void) {
|
export function waitForStore(name: string, cb: (v: any) => void) {
|
||||||
waitFor(filters.byStoreName(name), cb);
|
if (IS_DEV) lazyWebpackSearchHistory.push(["waitForStore", [name]]);
|
||||||
|
|
||||||
|
waitFor(filters.byStoreName(name), cb, { isIndirect: true });
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,23 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { proxyLazy } from "@utils/lazy";
|
|
||||||
import type { Channel, User } from "discord-types/general";
|
import type { Channel, User } from "discord-types/general";
|
||||||
|
|
||||||
// eslint-disable-next-line path-alias/no-relative
|
// eslint-disable-next-line path-alias/no-relative
|
||||||
import { _resolveReady, find, findByPropsLazy, findLazy, waitFor } from "../webpack";
|
import { _resolveReady, findByPropsLazy, findLazy, waitFor } from "../webpack";
|
||||||
import type * as t from "./types/utils";
|
import type * as t from "./types/utils";
|
||||||
|
|
||||||
export let FluxDispatcher: t.FluxDispatcher;
|
export let FluxDispatcher: t.FluxDispatcher;
|
||||||
|
|
||||||
|
waitFor(["dispatch", "subscribe"], m => {
|
||||||
|
FluxDispatcher = m;
|
||||||
|
const cb = () => {
|
||||||
|
m.unsubscribe("CONNECTION_OPEN", cb);
|
||||||
|
_resolveReady();
|
||||||
|
};
|
||||||
|
m.subscribe("CONNECTION_OPEN", cb);
|
||||||
|
});
|
||||||
|
|
||||||
export let ComponentDispatch;
|
export let ComponentDispatch;
|
||||||
waitFor(["ComponentDispatch", "ComponentDispatcher"], m => ComponentDispatch = m.ComponentDispatch);
|
waitFor(["ComponentDispatch", "ComponentDispatcher"], m => ComponentDispatch = m.ComponentDispatch);
|
||||||
|
|
||||||
|
@ -41,7 +50,9 @@ export let SnowflakeUtils: t.SnowflakeUtils;
|
||||||
waitFor(["fromTimestamp", "extractTimestamp"], m => SnowflakeUtils = m);
|
waitFor(["fromTimestamp", "extractTimestamp"], m => SnowflakeUtils = m);
|
||||||
|
|
||||||
export let Parser: t.Parser;
|
export let Parser: t.Parser;
|
||||||
|
waitFor("parseTopic", m => Parser = m);
|
||||||
export let Alerts: t.Alerts;
|
export let Alerts: t.Alerts;
|
||||||
|
waitFor(["show", "close"], m => Alerts = m);
|
||||||
|
|
||||||
const ToastType = {
|
const ToastType = {
|
||||||
MESSAGE: 0,
|
MESSAGE: 0,
|
||||||
|
@ -82,6 +93,13 @@ export const Toasts = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is the same module but this is easier
|
||||||
|
waitFor("showToast", m => {
|
||||||
|
Toasts.show = m.showToast;
|
||||||
|
Toasts.pop = m.popToast;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a simple toast. If you need more options, use Toasts.show manually
|
* Show a simple toast. If you need more options, use Toasts.show manually
|
||||||
*/
|
*/
|
||||||
|
@ -106,26 +124,8 @@ export const Clipboard: t.Clipboard = findByPropsLazy("SUPPORTS_COPY", "copy");
|
||||||
|
|
||||||
export const NavigationRouter: t.NavigationRouter = findByPropsLazy("transitionTo", "replaceWith", "transitionToGuild");
|
export const NavigationRouter: t.NavigationRouter = findByPropsLazy("transitionTo", "replaceWith", "transitionToGuild");
|
||||||
|
|
||||||
waitFor(["dispatch", "subscribe"], m => {
|
|
||||||
FluxDispatcher = m;
|
|
||||||
const cb = () => {
|
|
||||||
m.unsubscribe("CONNECTION_OPEN", cb);
|
|
||||||
_resolveReady();
|
|
||||||
};
|
|
||||||
m.subscribe("CONNECTION_OPEN", cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// This is the same module but this is easier
|
|
||||||
waitFor("showToast", m => {
|
|
||||||
Toasts.show = m.showToast;
|
|
||||||
Toasts.pop = m.popToast;
|
|
||||||
});
|
|
||||||
|
|
||||||
waitFor(["show", "close"], m => Alerts = m);
|
|
||||||
waitFor("parseTopic", m => Parser = m);
|
|
||||||
|
|
||||||
export let SettingsRouter: any;
|
export let SettingsRouter: any;
|
||||||
waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m);
|
waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m);
|
||||||
|
|
||||||
export const PermissionsBits: t.PermissionsBits = proxyLazy(() => find(m => typeof m.Permissions?.ADMINISTRATOR === "bigint").Permissions);
|
const { Permissions } = findLazy(m => typeof m.Permissions?.ADMINISTRATOR === "bigint") as { Permissions: t.PermissionsBits; };
|
||||||
|
export { Permissions as PermissionsBits };
|
||||||
|
|
|
@ -127,13 +127,6 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
|
||||||
return isWaitFor ? [null, null] : null;
|
return isWaitFor ? [null, null] : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* find but lazy
|
|
||||||
*/
|
|
||||||
export function findLazy(filter: FilterFn) {
|
|
||||||
return proxyLazy(() => find(filter));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function findAll(filter: FilterFn) {
|
export function findAll(filter: FilterFn) {
|
||||||
if (typeof filter !== "function")
|
if (typeof filter !== "function")
|
||||||
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
||||||
|
@ -244,6 +237,49 @@ export const findModuleId = traceFunction("findModuleId", function findModuleId(
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack", any[]]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a wrapper around {@link proxyLazy} to make our reporter test for your webpack finds.
|
||||||
|
*
|
||||||
|
* Wraps the result of {@link makeLazy} in a Proxy you can consume as if it wasn't lazy.
|
||||||
|
* On first property access, the lazy is evaluated
|
||||||
|
* @param factory lazy factory
|
||||||
|
* @param attempts how many times to try to evaluate the lazy before giving up
|
||||||
|
* @returns Proxy
|
||||||
|
*
|
||||||
|
* Note that the example below exists already as an api, see {@link findByPropsLazy}
|
||||||
|
* @example const mod = proxyLazy(() => findByProps("blah")); console.log(mod.blah);
|
||||||
|
*/
|
||||||
|
export function proxyLazyWebpack<T = any>(factory: () => any, attempts?: number) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["proxyLazyWebpack", [factory]]);
|
||||||
|
|
||||||
|
return proxyLazy<T>(factory, attempts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a wrapper around {@link LazyComponent} to make our reporter test for your webpack finds.
|
||||||
|
*
|
||||||
|
* A lazy component. The factory method is called on first render.
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
export function LazyComponentWebpack<T extends object = any>(factory: () => any, attempts?: number) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["LazyComponentWebpack", [factory]]);
|
||||||
|
|
||||||
|
return LazyComponent<T>(factory, attempts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find but lazy
|
||||||
|
*/
|
||||||
|
export function findLazy(filter: FilterFn) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["find", [filter]]);
|
||||||
|
|
||||||
|
return proxyLazy(() => find(filter));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the first module that has the specified properties
|
* Find the first module that has the specified properties
|
||||||
*/
|
*/
|
||||||
|
@ -258,6 +294,8 @@ export function findByProps(...props: string[]) {
|
||||||
* findByProps but lazy
|
* findByProps but lazy
|
||||||
*/
|
*/
|
||||||
export function findByPropsLazy(...props: string[]) {
|
export function findByPropsLazy(...props: string[]) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findByProps", props]);
|
||||||
|
|
||||||
return proxyLazy(() => findByProps(...props));
|
return proxyLazy(() => findByProps(...props));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +313,8 @@ export function findByCode(...code: string[]) {
|
||||||
* findByCode but lazy
|
* findByCode but lazy
|
||||||
*/
|
*/
|
||||||
export function findByCodeLazy(...code: string[]) {
|
export function findByCodeLazy(...code: string[]) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findByCode", code]);
|
||||||
|
|
||||||
return proxyLazy(() => findByCode(...code));
|
return proxyLazy(() => findByCode(...code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +332,8 @@ export function findStore(name: string) {
|
||||||
* findStore but lazy
|
* findStore but lazy
|
||||||
*/
|
*/
|
||||||
export function findStoreLazy(name: string) {
|
export function findStoreLazy(name: string) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findStore", [name]]);
|
||||||
|
|
||||||
return proxyLazy(() => findStore(name));
|
return proxyLazy(() => findStore(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +351,8 @@ export function findComponentByCode(...code: string[]) {
|
||||||
* Finds the first component that matches the filter, lazily.
|
* Finds the first component that matches the filter, lazily.
|
||||||
*/
|
*/
|
||||||
export function findComponentLazy<T extends object = any>(filter: FilterFn) {
|
export function findComponentLazy<T extends object = any>(filter: FilterFn) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findComponent", [filter]]);
|
||||||
|
|
||||||
return LazyComponent<T>(() => find(filter));
|
return LazyComponent<T>(() => find(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +360,8 @@ export function findComponentLazy<T extends object = any>(filter: FilterFn) {
|
||||||
* Finds the first component that includes all the given code, lazily
|
* Finds the first component that includes all the given code, lazily
|
||||||
*/
|
*/
|
||||||
export function findComponentByCodeLazy<T extends object = any>(...code: string[]) {
|
export function findComponentByCodeLazy<T extends object = any>(...code: string[]) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findComponentByCode", code]);
|
||||||
|
|
||||||
return LazyComponent<T>(() => findComponentByCode(...code));
|
return LazyComponent<T>(() => findComponentByCode(...code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +369,8 @@ export function findComponentByCodeLazy<T extends object = any>(...code: string[
|
||||||
* Finds the first component that is exported by the first prop name, lazily
|
* Finds the first component that is exported by the first prop name, lazily
|
||||||
*/
|
*/
|
||||||
export function findExportedComponentLazy<T extends object = any>(...props: string[]) {
|
export function findExportedComponentLazy<T extends object = any>(...props: string[]) {
|
||||||
|
if (IS_DEV) lazyWebpackSearchHistory.push(["findExportedComponent", props]);
|
||||||
|
|
||||||
return LazyComponent<T>(() => findByProps(...props)?.[props[0]]);
|
return LazyComponent<T>(() => findByProps(...props)?.[props[0]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +378,9 @@ export function findExportedComponentLazy<T extends object = any>(...props: stri
|
||||||
* Wait for a module that matches the provided filter to be registered,
|
* Wait for a module that matches the provided filter to be registered,
|
||||||
* then call the callback with the module as the first argument
|
* then call the callback with the module as the first argument
|
||||||
*/
|
*/
|
||||||
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn) {
|
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
||||||
|
if (IS_DEV && !isIndirect) lazyWebpackSearchHistory.push(["waitFor", Array.isArray(filter) ? filter : [filter]]);
|
||||||
|
|
||||||
if (typeof filter === "string")
|
if (typeof filter === "string")
|
||||||
filter = filters.byProps(filter);
|
filter = filters.byProps(filter);
|
||||||
else if (Array.isArray(filter))
|
else if (Array.isArray(filter))
|
||||||
|
|
Loading…
Reference in a new issue