1import { getConfig } from '@expo/config'; 2import { generateFaviconAsync, generateImageAsync } from '@expo/image-utils'; 3import fs from 'fs'; 4import path from 'path'; 5 6import { getUserDefinedFile } from './publicFolder'; 7 8const debug = require('debug')('expo:favicon') as typeof console.log; 9 10/** @returns the file system path for a user-defined favicon.ico file in the public folder. */ 11export function getUserDefinedFaviconFile(projectRoot: string): string | null { 12 return getUserDefinedFile(projectRoot, ['./favicon.ico']); 13} 14 15export async function getVirtualFaviconAssetsAsync( 16 projectRoot: string, 17 outputDir: string 18): Promise<((html: string) => string) | null> { 19 const existing = getUserDefinedFaviconFile(projectRoot); 20 if (existing) { 21 debug('Using user-defined favicon.ico file.'); 22 return null; 23 } 24 25 const data = await getFaviconFromExpoConfigAsync(projectRoot); 26 27 if (!data) { 28 return null; 29 } 30 31 await Promise.all( 32 [data].map((asset) => { 33 const assetPath = path.join(outputDir, asset.path); 34 debug('Writing asset to disk: ' + assetPath); 35 return fs.promises.writeFile(assetPath, asset.source); 36 }) 37 ); 38 39 return injectFaviconTag; 40} 41 42function injectFaviconTag(html: string): string { 43 if (!html.includes('</head>')) { 44 return html; 45 } 46 return html.replace('</head>', `<link rel="shortcut icon" href="/favicon.ico" /></head>`); 47} 48 49export async function getFaviconFromExpoConfigAsync(projectRoot: string) { 50 const { exp } = getConfig(projectRoot); 51 52 const src = exp.web?.favicon ?? null; 53 if (!src) { 54 return null; 55 } 56 57 const dims = [16, 32, 48]; 58 const cacheType = 'favicon'; 59 60 const size = dims[dims.length - 1]; 61 const { source } = await generateImageAsync( 62 { projectRoot, cacheType }, 63 { 64 resizeMode: 'contain', 65 src, 66 backgroundColor: 'transparent', 67 width: size, 68 height: size, 69 name: `favicon-${size}.png`, 70 } 71 ); 72 73 const faviconBuffer = await generateFaviconAsync(source, dims); 74 75 return { source: faviconBuffer, path: 'favicon.ico' }; 76} 77