Docs Infrastructure
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.
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.
The Hugo web server is only used for local development. Crossplane documentation uses Netlify for hosting.
Hugo only acts as an HTML compiler.
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/.
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.
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.
Running Hugo in production mode requires the Hugo extended version to
support PostCSS.
Standard Hugo fails to build the documentation.
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.
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.
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.
/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.JavaScript files
bootstrap/is the entire Bootstrap JavaScript library.colorMode.jsprovides the ability to change the light and dark mode color theme.customClipboard.jssupports thecopy-linescode box function.globalScripts.jsis the point of entry for Webpack to determine all dependencies. This bundles instant.page and Bootstrap’s JavaScript.hoverHighlight.jsprovides dynamic “hover to highlight” function.slackNotify.jscreates the “Join Crossplane Slack” bubble on the home page.tabDeepAnchor.jsrewrites 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.
Building JavaScript has two options:
npm run devnpm 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.
npm run prod to build the compiled JavaScript to use on the
Crossplane documentation site. 1npm run prod
2
3> prod
4> webpack --mode=production
5
6assets by status 80.9 KiB [cached] 1 asset
7asset ../../data/assets.json 158 bytes [compared for emit]
8orphan modules 180 KiB [orphan] 81 modules
9runtime modules 670 bytes 3 modules
10cacheable modules 223 KiB
11 modules by path ./src/js/*.js 186 KiB
12 ./src/js/globalScripts.js + 81 modules 181 KiB [built] [code generated]
13 ./src/js/colorMode.js 2.69 KiB [built] [code generated]
14 ./src/js/tabDeepAnchor.js 2.31 KiB [built] [code generated]
15 modules by path ./node_modules/ 37.6 KiB
16 ./node_modules/instant.page/instantpage.js 11.4 KiB [built] [code generated]
17 ./node_modules/clipboard/dist/clipboard.js 26.2 KiB [built] [code generated]
18webpack 5.89.0 compiled successfully in 1248 ms
Search
Algolia provides search functionality through their DocSearch program.
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.
1├── config.yaml # Hugo configuration file
2├── content # Root for all page content
3│ ├── contribute
4│ ├── master
5│ ├── media # Images used in docs pages
6│ ├── v1.13
7│ ├── v1.14
8│ └── v1.15
9├── hugo_stats.json # Generated by Hugo writeStats for PurgeCSS
10├── netlify.toml # Netlify configuration
11├── netlify_build.sh # Custom build script for Netlify
12├── package-lock.json # NodeJS dependency version lock
13├── package.json # NodeJS dependencies
14├── postcss.config.js # PostCSS configuration
15├── static # Legacy docs site images
16├── themes
17│ └── geekboot # The Hugo theme used by Crossplane
18│ ├── LICENSE-bootstrap
19│ ├── LICENSE-geekdoc
20│ ├── assets
21│ │ ├── js # Compiled JavaScript
22│ │ └── scss # Sytlesheets
23│ │ └── bootstrap # Unmodified Bootstrap 5.2 SCSS
24│ ├── data # Hugo mapping for JavaScript files. Autogenerated.
25│ ├── layouts # HTML template pages
26│ │ ├── 404.html # 404 page template
27│ │ ├── _default
28│ │ │ ├── _markup/ # Templates for rendering specific style components
29│ │ │ ├── baseof.html # Entrypoint template for all pages
30│ │ │ ├── list.html # List type pages, see partials/single-list.html
31│ │ │ ├── redirect.html # Provides HTML redirect functions
32│ │ │ ├── section.rss.xml # RSS feed template
33│ │ │ ├── single.html # Single type pages, see partials/single-list.html
34│ │ │ └── sitemap.xml # Sitemap template
35│ │ ├── partials # Template includes
36│ │ │ ├── analytics.html # Analytics and trackers
37│ │ │ ├── crds.html # Entrypoint for API documentation
38│ │ │ ├── docs-navbar.html # Top header links
39│ │ │ ├── docs-sidebar.html # left-side navigation menu
40│ │ │ ├── favicons.html # Favicons
41│ │ │ ├── feature-state-alert.html # Alert box for alpha/beta features
42│ │ │ ├── footer.html # Footer copyright and links
43│ │ │ ├── ga-tag.html # Google Analytics
44│ │ │ ├── google-analytics.html # Notice for GA release version
45│ │ │ ├── header.html # <head></head> content
46│ │ │ ├── icons # Icons from fontawesome and Crossplane specific
47│ │ │ ├── icons.html # SVG includes common enough to be on every page
48│ │ │ ├── left-nav.html # Left-hand navigation
49│ │ │ ├── master-version-alert.html # Alert box for the master version
50│ │ │ ├── mermaid.html # Styling and JavaScript for mermaid diagrams
51│ │ │ ├── meta-common.html # <meta> tags used on all pages
52│ │ │ ├── old-version-alert.html # Alert box for versions that aren't the latest
53│ │ │ ├── preview-version-alert.html # Alert box for preview versions
54│ │ │ ├── redirect.html # HTML meta redirect
55│ │ │ ├── release-notes.html # Release note summary page generator
56│ │ │ ├── scripts.html # Global JavaScript includes
57│ │ │ ├── search-button.html # Algolia search button
58│ │ │ ├── sidebar # Static links in the left-side nav
59│ │ │ ├── single-list.html # Template used by all single and list type pages
60│ │ │ ├── skippy.html # Shift the page when the target is an anchor link
61│ │ │ ├── social.html # Social media data includes
62│ │ │ ├── stylesheet-cached.html # Static CSS that never changes
63│ │ │ ├── stylesheet-dynamic.html # Dynamic CSS that may change between pages
64│ │ │ ├── toc.html # Table of contents modifications
65│ │ │ ├── utils # Utils imported from Geekdoc theme
66│ │ │ └── version-dropdown-menu.html # Version dropdown menu
67│ │ └── shortcodes
68│ │ ├── check.html # Produce and style a Checkmark
69│ │ ├── editCode.html # Code box with editable field
70│ │ ├── expand.html # Expand button
71│ │ ├── getCRDs.html # Generate API pages
72│ │ ├── hint.html # Hint boxes
73│ │ ├── hover.html # Hover to highlight
74│ │ ├── img.html # Image optimizer
75│ │ ├── include.html # Include an external file
76│ │ ├── markdown.html # Run content through the markdown engine again
77│ │ ├── param.html # Import from Bootstrap theme
78│ │ ├── partial.html # Import from Bootstrap theme
79│ │ ├── placeholder.html # Import from Bootstrap theme
80│ │ ├── propertylist.html # Import from Bootstrap theme
81│ │ ├── tab.html # Individual Tab. Related to tabs.html
82│ │ ├── table.html # Apply bootstrap styles to markdown tables
83│ │ ├── tabs.html # Tab builder, related to tab.html
84│ │ ├── url.html # Create a download link to a file. Used by the APIs
85│ │ └── year.html # Print the current year
86│ └── static # Static global image files
87└── utils # Scripts and tools related to the docs
88 ├── htmltest # htmltest link checker
89 ├── vale # Vale linter
90 │ └── styles
91 │ ├── Crossplane # Crossplane spelling exceptions
92 │ ├── Google # Google's Vale rules
93 │ ├── Microsoft # Microsoft's Vale rules
94 │ ├── alex # Write inclusive language
95 │ ├── gitlab # Gitlab's Vale rules
96 │ ├── proselint # Write better
97 │ └── write-good # Write better
98 └── webpack # JavaScript tools
99 ├── package-lock.json # NodeJS dependency version lock
100 ├── package.json # NodeJS dependencies
101 ├── src
102 │ └── js
103 │ ├── bootstrap/ # Unmodified Bootstrap JavaScript
104 │ ├── colorMode.js # Color mode switcher
105 │ ├── customClipboard.js # Custom copy-to-clipboard tool
106 │ ├── globalScripts.js # Point of entry for all scripts compiled by Webpack
107 │ ├── hoverHighlight.js # Hover to highlight
108 │ ├── slackNotify.js # "Join Crossplane Slack" bubble
109 │ └── tabDeepAnchor.js # Link inside a tab
110 └── webpack.config.js