fix(metro): magical fixes
This commit is contained in:
parent
ee6669f514
commit
af6ba01079
4 changed files with 41 additions and 32 deletions
|
|
@ -1,40 +1,45 @@
|
||||||
const factorySymbol = Symbol.for("bunny.lazyFactory");
|
const factorySymbol = Symbol("lazyFactory");
|
||||||
const cacheSymbol = Symbol("bunny.lazyCache");
|
const cacheSymbol = Symbol("lazyCache");
|
||||||
const dummySymbol = Symbol("bunny.lazyDummy");
|
|
||||||
|
|
||||||
const unconfigurable = ["arguments", "caller", "prototype"];
|
const unconfigurable = ["arguments", "caller", "prototype"];
|
||||||
const isUnconfigurable = (key: PropertyKey) => typeof key === "string" && unconfigurable.includes(key);
|
const isUnconfigurable = (key: PropertyKey) => typeof key === "string" && unconfigurable.includes(key);
|
||||||
|
|
||||||
const lazyHandler: ProxyHandler<any> = {
|
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 => {
|
ownKeys: target => {
|
||||||
const cacheKeys = Reflect.ownKeys(target[factorySymbol]() ?? target[dummySymbol]);
|
const cacheKeys = Reflect.ownKeys(target[factorySymbol]());
|
||||||
unconfigurable.forEach(key => isUnconfigurable(key) && cacheKeys.push(key));
|
unconfigurable.forEach(key => isUnconfigurable(key) && cacheKeys.push(key));
|
||||||
return cacheKeys;
|
return cacheKeys;
|
||||||
},
|
},
|
||||||
getOwnPropertyDescriptor: (target, p) => {
|
getOwnPropertyDescriptor: (target, p) => {
|
||||||
if (isUnconfigurable(p)) return Reflect.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);
|
if (descriptor) Object.defineProperty(target, p, descriptor);
|
||||||
return 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)
|
* 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 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
|
* @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 {
|
export function proxyLazy<T>(factory: () => T, fallback?: any): T {
|
||||||
dummy[factorySymbol] = () => dummy[cacheSymbol] ??= factory();
|
const dummy = function () { } as any;
|
||||||
dummy[dummySymbol] = dummy;
|
dummy[factorySymbol] = () => {
|
||||||
|
return (dummy[cacheSymbol] ??= factory()) ?? fallback;
|
||||||
|
};
|
||||||
|
|
||||||
return new Proxy(dummy, lazyHandler) as any;
|
return new Proxy(dummy, lazyHandler) as any;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
|
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
|
||||||
import { throttle } from "@lib/utils/throttle";
|
import { throttle } from "@lib/utils/throttle";
|
||||||
|
|
||||||
import { getCachedPolyfillModules } from "./modules";
|
|
||||||
|
|
||||||
type ModulesMap = {
|
type ModulesMap = {
|
||||||
_?: 1;
|
_?: 1;
|
||||||
[id: number]: 1 | void;
|
[id: number]: 1 | void;
|
||||||
|
|
@ -22,6 +20,7 @@ let _metroCache = null as unknown as MetroCacheStore;
|
||||||
export function getMetroCache() {
|
export function getMetroCache() {
|
||||||
return _metroCache;
|
return _metroCache;
|
||||||
}
|
}
|
||||||
|
window.getMetroCache = getMetroCache;
|
||||||
|
|
||||||
function buildInitCache() {
|
function buildInitCache() {
|
||||||
_metroCache = {
|
_metroCache = {
|
||||||
|
|
@ -59,14 +58,16 @@ export async function initMetroCache() {
|
||||||
const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache)));
|
const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache)));
|
||||||
|
|
||||||
export function getCacherForUniq(uniq: string, allFind: boolean) {
|
export function getCacherForUniq(uniq: string, allFind: boolean) {
|
||||||
const indexObject = _metroCache.findIndex[uniq] ??= {};
|
let indexObject = _metroCache.findIndex[uniq];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cacheId(moduleId: number) {
|
cacheId(moduleId: number) {
|
||||||
|
indexObject = _metroCache.findIndex[uniq] ??= {};
|
||||||
indexObject[moduleId] = 1;
|
indexObject[moduleId] = 1;
|
||||||
saveCache();
|
saveCache();
|
||||||
},
|
},
|
||||||
finish() {
|
finish() {
|
||||||
|
indexObject = _metroCache.findIndex[uniq] ??= {};
|
||||||
if (allFind) indexObject._ = 1;
|
if (allFind) indexObject._ = 1;
|
||||||
saveCache();
|
saveCache();
|
||||||
}
|
}
|
||||||
|
|
@ -74,13 +75,14 @@ export function getCacherForUniq(uniq: string, allFind: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPolyfillModuleCacher(name: string) {
|
export function getPolyfillModuleCacher(name: string) {
|
||||||
const indexObject = _metroCache.polyfillIndex[name] ??= {};
|
let indexObject = _metroCache.polyfillIndex[name];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getModules() {
|
getModules() {
|
||||||
return getCachedPolyfillModules(name);
|
return require("@metro/modules").getCachedPolyfillModules(name);
|
||||||
},
|
},
|
||||||
cacheId(moduleId: number) {
|
cacheId(moduleId: number) {
|
||||||
|
indexObject = _metroCache.polyfillIndex[name] ??= {};
|
||||||
indexObject[moduleId] = 1;
|
indexObject[moduleId] = 1;
|
||||||
saveCache();
|
saveCache();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { FilterFn } from "./types";
|
||||||
|
|
||||||
function testExports<A extends unknown[]>(moduleExports: any, moduleId: number, filter: FilterFn<A>) {
|
function testExports<A extends unknown[]>(moduleExports: any, moduleId: number, filter: FilterFn<A>) {
|
||||||
if (moduleExports.default && moduleExports.__esModule && filter(moduleExports.default, moduleId, true)) {
|
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)) {
|
if (!filter.defaultFilter && filter(moduleExports, moduleId, false)) {
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,6 @@ let patchedInspectSource = false;
|
||||||
let patchedImportTracker = false;
|
let patchedImportTracker = false;
|
||||||
let _importingModuleId: string | null = null;
|
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) {
|
for (const id in metroModules) {
|
||||||
const metroModule = metroModules[id];
|
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) {
|
function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
|
||||||
// Temporary
|
// Temporary
|
||||||
moduleExports.initSentry &&= () => undefined;
|
moduleExports.initSentry &&= () => undefined;
|
||||||
|
|
@ -136,6 +136,8 @@ export function requireModule(id: Metro.ModuleID) {
|
||||||
if (!metroModules[0]?.isInitialized) metroRequire(0);
|
if (!metroModules[0]?.isInitialized) metroRequire(0);
|
||||||
if (blacklistedIds.has(String(id))) return undefined;
|
if (blacklistedIds.has(String(id))) return undefined;
|
||||||
|
|
||||||
|
if (Number(id) === -1) return require("@metro/polyfills/redesign");
|
||||||
|
|
||||||
if (metroModules[id]?.isInitialized && !metroModules[id]?.hasError) {
|
if (metroModules[id]?.isInitialized && !metroModules[id]?.hasError) {
|
||||||
return metroRequire(id);
|
return metroRequire(id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue