Web Client Architecture
Relevant source files
The following files were used as context for generating this wiki page:
The Web Client is a modern single-page application (SPA) built with React, serving as the primary user interface for viewing and interacting with archived web pages. It is responsible for fetching data from the server backend and presenting it to the user. The client supports features like folder-based organization, searching, and different viewing modes for archived content, including a sandboxed iframe mode and a simplified "readability" mode.
The application is built using Vite and styled with Tailwind CSS. It communicates with a Hono-based server to retrieve page metadata and the archived HTML content.
Core Technologies and Dependencies
The web client is built on a modern frontend stack. The key libraries and their roles are defined in the package.json file.
| Dependency | Role | Source - React | Core UI library for building the user interface. | packages/web/package.json - @generouted/react-router | File-based routing for React, simplifying route definitions. | packages/web/package.json - react-router-dom | Core routing components for the React application. | packages/web/package.json - ahooks | A library of React Hooks, used here for data fetching (useRequest). | packages/web/src/pages/(layout)/page.[slug].tsx:2 - @mozilla/readability | Parses HTML to extract the main article content for "Read Mode". | packages/web/package.json:7 - i18next / react-i18next | Framework for internationalization (i18n). | packages/web/src/pages/(layout)/page.[slug].tsx:4 - tailwindcss | A utility-first CSS framework for styling. | packages/web/package.json
Sources: packages/web/package.json, packages/web/src/pages/(layout)/page.[slug].tsx
Application Structure
The web client is initialized from packages/web/index.html, which is a standard HTML5 document that mounts the React application into a <div id="root">.
<!-- packages/web/index.html:1-11 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="module" src="/src/index.tsx"></script>
<link rel="icon" href="/logo.svg" />
<title>Web Archive</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Sources: packages/web/index.html:1-11
Routing
The application uses @generouted/react-router for file-based routing. This means the URL structure of the application mirrors the file system layout inside packages/web/src/pages.
The diagram below illustrates the main routes and their corresponding page components.
/page/:slug: The primary route for viewing a saved page. Theslugcorresponds to the page's unique ID./showcase/page/:slug: A public-facing route to view pages that have been marked for "showcase".
Navigation and parameter access are handled by hooks like useNavigate and useParams provided by the router.
Sources: packages/web/src/pages/(layout)/page.[slug].tsx:9-10
Data Flow and State Management
Data Fetching
Data fetching from the server API is managed by the useRequest hook from the ahooks library. This hook simplifies handling loading states, errors, and caching. Data-fetching logic is abstracted into functions within packages/web/src/data/page.ts.
Key data fetching functions include:
getPageDetail(id: string): Fetches metadata for a specific page.deletePage(page: Page): Deletes a page.getPageContent(pageId: string): Fetches the raw HTML content of an archived page.
These functions make authenticated requests to the backend, attaching a JWT from localStorage to the Authorization header.
Sources: packages/web/src/data/page.ts, packages/web/src/pages/(layout)/page.[slug].tsx:13-25
API Interaction for Page Rendering
The following sequence diagram shows the process of fetching and rendering an archived page.
Global State
Global state, such as the readMode toggle, is managed via React's Context API. The AppContext provides this state to components throughout the application.
Sources: packages/web/src/pages/(layout)/page.[slug].tsx:70
Page Rendering
The web client offers two distinct modes for rendering archived content, controlled by the readMode application state.
Iframe Mode
This is the default mode. The raw HTML content of the archived page is fetched from the server and a local blob URL is created using URL.createObjectURL(). This URL is then used as the src for a sandboxed <iframe>. This approach isolates the archived page's scripts and styles, preventing them from interfering with the main application, while preserving the original look and feel of the page.
Sources: packages/web/srcsrc/pages/(layout)/page.[slug].tsx:92
Readability Mode
When "Read Mode" is enabled, the client uses the @mozilla/readability library to process the raw HTML. This library extracts the primary article content, stripping away ads, navigation bars, and other non-essential elements. The cleaned-up content is then rendered directly into the DOM, providing a simplified, clutter-free reading experience.
Sources: packages/web/package.json:7, packages/web/src/pages/(layout)/page.[slug].tsx:91
The ArchivePage component conditionally renders either ReadabilityPageContent or IframePageContent based on the readMode state.
// packages/web/src/pages/(layout)/page.[slug].tsx:90-93
<LoadingWrapper loading={pageLoading}>
{readMode
? <ReadabilityPageContent pageHtml={pageHtml || ''} />
: <IframePageContent pageContentUrl={pageContentUrl || ''} />}
</LoadingWrapper>
Sources: packages/web/src/pages/(layout)/page.[slug].tsx:90-93
Showcase Feature
The showcase provides a public view of selected archived pages. The ShowcasePage component at packages/web/src/pages/showcase/page.[slug].tsx handles this.
- It fetches public page content from the
/api/showcase/content?pageId={slug}endpoint, which does not require authentication. - It includes navigation to move to the "next" showcase page, with the logic handled by
getNextShowcasePageId. - Keyboard shortcuts (
ArrowLeft,ArrowRight) are implemented for navigation.
Sources: packages/web/srcsrc/pages/showcase/page.[slug].tsx
Internationalization (i18n)
The application supports multiple languages using react-i18next. Translation strings are stored in JSON files located in packages/web/src/assets/locales/.
Example of English translation keys:
// packages/web/src/assets/locales/en/translation.json
{
"download": "Download",
"open-iframe-mode": "open Iframe mode",
"open-read-mode": "open Read mode",
"delete-this-page-confirm": "Are you sure you want to delete this page?"
}
Sources: packages/web/src/assets/locales/en/translation.json
Summary
The web client for Web Archive is a well-structured React application that effectively separates concerns. It uses file-based routing for clarity, a robust hook-based library for asynchronous data fetching, and a flexible rendering system that offers both high-fidelity and simplified views of archived content. Its reliance on standard, popular libraries makes it maintainable and extensible.