This document explains Helm-specific architectural decisions that help maintain the site and guide contributors. For general Docusaurus concepts, see the official documentation.
The Helm homepage hero needs to fill the full viewport height minus the navbar for a clean presentation.
Uses a Docusaurus client module: src/client-modules/heroHeightCalculator.js
Handles: Window resize, orientation change, client-side navigation (SPA routing), and development hot reloading
Why client modules instead of static scripts: Integrates with Docusaurus build process and avoids file serving issues in different deployment environments.
Split the homepage into focused components so contributors can easily find and edit specific sections.
src/components/
├── HomeHeader/ # Hero section
├── HomeAbout/ # "What is Helm?" section
├── HomeFeatures/ # Feature cards
├── HomeGettingStarted/ # Installation tabs
└── HomeCommunity/ # Community links
Shared CSS modules: src/css/home-*.module.css for common patterns across components.
Date internationalization: Uses Intl.DateTimeFormat for locale-aware date formatting instead of hardcoded strings, automatically adapting to user's language settings.
Hero content must never be hidden behind navbar or waves, especially on mobile landscape or small windows.
Extreme height constraint (< 380px): Switches to side-by-side layout instead of stacked
Text scaling: Uses CSS clamp() for smooth scaling while maintaining readability
Container bounds: Absolute positioning keeps content above wave animations
Regenerate Helm CLI documentation for each release with consistent formatting and Docusaurus-compatible structure.
Uses an ESM Node.js script: scripts/regenerate-cli-docs.mjs
Why ESM over CommonJS: Modern package compatibility (ora, p-limit) and consistency with future Node.js direction while maintaining parallel processing capabilities for performance.
Post-processing steps: Automatically handles Docusaurus requirements like converting links to absolute paths, cleaning frontmatter, and creating proper index files - tasks that would be error-prone if done manually for each release.
See src/components/HomeHeader/styles.module.css for implementation details.
The HomeCommunity component displays event dates using locale-specific formatting, which causes unavoidable hydration mismatches between server and client rendering.
Following React's official guidance for suppressing unavoidable hydration mismatches, we use suppressHydrationWarning on date-displaying <span> elements in src/components/HomeCommunity/index.js.
Why this happens: The server renders dates using one locale during static generation, but the client may have a different locale, causing React error #418 (text content mismatch). Since dates are intentionally locale-aware for internationalization, this mismatch is expected and acceptable.
Implementation: Added suppressHydrationWarning prop to both date range and single date <span> elements in the CustomDate component.
Boat must appear to float on waves across all screen sizes while using minimal space in the hero section.
Scaling: Uses max(rem, vw) for viewport-proportional scaling with minimum readable sizes
Space efficiency: Boat can overflow above a compact wave container to maximize hero content space
Animation sync: Boat bob animation coordinates with wave heights for consistent floating appearance
See src/components/Boat/styles.module.css for implementation.
Homepage styles should only load on homepage, not other pages.
Uses CSS Modules with strategic sharing:
src/css/home-*.module.css- Shared patterns (sections, cards)- Component
styles.module.css- Component-specific styles
Why this approach: Only homepage components import homepage CSS, so other pages don't load unnecessary styles.
Blog and docs pages now use identical layout and navigation. This was done by swizzling Docusaurus theme components rather than custom CSS.
Core Components (don't delete):
src/theme/BlogLayout/ # Makes blog look like docs
src/theme/BlogBreadcrumbs/ # "Home → Blog → Post" navigation
src/theme/BlogListBreadcrumbs/ # "Home → Blog" navigation
src/theme/DocBreadcrumbs/ # "Home → Docs → Page" navigation
src/theme/TOCCollapsible/ # Mobile "On this page" menu
- Blog listing: Home → Blog
- Blog post: Home → Blog → Post Title
- Docs page: Home → Docs → Category → Page
Blog breadcrumbs broken? Check src/theme/BlogBreadcrumbs/index.js
Mobile TOC not working? Verify src/theme/TOCCollapsible/ and that blog posts use proper headers (##, ###)
Missing "Docs" in breadcrumbs? Check src/theme/DocBreadcrumbs/index.js has the "Docs" link
Layout looks wrong? Don't add custom CSS - edit the React components instead
See Docusaurus swizzling docs for how these theme components work.
This section provides guidance for working with markdown links in the Helm docs site.
Absolute paths are required for all links. Absolute paths are more verbose but necessary to avoid broken links in our multi-locale site due to the following Docusaurus i18n bug: facebook/docusaurus#10907.
The sections below include more information about how and when to use absolute file paths or URL paths.
When linking from one doc page to another or from one blog post to another, use the absolute file path:
- Exclude
/blog/or/docs/from the path - Start the path from the directory within
/blogs(eg/2024-10-07-kubecon-na-24/), or from the version-specific docs folder (eg,/topics/,/chart_template_guide/,/helm/) - Include the
.mdor.mdxfile extension
Examples:
✅ GOOD (doc to doc link): [Advanced Topics](/topics/advanced.md)
✅ GOOD (blog to blog link): [Helm at KubeCon/CloudNativeCon SLC](/2024-10-07-kubecon-na-24/index.md)
❌ AVOID (relative file path): [Advanced Topics](../topics/advanced.md)
❌ AVOID (relative file path): [Advanced Topics](advanced.md)
❌ AVOID (adding /docs): [Advanced Topics](/docs/topics/advanced.md)
❌ AVOID (absolute URL path, no .md/.mdx): [Advanced Topics](/docs/topics/advanced)When linking to a doc from a blog, or from a blog to a doc, use the absolute URL path:
- Include
/blog/or/docs/ - Exclude the
.mdor.mdxfile extension - If the doc or blog has a
slugdefined in its front matter, use the slug in the URL path instead of the filename
Examples:
✅ GOOD (file name without .md extension when no slug is in front matter): [See this blog post](/blog/2024-01-01-title)
✅ GOOD (when slug is in front matter): [See this blog post](/blog/my-slug)
❌ AVOID (don't use the file extension): [Advanced Topics](/docs/topics/advanced.md)Anchor links are challenging in multi-locale sites because anchor IDs are automatically generated from the heading text. This means that any links that point to English language anchor IDs will break in other locales if the given heading is translated to a different language.
For example:
English: ## Storage backends → #storage-backends
Chinese: ## 后端存储 → #后端存储 (different anchor ID)To avoid broken anchor links, add explicit IDs to headings in all translations. For example:
## Storage backends {#storage-backends}
## 后端存储 {#storage-backends}In this case, anchor links to the given ID will work across all locales since the anchor ID itself remains the same in all translations.
You can run a local build to check for broken links (yarn build). If there are broken links, you'll see an error like this in the build output:
Broken link on source page path = /docs/faq/changes_since_helm2
-> linking to /topics/charts.mdTo troubleshoot, go to the source page listed in the error message. Note that the source page with the broken link might be in the English docs, even if the broken link was triggered for a different locale.
During the migration from Hugo to Docusaurus, several legacy URL patterns needed to be preserved to avoid breaking existing links and integrations.
Netlify processes redirects from top to bottom, with the first matching rule taking precedence. This means more specific patterns must come before general ones.
Hugo served Go module import pages at /helm/, /helm/v2/, /helm/v3/, /helm/v4/, /chartmuseum/ using a content/en/code/ directory with metadata files processed by themes/helm/layouts/code/single.html.
Docusaurus replicates this functionality using static HTML files in /static/:
/static/helm/index.html/static/helm/v2/index.html/static/helm/v3/index.html/static/helm/v4/index.html/static/chartmuseum/index.html
Each file provides:
- Go import meta tags:
<meta name="go-import" content="...">for Go module proxy - Go source meta tags:
<meta name="go-source" content="...">for source code navigation - Client-side redirect:
<meta http-equiv="refresh">for browser users - Fallback link: HTML body with link to GitHub repository
Internal redirects handle Go module proxy requests:
[[redirects]]
from = "/helm/v3/*"
to = "/helm/v3"
status = 200
[[redirects]]
from = "/helm/v2/*"
to = "/helm/v2"
status = 200Legacy Helm v2 documentation from https://v2.helm.sh/docs/* redirects to the new combined site at /docs/2/*. These redirects:
- URL format changes: Map old underscore URLs to new dash URLs (e.g.,
using_helm/→using-helm/) - Category-level only: Target section landing pages (fragments not supported by Netlify)
- Temporary status: Use 302 status during migration phase for easy rollback if issues discovered
- Script-managed: Generated by
scripts/helm2-to-docusaurus.jsfor consistency
# TODO: Change status codes from 302 to 301 after cutover verification
[[redirects]]
from = "https://v2.helm.sh/docs/using_helm/"
to = "/docs/2/using-helm/"
status = 302- 302 (temporary) during testing/migration phase - allows easy rollback if issues are discovered
- 301 (permanent) after Docusaurus site cutover is verified - provides SEO benefits and signals permanent move
This follows Netlify's best practices for safe migrations.
Migrating legacy Helm documentation (v2 from Hugo, v3 from existing content) to Docusaurus while preserving URLs and fixing broken links.
Migration Orchestrators: scripts/migrate-v2-docs.js and scripts/migrate-v3-docs.js with corresponding yarn migrate:v2 and yarn migrate:v3 commands.
Modular Architecture: Scripts organized in scripts/util/, scripts/v2/, scripts/v3/ directories following UNIX philosophy - each script has a single purpose and can be composed together.
Key Features:
- Fresh start capability: Each migration clears and rebuilds from source
- Menu generation: Extracts navigation structure from live Helm v2 site
- Link path correction: Shared
scripts/util/href-diffs-process.jsapplies version-specific link fixes from JSON configuration files - Missing file handling: Adds helm commands not present in original navigation but available in source
Why this approach: Enables repeatable, testable migrations while maintaining URL compatibility and fixing legacy Hugo-to-Docusaurus link issues.
For contributors: Run yarn migrate:v2 or yarn migrate:v3 to regenerate versioned documentation. Link fixes are managed via JSON files in each version directory.
Detailed operational guides:
- HELM2-TO-DOCUSAURUS.md - v2 migration procedures
- HELM3-TO-DOCUSAURUS.md - v3 migration procedures
Once the Docusaurus migration is complete and verified, these Hugo-specific files should be removed:
config.toml- Hugo configuration file, replaced bydocusaurus.config.jsthemes/directory - Hugo theme files, replaced by Docusaurus theme componentscontent/en/code/directory - Hugo code metadata files, functionality replaced by Netlify redirects
Keep these files during the migration phase to:
- Reference Hugo configuration when setting up Docusaurus equivalents
- Understand legacy URL patterns for redirect configuration
- Maintain ability to rollback if needed during testing
Remove them only after:
- Docusaurus site cutover is verified
- All redirects are tested and working
- No rollback scenarios require Hugo functionality
The Helm project maintains community governance documents in a separate repository that need to be included in the website as an unversioned documentation section with proper Docusaurus integration.
Uses docusaurus-plugin-remote-content to import and transform content at build time.
Architecture:
- Multi-instance docs: Community docs are a separate Docusaurus docs plugin instance with
id: "community", creating/community/*URLs - Content transformation: Custom functions in
src/utils/communityDocsTransforms.jshandle all content processing - Configuration: Centralized in
docusaurus.config.jsundercustomFields.communityDocs - Files committed to Git: Imported files are tracked in version control to maintain clean git status and avoid complex .gitignore management
- Build settings: Uses
performCleanup: falseto prevent file deletion during i18n builds (workaround for plugin issue #98)
Import notice headers: Every imported file gets a warning header indicating it shouldn't be edited directly, with a link to the source file in the helm/community repository.
HIP (Helm Improvement Proposal) formatting: HIP documents get special treatment:
- Metadata fields (hip, authors, created, status, etc.) displayed as a markdown table
- Sidebar labels include HIP number for easy navigation (e.g., "0023: Utilize Server Side Apply")
- Frontmatter cleaned to remove duplicate metadata
Plain text file handling: .txt files (like meeting notes) are automatically:
- Converted to
.mdfiles during import - Title extracted from content headers
- Content wrapped in code blocks to preserve formatting
Link transformations: Only applied for configured exceptions - most links work as-is since the file structure mirrors the source repository.
The /community directory mixes imported files from helm/community with locally-maintained community docs. Committing imported files to Git:
- Avoids complex .gitignore patterns - No need to maintain a parallel list of which specific files to ignore
- Provides clean git status - Contributors don't see dozens of untracked files during development
- Enables offline development - With
noRuntimeDownloads: true,yarn startworks without network access - Simplifies mental model - All files in
/communityare tracked, regardless of source
The tradeoff of content duplication is acceptable since these files rarely change structure and the import notices clearly indicate they shouldn't be edited locally.
yarn download-remote-community- Fetch and transform latest content from helm/community repositoryyarn clear-remote-community- Remove imported files (useful for testing)
A GitHub Action (.github/workflows/update-community-docs.yml) runs weekly to:
- Check for updates in helm/community repository
- Apply transformations and import changes
- Create or update a PR if there are changes
- Skip if an identical PR already exists
The workflow can also be triggered manually through GitHub Actions UI.
To add new community documents:
- Add entry to
customFields.communityDocs.remoteDocsindocusaurus.config.js - Include optional
metafield for frontmatter overrides - Add link exceptions only if specific links need custom mapping
- Run
yarn download-remote-communityto test import locally
To modify transformation logic:
- Edit
src/utils/communityDocsTransforms.jsfor content processing - Test changes with
yarn download-remote-community
Docusaurus builds take ~11 minutes. Need faster builds for development workflow.
Custom Netlify plugins cache .docusaurus/, node_modules/, and build/ directories.
Current: cache-docusaurus-dirs-file (stable, 2-4 minute builds)
Future: cache-docusaurus-dirs-api (beta, potentially 10x faster)
Changed from make build (runs destructive clean) to make netlify-build (preserves cache).
- Production/branches: Isolated per branch
- PR previews: Shared across PRs via
CACHE_PER_BRANCH=false - Auto-invalidation:
yarn.lockchanges,CACHE_VERSIONenvironment variable
See netlify-plugins/README.md for configuration details.