Skip to content

Latest commit

 

History

History
152 lines (116 loc) · 7.29 KB

README.md

File metadata and controls

152 lines (116 loc) · 7.29 KB

Ghost Admin (React)

The React Ghost admin interface.

Architecture

The application uses admin-x-framework for API hooks and routing. Shade provides its application wrapper and design system. After Vite builds Admin, pnpm assemble:assets runs the standalone assembler in tools/scripts/ to copy dist/ into ghost/core/built/admin/. It ships Koenig’s embed renderer separately in ghost/core/built/embed-renderer/.

Sidebar visibility

Route handles own sidebar visibility. The hideAdminSidebar handle hides it for focused screens such as the editor.

CSS

src/index.css is the single Tailwind CSS entry point for Admin. It imports Shade's styles and uses @source directives to scan Admin, Shade, ActivityPub, Admin Framework, and the embedded Koenig selector. Only this app loads the @tailwindcss/vite plugin for the embedded Admin CSS lane.

Embedded Admin apps must not import @tryghost/shade/styles.css themselves. Doing so generates duplicate utilities and creates cascade conflicts.

Admin also owns the shared .koenig-react-editor width and centering rule. Koenig loads its own editor stylesheet through fetchKoenigLexical.

Shade's Tailwind imports are unlayered, so source order resolves overlapping utilities. Do not move Shade's imports into a CSS layer without accounting for the cascade.

Appearance

The shared ThemeProvider owns the appearance preference and the Admin theme controller. The controller applies the root dark class, follows system appearance and suppresses transitions during a switch.

Deploy compatibility

Ghost Admin and Ghost Core can deploy at different times. New Admin UI that depends on a new setting, endpoint, or configuration value must detect backend support and hide or safely disable the feature when it is absent. A Labs flag alone is not a compatibility check because the flag may exist before the supporting backend version is live.

Add an acceptance test for the older-backend case. The social accounts settings and membership tiers tests contain current examples of hiding controls until their supporting settings are present.

Code that fails to load

Screens, the editor and the search modal load their code when first needed. A signed-in shell preloads both Settings chunks when the browser is idle, keeping the first Settings visit from waiting on its code when preloading has finished. A browser never fetches a module again after loading it failed, so when that code fails to load the admin reloads at the same route. It reloads at most once a minute and not while the browser is offline; within that minute a failed screen is left on screen, where Admin's own screens offer Reload, as they do when they crash for any other reason. The search modal fails inside its own dialog, leaving the rest of the admin in place. Sentry gets each automatic reload as a warning, grouped apart from the failures left on screen, which are reported as errors.

Development

# Start development server (from monorepo root)
pnpm dev

Admin, Admin Framework and Shade hot-reload through Admin's dev server. It pre-bundles dependencies in a separate vite optimize run first, because Rolldown holds a cold pre-bundle's memory until its process exits.

Development commands do not change Labs settings. To preview a flagged feature in one browser tab, open http://localhost:2368/ghost/#/?labs=<flag>. These session overrides survive navigation and reloads in that tab; use ?labs= to clear them.

Build new Admin features in this React app. Use admin-x-framework for API access and Shade for UI. Product copy belongs in the ghost namespace; follow the internationalization guide.

pnpm dev runs pnpm nx run @tryghost/admin:build:dev before starting Admin's dev server. It builds Koenig Lexical and the Unsplash selector, the only workspace packages the dev server loads from built output.

Vite resolves Admin Framework and Shade through their source exports in development, production and tests. It tracks each package’s source and path aliases directly, and transforms Shade’s SVG icons with SVGR. The shared CSS lane stays in this app. Compiled library builds and watchers remain available for other consumers. Typechecks and editors still use the library declarations, which pnpm nx run @tryghost/admin:test:types builds.

The post editor is the largest area with documentation of its own — start at src/editor/README.md before changing anything under src/editor/.

Testing

  • Unit tests (pnpm test:unit): Vitest + jsdom, colocated *.test.ts(x) files.
  • Acceptance tests (pnpm test:acceptance): the real app in real Chromium against a fake admin API served through MSW — see test-utils/acceptance/README.md.
  • Typechecks (pnpm test:types): TypeScript checks app code, test code and Vite configuration without bundling Admin.
  • Browser e2e against a real Ghost instance lives in the top-level e2e/ workspace.

From the monorepo root, use pnpm nx run @tryghost/admin:test:unit or pnpm nx run @tryghost/admin:test:acceptance, or pnpm nx run @tryghost/admin:test:types to build the required React libraries first. These targets do not boot Ghost. The dependsOn list of test:types explicitly names the React dependencies with a build target; update it when adding one. Add it to build:dev, test:unit and test:acceptance only if Vite loads its built output rather than its source export.

Nx caches unit, acceptance and typecheck results. Their inputs include every transitive dependency's default inputs. Test inputs also include Core's aliased card assets, the lockfile and runtime settings such as Node version, platform, timezone and CI mode. A digest of local .env and .env.* files covers Vite's mode-specific configuration without printing their values. Shard and other CLI arguments get separate cache keys. Use --skip-nx-cache to force a fresh run.

pnpm test and pnpm check at the root run Admin's test:unit and test:types tasks and their prerequisites. Admin's aggregate test target schedules the same tasks and is not cached itself, so an outer cache cannot skip their input checks.

CI changes confined to Admin's *.test.ts(x), *.screen.ts, test-utils/ or vitest.acceptance.config.ts skip the build, packaging and browser E2E lane. Affected unit, app acceptance, lint and typecheck checks still run. Changes to runtime code or shared configuration keep the full lane.

Building for Production

# Build production bundle
pnpm nx run @tryghost/admin:build

The assembler reads the individual build outputs, so it can also be rerun with pnpm nx run @tryghost/admin:assemble:assets after those builds. It does not run compilers or upload sourcemaps. See Admin asset assembly for the input requirements.

This outputs to apps/admin/dist/ and updates the assets in ghost/core/built/admin/.

The build also writes hidden sourcemaps: .map files that no bundle references. With IS_SHIPPING set, as CI does for main and release tags, it injects Sentry debug IDs into the bundles. CI then uploads the maps with sentry-cli in a separate step, so a slow or unavailable Sentry can't block the build.