1import path from 'path'; 2import send from 'send'; 3import { parse } from 'url'; 4 5import { env } from '../../../utils/env'; 6import { parsePlatformHeader } from './resolvePlatform'; 7import { ServerRequest, ServerResponse } from './server.types'; 8 9const debug = require('debug')('expo:start:server:middleware:serveStatic') as typeof console.log; 10 11/** 12 * Adds support for serving the files in the static `public/` folder to web apps. 13 */ 14export class ServeStaticMiddleware { 15 constructor(private projectRoot: string) {} 16 getHandler() { 17 const publicPath = path.join(this.projectRoot, env.EXPO_PUBLIC_FOLDER); 18 19 debug(`Serving static files from:`, publicPath); 20 const opts = { 21 root: publicPath, 22 }; 23 return (req: ServerRequest, res: ServerResponse, next: any) => { 24 if (!req?.url || (req.method !== 'GET' && req.method !== 'HEAD')) { 25 return next(); 26 } 27 28 const platform = parsePlatformHeader(req); 29 // Currently this is web-only 30 if (platform && platform !== 'web') { 31 return next(); 32 } 33 34 const pathname = parse(req.url).pathname; 35 if (!pathname) { 36 return next(); 37 } 38 39 debug(`Maybe serve static:`, pathname); 40 const stream = send(req, pathname, opts); 41 42 // add file listener for fallthrough 43 let forwardError = false; 44 stream.on('file', function onFile() { 45 // once file is determined, always forward error 46 forwardError = true; 47 }); 48 49 // forward errors 50 stream.on('error', function error(err: any) { 51 if (forwardError || !(err.statusCode < 500)) { 52 next(err); 53 return; 54 } 55 56 next(); 57 }); 58 59 // pipe 60 stream.pipe(res); 61 }; 62 } 63} 64