perf+refactor(metro): improve polyfill impl
This commit is contained in:
parent
15deb757e4
commit
820249b6b3
10 changed files with 71 additions and 66 deletions
|
|
@ -12,7 +12,7 @@ import { lazyDestructure, proxyLazy } from "@lib/utils/lazy";
|
|||
import { Author } from "@lib/utils/types";
|
||||
import { chroma } from "@metro/common";
|
||||
import { byMutableProp } from "@metro/filters";
|
||||
import { createLazyModule } from "@metro/proxy";
|
||||
import { createLazyModule } from "@metro/lazy";
|
||||
import { findByNameProxy, findByProps, findByPropsProxy, findByStoreNameProxy } from "@metro/utils";
|
||||
import { ImageBackground, Platform, processColor } from "react-native";
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { settings } from "@lib/settings";
|
|||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { Button, CompatButton, SafeAreaView } from "@metro/common/components";
|
||||
import { _lazyContextSymbol, LazyModuleContext } from "@metro/proxy";
|
||||
import { _lazyContextSymbol, LazyModuleContext } from "@metro/lazy";
|
||||
import { findByNameProxy, findByProps } from "@metro/utils";
|
||||
import { semanticColors } from "@ui/color";
|
||||
import { Codeblock, ErrorBoundary as _ErrorBoundary } from "@ui/components";
|
||||
|
|
|
|||
|
|
@ -1,21 +1,13 @@
|
|||
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
|
||||
import { debounce } from "es-toolkit";
|
||||
|
||||
const CACHE_VERSION = 34;
|
||||
import { ModuleFlags, ModulesMapInternal } from "./enums";
|
||||
|
||||
const CACHE_VERSION = 52;
|
||||
const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key__";
|
||||
|
||||
export enum ExportsFlags {
|
||||
EXISTS = 1 << 0,
|
||||
BLACKLISTED = 1 << 1
|
||||
}
|
||||
|
||||
export enum ModulesMapInternal {
|
||||
FULL_LOOKUP,
|
||||
NOT_FOUND
|
||||
}
|
||||
|
||||
type ModulesMap = {
|
||||
[flag in number | `_${ModulesMapInternal}`]?: 0 | ExportsFlags | undefined;
|
||||
[flag in number | `_${ModulesMapInternal}`]?: ModuleFlags;
|
||||
};
|
||||
|
||||
let _metroCache = null as unknown as ReturnType<typeof buildInitCache>;
|
||||
|
|
@ -33,13 +25,13 @@ function buildInitCache() {
|
|||
assetsIndex: {} as Record<string, ModulesMap | undefined>
|
||||
} as const;
|
||||
|
||||
// Make sure all assets are cached. Delay by a second
|
||||
// Force load all modules so useful modules are pre-cached. Delay by a second
|
||||
// because force loading it all will results in an unexpected crash.
|
||||
setTimeout(() => {
|
||||
for (const id in window.modules) {
|
||||
require("@metro/modules").requireModule(id);
|
||||
}
|
||||
}, 1000);
|
||||
}, 100);
|
||||
|
||||
_metroCache = cache;
|
||||
return cache;
|
||||
|
|
@ -52,6 +44,10 @@ export async function initMetroCache() {
|
|||
|
||||
try {
|
||||
_metroCache = JSON.parse(rawCache);
|
||||
if (_metroCache._v !== CACHE_VERSION) {
|
||||
_metroCache = null!;
|
||||
throw "cache invalidated; cache version outdated";
|
||||
}
|
||||
if (_metroCache._buildNumber !== ClientInfoManager.Build) {
|
||||
_metroCache = null!;
|
||||
throw "cache invalidated; version mismatch";
|
||||
|
|
@ -70,21 +66,21 @@ const saveCache = debounce(() => {
|
|||
}, 1000);
|
||||
|
||||
function extractExportsFlags(moduleExports: any) {
|
||||
if (!moduleExports) return 0;
|
||||
if (!moduleExports) return undefined;
|
||||
|
||||
const bit = ExportsFlags.EXISTS;
|
||||
const bit = ModuleFlags.EXISTS;
|
||||
return bit;
|
||||
}
|
||||
|
||||
export function indexExportsFlags(moduleId: number, moduleExports: any) {
|
||||
const flags = extractExportsFlags(moduleExports);
|
||||
if (flags !== ExportsFlags.EXISTS) {
|
||||
if (flags && flags !== ModuleFlags.EXISTS) {
|
||||
_metroCache.exportsIndex[moduleId] = flags;
|
||||
}
|
||||
}
|
||||
|
||||
export function indexBlacklistFlag(id: number) {
|
||||
_metroCache.exportsIndex[id] |= ExportsFlags.BLACKLISTED;
|
||||
_metroCache.exportsIndex[id] |= ModuleFlags.BLACKLISTED;
|
||||
}
|
||||
|
||||
export function getCacherForUniq(uniq: string, allFind: boolean) {
|
||||
|
|
|
|||
9
src/metro/enums.ts
Normal file
9
src/metro/enums.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export enum ModuleFlags {
|
||||
EXISTS = 1 << 0,
|
||||
BLACKLISTED = 1 << 1
|
||||
}
|
||||
|
||||
export enum ModulesMapInternal {
|
||||
FULL_LOOKUP,
|
||||
NOT_FOUND
|
||||
}
|
||||
|
|
@ -9,8 +9,8 @@ function filterExports<A extends unknown[]>(
|
|||
): [any, boolean] | [void, false] {
|
||||
if (
|
||||
moduleExports.default &&
|
||||
moduleExports.__esModule &&
|
||||
filter(moduleExports.default, moduleId, true)
|
||||
moduleExports.__esModule &&
|
||||
filter(moduleExports.default, moduleId, true)
|
||||
) {
|
||||
return [filter.raw ? moduleExports : moduleExports.default, !filter.raw];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,10 @@ import { proxyLazy } from "@lib/utils/lazy";
|
|||
import { getMetroCache } from "./caches";
|
||||
import { findExports } from "./finders";
|
||||
import { metroModules, subscribeModule } from "./modules";
|
||||
import type { FilterFn } from "./types";
|
||||
import type { FilterFn, LazyModuleContext } from "./types";
|
||||
|
||||
export const _lazyContextSymbol = Symbol.for("bunny.metro.lazyContext");
|
||||
export const _lazyContexts = new WeakMap<any, LazyModuleContext<any[]>>();
|
||||
|
||||
export interface LazyModuleContext<A extends unknown[] = unknown[]> {
|
||||
filter: FilterFn<A>;
|
||||
indexed: boolean;
|
||||
moduleId?: number;
|
||||
getExports(cb: (exports: any) => void): () => void;
|
||||
subscribe(cb: (exports: any) => void): () => void;
|
||||
forceLoad(): any;
|
||||
get cache(): any;
|
||||
}
|
||||
export const _lazyContexts = new WeakMap<any, LazyModuleContext>();
|
||||
|
||||
function getIndexedFind<A extends unknown[]>(filter: FilterFn<A>) {
|
||||
const modulesMap = getMetroCache().findIndex[filter.uniq];
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { ExportsFlags, getMetroCache, indexBlacklistFlag, indexExportsFlags, ModulesMapInternal } from "@metro/caches";
|
||||
import { getMetroCache, indexBlacklistFlag, indexExportsFlags } from "@metro/caches";
|
||||
import { Metro } from "@metro/types";
|
||||
|
||||
import { ModuleFlags, ModulesMapInternal } from "./enums";
|
||||
|
||||
const { before, instead } = require("spitroast");
|
||||
|
||||
export const metroModules: Metro.ModuleList = window.modules;
|
||||
|
|
@ -21,7 +23,7 @@ for (const key in metroModules) {
|
|||
const metroModule = metroModules[id];
|
||||
|
||||
const cache = getMetroCache().exportsIndex[id];
|
||||
if (cache & ExportsFlags.BLACKLISTED) {
|
||||
if (cache & ModuleFlags.BLACKLISTED) {
|
||||
blacklistModule(id);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -175,7 +177,7 @@ export function requireModule(id: Metro.ModuleID) {
|
|||
return metroRequire(id);
|
||||
}
|
||||
|
||||
// Disable Internal Metro error reporting logic
|
||||
// Disable Internal RN error reporting logic
|
||||
const originalHandler = ErrorUtils.getGlobalHandler();
|
||||
ErrorUtils.setGlobalHandler(noopHandler);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { getPolyfillModuleCacher } from "@metro/caches";
|
||||
import { byProps } from "@metro/filters";
|
||||
import { LiteralUnion } from "type-fest";
|
||||
|
||||
const redesignProps = new Set([
|
||||
|
|
@ -100,39 +99,38 @@ const redesignProps = new Set([
|
|||
|
||||
type Keys = LiteralUnion<typeof redesignProps extends Set<infer U> ? U : string, string>;
|
||||
|
||||
const _module = {} as Record<Keys, any>;
|
||||
const _source = {} as Record<Keys, number>;
|
||||
|
||||
const cacher = getPolyfillModuleCacher("redesign_module");
|
||||
|
||||
const _module = {} as Record<Keys, any>;
|
||||
export default _module;
|
||||
for (const [id, moduleExports] of cacher.getModules()) {
|
||||
for (const prop of redesignProps) {
|
||||
let actualExports: any;
|
||||
|
||||
for (const prop of redesignProps) {
|
||||
const filter = byProps(prop);
|
||||
const candidates: any[] = [];
|
||||
if (moduleExports[prop]) {
|
||||
actualExports = moduleExports;
|
||||
} else if (moduleExports.default?.[prop]) {
|
||||
actualExports = moduleExports.default;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const [id, moduleExports] of cacher.getModules()) {
|
||||
if (filter(moduleExports, id, false)) {
|
||||
cacher.cacheId(id);
|
||||
candidates.push(moduleExports);
|
||||
} else if (
|
||||
moduleExports.__esModule
|
||||
&& moduleExports.default
|
||||
&& filter(moduleExports.default, id, false)
|
||||
) {
|
||||
cacher.cacheId(id);
|
||||
candidates.push(moduleExports.default);
|
||||
const exportsKeysLength = Reflect.ownKeys(actualExports).length;
|
||||
if (_source[prop] && exportsKeysLength >= _source[prop]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_module[prop] = actualExports[prop];
|
||||
_source[prop] = Reflect.ownKeys(actualExports).length;
|
||||
cacher.cacheId(id);
|
||||
|
||||
if (exportsKeysLength === 1) {
|
||||
redesignProps.delete(prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.length === 0) continue;
|
||||
|
||||
const bestCandidate = candidates.reduce(
|
||||
(c1, c2) =>
|
||||
(Object.keys(c2).length < Object.keys(c1).length)
|
||||
? c2
|
||||
: c1
|
||||
);
|
||||
|
||||
_module[prop] = bestCandidate[prop];
|
||||
}
|
||||
|
||||
cacher.finish();
|
||||
|
||||
export default _module;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,16 @@ export interface FilterDefinition<A extends unknown[]> {
|
|||
uniqMaker(args: A): string;
|
||||
}
|
||||
|
||||
export interface LazyModuleContext<A extends unknown[] = unknown[]> {
|
||||
filter: FilterFn<A>;
|
||||
indexed: boolean;
|
||||
moduleId?: number;
|
||||
getExports(cb: (exports: any) => void): () => void;
|
||||
subscribe(cb: (exports: any) => void): () => void;
|
||||
forceLoad(): any;
|
||||
get cache(): any;
|
||||
}
|
||||
|
||||
export interface Dispatcher {
|
||||
_actionHandlers: unknown;
|
||||
_interceptors?: ((payload: any) => void | boolean)[];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
import { byDisplayName, byFilePath, byName, byProps, byStoreName, byTypeName } from "./filters";
|
||||
import { findAllExports, findExports } from "./finders";
|
||||
import { createLazyModule } from "./proxy";
|
||||
import { createLazyModule } from "./lazy";
|
||||
import { FilterCheckDef, FilterDefinition, ModuleExports } from "./types";
|
||||
|
||||
export function createFilterDefinition<A extends unknown[]>(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue