Skip to content

Commit

Permalink
[Ref/Feat] Clean up our routing and make it faster (#3540)
Browse files Browse the repository at this point in the history
* Move to createHashRouter

This brings Heroic in line with modern react-router usage and allows for some
new features

* Make Library an Index Route

* Pass `store` to WebView via params

* Lazily load all routes

The code for this is a little verbose, but it enables Vite to split code into
multiple files.

Build output before (note the large file sizes):
build/assets/index.8e7c2c97.js                       2.58 KiB / gzip:   1.01 KiB
build/assets/index.ae6fe98a.js                     564.94 KiB / gzip: 181.67 KiB
build/assets/App.63d9df39.js                      1208.01 KiB / gzip: 361.96 KiB

Build output after:
build/assets/index.4b57bd40.js                      10.33 KiB / gzip:   3.71 KiB
build/assets/index.dda1a522.js                      10.12 KiB / gzip:   3.92 KiB
build/assets/index.22363332.js                       7.89 KiB / gzip:   3.02 KiB
build/assets/index.d02459a2.js                       4.05 KiB / gzip:   1.62 KiB
build/assets/index.c7dbdf3e.js                       3.56 KiB / gzip:   1.25 KiB
build/assets/index.51987511.js                       2.63 KiB / gzip:   1.02 KiB
build/assets/index.11c6e1ab.js                      41.67 KiB / gzip:  13.69 KiB
build/assets/index.f9487201.js                     350.03 KiB / gzip: 109.55 KiB
build/assets/App.f1d932b1.js                       417.92 KiB / gzip: 125.16 KiB
build/assets/index.886bf77e.js                     385.92 KiB / gzip: 111.35 KiB
build/assets/index.55a76c73.js                     564.94 KiB / gzip: 181.67 KiB

This means that on Heroic startup, Electron has to run "only" ~570KiB of
JavaScript instead of ~1.2MiB. In my tests, this speeds up startup time by
roughly 10%

* Fixup exports
  • Loading branch information
CommandMC authored Mar 22, 2024
1 parent e374731 commit 32772c6
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 85 deletions.
155 changes: 95 additions & 60 deletions src/frontend/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import React, { useContext } from 'react'

import './App.css'
import { HashRouter, Navigate, Route, Routes } from 'react-router-dom'
import Login from './screens/Login'
import WebView from './screens/WebView'
import { GamePage } from './screens/Game'
import Library from './screens/Library'
import WineManager from './screens/WineManager'
import {
createHashRouter,
Navigate,
Outlet,
RouterProvider
} from 'react-router-dom'
import Sidebar from './components/UI/Sidebar'
import Settings from './screens/Settings'
import Accessibility from './screens/Accessibility'
import ContextProvider from './state/ContextProvider'
import { ControllerHints, Help, OfflineMessage } from './components/UI'
import DownloadManager from './screens/DownloadManager'
import DialogHandler from './components/UI/DialogHandler'
import SettingsModal from './screens/Settings/components/SettingsModal'
import ExternalLinkDialog from './components/UI/ExternalLinkDialog'
import WindowControls from './components/UI/WindowControls'
import classNames from 'classnames'

function App() {
function Root() {
const {
isSettingsModalOpen,
isRTL,
Expand All @@ -44,57 +41,95 @@ function App() {
// disable dragging for all elements by default
onDragStart={(e) => e.preventDefault()}
>
<HashRouter>
<OfflineMessage />
<Sidebar />
<main className="content">
<DialogHandler />
{isSettingsModalOpen.gameInfo && (
<SettingsModal
gameInfo={isSettingsModalOpen.gameInfo}
type={isSettingsModalOpen.type}
/>
)}
<ExternalLinkDialog />
<Routes>
<Route path="/" element={<Navigate replace to="/library" />} />
<Route path="/library" element={<Library />} />
<Route path="login" element={<Login />} />
<Route path="epicstore" element={<WebView store="epic" />} />
<Route path="gogstore" element={<WebView store="gog" />} />
<Route path="amazonstore" element={<WebView store="amazon" />} />
<Route path="wiki" element={<WebView />} />
<Route path="/gamepage">
<Route path=":runner">
<Route path=":appName" element={<GamePage />} />
</Route>
</Route>
<Route path="/store-page" element={<WebView />} />
<Route path="/last-url" element={<WebView />} />
<Route path="loginweb">
<Route path=":runner" element={<WebView />} />
</Route>
<Route path="settings">
<Route path=":runner">
<Route path=":appName">
<Route path=":type" element={<Settings />} />
</Route>
</Route>
</Route>
<Route path="/wine-manager" element={<WineManager />} />
<Route path="/download-manager" element={<DownloadManager />} />
<Route path="/accessibility" element={<Accessibility />} />
</Routes>
</main>
<div className="controller">
<ControllerHints />
<div className="simple-keyboard"></div>
</div>
{showOverlayControls && <WindowControls />}
{experimentalFeatures.enableHelp && <Help items={help.items} />}
</HashRouter>
<OfflineMessage />
<Sidebar />
<main className="content">
<DialogHandler />
{isSettingsModalOpen.gameInfo && (
<SettingsModal
gameInfo={isSettingsModalOpen.gameInfo}
type={isSettingsModalOpen.type}
/>
)}
<ExternalLinkDialog />
<Outlet />
</main>
<div className="controller">
<ControllerHints />
<div className="simple-keyboard"></div>
</div>
{showOverlayControls && <WindowControls />}
{experimentalFeatures.enableHelp && <Help items={help.items} />}
</div>
)
}

export default App
function makeLazyFunc(
importedFile: Promise<Record<'default', React.ComponentType>>
) {
return async () => {
const component = await importedFile
return { Component: component.default }
}
}

const router = createHashRouter([
{
path: '/',
element: <Root />,
children: [
{
index: true,
lazy: makeLazyFunc(import('./screens/Library'))
},
{
path: 'login',
lazy: makeLazyFunc(import('./screens/Login'))
},
{
path: 'store/:store',
lazy: makeLazyFunc(import('./screens/WebView'))
},
{
path: 'wiki',
lazy: makeLazyFunc(import('./screens/WebView'))
},
{
path: 'gamepage/:runner/:appName',
lazy: makeLazyFunc(import('./screens/Game/GamePage'))
},
{
path: 'store-page',
lazy: makeLazyFunc(import('./screens/WebView'))
},
{
path: 'loginweb/:runner',
lazy: makeLazyFunc(import('./screens/WebView'))
},
{
path: 'settings/:runner/:appName/:type',
lazy: makeLazyFunc(import('./screens/Settings'))
},
{
path: 'wine-manager',
lazy: makeLazyFunc(import('./screens/WineManager'))
},
{
path: 'download-manager',
lazy: makeLazyFunc(import('./screens/DownloadManager'))
},
{
path: 'accessibility',
lazy: makeLazyFunc(import('./screens/Accessibility'))
},
{
path: '*',
element: <Navigate replace to="/" />
}
]
}
])

export default function App() {
return <RouterProvider router={router} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ export default function SidebarLinks() {
}

// By default, open Epic Store
let defaultStore = '/epicstore'
let defaultStore = 'epic'
if (!epic.username && !gog.username && amazon.user_id) {
// If only logged in to Amazon Games, open Amazon Gaming
defaultStore = '/amazonstore'
defaultStore = 'amazon'
} else if (!epic.username && gog.username) {
// Otherwise, if not logged in to Epic Games, open GOG Store
defaultStore = '/gogstore'
defaultStore = 'gog'
}

// if we have a stored last-url, default to the `/last-url` route
Expand Down Expand Up @@ -124,7 +124,7 @@ export default function SidebarLinks() {
active: isActive || location.pathname.includes('gamepage')
})
}
to={'/library'}
to={'/'}
onClick={async () => handleRefresh()}
>
<>
Expand All @@ -141,7 +141,7 @@ export default function SidebarLinks() {
active: isActive || location.pathname.includes('store')
})
}
to={defaultStore}
to={`/store/${defaultStore}`}
>
<>
<div className="Sidebar__itemIcon">
Expand All @@ -159,7 +159,7 @@ export default function SidebarLinks() {
active: isActive
})
}
to="/epicstore"
to="/store/epic"
>
<span>{t('store', 'Epic Store')}</span>
</NavLink>
Expand All @@ -170,7 +170,7 @@ export default function SidebarLinks() {
active: isActive
})
}
to="/gogstore"
to="/store/gog"
>
<span>{t('gog-store', 'GOG Store')}</span>
</NavLink>
Expand All @@ -181,7 +181,7 @@ export default function SidebarLinks() {
active: isActive
})
}
to="/amazonstore"
to="/store/amazon"
>
<span>{t('prime-gaming', 'Prime Gaming')}</span>
</NavLink>
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/screens/Game/GamePage/components/DotsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext, useState } from 'react'
import GameContext from '../../GameContext'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { GameSubMenu } from '../..'
import GameSubMenu from '../../GameSubMenu'
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
import { GameInfo } from 'common/types'
import {
Expand Down
2 changes: 0 additions & 2 deletions src/frontend/screens/Game/index.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/frontend/screens/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default React.memo(function NewLogin() {

async function handleLibraryClick() {
await refreshLibrary({ runInBackground: false })
navigate('/library')
navigate('/')
}

return (
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/screens/Settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function Settings() {
if (!fromGameCard) {
returnPath = `/gamepage/${runner}/${appName}`
if (returnPath.includes('default')) {
returnPath = '/library'
returnPath = '/'
}
}

Expand Down
23 changes: 11 additions & 12 deletions src/frontend/screens/WebView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { useNavigate, useLocation, useParams } from 'react-router'
import { ToggleSwitch, UpdateComponent } from 'frontend/components/UI'
import WebviewControls from 'frontend/components/UI/WebviewControls'
import ContextProvider from 'frontend/state/ContextProvider'
import { Runner } from 'common/types'
import './index.css'
import LoginWarning from '../Login/components/LoginWarning'
import { NileLoginData } from 'common/types/nile'
Expand All @@ -21,11 +20,7 @@ import {
DialogHeader
} from 'frontend/components/UI/Dialog'

interface Props {
store?: 'epic' | 'gog' | 'amazon'
}

const validStoredUrl = (url: string, store: 'epic' | 'gog' | 'amazon') => {
const validStoredUrl = (url: string, store: string) => {
switch (store) {
case 'epic':
return url.includes('epicgames.com')
Expand All @@ -38,7 +33,7 @@ const validStoredUrl = (url: string, store: 'epic' | 'gog' | 'amazon') => {
}
}

export default function WebView({ store }: Props) {
export default function WebView() {
const { i18n } = useTranslation()
const { pathname, search } = useLocation()
const { t } = useTranslation()
Expand All @@ -56,6 +51,11 @@ export default function WebView({ store }: Props) {
const navigate = useNavigate()
const webviewRef = useRef<Electron.WebviewTag>(null)

// `store` is set to epic/gog/amazon depending on which storefront we're
// supposed to show, `runner` is set to a runner if we're supposed to show its
// login prompt
const { store, runner } = useParams()

let lang = i18n.language
if (i18n.language === 'pt') {
lang = 'pt-BR'
Expand All @@ -73,12 +73,11 @@ export default function WebView({ store }: Props) {
'https://auth.gog.com/auth?client_id=46899977096215655&redirect_uri=https%3A%2F%2Fembed.gog.com%2Fon_login_success%3Forigin%3Dclient&response_type=code&layout=galaxy'

const trueAsStr = 'true' as unknown as boolean | undefined
const { runner } = useParams() as { runner: Runner }

const urls: { [pathname: string]: string } = {
'/epicstore': epicStore,
'/gogstore': gogStore,
'/amazonstore': amazonStore,
'/store/epic': epicStore,
'/store/gog': gogStore,
'/store/amazon': amazonStore,
'/wiki': wikiURL,
'/loginEpic': epicLoginUrl,
'/loginGOG': gogLoginUrl,
Expand All @@ -89,7 +88,7 @@ export default function WebView({ store }: Props) {
let startUrl = urls[pathname]

if (store) {
sessionStorage.setItem('last-store', `/${store}store`)
sessionStorage.setItem('last-store', store)
const lastUrl = sessionStorage.getItem(`last-url-${store}`)
if (lastUrl && validStoredUrl(lastUrl, store)) {
startUrl = lastUrl
Expand Down

0 comments on commit 32772c6

Please sign in to comment.