Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(console): safely lazy load pages #6332

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions packages/console/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
unnamedComponents: 'arrow-function',
},
],
'react/jsx-pascal-case': ['error', { ignore: ['__Internal__*'] }],
'import/no-unused-modules': [
'error',
{
Expand All @@ -30,6 +31,8 @@ module.exports = {
'**/assets/docs/guides/*/index.ts',
'**/assets/docs/guides/*/components/**/*.tsx',
'**/mdx-components*/*/index.tsx',
'*.config.js',
'*.config.ts',
],
rules: {
'import/no-unused-modules': 'off',
Expand All @@ -49,12 +52,6 @@ module.exports = {
],
},
},
{
files: ['*.config.js', '*.config.ts', '*.d.ts'],
rules: {
'import/no-unused-modules': 'off',
},
},
{
files: ['*.d.ts'],
rules: {
Expand Down
5 changes: 3 additions & 2 deletions packages/console/src/containers/ConsoleContent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { lazy, Suspense } from 'react';
import { Suspense } from 'react';
import { useOutletContext, useRoutes } from 'react-router-dom';

import { isDevFeaturesEnabled } from '@/consts/env';
Expand All @@ -7,14 +7,15 @@ import { Daisy } from '@/ds-components/Spinner';
import Tag from '@/ds-components/Tag';
import { useConsoleRoutes } from '@/hooks/use-console-routes';
import { usePlausiblePageview } from '@/hooks/use-plausible-pageview';
import safeLazy from '@/utils/lazy';

import type { AppContentOutletContext } from '../AppContent/types';

import { Skeleton } from './Sidebar';
import useTenantScopeListener from './hooks';
import styles from './index.module.scss';

const Sidebar = lazy(async () => import('./Sidebar'));
const Sidebar = safeLazy(async () => import('./Sidebar'));

function ConsoleContent() {
const { scrollableContent } = useOutletContext<AppContentOutletContext>();
Expand Down
61 changes: 35 additions & 26 deletions packages/console/src/containers/ConsoleRoutes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ossConsolePath } from '@logto/schemas';
import { Suspense } from 'react';
import { Navigate, Outlet, Route, Routes } from 'react-router-dom';
import { SWRConfig } from 'swr';

import AppLoading from '@/components/AppLoading';
import { isCloud } from '@/consts/env';
import AppBoundary from '@/containers/AppBoundary';
import AppContent, { RedirectToFirstItem } from '@/containers/AppContent';
Expand All @@ -12,10 +14,14 @@ import { GlobalRoute } from '@/contexts/TenantsProvider';
import useSwrOptions from '@/hooks/use-swr-options';
import Callback from '@/pages/Callback';
import CheckoutSuccessCallback from '@/pages/CheckoutSuccessCallback';
import Profile from '@/pages/Profile';
import Welcome from '@/pages/Welcome';
import safeLazy from '@/utils/lazy';
import { dropLeadingSlash } from '@/utils/url';

import { __Internal__ImportError } from './internal';

const Welcome = safeLazy(async () => import('@/pages/Welcome'));
const Profile = safeLazy(async () => import('@/pages/Profile'));

function Layout() {
const swrOptions = useSwrOptions();

Expand All @@ -30,32 +36,35 @@ function Layout() {

export function ConsoleRoutes() {
return (
<Routes>
{/**
* OSS doesn't have a tenant concept nor root path handling component, but it may
* navigate to the root path in frontend. In this case, we redirect it to the OSS
* console path to trigger the console routes.
*/}
{!isCloud && <Route path="/" element={<Navigate to={ossConsolePath} />} />}
<Route path="/:tenantId" element={<Layout />}>
<Route path="callback" element={<Callback />} />
<Route path="welcome" element={<Welcome />} />
<Route element={<ProtectedRoutes />}>
<Route path={dropLeadingSlash(GlobalRoute.Profile) + '/*'} element={<Profile />} />
<Route element={<TenantAccess />}>
{isCloud && (
<Route
path={dropLeadingSlash(GlobalRoute.CheckoutSuccessCallback)}
element={<CheckoutSuccessCallback />}
/>
)}
<Route element={<AppContent />}>
<Route index element={<RedirectToFirstItem />} />
<Route path="*" element={<ConsoleContent />} />
<Suspense fallback={<AppLoading />}>
<Routes>
{/**
* OSS doesn't have a tenant concept nor root path handling component, but it may
* navigate to the root path in frontend. In this case, we redirect it to the OSS
* console path to trigger the console routes.
*/}
{!isCloud && <Route path="/" element={<Navigate to={ossConsolePath} />} />}
<Route path="/:tenantId" element={<Layout />}>
<Route path="callback" element={<Callback />} />
<Route path="welcome" element={<Welcome />} />
<Route path="__internal__/import-error" element={<__Internal__ImportError />} />
<Route element={<ProtectedRoutes />}>
<Route path={dropLeadingSlash(GlobalRoute.Profile) + '/*'} element={<Profile />} />
<Route element={<TenantAccess />}>
{isCloud && (
<Route
path={dropLeadingSlash(GlobalRoute.CheckoutSuccessCallback)}
element={<CheckoutSuccessCallback />}
/>
)}
<Route element={<AppContent />}>
<Route index element={<RedirectToFirstItem />} />
<Route path="*" element={<ConsoleContent />} />
</Route>
</Route>
</Route>
</Route>
</Route>
</Routes>
</Routes>
</Suspense>
);
}
10 changes: 10 additions & 0 deletions packages/console/src/containers/ConsoleRoutes/internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import safeLazy from '@/utils/lazy';

export const __Internal__ImportError = safeLazy(async () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const module = await import(
/* @vite-ignore */ `${window.location.origin}/some-non-existing-path`
);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return module;
});
gao-sun marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 5 additions & 4 deletions packages/console/src/hooks/use-console-routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { condArray } from '@silverhand/essentials';
import { lazy, useMemo } from 'react';
import { useMemo } from 'react';
import { type RouteObject } from 'react-router-dom';

import { isCloud } from '@/consts/env';
import NotFound from '@/pages/NotFound';
import safeLazy from '@/utils/lazy';

import { apiResources } from './routes/api-resources';
import { applications } from './routes/applications';
Expand All @@ -20,9 +21,9 @@ import { useTenantSettings } from './routes/tenant-settings';
import { users } from './routes/users';
import { webhooks } from './routes/webhooks';

const Dashboard = lazy(async () => import('@/pages/Dashboard'));
const GetStarted = lazy(async () => import('@/pages/GetStarted'));
const SigningKeys = lazy(async () => import('@/pages/SigningKeys'));
const Dashboard = safeLazy(async () => import('@/pages/Dashboard'));
const GetStarted = safeLazy(async () => import('@/pages/GetStarted'));
const SigningKeys = safeLazy(async () => import('@/pages/SigningKeys'));

export const useConsoleRoutes = () => {
const tenantSettings = useTenantSettings();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { ApiResourceDetailsTabs } from '@/consts';
import safeLazy from '@/utils/lazy';

const ApiResources = lazy(async () => import('@/pages/ApiResources'));
const ApiResourceDetails = lazy(async () => import('@/pages/ApiResourceDetails'));
const ApiResourcePermissions = lazy(
const ApiResources = safeLazy(async () => import('@/pages/ApiResources'));
const ApiResourceDetails = safeLazy(async () => import('@/pages/ApiResourceDetails'));
const ApiResourcePermissions = safeLazy(
async () => import('@/pages/ApiResourceDetails/ApiResourcePermissions')
);
const ApiResourceSettings = lazy(
const ApiResourceSettings = safeLazy(
async () => import('@/pages/ApiResourceDetails/ApiResourceSettings')
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { ApplicationDetailsTabs } from '@/consts';
import safeLazy from '@/utils/lazy';

const Applications = lazy(async () => import('@/pages/Applications'));
const ApplicationDetails = lazy(async () => import('@/pages/ApplicationDetails'));
const AuditLogDetails = lazy(async () => import('@/pages/AuditLogDetails'));
const Applications = safeLazy(async () => import('@/pages/Applications'));
const ApplicationDetails = safeLazy(async () => import('@/pages/ApplicationDetails'));
const AuditLogDetails = safeLazy(async () => import('@/pages/AuditLogDetails'));

export const applications: RouteObject = {
path: 'applications',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { lazy } from 'react';
import { type RouteObject } from 'react-router-dom';

const AuditLogs = lazy(async () => import('@/pages/AuditLogs'));
const AuditLogDetails = lazy(async () => import('@/pages/AuditLogDetails'));
import safeLazy from '@/utils/lazy';

const AuditLogs = safeLazy(async () => import('@/pages/AuditLogs'));
const AuditLogDetails = safeLazy(async () => import('@/pages/AuditLogDetails'));

export const auditLogs: RouteObject = {
path: 'audit-logs',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { lazy } from 'react';
import { Navigate } from 'react-router-dom';

import { ConnectorsTabs } from '@/consts';
import safeLazy from '@/utils/lazy';

const Connectors = lazy(async () => import('@/pages/Connectors'));
const ConnectorDetails = lazy(async () => import('@/pages/ConnectorDetails'));
const Connectors = safeLazy(async () => import('@/pages/Connectors'));
const ConnectorDetails = safeLazy(async () => import('@/pages/ConnectorDetails'));

export const connectors = {
path: 'connectors',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { lazy } from 'react';
import { type RouteObject } from 'react-router-dom';

const CustomizeJwt = lazy(async () => import('@/pages/CustomizeJwt'));
const CustomizeJwtDetails = lazy(async () => import('@/pages/CustomizeJwtDetails'));
import safeLazy from '@/utils/lazy';

const CustomizeJwt = safeLazy(async () => import('@/pages/CustomizeJwt'));
const CustomizeJwtDetails = safeLazy(async () => import('@/pages/CustomizeJwtDetails'));

export const customizeJwt: RouteObject = {
path: 'customize-jwt',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { EnterpriseSsoDetailsTabs } from '@/consts/page-tabs';
import safeLazy from '@/utils/lazy';

const EnterpriseSso = lazy(async () => import('@/pages/EnterpriseSso'));
const EnterpriseSsoDetails = lazy(async () => import('@/pages/EnterpriseSsoDetails'));
const EnterpriseSso = safeLazy(async () => import('@/pages/EnterpriseSso'));
const EnterpriseSsoDetails = safeLazy(async () => import('@/pages/EnterpriseSsoDetails'));

export const enterpriseSso: RouteObject = {
path: 'enterprise-sso',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { lazy } from 'react';
import { type RouteObject } from 'react-router-dom';

const Mfa = lazy(async () => import('@/pages/Mfa'));
import safeLazy from '@/utils/lazy';

const Mfa = safeLazy(async () => import('@/pages/Mfa'));

export const mfa: RouteObject = { path: 'mfa', element: <Mfa /> };
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { OrganizationRoleDetailsTabs, OrganizationTemplateTabs } from '@/consts';
import safeLazy from '@/utils/lazy';

const OrganizationTemplate = lazy(async () => import('@/pages/OrganizationTemplate'));
const OrganizationRoles = lazy(
const OrganizationTemplate = safeLazy(async () => import('@/pages/OrganizationTemplate'));
const OrganizationRoles = safeLazy(
async () => import('@/pages/OrganizationTemplate/OrganizationRoles')
);
const OrganizationPermissions = lazy(
const OrganizationPermissions = safeLazy(
async () => import('@/pages/OrganizationTemplate/OrganizationPermissions')
);
const OrganizationRoleDetails = lazy(async () => import('@/pages/OrganizationRoleDetails'));
const Permissions = lazy(async () => import('@/pages/OrganizationRoleDetails/Permissions'));
const Settings = lazy(async () => import('@/pages/OrganizationRoleDetails/Settings'));
const OrganizationRoleDetails = safeLazy(async () => import('@/pages/OrganizationRoleDetails'));
const Permissions = safeLazy(async () => import('@/pages/OrganizationRoleDetails/Permissions'));
const Settings = safeLazy(async () => import('@/pages/OrganizationRoleDetails/Settings'));

export const organizationTemplate: RouteObject[] = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { condArray } from '@silverhand/essentials';
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { OrganizationDetailsTabs } from '@/pages/OrganizationDetails/types';
import safeLazy from '@/utils/lazy';

const Organizations = lazy(async () => import('@/pages/Organizations'));
const OrganizationDetails = lazy(async () => import('@/pages/OrganizationDetails'));
const MachineToMachine = lazy(async () => import('@/pages/OrganizationDetails/MachineToMachine'));
const Members = lazy(async () => import('@/pages/OrganizationDetails/Members'));
const Settings = lazy(async () => import('@/pages/OrganizationDetails/Settings'));
const Organizations = safeLazy(async () => import('@/pages/Organizations'));
const OrganizationDetails = safeLazy(async () => import('@/pages/OrganizationDetails'));
const MachineToMachine = safeLazy(
async () => import('@/pages/OrganizationDetails/MachineToMachine')
);
const Members = safeLazy(async () => import('@/pages/OrganizationDetails/Members'));
const Settings = safeLazy(async () => import('@/pages/OrganizationDetails/Settings'));

export const organizations: RouteObject = {
path: 'organizations',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { lazy } from 'react';
import { type RouteObject } from 'react-router-dom';

const ChangePasswordModal = lazy(
import safeLazy from '@/utils/lazy';

const ChangePasswordModal = safeLazy(
async () => import('@/pages/Profile/containers/ChangePasswordModal')
);
const LinkEmailModal = lazy(async () => import('@/pages/Profile/containers/LinkEmailModal'));
const VerificationCodeModal = lazy(
const LinkEmailModal = safeLazy(async () => import('@/pages/Profile/containers/LinkEmailModal'));
const VerificationCodeModal = safeLazy(
async () => import('@/pages/Profile/containers/VerificationCodeModal')
);
const VerifyPasswordModal = lazy(
const VerifyPasswordModal = safeLazy(
async () => import('@/pages/Profile/containers/VerifyPasswordModal')
);

Expand Down
14 changes: 7 additions & 7 deletions packages/console/src/hooks/use-console-routes/routes/roles.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { RoleDetailsTabs } from '@/consts/page-tabs';
import safeLazy from '@/utils/lazy';

const Roles = lazy(async () => import('@/pages/Roles'));
const RoleDetails = lazy(async () => import('@/pages/RoleDetails'));
const RolePermissions = lazy(async () => import('@/pages/RoleDetails/RolePermissions'));
const RoleSettings = lazy(async () => import('@/pages/RoleDetails/RoleSettings'));
const RoleUsers = lazy(async () => import('@/pages/RoleDetails/RoleUsers'));
const RoleApplications = lazy(async () => import('@/pages/RoleDetails/RoleApplications'));
const Roles = safeLazy(async () => import('@/pages/Roles'));
const RoleDetails = safeLazy(async () => import('@/pages/RoleDetails'));
const RolePermissions = safeLazy(async () => import('@/pages/RoleDetails/RolePermissions'));
const RoleSettings = safeLazy(async () => import('@/pages/RoleDetails/RoleSettings'));
const RoleUsers = safeLazy(async () => import('@/pages/RoleDetails/RoleUsers'));
const RoleApplications = safeLazy(async () => import('@/pages/RoleDetails/RoleApplications'));

export const roles: RouteObject = {
path: 'roles',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { lazy } from 'react';
import { Navigate, type RouteObject } from 'react-router-dom';

import { SignInExperienceTab } from '@/pages/SignInExperience/types';
import safeLazy from '@/utils/lazy';

const SignInExperience = lazy(async () => import('@/pages/SignInExperience'));
const SignInExperience = safeLazy(async () => import('@/pages/SignInExperience'));

export const signInExperience: RouteObject = {
path: 'sign-in-experience',
Expand Down
Loading
Loading