|  | 
|  | 1 | +--- | 
|  | 2 | +title: Client Architecture | 
|  | 3 | +description: Understanding how the CodeHarborHub client system works | 
|  | 4 | +--- | 
|  | 5 | + | 
|  | 6 | +The **client architecture** of CodeHarborHub (built on Docusaurus) defines how the front-end interacts with React components, themes, and client-side modules. It focuses on modularity, performance, and extensibility — allowing you to customize your learning platform’s UI and logic. | 
|  | 7 | + | 
|  | 8 | +--- | 
|  | 9 | + | 
|  | 10 | +## Theme Aliases {#theme-aliases} | 
|  | 11 | + | 
|  | 12 | +Themes in CodeHarborHub work by exporting a set of **React components** such as `Navbar`, `Layout`, and `Footer`. These components render structured data provided by plugins.   | 
|  | 13 | + | 
|  | 14 | +They are imported using the Webpack alias `@theme`: | 
|  | 15 | + | 
|  | 16 | +```js | 
|  | 17 | +import Navbar from '@theme/Navbar'; | 
|  | 18 | +``` | 
|  | 19 | + | 
|  | 20 | +### How it works | 
|  | 21 | + | 
|  | 22 | +The `@theme` alias points to several possible directories in this order of priority: | 
|  | 23 | + | 
|  | 24 | +1. `website/src/theme` — The **user’s custom theme directory** (highest priority).   | 
|  | 25 | +2. `node_modules/@docusaurus/theme-*` — Theme package components.   | 
|  | 26 | +3. Core fallback components provided by Docusaurus (least used).   | 
|  | 27 | + | 
|  | 28 | +This creates a **layered architecture** — higher layers override lower ones.   | 
|  | 29 | +For example: | 
|  | 30 | + | 
|  | 31 | +``` | 
|  | 32 | +website | 
|  | 33 | +├── node_modules | 
|  | 34 | +│   └── @docusaurus/theme-classic | 
|  | 35 | +│       └── theme | 
|  | 36 | +│           └── Navbar.js | 
|  | 37 | +└── src | 
|  | 38 | +    └── theme | 
|  | 39 | +        └── Navbar.js | 
|  | 40 | +``` | 
|  | 41 | + | 
|  | 42 | +Here, `website/src/theme/Navbar.js` takes precedence whenever you import `@theme/Navbar`. This concept is known as **swizzling** — overriding or extending existing components. | 
|  | 43 | + | 
|  | 44 | +### Wrapping and Extending Components | 
|  | 45 | + | 
|  | 46 | +If you want to extend a theme component instead of replacing it, use: | 
|  | 47 | + | 
|  | 48 | +- `@theme-original` — Imports the next component down the stack. | 
|  | 49 | +- `@theme-init` — Imports the base implementation from the original theme. | 
|  | 50 | + | 
|  | 51 | +Example: enhancing a `CodeBlock` component with a live playground: | 
|  | 52 | + | 
|  | 53 | +```js | 
|  | 54 | +import InitialCodeBlock from '@theme-init/CodeBlock'; | 
|  | 55 | +import React from 'react'; | 
|  | 56 | +import ReactLivePlayground from '@theme/ReactLivePlayground'; | 
|  | 57 | + | 
|  | 58 | +export default function CodeBlock(props) { | 
|  | 59 | +  return props.live ? ( | 
|  | 60 | +    <ReactLivePlayground {...props} /> | 
|  | 61 | +  ) : ( | 
|  | 62 | +    <InitialCodeBlock {...props} /> | 
|  | 63 | +  ); | 
|  | 64 | +} | 
|  | 65 | +``` | 
|  | 66 | + | 
|  | 67 | +:::warning | 
|  | 68 | +Unless you’re building a reusable theme (like `@docusaurus/theme-live-codeblock`), you won’t usually need `@theme-init`. | 
|  | 69 | +::: | 
|  | 70 | + | 
|  | 71 | +### Visualization of Theme Stack | 
|  | 72 | + | 
|  | 73 | +Internally, CodeHarborHub loads components as a “stack” of layers: | 
|  | 74 | + | 
|  | 75 | +```text | 
|  | 76 | ++-------------------------------------------------+ | 
|  | 77 | +|        website/src/theme/CodeBlock.js           | <-- @theme/CodeBlock | 
|  | 78 | ++-------------------------------------------------+ | 
|  | 79 | +| theme-live-codeblock/theme/CodeBlock/index.js   | <-- @theme-original/CodeBlock | 
|  | 80 | ++-------------------------------------------------+ | 
|  | 81 | +| plugin-awesome-codeblock/theme/CodeBlock.js     | | 
|  | 82 | ++-------------------------------------------------+ | 
|  | 83 | +| theme-classic/theme/CodeBlock/index.js          | <-- @theme-init/CodeBlock | 
|  | 84 | ++-------------------------------------------------+ | 
|  | 85 | +``` | 
|  | 86 | + | 
|  | 87 | +The **site layer** (`src/theme`) always takes precedence since it’s loaded last. | 
|  | 88 | + | 
|  | 89 | +--- | 
|  | 90 | + | 
|  | 91 | +## Client Modules {#client-modules} | 
|  | 92 | + | 
|  | 93 | +Client modules are **global scripts or styles** that run before React renders your site. They include JS and CSS that modify global state, register event listeners, or add global styling. | 
|  | 94 | + | 
|  | 95 | +Under the hood: | 
|  | 96 | + | 
|  | 97 | +```js title="@docusaurus/core/App.tsx" | 
|  | 98 | +import '@generated/client-modules'; | 
|  | 99 | +``` | 
|  | 100 | + | 
|  | 101 | +### Declaring Client Modules | 
|  | 102 | + | 
|  | 103 | +Plugins and sites can declare client modules using: | 
|  | 104 | + | 
|  | 105 | +- [`getClientModules`](https://docusaurus.io/docs/api/plugin-methods/lifecycle-apis#getClientModules) | 
|  | 106 | +- [`siteConfig.clientModules`](https://docusaurus.io/docs/api/docusaurus-config#clientModules) | 
|  | 107 | + | 
|  | 108 | +These modules are imported globally and executed both during server-side rendering (SSR) and client-side hydration. | 
|  | 109 | + | 
|  | 110 | +Example of a client-side script: | 
|  | 111 | + | 
|  | 112 | +```js title="mySiteGlobalJs.js" | 
|  | 113 | +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; | 
|  | 114 | + | 
|  | 115 | +if (ExecutionEnvironment.canUseDOM) { | 
|  | 116 | +  window.addEventListener('keydown', (e) => { | 
|  | 117 | +    if (e.code === 'Period') { | 
|  | 118 | +      location.assign(location.href.replace('.com', '.dev')); | 
|  | 119 | +    } | 
|  | 120 | +  }); | 
|  | 121 | +} | 
|  | 122 | +``` | 
|  | 123 | + | 
|  | 124 | +Example of global CSS: | 
|  | 125 | + | 
|  | 126 | +```css title="mySiteGlobalCss.css" | 
|  | 127 | +/* Global stylesheet */ | 
|  | 128 | +.globalSelector { | 
|  | 129 | +  color: #007bff; | 
|  | 130 | +  font-weight: bold; | 
|  | 131 | +} | 
|  | 132 | +``` | 
|  | 133 | + | 
|  | 134 | +--- | 
|  | 135 | + | 
|  | 136 | +## Client Module Lifecycles {#client-module-lifecycles} | 
|  | 137 | + | 
|  | 138 | +Client modules can define **lifecycle functions** to handle route transitions in your single-page app (SPA). | 
|  | 139 | + | 
|  | 140 | +### Available Lifecycle Methods | 
|  | 141 | + | 
|  | 142 | +- `onRouteUpdate`: triggered when navigation starts   | 
|  | 143 | +- `onRouteDidUpdate`: triggered after the new route has rendered   | 
|  | 144 | + | 
|  | 145 | +These functions receive `{ location, previousLocation }` as parameters. | 
|  | 146 | + | 
|  | 147 | +Example: | 
|  | 148 | + | 
|  | 149 | +```js title="myClientModule.js" | 
|  | 150 | +export function onRouteDidUpdate({location, previousLocation}) { | 
|  | 151 | +  if (location.pathname !== previousLocation?.pathname) { | 
|  | 152 | +    const title = document.querySelector('h1'); | 
|  | 153 | +    if (title) title.innerText += ' 🚀'; | 
|  | 154 | +  } | 
|  | 155 | +} | 
|  | 156 | + | 
|  | 157 | +export function onRouteUpdate({location, previousLocation}) { | 
|  | 158 | +  if (location.pathname !== previousLocation?.pathname) { | 
|  | 159 | +    const progress = setTimeout(() => { | 
|  | 160 | +      nprogress.start(); | 
|  | 161 | +    }, 200); | 
|  | 162 | +    return () => clearTimeout(progress); | 
|  | 163 | +  } | 
|  | 164 | +} | 
|  | 165 | +``` | 
|  | 166 | +
 | 
|  | 167 | +TypeScript version: | 
|  | 168 | +
 | 
|  | 169 | +```ts title="myClientModule.ts" | 
|  | 170 | +import type {ClientModule} from '@docusaurus/types'; | 
|  | 171 | + | 
|  | 172 | +const module: ClientModule = { | 
|  | 173 | +  onRouteUpdate({location, previousLocation}) { | 
|  | 174 | +    // Custom navigation logic | 
|  | 175 | +  }, | 
|  | 176 | +  onRouteDidUpdate({location, previousLocation}) { | 
|  | 177 | +    // DOM manipulations or analytics | 
|  | 178 | +  }, | 
|  | 179 | +}; | 
|  | 180 | + | 
|  | 181 | +export default module; | 
|  | 182 | +``` | 
|  | 183 | +
 | 
|  | 184 | +Both lifecycles run on the **client side only** and are safe for accessing browser globals. | 
|  | 185 | +
 | 
|  | 186 | +--- | 
|  | 187 | +
 | 
|  | 188 | +:::tip Prefer React-based Implementations | 
|  | 189 | +
 | 
|  | 190 | +If your feature depends on **state**, **hooks**, or **context**,   | 
|  | 191 | +it’s better to use [component swizzling](https://docusaurus.io/docs/swizzling#wrapping) instead of client modules.   | 
|  | 192 | +Client modules are ideal for simple global effects, not for complex UI logic. | 
|  | 193 | +::: | 
|  | 194 | +
 | 
|  | 195 | +--- | 
|  | 196 | +
 | 
|  | 197 | +By understanding **theme aliases** and **client modules**, you can fully control CodeHarborHub’s front-end architecture — blending flexibility, modular design, and smooth client-side experiences. | 
0 commit comments