Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
[dev-server][xdl] suppress remote debugging EISDIR error (#3889)
Browse files Browse the repository at this point in the history
# Why

facebook/react-native#28844

# How

prepending a middleware in metro and return 404 for `/debugger-ui/*.map` requests

# Test Plan

initialize a sdk43 project. launch app, enable remote debugging and open inspector. seeing if there are EISDIR errors.
  • Loading branch information
Kudo committed Oct 19, 2021
1 parent 78e0a24 commit 7874392
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 21 deletions.
1 change: 1 addition & 0 deletions packages/dev-server/src/MetroDevServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,4 @@ export function attachInspectorProxy(
}

export { LogReporter, createDevServerMiddleware };
export * from './middlwareMutations';
4 changes: 3 additions & 1 deletion packages/dev-server/src/middleware/devServerMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
import bodyParser from 'body-parser';
import type { Server as ConnectServer } from 'connect';

import { prependMiddleware, replaceMiddlewareWith } from '../middlwareMutations';
import clientLogsMiddleware from './clientLogsMiddleware';
import createJsInspectorMiddleware from './createJsInspectorMiddleware';
import { remoteDevtoolsCorsMiddleware } from './remoteDevtoolsCorsMiddleware';
import { remoteDevtoolsSecurityHeadersMiddleware } from './remoteDevtoolsSecurityHeadersMiddleware';
import { replaceMiddlewareWith } from './replaceMiddlewareWith';
import { suppressRemoteDebuggingErrorMiddleware } from './suppressErrorMiddleware';

export type AttachToServerFunction = ReturnType<
typeof createReactNativeDevServerMiddleware
Expand Down Expand Up @@ -54,6 +55,7 @@ export function createDevServerMiddleware({
remoteDevtoolsSecurityHeadersMiddleware
);
middleware.use(remoteDevtoolsCorsMiddleware);
prependMiddleware(middleware, suppressRemoteDebuggingErrorMiddleware);

middleware.use(bodyParser.json());
middleware.use('/logs', clientLogsMiddleware(logger));
Expand Down
12 changes: 0 additions & 12 deletions packages/dev-server/src/middleware/replaceMiddlewareWith.ts

This file was deleted.

17 changes: 17 additions & 0 deletions packages/dev-server/src/middleware/suppressErrorMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { IncomingMessage, ServerResponse } from 'http';

// Middleware to suppress `EISDIR` error when opening javascript inspector in remote debugging.
// A workaround for https://github.com/facebook/react-native/issues/28844
// The root cause is that metro cannot serve sourcemap requests for /debugger-ui/
export function suppressRemoteDebuggingErrorMiddleware(
req: IncomingMessage,
res: ServerResponse,
next: (err?: Error) => void
) {
if (req.url?.match(/\/debugger-ui\/.+\.map$/)) {
res.writeHead(404);
res.end('Sourcemap for /debugger-ui/ is not supported.');
return;
}
next();
}
30 changes: 30 additions & 0 deletions packages/dev-server/src/middlwareMutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Server as ConnectServer, HandleFunction } from 'connect';

/**
* Prepends a `middleware` to current server middleware stack.
*
* @param app connect app server instance
* @param middleware target middleware to be prepended
*/
export function prependMiddleware(app: ConnectServer, middleware: HandleFunction) {
app.use(middleware);
app.stack.unshift(app.stack.pop()!);
}

/**
* Replaces source middleware with a new middlware in connect app
*
* @param app connect app server instance
* @param sourceMiddleware source middlware to be matched and replaces
* @param targetMiddleware new middlware
*/
export function replaceMiddlewareWith(
app: ConnectServer,
sourceMiddleware: HandleFunction,
targetMiddleware: HandleFunction
) {
const item = app.stack.find(middleware => middleware.handle === sourceMiddleware);
if (item) {
item.handle = targetMiddleware;
}
}
20 changes: 12 additions & 8 deletions packages/xdl/src/start/startDevServerAsync.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ExpoConfig, getConfig, ProjectTarget } from '@expo/config';
import { MessageSocket, MetroDevServerOptions, runMetroDevServerAsync } from '@expo/dev-server';
import {
MessageSocket,
MetroDevServerOptions,
prependMiddleware,
runMetroDevServerAsync,
} from '@expo/dev-server';
import http from 'http';

import {
Expand Down Expand Up @@ -70,19 +75,18 @@ export async function startDevServerAsync(
startOptions.forceManifestType === 'expo-updates' ||
(startOptions.forceManifestType !== 'classic' && easProjectId);

if (useExpoUpdatesManifest) {
middleware.use(ExpoUpdatesManifestHandler.getManifestHandler(projectRoot));
} else {
middleware.use(ManifestHandler.getManifestHandler(projectRoot));
}

// We need the manifest handler to be the first middleware to run so our
// routes take precedence over static files. For example, the manifest is
// served from '/' and if the user has an index.html file in their project
// then the manifest handler will never run, the static middleware will run
// and serve index.html instead of the manifest.
// https://github.com/expo/expo/issues/13114
middleware.stack.unshift(middleware.stack.pop());
prependMiddleware(
middleware,
useExpoUpdatesManifest
? ExpoUpdatesManifestHandler.getManifestHandler(projectRoot)
: ManifestHandler.getManifestHandler(projectRoot)
);

return [server, middleware, messageSocket];
}

0 comments on commit 7874392

Please sign in to comment.