1// Copyright 2023-present 650 Industries (Expo). All rights reserved. 2import { getPackageJson } from '@expo/config'; 3import { resolveEntryPoint } from '@expo/config/paths'; 4import chalk from 'chalk'; 5import path from 'path'; 6 7import { getServerRoot } from './getModulesPaths'; 8 9const debug = require('debug')('expo:metro:config:rewriteRequestUrl'); 10 11export function getRewriteRequestUrl(projectRoot: string) { 12 function rewriteExpoRequestUrl(url: string): string { 13 // Like: `/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry` 14 // Sometimes a fully qualified URL is passed in, e.g. `http://localhost:19001/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry` 15 if (url.includes('/.expo/.virtual-metro-entry.bundle?')) { 16 const ensured = url.startsWith('/') ? new URL(url, 'https://acme.dev') : new URL(url); 17 // TODO: Maybe this function could be memoized in some capacity? 18 const { search, searchParams } = ensured; 19 20 const platform = searchParams.get('platform') ?? 'web'; 21 22 debug('Rewriting magic request url to entry point', { url, platform }); 23 24 const entry = resolveEntryPoint(projectRoot, { 25 platform, 26 // @ts-ignore 27 projectConfig: { 28 pkg: getPackageJson(projectRoot), 29 }, 30 }); 31 32 if (!entry) { 33 throw new Error( 34 chalk`The project entry file could not be resolved (platform: ${platform}, root: ${projectRoot}). Define it in the {bold package.json} "main" field.` 35 ); 36 } 37 38 const serverRoot = getServerRoot(projectRoot); 39 const relativeEntry = path.relative(serverRoot, entry).replace(/\.[tj]sx?$/, ''); 40 debug('Resolved entry point', { entry, relativeEntry, serverRoot }); 41 42 // Only return the pathname when url is relative 43 if (url.startsWith('/')) { 44 // Like: `/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry` 45 return '/' + relativeEntry + '.bundle' + search; 46 } 47 48 // Modify the pathname within the URL and return the full URL 49 ensured.pathname = '/' + relativeEntry + '.bundle'; 50 // Like: `http://localhost:19001/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry` 51 return ensured.toString(); 52 } 53 54 return url; 55 } 56 return rewriteExpoRequestUrl; 57} 58