fix(metro): magical fixes

This commit is contained in:
amsyarasyiq 2024-05-21 16:04:56 +08:00
parent ee6669f514
commit af6ba01079
4 changed files with 41 additions and 32 deletions

View file

@ -1,40 +1,45 @@
const factorySymbol = Symbol.for("bunny.lazyFactory");
const cacheSymbol = Symbol("bunny.lazyCache");
const dummySymbol = Symbol("bunny.lazyDummy");
const factorySymbol = Symbol("lazyFactory");
const cacheSymbol = Symbol("lazyCache");
const unconfigurable = ["arguments", "caller", "prototype"];
const isUnconfigurable = (key: PropertyKey) => typeof key === "string" && unconfigurable.includes(key);
const lazyHandler: ProxyHandler<any> = {
...Object.fromEntries(Object.getOwnPropertyNames(Reflect).map(fnName => {
return [fnName, (target: any, ...args: any[]) => {
// @ts-ignore
const func = s => Reflect[fnName](s, ...args);
return func(target[factorySymbol]()) ?? func(target[dummySymbol]);
}];
})),
ownKeys: target => {
const cacheKeys = Reflect.ownKeys(target[factorySymbol]() ?? target[dummySymbol]);
const cacheKeys = Reflect.ownKeys(target[factorySymbol]());
unconfigurable.forEach(key => isUnconfigurable(key) && cacheKeys.push(key));
return cacheKeys;
},
getOwnPropertyDescriptor: (target, p) => {
if (isUnconfigurable(p)) return Reflect.getOwnPropertyDescriptor(target, p);
const descriptor = Reflect.getOwnPropertyDescriptor(target[factorySymbol]() ?? target[dummySymbol], p);
const descriptor = Reflect.getOwnPropertyDescriptor(target[factorySymbol](), p);
if (descriptor) Object.defineProperty(target, p, descriptor);
return descriptor;
},
}
};
// Mirror all Reflect methods
Object.getOwnPropertyNames(Reflect).forEach(fnName => {
// @ts-ignore
lazyHandler[fnName] ??= (target: any, ...args: any[]) => {
// @ts-ignore
return Reflect[fnName](target[factorySymbol](), ...args);
};
});
/**
* Lazy proxy that will only call the factory function when needed (when a property is accessed)
* @param factory Factory function to create the object
* @param fallback A fallback value to return if the factory returns undefined
* @returns A proxy that will call the factory function only when needed
* @example const ChannelStore = proxyLazy(() => findByProps("getChannelId"));
*/
export function proxyLazy<T>(factory: () => T, dummy: any = () => void 0): T {
dummy[factorySymbol] = () => dummy[cacheSymbol] ??= factory();
dummy[dummySymbol] = dummy;
export function proxyLazy<T>(factory: () => T, fallback?: any): T {
const dummy = function () { } as any;
dummy[factorySymbol] = () => {
return (dummy[cacheSymbol] ??= factory()) ?? fallback;
};
return new Proxy(dummy, lazyHandler) as any;
}

View file

@ -1,8 +1,6 @@
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
import { throttle } from "@lib/utils/throttle";
import { getCachedPolyfillModules } from "./modules";
type ModulesMap = {
_?: 1;
[id: number]: 1 | void;
@ -22,6 +20,7 @@ let _metroCache = null as unknown as MetroCacheStore;
export function getMetroCache() {
return _metroCache;
}
window.getMetroCache = getMetroCache;
function buildInitCache() {
_metroCache = {
@ -59,14 +58,16 @@ export async function initMetroCache() {
const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache)));
export function getCacherForUniq(uniq: string, allFind: boolean) {
const indexObject = _metroCache.findIndex[uniq] ??= {};
let indexObject = _metroCache.findIndex[uniq];
return {
cacheId(moduleId: number) {
indexObject = _metroCache.findIndex[uniq] ??= {};
indexObject[moduleId] = 1;
saveCache();
},
finish() {
indexObject = _metroCache.findIndex[uniq] ??= {};
if (allFind) indexObject._ = 1;
saveCache();
}
@ -74,13 +75,14 @@ export function getCacherForUniq(uniq: string, allFind: boolean) {
}
export function getPolyfillModuleCacher(name: string) {
const indexObject = _metroCache.polyfillIndex[name] ??= {};
let indexObject = _metroCache.polyfillIndex[name];
return {
getModules() {
return getCachedPolyfillModules(name);
return require("@metro/modules").getCachedPolyfillModules(name);
},
cacheId(moduleId: number) {
indexObject = _metroCache.polyfillIndex[name] ??= {};
indexObject[moduleId] = 1;
saveCache();
}

View file

@ -4,7 +4,7 @@ import { FilterFn } from "./types";
function testExports<A extends unknown[]>(moduleExports: any, moduleId: number, filter: FilterFn<A>) {
if (moduleExports.default && moduleExports.__esModule && filter(moduleExports.default, moduleId, true)) {
return [moduleExports.default, true];
return [filter.defaultFilter ? moduleExports : moduleExports.default, !filter.defaultFilter];
}
if (!filter.defaultFilter && filter(moduleExports, moduleId, false)) {

View file

@ -13,16 +13,6 @@ let patchedInspectSource = false;
let patchedImportTracker = false;
let _importingModuleId: string | null = null;
/** Makes the module associated with the specified ID non-enumberable. */
function blacklistModule(id: string) {
Object.defineProperty(metroModules, id, { enumerable: false });
blacklistedIds.add(id);
}
function isBadExports(exports: any) {
return !exports || exports === window || exports["<!@ pylix was here :fuyusquish: !@>"] === null;
}
for (const id in metroModules) {
const metroModule = metroModules[id];
@ -57,6 +47,16 @@ for (const id in metroModules) {
}
}
/** Makes the module associated with the specified ID non-enumberable. */
function blacklistModule(id: string) {
Object.defineProperty(metroModules, id, { enumerable: false });
blacklistedIds.add(id);
}
function isBadExports(exports: any) {
return !exports || exports === window || exports["<!@ pylix was here :fuyusquish: !@>"] === null;
}
function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
// Temporary
moduleExports.initSentry &&= () => undefined;
@ -136,6 +136,8 @@ export function requireModule(id: Metro.ModuleID) {
if (!metroModules[0]?.isInitialized) metroRequire(0);
if (blacklistedIds.has(String(id))) return undefined;
if (Number(id) === -1) return require("@metro/polyfills/redesign");
if (metroModules[id]?.isInitialized && !metroModules[id]?.hasError) {
return metroRequire(id);
}