20 KiB
title | weight | description |
---|---|---|
Docs Infrastructure | 600 | Learn how the docs and our tools are built |
The Crossplane document website is in a standalone GitHub repository separate from Crossplane core.
The Crossplane docs tools consist of:
- Netlify - web hosting and DNS provided by the CNCF.
- Hugo - to compile markdown to static HTML.
- Bootstrap - for pre-built CSS options.
- PostCSS - for CSS optimization.
- Webpack - for Javascript optimization.
Netlify
Builds for production deploys and PR previews are automatically done by Netlify.
{{< hint "note" >}} The CNCF controls Netlify access. {{< /hint >}}
Settings for Netlify are inside
netlify.toml
.
Settings inside the netlify.toml
file override any settings in the Netlify web
interface.
The
build
directive defines what Netlify does to build the site.
The
HUGO_VERSION
settings defines which version of Hugo Netlify uses.
The
redirects
are server side HTTP redirects for moved pages.
The Netlify documentation
has more information about configuring netlify.toml
.
Netlify automatically detects the
package.json
file and loads the listed NodeJS dependencies.
netlify_build.sh
During a build Netlify runs the Bash script
netlify_build.sh
.
The script creates a new docs section called latest
and copies the defined
LATEST_VER
to /latest
.
Next the script enables writeStats
in the Hugo configuration file.
Then, using the Netlify $CONTEXT
environmental variable
Hugo runs, defining the BaseURL
to
use for generating internal links.
Hugo
Crossplane uses Hugo, a static site generator.
Hugo combines HTML templates, markdown content and generates static HTML content.
{{<hint "note" >}} The Hugo web server is only used for local development. Crossplane documentation uses Netlify for hosting.
Hugo only acts as an HTML compiler. {{< /hint >}}
Hugo influences the directory structure of the repository.
The /content
directory is the root directory for all documentation content.
The /themes/geekboot
directory is the root directory for all website related
files, like HTML templates, shortcodes and global media files.
The /utils/
directory is for JavaScript source code and files unrelated to
Hugo used in the website.
CSS
Crossplane documentation uses Bootstrap 5.2.
Bootstrap provides multiple prebuilt styles and features making CSS easier.
The docs import all Bootstrap SCSS files and rely on Hugo and PostCSS to optimize the compiled CSS file.
The unmodified Bootstrap SCSS files are in
/themes/geekboot/assets/scss/bootstrap/
.
Any docs-specific overrides are in per-element SCSS files located one directory
higher in /themes/geekboot/assets/scss/
.
{{<hint "important" >}} Don't edit the original Bootstrap stylesheets. It makes the ability to upgrade to future Bootstrap versions difficult or impossible. {{< /hint >}}
The file /themes/geekboot/assets/scss/docs.scss
defines all the stylesheets
Hugo loads and compiles. Add any new styles to the docs.scss
file to include
them.
Color themes
Crossplane docs support a light and dark color theme that's applied via CSS variables.
Universal and default variables are defined in
/themes/geekboot/assets/scss/_variables.scss
.
Provide theme specific color overrides in
/themes/geekboot/assets/scss/light-mode.scss
or
/themes/geekboot/assets/scss/dark-mode.scss
.
{{<hint "note" >}} When creating new styles, use variables for any colors, even if both themes share the color. {{< /hint >}}
SCSS compilation
Hugo compiles the SCSS to CSS. Local development doesn't require SCSS installed.
For local development (when using hugo server
) Hugo compiles SCSS without
any optimizations.
In production, when publishing on Netlify or using
hugo server --environment production
, Hugo compiles SCSS and optimizes the
CSS with PostCSS.
The PostCSS configuration is in /postcss.config.js
.
The optimizations includes:
- postcss-lightningcss - for building, minimizing and generating a source map.
- PurgeCSS - removes unused styles to reduce the CSS file size.
- postcss-sort-media-queries- to organize the output CSS for another small performance boost.
How optimization works
Crossplane runs a different Hugo CSS command if it's in local development or production.
Hugo is in "production" when using hugo
to only build HTML or with
hugo server --environment production
.
{{<hint "important" >}}
Running Hugo in production
mode requires the Hugo extended version to
support PostCSS.
Standard Hugo fails to build the documentation. {{< /hint >}}
PurgeCSS relies on a JSON file of every HTML tag and CSS class used across the website and only preserves the matching CSS styles. The resulting file is around 20x smaller than unoptimized CSS.
Hugo generates the JSON file with the buildStats
(or writeStats
)
configuration setting
enabled.
{{<hint "important" >}} Some tags or classes are dynamically created or not always enabled, like light or dark mode.
Exclude these style sheets from CSS optimization with the
purgecss start ignore
comment.
For example, the Crossplane documentation ignores the color-modes
style sheet.
/* purgecss start ignore */
@import "color-modes";
/* purgecss end ignore */
{{< /hint >}}
The Crossplane documentation only enables this flag during Netlify builds.
Manually update the config.yaml
file to enable local optimization.
Optimizing CSS locally with PostCSS requires installing extra packages.
JavaScript
A goal of the documentation website is to use as little JavaScript as possible. Unless the script provides a significant improvement in performance, capability or user experience.
Local development has no run-time JavaScript dependencies. To prevent dependencies, making JavaScript changes requires compiling and committing to git.
The source JavaScript is in /utils/webpack/src/js
and
requires Webpack to bundle and optimize the code.
Webpack places the compiled JavaScript in /themes/geekboot/assets/js/
and
updates /themes/geekboot/data/assets.json
to tell Hugo the new compiled
JavaScript filename.
{{< hint "important" >}}
The JavaScript source in /utils/webpack/src
, newly compiled JavaScript in
/themes/geekboot/assets/js
and updated /themes/geekboot/data/assets.json
must be in git for production and preview deploys to use the changed JavaScript.
{{< /hint >}}
JavaScript files
bootstrap/
is the entire Bootstrap JavaScript library.colorMode.js
provides the ability to change the light and dark mode color theme.customClipboard.js
supports thecopy-lines
code box function.globalScripts.js
is the point of entry for Webpack to determine all dependencies. This bundles instant.page and Bootstrap's JavaScript.hoverHighlight.js
provides dynamic "hover to highlight" function.slackNotify.js
creates the "Join Crossplane Slack" bubble on the home page.tabDeepAnchor.js
rewrites anchor links inside tabs to open a tab and present the anchor.
The globalScripts.js
file is the entry point for Webpack. Any JavaScript
modules or scripts must be in globalScripts.js
to get compiled.
Building JavaScript
Requirements:
From the /utils/webpack
director use npm
to install the NodeJS dependencies.
cd utils/webpack
npm install
Building JavaScript has two options:
npm run dev
npm run prod
Using the dev
argument doesn't optimize the JavaScript, simplifying
debugging.
Using the prod
argument optimizes the JavaScript but makes debugging more
difficult.
{{<hint "important" >}}
Always use npm run prod
to build the compiled JavaScript to use on the
Crossplane documentation site.
{{< /hint >}}
npm run prod
> prod
> webpack --mode=production
assets by status 80.9 KiB [cached] 1 asset
asset ../../data/assets.json 158 bytes [compared for emit]
orphan modules 180 KiB [orphan] 81 modules
runtime modules 670 bytes 3 modules
cacheable modules 223 KiB
modules by path ./src/js/*.js 186 KiB
./src/js/globalScripts.js + 81 modules 181 KiB [built] [code generated]
./src/js/colorMode.js 2.69 KiB [built] [code generated]
./src/js/tabDeepAnchor.js 2.31 KiB [built] [code generated]
modules by path ./node_modules/ 37.6 KiB
./node_modules/instant.page/instantpage.js 11.4 KiB [built] [code generated]
./node_modules/clipboard/dist/clipboard.js 26.2 KiB [built] [code generated]
webpack 5.89.0 compiled successfully in 1248 ms
Search
Algolia provides search functionality through their DocSearch program.
{{< hint note >}} Crossplane docs don't use the Netlify Algolia plugin and relies on the Algolia Crawler to discover new content and changes. {{< /hint >}}
Sitemap and robots
Hugo generates the robots.txt
automatically.
For search engine discovery Crossplane uses a sitemap.xml
file generated from
the sitemap.xml
template.
Link checking
Crossplane checks links with Hugo and
htmltest
.
Hugo builds fail for any broken links in a Hugo ref
shortcode.
To catch markdown links htmltest
crawls rendered HTML and validates all
internal links.
On Monday a
GitHub Action
runs to validate external links with htmltest
.
The configuration for htmltest
is in
/utils/htmlstest
.
Annotated website tree
Expand the tab below to see an annotated tree
output of the website repository.
{{}}
├── config.yaml # Hugo configuration file
├── content # Root for all page content
│ ├── contribute
│ ├── master
│ ├── media # Images used in docs pages
│ ├── v1.13
│ ├── v1.14
│ └── v1.15
├── hugo_stats.json # Generated by Hugo writeStats for PurgeCSS
├── netlify.toml # Netlify configuration
├── netlify_build.sh # Custom build script for Netlify
├── package-lock.json # NodeJS dependency version lock
├── package.json # NodeJS dependencies
├── postcss.config.js # PostCSS configuration
├── static # Legacy docs site images
├── themes
│ └── geekboot # The Hugo theme used by Crossplane
│ ├── LICENSE-bootstrap
│ ├── LICENSE-geekdoc
│ ├── assets
│ │ ├── js # Compiled JavaScript
│ │ └── scss # Sytlesheets
│ │ └── bootstrap # Unmodified Bootstrap 5.2 SCSS
│ ├── data # Hugo mapping for JavaScript files. Autogenerated.
│ ├── layouts # HTML template pages
│ │ ├── 404.html # 404 page template
│ │ ├── _default
│ │ │ ├── _markup/ # Templates for rendering specific style components
│ │ │ ├── baseof.html # Entrypoint template for all pages
│ │ │ ├── list.html # List type pages, see partials/single-list.html
│ │ │ ├── redirect.html # Provides HTML redirect functions
│ │ │ ├── section.rss.xml # RSS feed template
│ │ │ ├── single.html # Single type pages, see partials/single-list.html
│ │ │ └── sitemap.xml # Sitemap template
│ │ ├── partials # Template includes
│ │ │ ├── analytics.html # Analytics and trackers
│ │ │ ├── crds.html # Entrypoint for API documentation
│ │ │ ├── docs-navbar.html # Top header links
│ │ │ ├── docs-sidebar.html # left-side navigation menu
│ │ │ ├── favicons.html # Favicons
│ │ │ ├── feature-state-alert.html # Alert box for alpha/beta features
│ │ │ ├── footer.html # Footer copyright and links
│ │ │ ├── ga-tag.html # Google Analytics
│ │ │ ├── google-analytics.html # Notice for GA release version
│ │ │ ├── header.html # <head></head> content
│ │ │ ├── icons # Icons from fontawesome and Crossplane specific
│ │ │ ├── icons.html # SVG includes common enough to be on every page
│ │ │ ├── left-nav.html # Left-hand navigation
│ │ │ ├── master-version-alert.html # Alert box for the master version
│ │ │ ├── mermaid.html # Styling and JavaScript for mermaid diagrams
│ │ │ ├── meta-common.html # <meta> tags used on all pages
│ │ │ ├── ms-clarity.html # Microsoft Clarity tags
│ │ │ ├── old-version-alert.html # Alert box for versions that aren't the latest
│ │ │ ├── redirect.html # HTML meta redirect
│ │ │ ├── release-notes.html # Release note summary page generator
│ │ │ ├── rollworks.html # Rollworks analytics tags
│ │ │ ├── scripts.html # Global JavaScript includes
│ │ │ ├── search-button.html # Algolia search button
│ │ │ ├── sidebar # Static links in the left-side nav
│ │ │ ├── single-list.html # Template used by all single and list type pages
│ │ │ ├── skippy.html # Shift the page when the target is an anchor link
│ │ │ ├── social.html # Social media data includes
│ │ │ ├── stylesheet-cached.html # Static CSS that never changes
│ │ │ ├── stylesheet-dynamic.html # Dynamic CSS that may change between pages
│ │ │ ├── toc.html # Table of contents modifications
│ │ │ ├── utils # Utils imported from Geekdoc theme
│ │ │ └── version-dropdown-menu.html # Version dropdown menu
│ │ └── shortcodes
│ │ ├── check.html # Produce and style a Checkmark
│ │ ├── editCode.html # Code box with editable field
│ │ ├── expand.html # Expand button
│ │ ├── getCRDs.html # Generate API pages
│ │ ├── hint.html # Hint boxes
│ │ ├── hover.html # Hover to highlight
│ │ ├── img.html # Image optimizer
│ │ ├── include.html # Include an external file
│ │ ├── markdown.html # Run content through the markdown engine again
│ │ ├── param.html # Import from Bootstrap theme
│ │ ├── partial.html # Import from Bootstrap theme
│ │ ├── placeholder.html # Import from Bootstrap theme
│ │ ├── propertylist.html # Import from Bootstrap theme
│ │ ├── tab.html # Individual Tab. Related to tabs.html
│ │ ├── table.html # Apply bootstrap styles to markdown tables
│ │ ├── tabs.html # Tab builder, related to tab.html
│ │ ├── url.html # Create a download link to a file. Used by the APIs
│ │ └── year.html # Print the current year
│ └── static # Static global image files
└── utils # Scripts and tools related to the docs
├── htmltest # htmltest link checker
├── vale # Vale linter
│ └── styles
│ ├── Crossplane # Crossplane spelling exceptions
│ ├── Google # Google's Vale rules
│ ├── Microsoft # Microsoft's Vale rules
│ ├── alex # Write inclusive language
│ ├── gitlab # Gitlab's Vale rules
│ ├── proselint # Write better
│ └── write-good # Write better
└── webpack # JavaScript tools
├── package-lock.json # NodeJS dependency version lock
├── package.json # NodeJS dependencies
├── src
│ └── js
│ ├── bootstrap/ # Unmodified Bootstrap JavaScript
│ ├── colorMode.js # Color mode switcher
│ ├── customClipboard.js # Custom copy-to-clipboard tool
│ ├── globalScripts.js # Point of entry for all scripts compiled by Webpack
│ ├── hoverHighlight.js # Hover to highlight
│ ├── slackNotify.js # "Join Crossplane Slack" bubble
│ └── tabDeepAnchor.js # Link inside a tab
└── webpack.config.js
{{}}