Improve dynamic import error message (#3500)

* Improve dynamic import error message
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
DingDongSoLong4
2023-03-03 03:18:46 +02:00
committed by GitHub
parent 7b07810c12
commit 381486904b
10 changed files with 111 additions and 54 deletions

View File

@@ -1,4 +1,4 @@
import React, { lazy, Suspense, useEffect, useState } from "react";
import React, { Suspense, useEffect, useState } from "react";
import { Route, Switch, useRouteMatch } from "react-router-dom";
import { IntlProvider, CustomFormats } from "react-intl";
import { Helmet } from "react-helmet";
@@ -31,25 +31,32 @@ import { ReleaseNotesDialog } from "./components/Dialogs/ReleaseNotesDialog";
import { IUIConfig } from "./core/config";
import { releaseNotes } from "./docs/en/ReleaseNotes";
import { getPlatformURL, getBaseURL } from "./core/createClient";
import { lazyComponent } from "./utils/lazyComponent";
const Performers = lazy(() => import("./components/Performers/Performers"));
const FrontPage = lazy(() => import("./components/FrontPage/FrontPage"));
const Scenes = lazy(() => import("./components/Scenes/Scenes"));
const Settings = lazy(() => import("./components/Settings/Settings"));
const Stats = lazy(() => import("./components/Stats"));
const Studios = lazy(() => import("./components/Studios/Studios"));
const Galleries = lazy(() => import("./components/Galleries/Galleries"));
const Performers = lazyComponent(
() => import("./components/Performers/Performers")
);
const FrontPage = lazyComponent(
() => import("./components/FrontPage/FrontPage")
);
const Scenes = lazyComponent(() => import("./components/Scenes/Scenes"));
const Settings = lazyComponent(() => import("./components/Settings/Settings"));
const Stats = lazyComponent(() => import("./components/Stats"));
const Studios = lazyComponent(() => import("./components/Studios/Studios"));
const Galleries = lazyComponent(
() => import("./components/Galleries/Galleries")
);
const Movies = lazy(() => import("./components/Movies/Movies"));
const Tags = lazy(() => import("./components/Tags/Tags"));
const Images = lazy(() => import("./components/Images/Images"));
const Setup = lazy(() => import("./components/Setup/Setup"));
const Migrate = lazy(() => import("./components/Setup/Migrate"));
const Movies = lazyComponent(() => import("./components/Movies/Movies"));
const Tags = lazyComponent(() => import("./components/Tags/Tags"));
const Images = lazyComponent(() => import("./components/Images/Images"));
const Setup = lazyComponent(() => import("./components/Setup/Setup"));
const Migrate = lazyComponent(() => import("./components/Setup/Migrate"));
const SceneFilenameParser = lazy(
const SceneFilenameParser = lazyComponent(
() => import("./components/SceneFilenameParser/SceneFilenameParser")
);
const SceneDuplicateChecker = lazy(
const SceneDuplicateChecker = lazyComponent(
() => import("./components/SceneDuplicateChecker/SceneDuplicateChecker")
);

View File

@@ -1,4 +1,6 @@
import React from "react";
import { FormattedMessage } from "react-intl";
import { isLazyComponentError } from "src/utils/lazyComponent";
interface IErrorBoundaryProps {
children?: React.ReactNode;
@@ -10,6 +12,7 @@ type ErrorInfo = {
interface IErrorBoundaryState {
error?: Error;
errorHelpId?: string;
errorInfo?: ErrorInfo;
}
@@ -23,22 +26,35 @@ export class ErrorBoundary extends React.Component<
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
let errorHelpId: string | undefined;
if (isLazyComponentError(error)) {
errorHelpId = "errors.lazy_component_error_help";
}
this.setState({
error,
errorHelpId,
errorInfo,
});
}
public render() {
if (this.state.errorInfo) {
const { error, errorHelpId, errorInfo } = this.state;
if (errorInfo) {
// Error path
return (
<div>
<h2>Something went wrong.</h2>
<h2>
<FormattedMessage id="errors.something_went_wrong" />
</h2>
{errorHelpId && (
<h5>
<FormattedMessage id={errorHelpId} />
</h5>
)}
<details className="error-message">
{this.state.error && this.state.error.toString()}
{error?.toString()}
<br />
{this.state.errorInfo.componentStack}
{errorInfo.componentStack.trim().replaceAll(/^\s*/gm, " ")}
</details>
</div>
);

View File

@@ -1,6 +1,7 @@
import React, { lazy, Suspense, useState } from "react";
import React, { Suspense, useState } from "react";
import { lazyComponent } from "src/utils/lazyComponent";
const Manual = lazy(() => import("./Manual"));
const Manual = lazyComponent(() => import("./Manual"));
interface IManualContextState {
openManual: (tab?: string) => void;

View File

@@ -1,12 +1,5 @@
import { Tab, Nav, Dropdown, Button, ButtonGroup } from "react-bootstrap";
import React, {
useEffect,
useState,
useMemo,
useContext,
lazy,
useRef,
} from "react";
import React, { useEffect, useState, useMemo, useContext, useRef } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useParams, useLocation, useHistory, Link } from "react-router-dom";
import { Helmet } from "react-helmet";
@@ -36,29 +29,38 @@ import { OrganizedButton } from "./OrganizedButton";
import { ConfigurationContext } from "src/hooks/Config";
import { getPlayerPosition } from "src/components/ScenePlayer/util";
import { faEllipsisV } from "@fortawesome/free-solid-svg-icons";
import { lazyComponent } from "src/utils/lazyComponent";
const SubmitStashBoxDraft = lazy(
const SubmitStashBoxDraft = lazyComponent(
() => import("src/components/Dialogs/SubmitDraft")
);
const ScenePlayer = lazy(
const ScenePlayer = lazyComponent(
() => import("src/components/ScenePlayer/ScenePlayer")
);
const GalleryViewer = lazy(
const GalleryViewer = lazyComponent(
() => import("src/components/Galleries/GalleryViewer")
);
const ExternalPlayerButton = lazy(() => import("./ExternalPlayerButton"));
const ExternalPlayerButton = lazyComponent(
() => import("./ExternalPlayerButton")
);
const QueueViewer = lazy(() => import("./QueueViewer"));
const SceneMarkersPanel = lazy(() => import("./SceneMarkersPanel"));
const SceneFileInfoPanel = lazy(() => import("./SceneFileInfoPanel"));
const SceneEditPanel = lazy(() => import("./SceneEditPanel"));
const SceneDetailPanel = lazy(() => import("./SceneDetailPanel"));
const SceneMoviePanel = lazy(() => import("./SceneMoviePanel"));
const SceneGalleriesPanel = lazy(() => import("./SceneGalleriesPanel"));
const DeleteScenesDialog = lazy(() => import("../DeleteScenesDialog"));
const GenerateDialog = lazy(() => import("../../Dialogs/GenerateDialog"));
const SceneVideoFilterPanel = lazy(() => import("./SceneVideoFilterPanel"));
const QueueViewer = lazyComponent(() => import("./QueueViewer"));
const SceneMarkersPanel = lazyComponent(() => import("./SceneMarkersPanel"));
const SceneFileInfoPanel = lazyComponent(() => import("./SceneFileInfoPanel"));
const SceneEditPanel = lazyComponent(() => import("./SceneEditPanel"));
const SceneDetailPanel = lazyComponent(() => import("./SceneDetailPanel"));
const SceneMoviePanel = lazyComponent(() => import("./SceneMoviePanel"));
const SceneGalleriesPanel = lazyComponent(
() => import("./SceneGalleriesPanel")
);
const DeleteScenesDialog = lazyComponent(() => import("../DeleteScenesDialog"));
const GenerateDialog = lazyComponent(
() => import("../../Dialogs/GenerateDialog")
);
const SceneVideoFilterPanel = lazyComponent(
() => import("./SceneVideoFilterPanel")
);
import { objectPath, objectTitle } from "src/core/files";
interface IProps {

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState, useMemo, lazy } from "react";
import React, { useEffect, useState, useMemo } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import {
Button,
@@ -50,9 +50,10 @@ import {
import { objectTitle } from "src/core/files";
import { galleryTitle } from "src/core/galleries";
import { useRatingKeybinds } from "src/hooks/keybinds";
import { lazyComponent } from "src/utils/lazyComponent";
const SceneScrapeDialog = lazy(() => import("./SceneScrapeDialog"));
const SceneQueryModal = lazy(() => import("./SceneQueryModal"));
const SceneScrapeDialog = lazyComponent(() => import("./SceneScrapeDialog"));
const SceneQueryModal = lazyComponent(() => import("./SceneQueryModal"));
interface IProps {
scene: Partial<GQL.SceneDataFragment>;

View File

@@ -1,14 +1,15 @@
import React, { lazy } from "react";
import React from "react";
import { Route, Switch } from "react-router-dom";
import { useIntl } from "react-intl";
import { Helmet } from "react-helmet";
import { TITLE_SUFFIX } from "src/components/Shared/constants";
import { PersistanceLevel } from "src/hooks/ListHook";
import { lazyComponent } from "src/utils/lazyComponent";
const SceneList = lazy(() => import("./SceneList"));
const SceneMarkerList = lazy(() => import("./SceneMarkerList"));
const Scene = lazy(() => import("./SceneDetails/Scene"));
const SceneCreate = lazy(() => import("./SceneDetails/SceneCreate"));
const SceneList = lazyComponent(() => import("./SceneList"));
const SceneMarkerList = lazyComponent(() => import("./SceneMarkerList"));
const Scene = lazyComponent(() => import("./SceneDetails/Scene"));
const SceneCreate = lazyComponent(() => import("./SceneDetails/SceneCreate"));
const Scenes: React.FC = () => {
const intl = useIntl();

View File

@@ -1,7 +1,8 @@
import React, { lazy, Suspense, useCallback, useState } from "react";
import React, { Suspense, useCallback, useState } from "react";
import { lazyComponent } from "src/utils/lazyComponent";
import { ILightboxImage } from "./types";
const LightboxComponent = lazy(() => import("./Lightbox"));
const LightboxComponent = lazyComponent(() => import("./Lightbox"));
export interface IState {
images: ILightboxImage[];

View File

@@ -739,7 +739,7 @@ div.dropdown-menu {
}
.error-message {
white-space: "pre-wrap";
white-space: pre-wrap;
}
.btn-toolbar .form-control {

View File

@@ -840,6 +840,10 @@
"warmth": "Warmth"
},
"empty_server": "Add some scenes to your server to view recommendations on this page.",
"errors": {
"something_went_wrong": "Something went wrong.",
"lazy_component_error_help": "If you recently upgraded Stash, please reload the page or clear your browser cache."
},
"ethnicity": "Ethnicity",
"existing_value": "existing value",
"eye_color": "Eye Colour",

View File

@@ -0,0 +1,24 @@
import { ComponentType, lazy } from "react";
interface ILazyComponentError {
__lazyComponentError?: true;
}
export const isLazyComponentError = (e: unknown) => {
return !!(e as ILazyComponentError).__lazyComponentError;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const lazyComponent = <T extends ComponentType<any>>(
factory: Parameters<typeof lazy<T>>[0]
) => {
return lazy<T>(async () => {
try {
return await factory();
} catch (e) {
// set flag to identify lazy component loading errors
(e as ILazyComponentError).__lazyComponentError = true;
throw e;
}
});
};