// Learn more https://docs.expo.io/guides/customizing-metro const { getDefaultConfig } = require("expo/metro-config"); const path = require("node:path"); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); // ======================================================= // STREAMYFIN METRO CONFIG - PERFORMANCE OPTIMIZED 🚀 // ======================================================= // Advanced configuration for multi-platform Jellyfin client // Optimized for media streaming, TV support, and Bun // ======================================================= // HERMES + ADVANCED PERFORMANCE // ============================== config.transformer.hermesParser = true; // CPU optimization (your existing setting) const os = require("node:os"); config.maxWorkers = Math.max(1, os.cpus().length - 1); // JAVASCRIPT OPTIMIZATION (Safe & Stable) // ======================================== config.transformer = { ...config.transformer, hermesParser: true, // NEW: Inline requires for 15-30% startup improvement inlineRequires: true, // ADVANCED: Hermes-optimized minification for streaming apps minifierConfig: { mangle: { keep_fnames: process.env.NODE_ENV === "development", }, output: { ascii_only: true, beautify: false, semicolons: false, }, compress: { // Production-only optimizations drop_console: process.env.NODE_ENV === "production", dead_code: true, drop_debugger: true, conditionals: true, evaluate: true, unused: true, reduce_vars: true, // Keep class names for error reporting keep_classnames: true, // Preserve function names for performance profiling in dev keep_fnames: process.env.NODE_ENV === "development", }, }, }; // RESOLVER OPTIMIZATIONS ENHANCED // =============================== config.resolver = { ...config.resolver, // NEW: Package exports (stable in recent Metro) unstable_enablePackageExports: true, // ENHANCED: Extensions optimized for Streamyfin assetExts: [ ...config.resolver.assetExts, // Video formats (enhanced for Jellyfin) "mkv", "mp4", "avi", "mov", "wmv", "flv", "webm", "m4v", "mpg", "mpeg", // Audio formats "mp3", "wav", "flac", "aac", "m4a", "ogg", "wma", "opus", // Subtitle files (complete for media) "srt", "vtt", "ass", "ssa", "sub", "idx", "sbv", "ttml", // Database/Cache "db", "sqlite", "realm", "json5", // Fonts (TV optimized) "woff2", "woff", "eot", "otf", // Images (enhanced for thumbnails) "avif", "heic", "heif", // Modern formats ], sourceExts: [ ...config.resolver.sourceExts, "mjs", "cjs", // Modern JS support ], // NEW: Platform prioritization for performance platforms: ["ios", "android", "native", "web", "tv"], }; // SERIALIZER OPTIMIZATIONS (Production) // ==================================== if (process.env.NODE_ENV === "production") { config.serializer = { ...config.serializer, // NEW: Module IDs optimized for caching createModuleIdFactory: () => { return (path) => { // Shorter module IDs for smaller bundles return require("node:crypto") .createHash("sha1") .update(path) .digest("hex") .substring(0, 8); }; }, // NEW: Bundle pre-loading for streaming apps getModulesRunBeforeMainModule: (_entryFilePath) => [ // Pre-load critical modules for faster TTI require.resolve("react-native/Libraries/Core/InitializeCore"), ], // Web bundle splitting (if applicable) ...(process.env.EXPO_PLATFORM === "web" && { // Experimental code splitting for web experimentalSerializerHook: () => {}, }), }; } // TV PLATFORM ENHANCEMENTS // ======================== if (process.env?.EXPO_TV === "1") { const originalSourceExts = config.resolver.sourceExts; const tvSourceExts = [ ...originalSourceExts.map((ext) => `tv.${ext}`), ...originalSourceExts, ]; config.resolver.sourceExts = tvSourceExts; // NEW: TV-specific optimizations config.transformer = { ...config.transformer, // Optimize transforms for TV hardware experimentalImportSupport: false, // Reduce complexity on TV // Use legacy transformer for better TV compatibility allowOptionalDependencies: true, }; console.log("đŸ“ē TV platform optimized for Streamyfin"); console.log(`📁 TV extensions: ${tvSourceExts.slice(0, 6).join(", ")}...`); } // DEVELOPMENT ENHANCEMENTS // ======================== if (process.env.NODE_ENV === "development") { // NEW: Enhanced error reporting config.reporter = { update: (event) => { if (event.type === "bundle_build_failed") { console.error( "🔴 Streamyfin Bundle Build Failed:", event.error.message, ); } else if (event.type === "bundle_build_done") { console.log( "✅ Streamyfin Bundle Ready:", event.bundleDetails?.bundleSize || "Unknown size", ); } }, }; console.log("🚀 Streamyfin Metro Config - OPTIMIZED VERSION"); console.log(`đŸ“Ļ Workers: ${config.maxWorkers}`); console.log(`đŸŽ¯ Hermes: ${config.transformer.hermesParser}`); console.log(`⚡ Inline requires: ${config.transformer.inlineRequires}`); console.log( `đŸ“ē TV support: ${process.env.EXPO_TV === "1" ? "ENABLED" : "DISABLED"}`, ); } // STREAMING APP SPECIFIC OPTIMIZATIONS // =================================== // NEW: Cache hints for better performance if (typeof config.cacheStores === "undefined") { // Only add if not causing issues try { const MetroCache = require("metro-cache"); config.cacheStores = [ new MetroCache.FileStore({ root: path.join(os.tmpdir(), "streamyfin-metro-cache"), }), ]; } catch (_e) { // Fallback: use default cache console.log("â„šī¸ Using default Metro cache (custom cache not available)"); } } // NEW: Network request optimizations for streaming config.server = { ...config.server, // Enhanced request handling for media assets enhanceMiddleware: (middleware, _server) => { // Add caching headers for static assets return (req, res, next) => { if (req.url?.match(/\.(mp4|mkv|jpg|jpeg|png|webp)$/)) { res.setHeader("Cache-Control", "public, max-age=31536000"); } return middleware(req, res, next); }; }, }; module.exports = config;