mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
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:
@@ -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")
|
||||
);
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -739,7 +739,7 @@ div.dropdown-menu {
|
||||
}
|
||||
|
||||
.error-message {
|
||||
white-space: "pre-wrap";
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.btn-toolbar .form-control {
|
||||
|
||||
@@ -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",
|
||||
|
||||
24
ui/v2.5/src/utils/lazyComponent.ts
Normal file
24
ui/v2.5/src/utils/lazyComponent.ts
Normal 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;
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user