UNPKG

3.08 kBJavaScriptView Raw
1/**
2 * react-router v8.0.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import "./mode.js";
12//#region lib/server-runtime/errors.ts
13/**
14* This thing probably warrants some explanation.
15*
16* The whole point here is to emulate componentDidCatch for server rendering and
17* data loading. It can get tricky. React can do this on component boundaries
18* but doesn't support it for server rendering or data loading. We know enough
19* with nested routes to be able to emulate the behavior (because we know them
20* statically before rendering.)
21*
22* Each route can export an `ErrorBoundary`.
23*
24* - When rendering throws an error, the nearest error boundary will render
25* (normal react componentDidCatch). This will be the route's own boundary, but
26* if none is provided, it will bubble up to the parents.
27* - When data loading throws an error, the nearest error boundary will render
28* - When performing an action, the nearest error boundary for the action's
29* route tree will render (no redirect happens)
30*
31* During normal react rendering, we do nothing special, just normal
32* componentDidCatch.
33*
34* For server rendering, we mutate `renderBoundaryRouteId` to know the last
35* layout that has an error boundary that tried to render. This emulates which
36* layout would catch a thrown error. If the rendering fails, we catch the error
37* on the server, and go again a second time with the emulator holding on to the
38* information it needs to render the same error boundary as a dynamically
39* thrown render error.
40*
41* When data loading, server or client side, we use the emulator to likewise
42* hang on to the error and re-render at the appropriate layout (where a thrown
43* error would have been caught by cDC).
44*
45* When actions throw, it all works the same. There's an edge case to be aware
46* of though. Actions normally are required to redirect, but in the case of
47* errors, we render the action's route with the emulator holding on to the
48* error. If during this render a parent route/loader throws we ignore that new
49* error and render the action's original error as deeply as possible. In other
50* words, we simply ignore the new error and use the action's error in place
51* because it came first, and that just wouldn't be fair to let errors cut in
52* line.
53*/
54function sanitizeError(error, serverMode) {
55 if (error instanceof Error && serverMode !== "development") {
56 let sanitized = /* @__PURE__ */ new Error("Unexpected Server Error");
57 sanitized.stack = void 0;
58 return sanitized;
59 }
60 return error;
61}
62function sanitizeErrors(errors, serverMode) {
63 return Object.entries(errors).reduce((acc, [routeId, error]) => {
64 return Object.assign(acc, { [routeId]: sanitizeError(error, serverMode) });
65 }, {});
66}
67function serializeError(error, serverMode) {
68 let sanitized = sanitizeError(error, serverMode);
69 return {
70 message: sanitized.message,
71 stack: sanitized.stack
72 };
73}
74//#endregion
75export { sanitizeError, sanitizeErrors, serializeError };