Add back top level destructuring for backwards compabitlity
This commit is contained in:
parent
4677ac779a
commit
e801c71fdf
|
@ -10,9 +10,9 @@ import * as Webpack from "@webpack";
|
||||||
import { wreq } from "@webpack";
|
import { wreq } from "@webpack";
|
||||||
import { AnyModuleFactory, ModuleFactory } from "webpack";
|
import { AnyModuleFactory, ModuleFactory } from "webpack";
|
||||||
|
|
||||||
|
export async function loadLazyChunks() {
|
||||||
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
|
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
|
||||||
|
|
||||||
export async function loadLazyChunks() {
|
|
||||||
try {
|
try {
|
||||||
LazyChunkLoaderLogger.log("Loading all chunks...");
|
LazyChunkLoaderLogger.log("Loading all chunks...");
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@ import { addPatch, patches } from "plugins";
|
||||||
|
|
||||||
import { loadLazyChunks } from "./loadLazyChunks";
|
import { loadLazyChunks } from "./loadLazyChunks";
|
||||||
|
|
||||||
|
async function runReporter() {
|
||||||
const ReporterLogger = new Logger("Reporter");
|
const ReporterLogger = new Logger("Reporter");
|
||||||
|
|
||||||
async function runReporter() {
|
|
||||||
try {
|
try {
|
||||||
ReporterLogger.log("Starting test...");
|
ReporterLogger.log("Starting test...");
|
||||||
|
|
||||||
|
|
|
@ -69,11 +69,22 @@ const handler: ProxyHandler<any> = {
|
||||||
*
|
*
|
||||||
* @param factory Factory returning the result
|
* @param factory Factory returning the result
|
||||||
* @param attempts How many times to try to evaluate the factory before giving up
|
* @param attempts How many times to try to evaluate the factory before giving up
|
||||||
|
* @param errMsg The error message to throw when the factory fails
|
||||||
|
* @param primitiveErrMsg The error message to throw when factory result is a primitive
|
||||||
* @returns Result of factory function
|
* @returns Result of factory function
|
||||||
*/
|
*/
|
||||||
export function proxyLazy<T = any>(factory: () => T, attempts = 5): T {
|
export function proxyLazy<T = any>(
|
||||||
|
factory: () => T,
|
||||||
|
attempts = 5,
|
||||||
|
errMsg: string | (() => string) = `proxyLazy factory failed:\n\n${factory}`,
|
||||||
|
primitiveErrMsg = "proxyLazy called on a primitive value.",
|
||||||
|
isChild = false
|
||||||
|
): T {
|
||||||
const get = makeLazy(factory, attempts, { isIndirect: true });
|
const get = makeLazy(factory, attempts, { isIndirect: true });
|
||||||
|
|
||||||
|
let isSameTick = true;
|
||||||
|
if (!isChild) setTimeout(() => isSameTick = false, 0);
|
||||||
|
|
||||||
const proxyDummy = Object.assign(function () { }, {
|
const proxyDummy = Object.assign(function () { }, {
|
||||||
[SYM_LAZY_GET]() {
|
[SYM_LAZY_GET]() {
|
||||||
if (!proxyDummy[SYM_LAZY_CACHED]) {
|
if (!proxyDummy[SYM_LAZY_CACHED]) {
|
||||||
|
@ -82,7 +93,7 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5): T {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!proxyDummy[SYM_LAZY_CACHED]) {
|
if (!proxyDummy[SYM_LAZY_CACHED]) {
|
||||||
throw new Error(`proxyLazy factory failed:\n\n${factory}`);
|
throw new Error(typeof errMsg === "string" ? errMsg : errMsg());
|
||||||
} else {
|
} else {
|
||||||
if (typeof proxyDummy[SYM_LAZY_CACHED] === "function") {
|
if (typeof proxyDummy[SYM_LAZY_CACHED] === "function") {
|
||||||
proxy.toString = proxyDummy[SYM_LAZY_CACHED].toString.bind(proxyDummy[SYM_LAZY_CACHED]);
|
proxy.toString = proxyDummy[SYM_LAZY_CACHED].toString.bind(proxyDummy[SYM_LAZY_CACHED]);
|
||||||
|
@ -102,12 +113,34 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5): T {
|
||||||
return Reflect.get(target, p, receiver);
|
return Reflect.get(target, p, receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're still in the same tick, it means the lazy was immediately used.
|
||||||
|
// thus, we lazy proxy the get access to make things like destructuring work as expected
|
||||||
|
// meow here will also be a lazy
|
||||||
|
// `const { meow } = proxyLazy(() => ({ meow: [] }));`
|
||||||
|
if (!isChild && isSameTick) {
|
||||||
|
console.warn(
|
||||||
|
"Destructuring webpack finds/proxyInner/proxyLazy at top level is deprecated. For more information read https://github.com/Vendicated/Vencord/pull/2409#issue-2277161516" +
|
||||||
|
"\nConsider not destructuring, using findProp or if you really need to destructure, using mapMangledModule instead."
|
||||||
|
);
|
||||||
|
|
||||||
|
return proxyLazy(
|
||||||
|
() => {
|
||||||
|
const lazyTarget = target[SYM_LAZY_GET]();
|
||||||
|
return Reflect.get(lazyTarget, p, lazyTarget);
|
||||||
|
},
|
||||||
|
attempts,
|
||||||
|
errMsg,
|
||||||
|
primitiveErrMsg,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const lazyTarget = target[SYM_LAZY_GET]();
|
const lazyTarget = target[SYM_LAZY_GET]();
|
||||||
if (typeof lazyTarget === "object" || typeof lazyTarget === "function") {
|
if (typeof lazyTarget === "object" || typeof lazyTarget === "function") {
|
||||||
return Reflect.get(lazyTarget, p, lazyTarget);
|
return Reflect.get(lazyTarget, p, lazyTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("proxyLazy called on a primitive value.");
|
throw new Error(primitiveErrMsg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,18 @@ const handler: ProxyHandler<any> = {
|
||||||
* IMPORTANT:
|
* IMPORTANT:
|
||||||
* Destructuring at top level is not supported for proxyInner.
|
* Destructuring at top level is not supported for proxyInner.
|
||||||
*
|
*
|
||||||
* @param err The error message to throw when the inner value is not set
|
* @param errMsg 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
|
* @param primitiveErrMsg The error message to throw when the inner value is a primitive
|
||||||
* @returns A proxy which will act like the inner value when accessed
|
* @returns A proxy which will act like the inner value when accessed
|
||||||
*/
|
*/
|
||||||
export function proxyInner<T = any>(
|
export function proxyInner<T = any>(
|
||||||
errMsg: string | (() => string) = "Proxy inner value is undefined, setInnerValue was never called.",
|
errMsg: string | (() => string) = "Proxy inner value is undefined, setInnerValue was never called.",
|
||||||
primitiveErrMsg = "proxyInner called on a primitive value."
|
primitiveErrMsg = "proxyInner called on a primitive value. This can happen if you try to destructure a primitive at the same tick as the proxy was created.",
|
||||||
|
isChild = false
|
||||||
): [proxy: T, setInnerValue: (innerValue: T) => void] {
|
): [proxy: T, setInnerValue: (innerValue: T) => void] {
|
||||||
|
let isSameTick = true;
|
||||||
|
if (!isChild) setTimeout(() => isSameTick = false, 0);
|
||||||
|
|
||||||
const proxyDummy = Object.assign(function () { }, {
|
const proxyDummy = Object.assign(function () { }, {
|
||||||
[SYM_PROXY_INNER_GET]: function () {
|
[SYM_PROXY_INNER_GET]: function () {
|
||||||
if (proxyDummy[SYM_PROXY_INNER_VALUE] == null) {
|
if (proxyDummy[SYM_PROXY_INNER_VALUE] == null) {
|
||||||
|
@ -68,6 +72,29 @@ export function proxyInner<T = any>(
|
||||||
return Reflect.get(target, p, receiver);
|
return Reflect.get(target, p, receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're still in the same tick, it means the proxy was immediately used.
|
||||||
|
// And, if the inner value is still nullish, it means the proxy was used before setInnerValue was called.
|
||||||
|
// So, proxy the get access to make things like destructuring work as expected.
|
||||||
|
// We dont need to proxy if the inner value is available, and recursiveSetInnerValue won't ever be called anyways,
|
||||||
|
// because the top setInnerValue was called before we proxied the get access
|
||||||
|
// example here will also be a proxy:
|
||||||
|
// `const { example } = findByProps("example");`
|
||||||
|
if (isSameTick && !isChild && proxyDummy[SYM_PROXY_INNER_VALUE] == null) {
|
||||||
|
console.warn(
|
||||||
|
"Destructuring webpack finds/proxyInner/proxyLazy at top level is deprecated. For more information read https://github.com/Vendicated/Vencord/pull/2409#issue-2277161516" +
|
||||||
|
"\nConsider not destructuring, using findProp or if you really need to destructure, using mapMangledModule instead."
|
||||||
|
);
|
||||||
|
|
||||||
|
const [recursiveProxy, recursiveSetInnerValue] = proxyInner(errMsg, primitiveErrMsg, true);
|
||||||
|
|
||||||
|
recursiveSetInnerValues.push((innerValue: T) => {
|
||||||
|
// Set the inner value of the destructured value as the prop value p of the parent
|
||||||
|
recursiveSetInnerValue(Reflect.get(innerValue as object, p, innerValue));
|
||||||
|
});
|
||||||
|
|
||||||
|
return recursiveProxy;
|
||||||
|
}
|
||||||
|
|
||||||
const innerTarget = target[SYM_PROXY_INNER_GET]();
|
const innerTarget = target[SYM_PROXY_INNER_GET]();
|
||||||
if (typeof innerTarget === "object" || typeof innerTarget === "function") {
|
if (typeof innerTarget === "object" || typeof innerTarget === "function") {
|
||||||
return Reflect.get(innerTarget, p, innerTarget);
|
return Reflect.get(innerTarget, p, innerTarget);
|
||||||
|
@ -77,8 +104,14 @@ export function proxyInner<T = any>(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Values destructured in the same tick the proxy was created will push their setInnerValue here
|
||||||
|
const recursiveSetInnerValues = [] as Array<(innerValue: T) => void>;
|
||||||
|
|
||||||
|
// Once we set the parent inner value, we will call the setInnerValue functions of the destructured values,
|
||||||
|
// for them to get the proper value from the parent and use as their inner instead
|
||||||
function setInnerValue(innerValue: T) {
|
function setInnerValue(innerValue: T) {
|
||||||
proxyDummy[SYM_PROXY_INNER_VALUE] = innerValue;
|
proxyDummy[SYM_PROXY_INNER_VALUE] = innerValue;
|
||||||
|
recursiveSetInnerValues.forEach(setInnerValue => setInnerValue(innerValue));
|
||||||
|
|
||||||
// Avoid binding toString if the inner value is null.
|
// Avoid binding toString if the inner value is null.
|
||||||
// This can happen if we are setting the inner value as another instance of proxyInner, which will cause that proxy to instantly evaluate and throw an error
|
// This can happen if we are setting the inner value as another instance of proxyInner, which will cause that proxy to instantly evaluate and throw an error
|
||||||
|
|
|
@ -254,7 +254,7 @@ export function find<T = any>(filter: FilterFn, parse: (module: ModuleExports) =
|
||||||
if (typeof parse !== "function")
|
if (typeof parse !== "function")
|
||||||
throw new Error("Invalid find parse. Expected a function got " + typeof parse);
|
throw new Error("Invalid find parse. Expected a function got " + typeof parse);
|
||||||
|
|
||||||
const [proxy, setInnerValue] = proxyInner<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value.");
|
const [proxy, setInnerValue] = proxyInner<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find.");
|
||||||
waitFor(filter, m => setInnerValue(parse(m)), { isIndirect: true });
|
waitFor(filter, m => setInnerValue(parse(m)), { isIndirect: true });
|
||||||
|
|
||||||
if (IS_REPORTER && !isIndirect) {
|
if (IS_REPORTER && !isIndirect) {
|
||||||
|
@ -552,7 +552,7 @@ export function mapMangledModule<S extends PropertyKey>(code: string | RegExp |
|
||||||
export function findModuleFactory(...code: CodeFilter) {
|
export function findModuleFactory(...code: CodeFilter) {
|
||||||
const filter = filters.byFactoryCode(...code);
|
const filter = filters.byFactoryCode(...code);
|
||||||
|
|
||||||
const [proxy, setInnerValue] = proxyInner<AnyModuleFactory>(`Webpack module factory find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value.");
|
const [proxy, setInnerValue] = proxyInner<AnyModuleFactory>(`Webpack module factory find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find.");
|
||||||
waitFor(filter, (_, { factory }) => setInnerValue(factory));
|
waitFor(filter, (_, { factory }) => setInnerValue(factory));
|
||||||
|
|
||||||
if (proxy[SYM_PROXY_INNER_VALUE] != null) return proxy[SYM_PROXY_INNER_VALUE] as AnyModuleFactory;
|
if (proxy[SYM_PROXY_INNER_VALUE] != null) return proxy[SYM_PROXY_INNER_VALUE] as AnyModuleFactory;
|
||||||
|
@ -573,7 +573,7 @@ export function findModuleFactory(...code: CodeFilter) {
|
||||||
export function webpackDependantLazy<T = any>(factory: () => T, attempts?: number) {
|
export function webpackDependantLazy<T = any>(factory: () => T, attempts?: number) {
|
||||||
if (IS_REPORTER) webpackSearchHistory.push(["webpackDependantLazy", [factory]]);
|
if (IS_REPORTER) webpackSearchHistory.push(["webpackDependantLazy", [factory]]);
|
||||||
|
|
||||||
return proxyLazy<T>(factory, attempts);
|
return proxyLazy<T>(factory, attempts, `Webpack dependant lazy factory failed:\n\n${factory}`, "Webpack dependant lazy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the lazy.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue