Files
paseo/packages/app/metro.config.cjs
T
Mohamed Boudra 006fd053ac Record Android freezes in opt-in diagnostic builds (#7456)
* feat(app): record Android stalls in opt-in diagnostic builds

* refactor(app): own watchdog sinks and bounded log storage

* fix(app): preserve cumulative browser profiling history
2026-10-21 13:48:05 +07:00

123 lines
4.2 KiB
JavaScript

const { getDefaultConfig } = require("expo/metro-config");
const { resolve } = require("metro-resolver");
const path = require("path");
const projectRoot = __dirname;
const appNodeModulesRoot = path.resolve(projectRoot, "node_modules");
const appSrcRoot = path.resolve(projectRoot, "src");
const isWatchdogBuild = process.env.PASEO_WATCHDOG_BUILD === "1";
const isFdroidBuild = process.env.PASEO_FDROID_BUILD === "1";
const fdroidModuleOverrides = {
"expo-camera": path.resolve(appSrcRoot, "fdroid/expo-camera.tsx"),
"expo-notifications": path.resolve(appSrcRoot, "fdroid/expo-notifications.ts"),
};
const customWebPlatform = (process.env.PASEO_WEB_PLATFORM ?? "")
.trim()
.replace(/^\./, "")
.toLowerCase();
const config = getDefaultConfig(projectRoot);
config.cacheVersion = isWatchdogBuild ? "watchdog" : "standard";
const defaultResolveRequest = config.resolver.resolveRequest ?? resolve;
// Keep app exports deterministic across dev machines and CI. Metro's Watchman
// crawler behavior depends on the host Watchman build/capabilities, while the
// node crawler is the path used when Watchman is absent.
config.resolver.useWatchman = false;
const escapedAppSrcRoot = appSrcRoot
.split(path.sep)
.map((segment) => segment.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"))
.join("[\\\\/]");
const pathSeparatorPattern = "[\\\\/]";
config.resolver.extraNodeModules = {
...config.resolver.extraNodeModules,
react: path.join(appNodeModulesRoot, "react"),
"react-dom": path.join(appNodeModulesRoot, "react-dom"),
"react/jsx-runtime": path.join(appNodeModulesRoot, "react/jsx-runtime"),
"react/jsx-dev-runtime": path.join(appNodeModulesRoot, "react/jsx-dev-runtime"),
};
config.resolver.blockList = new RegExp(
`(^${escapedAppSrcRoot}${pathSeparatorPattern}.*\\.(test|spec)\\.(ts|tsx)$|${pathSeparatorPattern}__tests__${pathSeparatorPattern}.*)$`,
);
function isLocalModuleImport(moduleName) {
return (
moduleName.startsWith("./") ||
moduleName.startsWith("../") ||
moduleName.startsWith("@/") ||
path.isAbsolute(moduleName)
);
}
function resolveWithCustomWebOverlay(context, moduleName, platform) {
const shouldResolveCustomWebVariant =
platform === "web" &&
customWebPlatform.length > 0 &&
customWebPlatform !== "web" &&
isLocalModuleImport(moduleName);
if (shouldResolveCustomWebVariant) {
const overlayContext = {
...context,
// Resolve only "<custom-platform>.<ext>" variants in overlay mode.
sourceExts: context.sourceExts.map((ext) => `${customWebPlatform}.${ext}`),
preferNativePlatform: false,
};
try {
return defaultResolveRequest(overlayContext, moduleName, null);
} catch {
// Ignore overlay misses and continue with normal web resolution.
}
}
return defaultResolveRequest(context, moduleName, platform);
}
config.resolver.resolveRequest = (context, moduleName, platform) => {
if (
isWatchdogBuild &&
platform === "android" &&
/[/\\]Renderer[/\\]shims[/\\]/.test(context.originModulePath) &&
/implementations\/(ReactFabric|ReactNativeRenderer)-prod$/.test(moduleName)
) {
return defaultResolveRequest(context, moduleName.replace(/-prod$/, "-profiling"), platform);
}
if (isFdroidBuild && platform === "android" && fdroidModuleOverrides[moduleName]) {
return resolveWithCustomWebOverlay(context, fdroidModuleOverrides[moduleName], platform);
}
return resolveWithCustomWebOverlay(context, moduleName, platform);
};
if (process.env.PASEO_SERVE_SIM_PREVIEW === "1") {
const { simMiddleware } = require("serve-sim/middleware");
const originalEnhanceMiddleware = config.server?.enhanceMiddleware;
config.server = config.server ?? {};
config.server.enhanceMiddleware = (metroMiddleware, server) => {
const middleware = originalEnhanceMiddleware
? originalEnhanceMiddleware(metroMiddleware, server)
: metroMiddleware;
const serveSimulator = simMiddleware({
basePath: "/.sim",
device: process.env.PASEO_SERVE_SIM_DEVICE_UDID,
});
return (req, res, next) => {
serveSimulator(req, res, (error) => {
if (error) {
if (next) {
next(error);
return;
}
throw error;
}
middleware(req, res, next);
});
};
};
}
module.exports = config;