The official website for Apache HBase, built with modern web technologies to provide a fast, accessible, and maintainable web presence.
Most pages (except the home page) store content in Markdown (.md) or JSON (.json) files located in app/pages/[page-name]/. This makes it easy to update content without touching code.
Examples:
app/pages/team/content.md - Markdown content for team pageapp/pages/powered-by-hbase/companies.json - JSON data for companiesapp/pages/news/events.json - JSON data for news/eventsEdit these files with any text editor, then run npm run build to regenerate the site.
Before you begin, ensure you have the following installed:
Node.js version 22 - JavaScript runtime (like the JVM for Java)
node --version (should show v20.19+ or v22.12+)NPM - Node Package Manager (like Maven for Java)
npm --versionThis website uses modern web technologies. Here's what each one does (with Java analogies):
The website uses progressive enhancement (learn more), which means:
With JavaScript enabled: Users get a Single Page Application (SPA) experience
Without JavaScript: Users still get a fully functional website
This approach ensures the website works for all users, regardless of their browser capabilities or connection speed.
shadcn/ui - Pre-built, accessible UI components
Radix UI - Low-level, accessible UI primitives
className="text-blue-500 font-bold" makes blue, bold textTypeScript - Typed superset of JavaScript
ESLint + Prettier - Code linting and formatting (like Checkstyle + google-java-format)
npm run lint:fix handles both linting and formattingeslint.config.js and prettier.config.jsThe project follows a clear directory structure with separation of concerns:
my-react-router-app/ ├── app/ # Application source code │ ├── ui/ # Reusable UI components (no business logic) │ │ ├── button.tsx # Generic button component │ │ ├── card.tsx # Card container component │ │ └── ... # Other UI primitives │ │ │ ├── components/ # Reusable components WITH business logic │ │ ├── site-navbar.tsx # Website navigation bar │ │ ├── site-footer.tsx # Website footer │ │ ├── theme-toggle.tsx # Dark/light mode toggle │ │ └── markdown-layout.tsx # Layout for markdown content pages │ │ │ ├── pages/ # Complete pages (composed of ui + components) │ │ ├── home/ # Home page │ │ │ ├── index.tsx # Main page component (exported) │ │ │ ├── hero.tsx # Hero section (not exported) │ │ │ ├── features.tsx # Features section (not exported) │ │ │ └── ... │ │ ├── downloads/ # Downloads page │ │ │ ├── index.tsx # Main page component (exported) │ │ │ └── content.md # Markdown content │ │ └── ... │ │ │ ├── routes/ # Route definitions and metadata │ │ ├── home.tsx # Home route configuration │ │ ├── download.tsx # Downloads route configuration │ │ └── ... │ │ │ ├── lib/ # Utility functions and integrations │ │ ├── utils.ts # Helper functions │ │ └── theme-provider.tsx # Theme management │ │ │ ├── routes.ts # Main routing configuration │ ├── root.tsx # Root layout component │ └── app.css # Global styles │ ├── build/ # Generated files (DO NOT EDIT) │ ├── public/ # Static files (copied as-is to build/) │ ├── favicon.ico # Website icon │ └── images/ # Images and other static assets │ ├── node_modules/ # Dependencies (like Maven's .m2 directory) ├── package.json # Project metadata and dependencies (like pom.xml) ├── tsconfig.json # TypeScript configuration └── react-router.config.ts # React Router framework configuration
UI Components (/ui): Pure, reusable components with no business logic
Business Components (/components): Reusable across pages
Pages (/pages): Complete pages combining ui and components
index.tsx is exported/componentsRoutes (/routes): Define routing and metadata
Always use the custom Link component from @/components/link instead of importing Link directly from react-router.
The HBase website includes pages that are not part of this React Router application (e.g., documentation pages, API docs). The custom Link component automatically determines whether a link should trigger a hard reload or use React Router's client-side navigation:
Usage:
// ✅ CORRECT - Use custom Link component import { Link } from "@/components/link"; export const MyComponent = () => ( <Link to="/team">Team</Link> );
// ❌ WRONG - Do not import Link from react-router import { Link } from "react-router"; export const MyComponent = () => ( <Link to="/team">Team</Link> );
The ESLint configuration includes a custom rule (custom/no-react-router-link) that will throw an error if you attempt to import Link from react-router, helping enforce this convention automatically.
Think of this as mvn install:
npm install
This downloads all required packages from npm (similar to Maven Central).
Important: Before starting the development server, generate the developers.json file from the root pom.xml:
npm run extract-developers
This extracts the developer information from the parent pom.xml file and creates app/pages/team/developers.json, which is required for the Team page to work properly. Re-run this command whenever the developers section in pom.xml changes.
npm run dev
This starts a local development server with:
http://localhost:5173app/ directorynpm run dev is runningAdd a new page:
app/pages/my-new-page/index.tsx in that directoryapp/routes/my-new-page.tsxapp/routes.tsUpdate content:
.md or .json fileAdd a UI component:
Check code quality:
npm run lint
Fix linting and formatting issues:
npm run lint:fix
The project uses Vitest for testing React components.
Run tests:
# Run tests in watch mode (for development) npm test # Run tests once (for CI/CD) npm run test:run # Run tests with UI npm run test:ui
Test coverage includes:
Writing new tests:
Use the renderWithProviders utility in test/utils.tsx to ensure components have access to routing and theme context:
import { renderWithProviders, screen } from './utils' import { MyComponent } from '@/components/my-component' describe('MyComponent', () => { it('renders correctly', () => { renderWithProviders(<MyComponent />) expect(screen.getByText('Hello World')).toBeInTheDocument() }) })
CI/CD Workflow:
Before merging or deploying, run the full CI pipeline:
npm run ci
This command runs all quality checks and builds the project:
npm run lint - Check lintingnpm run typecheck - Check typesnpm run test:run - Run testsnpm run build - Build for productionAll checks must pass before code is considered ready for deployment.
CI/CD Pipeline Example:
# Example for GitHub Actions, GitLab CI, etc. - npm run ci # Runs all checks and build
Create an optimized production build:
npm run build
This command:
build/ directoryGenerated files location:
build/ ├── client/ # Everything needed for the website │ ├── *.html # Pre-rendered HTML pages │ ├── assets/ # Optimized JavaScript and CSS │ │ ├── *.js # JavaScript bundles (minified) │ │ ├── *.css # Stylesheets (minified) │ │ └── manifest-*.js # Asset manifest │ └── images/ # Optimized images └── server/ # Server-side code (if applicable)
The build/client/ directory contains everything needed to deploy the website to any static file host.
The website is integrated with the Apache HBase Maven build system using the frontend-maven-plugin. The website is configured to build only during site generation (mvn site) and will not build during regular Maven lifecycle phases like mvn clean install.
The website build is triggered only when you run:
mvn site
The website will NOT build during regular commands like:
mvn clean installmvn packagemvn compileThis keeps regular HBase builds fast while still allowing the website to be generated when needed.
mvn siteWhen you run mvn site, the website module automatically:
Cleans previous build artifacts
build/ directorynode_modules/ directoryInstalls Node.js v22.20.0 and npm 11.6.2 (if not already available)
target/ directoryRuns npm install to install all dependencies
package.jsonnode_modules/Extracts developers data from the parent pom.xml
app/pages/team/developers.jsonRuns npm run ci which executes:
npm run lint - ESLint code quality checksnpm run typecheck - TypeScript type checkingnpm run test:run - Vitest unit testsnpm run build - Production buildBuild Output: Generated files are in build/ directory
Build HBase WITHOUT the Website (default):
# From HBase root directory mvn clean install
Build the Website:
# From HBase root or hbase-website directory mvn site
This generates the full HBase website including documentation and the React-based website.
Build Website Only:
# From hbase-website directory cd hbase-website mvn site
The frontend-maven-plugin binds to these site-specific Maven phases:
npm install, and extracts developers datanpm run ci (lint, typecheck, test, build)The Maven configuration ensures consistent builds across different environments:
mvn clean install (website not included)mvn site to generate the full website and documentationnpm install or npm run ci when using mvn siteBuild Fails During npm install:
# Clean and rebuild cd hbase-website mvn clean site
This will:
build/ directorynode_modules/ directorytarget/ directoryBuild Fails During npm run ci:
This usually indicates:
To diagnose, run the commands directly:
cd hbase-website npm install npm run lint # Check linting npm run typecheck # Check types npm run test:run # Check tests npm run build # Check build
Fix any errors and try the Maven build again.
target/, node/, node_modules/, build/The website only builds when you explicitly run mvn site.
If you're working on the website:
# Use npm for faster development iteration cd hbase-website npm install npm run dev # Start dev server with hot reload # Or use Maven to build the website cd hbase-website mvn site
Since this site uses Static Site Generation (SSG), you can deploy the build/client/ directory to any static file host:
build/client/ contents to your web rootbuild/client/ contents to your web rootbuild/client/ to gh-pages branchIf you see type errors related to React Router's +types, regenerate them:
npx react-router typegen
If npm run dev fails because port 5173 is in use:
# Kill the process using the port lsof -ti:5173 | xargs kill -9 # Or change the port in vite.config.ts
Nuclear option - removes all generated files:
rm -rf node_modules/ build/ .react-router/ npm install npm run build
Built with ❤️ for the Apache HBase community.