Skip to content

apache/phoenix-site

Repository files navigation

Apache Phoenix Website

The official website for Apache Phoenix, built with modern web technologies to provide a fast, accessible, and maintainable web presence.


Table of Contents


Content Editing

Most landing pages store content in Markdown (.md) or JSON (.json) files located in app/pages/_landing/[page-name]/. Docs content lives under app/pages/_docs/ and is authored in MDX.

Examples:

  • app/pages/_landing/mailing-lists/content.md - Markdown content for a landing page
  • app/pages/_landing/team/developers.json - JSON data for the team page
  • app/pages/_landing/news/events.json - JSON data for news/events
  • app/pages/_docs/docs/_mdx/(multi-page)/... - MDX content for documentation
  • phoenix-version.ts - Shared Phoenix version constant used in docs/PDF cover

Development

Prerequisites

Before you begin, ensure you have the following installed:

  • Node.js version 22

    • Download from nodejs.org
    • Verify installation: node --version (should show v22.12+)
  • npm

    • Comes bundled with Node.js
    • Verify installation: npm --version

Technology Stack

This website uses modern web technologies. Here is what each one does (with Java analogies):

Core Framework

  • React Router - full-stack web framework with SSG
    • Handles routing (similar to Spring MVC controllers)
    • Provides server-side rendering for better performance and SEO
    • Enables progressive enhancement
    • Documentation

Documentation Framework

  • Fumadocs - documentation framework used for the docs section
    • Provides MDX-based docs structure and navigation
    • Lives alongside landing pages in the same React Router app
    • Supports multi-page and single-page docs from the same MDX sources
    • Documentation

Progressive Enhancement

The website uses progressive enhancement (learn more), which means:

  • With JavaScript enabled: users get a SPA experience

    • Fast page transitions without full page reloads
    • Smooth animations and interactive features
    • Enhanced user experience
  • Without JavaScript: users still get a fully functional website

    • All links and forms work via traditional HTML
    • Content remains accessible
    • Better behavior for search engines and assistive tools

This approach ensures the website works for all users, regardless of browser capabilities or connection speed.

UI Components

  • shadcn/ui - pre-built, accessible UI components
    • Similar to component libraries like PrimeFaces or Vaadin
    • Provides buttons, cards, navigation menus, and more
    • Documentation

Styling

  • TailwindCSS - utility-first CSS framework
    • Apply classes directly in components instead of maintaining large CSS files
    • Example: className="text-blue-500 font-bold" makes blue, bold text

Code Quality Tools

  • TypeScript - typed superset of JavaScript

    • Similar to Java's type system
    • Catches errors at compile-time instead of runtime
    • Provides better autocomplete and IDE support
  • ESLint + Prettier - linting and formatting

    • ESLint analyzes code for potential errors and style issues
    • Prettier enforces consistent formatting
    • npm run lint:fix handles both linting and markdown formatting
    • Configuration files: eslint.config.js and prettier.config.js

Project Architecture

The project follows a clear directory structure with separation of concerns:

phoenix-site/
├── app/                               # Application source code
│   ├── ui/                            # Reusable UI primitives
│   ├── components/                    # Reusable components with business logic
│   ├── pages/                         # Full pages
│   │   ├── _landing/                  # Landing pages + layout
│   │   └── _docs/                     # Documentation pages (Fumadocs)
│   ├── routes/                        # Route definitions
│   ├── routes.ts                      # Main routing configuration
│   ├── root.tsx                       # Root layout component
│   └── app.css                        # Global styles
│
├── build/                             # Generated files (do not edit)
├── output/                            # Committed website artifact for publishing
├── public/                            # Static files copied to build output
├── scripts/                           # Helper scripts (e.g. generate-language.ts)
├── e2e-tests/                         # Playwright tests
├── unit-tests/                        # Vitest tests
├── phoenix-version.ts                 # Shared Phoenix version constant
└── package.json                       # Scripts and dependencies

Key Principles

  1. UI components (app/ui) are pure, reusable building blocks with no page-level business logic.
  2. Business components (app/components) can be shared across multiple pages.
  3. Pages (app/pages) compose UI + business components into complete routes.
  4. Routes (app/routes) map URLs to pages and define route-level metadata.
  5. Two layout systems exist in one app:
    • Landing pages under app/pages/_landing/
    • Docs pages under app/pages/_docs/
  6. Documentation versions:
    • Multi-page docs in app/pages/_docs/docs/_mdx/(multi-page)/ are the source of truth.
    • Single-page docs in app/pages/_docs/docs/_mdx/single-page/ aggregate from multi-page docs.

Important Conventions

Custom Link Component

Always use the custom Link component from @/components/link instead of importing Link directly from react-router.

The Phoenix website includes both React-routed pages and static/legacy pages. The custom Link component automatically decides whether to use client-side navigation or trigger a full page load.

Correct usage:

import { Link } from "@/components/link";

export const MyComponent = () => <Link to="/team">Team</Link>;

Wrong usage:

import { Link } from "react-router";

export const MyComponent = () => <Link to="/team">Team</Link>;

The ESLint configuration includes custom/no-react-router-link to enforce this convention.

Getting Started

1. Install Dependencies

npm install

This downloads all required packages from npm.

2. Generate Docs Metadata and Language Pages

Before starting the development server, generate docs metadata and generated language pages:

npm run generate-language
npm run fumadocs-init

generate-language updates generated docs pages (for example grammar/functions/datatypes). fumadocs-init refreshes Fumadocs metadata and page maps.

3. Start Development Server

npm run dev

This starts a local development server with:

  • Hot Module Replacement (HMR): updates without full page reload
  • Default URL: http://localhost:5173

Development Workflow

Making Changes

  1. Edit code in app/.
  2. Save the file and verify updates in browser.
  3. Check terminal output and browser console for errors.

Common Tasks

Add a new page:

  1. Create directory in app/pages/my-new-page/
  2. Add index.tsx in that directory
  3. Add a route file in app/routes/
  4. Register it in app/routes.ts

Add a new documentation page:

  1. Create a .mdx file in app/pages/_docs/docs/_mdx/(multi-page)/.
  2. Add it to the relevant meta.json in that docs section.
  3. If needed in the single-page docs, include it from app/pages/_docs/docs/_mdx/single-page/index.mdx.
  4. Run npm run fumadocs-init.

Update content:

  • Edit the relevant .md, .mdx, or .json file.

Add a UI component:

  • Check existing shadcn/ui primitives first.
  • Add custom components only when needed.

Update the 404 page:

  • Edit the content in app/routes/404.tsx.
  • Apache 404 handling lives in public/.htaccess (uses ErrorDocument 404 /404).

Check code quality:

npm run lint

Fix linting and formatting issues:

npm run lint:fix

Testing

The project uses Vitest for unit testing and Playwright for e2e testing.

Playwright runs against the production build by serving build/client/ locally on port 5178.

Export Documentation PDF

The docs PDF export is implemented as a Playwright e2e test in e2e-tests/export-pdf.spec.ts. It renders single-page docs in both light and dark themes to produce static PDF assets.

The export quality depends heavily on print styles in app/app.css (@media print rules).

The displayed Phoenix version on the PDF cover is sourced from phoenix-version.ts (PHOENIX_VERSION) and consumed by app/pages/_docs/docs/index.tsx.

Manual command:

npm run export-pdf

Run Tests

# Run all tests
npm test

# Run unit tests once (CI mode)
npm run test:unit:run

# Run unit tests with UI
npm run test:unit:ui

# Run e2e tests
npm run test:e2e

# Run e2e tests with UI
npm run test:e2e:ui

Building for Production

During local development, running CI checks is usually enough:

npm run ci

Before opening a pull request, you must run the full website build script:

./build.sh

build.sh is the required pre-PR build step for all contributors (not just Linux users). It:

  1. Ensures Node/npm are available (bootstraps via nvm when needed)
  2. Runs a clean dependency install (npm ci)
  3. Runs the complete CI pipeline (npm run ci)
  4. Copies build/client/ into output/

Current CI sequence used by npm run ci:

  1. npm run generate-language
  2. npm run fumadocs-init
  3. npm run lint
  4. npm run typecheck
  5. npm run build
  6. npm run test:unit:run
  7. npx playwright install
  8. npm run test:e2e

There is currently no remote CI/CD runner executing build.sh for this repository. The output/ artifact is produced locally and must be included in your pull request.

Deployment

Static Hosting

The published website artifact is the committed output/ directory. The expected publishing workflow is:

  1. Run ./build.sh locally
  2. Commit source changes and updated output/
  3. Push your branch and open a PR

After merge, output/ can be deployed to static hosting.

The output/ content (generated from build/client/) can be served from any static host:

  • Apache HTTP Server
  • Nginx
  • GitHub Pages
  • Any CDN/static object storage

Troubleshooting

E2E Test Fails

Depending on your machine, it's theoretically possible that the E2E tests can fail due to a timeout. For the E2E tests to start working, it has to warm up the entire application first. The documentation is quite heavy, so it takes time. On slower machines the current timeout (60 secs) might not be sufficient. Therefore, you might want to extend it locally in playwright.config.ts

TypeScript Types Are Broken

If you see type errors related to React Router +types, regenerate them:

npx react-router typegen

Port Already in Use

If npm run dev fails because port 5173 is in use:

lsof -ti:5173 | xargs kill -9

Or change the port in vite.config.ts.

Build Fails

  1. Clear generated files:

    rm -rf build/ node_modules/ .vite/ .react-router/ .source/
  2. Reinstall dependencies:

    npm install
  3. Try building again:

    npm run build

Additional Resources


Built for the Apache Phoenix community.

About

Apache phoenix

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors