docs/content/contribute/infrastructure.md

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:

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.

  • Sass
  • NPM
  • NPM packages defined in /package.json with npm install.

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 the copy-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:

  1. npm run dev
  2. 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

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.

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
│       │   │   ├── preview-version-alert.html  # Alert box for preview versions
│       │   │   ├── 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

{{}}