Skip to content

Commit bd1819e

Browse files
committed
better error handling and sanitization of errors in production
1 parent 37e6ad6 commit bd1819e

File tree

5 files changed

+31
-12
lines changed

5 files changed

+31
-12
lines changed

packages/remix-react/components.tsx

+21-12
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,8 @@ export type ScriptProps = Omit<
894894
* @see https://remix.run/components/scripts
895895
*/
896896
export function Scripts(props: ScriptProps) {
897-
let { manifest, serverHandoffString, abortDelay } = useRemixContext();
897+
let { manifest, serverHandoffString, abortDelay, serializeError } =
898+
useRemixContext();
898899
let { router, static: isStatic, staticContext } = useDataRouterContext();
899900
let { matches } = useDataRouterStateContext();
900901
let navigation = useNavigation();
@@ -903,6 +904,16 @@ export function Scripts(props: ScriptProps) {
903904
isHydrated = true;
904905
}, []);
905906

907+
let serializeErrorImp = (error: unknown) => {
908+
let toSerialize: unknown;
909+
if (serializeError && error instanceof Error) {
910+
toSerialize = serializeError(error);
911+
} else {
912+
toSerialize = error;
913+
}
914+
return toSerialize;
915+
};
916+
906917
let deferredScripts: any[] = [];
907918
let initialScripts = React.useMemo(() => {
908919
let contextScript = staticContext
@@ -981,16 +992,7 @@ export function Scripts(props: ScriptProps) {
981992
} else {
982993
let trackedPromise = deferredData.data[key] as TrackedPromise;
983994
if (typeof trackedPromise._error !== "undefined") {
984-
let toSerialize: { message: string; stack?: string } =
985-
process.env.NODE_ENV === "development"
986-
? {
987-
message: trackedPromise._error.message,
988-
stack: trackedPromise._error.stack,
989-
}
990-
: {
991-
message: "Unexpected Server Error",
992-
stack: undefined,
993-
};
995+
let toSerialize = serializeErrorImp(trackedPromise._error);
994996
return `${JSON.stringify(
995997
key
996998
)}:__remixContext.p(!1, ${escapeHtml(
@@ -1008,7 +1010,14 @@ export function Scripts(props: ScriptProps) {
10081010
try {
10091011
serializedData = JSON.stringify(data);
10101012
} catch (error) {
1011-
console.error(error);
1013+
let toSerialize = serializeErrorImp(
1014+
trackedPromise._error
1015+
);
1016+
return `${JSON.stringify(
1017+
key
1018+
)}:__remixContext.p(!1, ${escapeHtml(
1019+
JSON.stringify(toSerialize)
1020+
)})`;
10121021
}
10131022
return `${JSON.stringify(
10141023
key

packages/remix-react/entry.ts

+6
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ import type { RouteManifest, EntryRoute } from "./routes";
44
import type { RouteModules } from "./routeModules";
55

66
// Object passed to RemixContext.Provider
7+
8+
type SerializedError = {
9+
message: string;
10+
stack?: string;
11+
};
712
export interface RemixContextObject {
813
manifest: AssetsManifest;
914
routeModules: RouteModules;
1015
serverHandoffString?: string;
1116
future: FutureConfig;
1217
abortDelay?: number;
1318
dev?: { port: number };
19+
serializeError?(error: Error): SerializedError;
1420
}
1521

1622
// Additional React-Router information needed at runtime, but not hydrated

packages/remix-react/server.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export function RemixServer({
4848
routeModules,
4949
serverHandoffString,
5050
future: context.future,
51+
serializeError: context.serializeError,
5152
abortDelay,
5253
}}
5354
>

packages/remix-server-runtime/entry.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { StaticHandlerContext } from "@remix-run/router";
22

3+
import type { SerializedError } from "./errors";
34
import type { RouteManifest, ServerRouteManifest, EntryRoute } from "./routes";
45
import type { RouteModules, EntryRouteModule } from "./routeModules";
56

@@ -9,6 +10,7 @@ export interface EntryContext {
910
serverHandoffString?: string;
1011
staticHandlerContext: StaticHandlerContext;
1112
future: FutureConfig;
13+
serializeError(error: Error): SerializedError;
1214
}
1315

1416
type Dev = {

packages/remix-server-runtime/server.ts

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ async function handleDocumentRequestRR(
298298
future: build.future,
299299
}),
300300
future: build.future,
301+
serializeError: (err) => serializeError(err, serverMode),
301302
};
302303

303304
let handleDocumentRequestFunction = build.entry.module.default;

0 commit comments

Comments
 (0)