As part of our effort to standardize on Next.js and MDX as the platform for HashiCorp's product websites and documentation, we'll be migrating the documentation portion of the Terraform website to MDX sometime on December 13 and 14.
MDX is a dialect of Markdown that allows you to use JSX, the component language commonly used for React.
Currently, we're using a hybrid approach where the marketing pages for terraform.io
are served from a Next.js application running on Vercel, and the documentation pages are generated by Middleman and served by Fastly. After this change, those documentation pages will be served from the same Next.js application on Vercel as our marketing pages.
All Markdown files (previously using the .html.md
extension) will be automatically translated into MDX, and use the .mdx
extension.
The content
directory of terraform-website
will now contain the docs files at the root, instead of them being placed in a source
directory. The folder will also contain symlinks into terraform
and terraform-cdk
for the following folders:
terraform
content/cli
->terraform/website/docs/cli
content/configuration
->terraform/website/docs/configuration
content/guides
->terraform/website/guides
content/internals
->terraform/website/docs/internals
content/intro
->terraform/website/intro
content/language
->terraform/website/docs/language
terraform-cdk
content/cdktf
->terraform-cdk/website/docs/cdktf
These symlinks point to the submodules, which are both pinned to the stable-website
branch of their respective repos.
Previously, the docs navigation was a large HTML file that needed to be manually updated to include new pages. With the new Next.js setup, we generate the navigation structure from JSON files in the /data
folder. Here's an example from the docs-nav-data.json
file which controls the navigation sidebar on the /docs
path:
[
{ "title": "Intro to Terraform", "href": "/intro" },
{ "title": "Configuration Language", "href": "/language" },
{ "title": "Terraform CLI", "href": "/cli" },
{ "title": "Terraform Cloud", "href": "/cloud-docs" },
{ "title": "Terraform Enterprise", "href": "/enterprise" },
{ "title": "Provider Use", "href": "/language/providers" },
{ "title": "Plugin Development", "href": "/plugin" },
{ "title": "Terraform Registry Publishing", "href": "/registry" },
{ "title": "CDK for Terraform", "href": "/cdktf" },
{ "title": "Glossary", "path": "glossary" }
]
title
determines the actual text listed in the sidebar. href
is used to jump to a new page not contained as a child page for the given navigation file (or an external URL like learn.hashicorp.com
), and path
is used to navigate to a child page. In this example, the Glossary is expected to be at a glossary.mdx
file in the content/docs
folder. If that file wasn't able to be found, a build error will be thrown. Additionally, if an .mdx
file was in the content/docs
folder but not listed in the docs-nav-data.json
file, an error will be thrown. This ensures that all .mdx
files are in the navigation structure, and all files referenced by the navigation data exist on disk.
We can also define child routes using the routes
parameter. Here's an example from the cloud-docs-nav-data.json
file.
[
{ "heading": "Terraform Cloud / Enterprise" },
{ "title": "Overview of Features", "path": "overview" },
{
"title": "Migrating from Local Terraform",
"routes": [
{ "title": "Overview", "path": "migrate" },
{
"title": "Migrating Multiple Workspaces",
"path": "migrate/workspaces"
}
]
}
In this example, "Overview of Features" will link to /cloud-docs/overview
, and render the MDX file at content/cloud-docs/overview.mdx
. The "Overview" item beneath the "Migrating for Local Terraform" heading will link to /cloud-docs/migrate
, and render the MDX file at content/cloud-docs/migrate.mdx
, but will also render the file from content/cloud-docs/migrate/index.mdx
if the previous file couldn't be found (similar to how index.html
works for most web servers). The "Migrating Multiple Workspaces" item will link to /cloud-docs/migrate/workspaces
, and render the file at content/cloud-docs/migrate/workspaces.mdx
.
One thing to keep in mind is that the heading "Migrating from Local Terraform" isn't linked to a page; the convention we're using now is to define a child route with the heading "Overview" as used above. This allows the user to expand/collapse navigation areas without performing a navigation.
Additionally, you can control the heading displayed above the sidebar by placing an object with the key heading
as the first element of the navigation data array.
The primary navigation for the site (that renders horizontally at the top) is defined in data/primary-navigation.js
. It's largely the same, except it uses text
instead of title
, url
instead of path
and href
, and submenu
instead of routes
.
While Markdown allows you to embed arbitrary HTML, MDX requires that you use JSX. While these two are very similar, there's some differences that, if you're not careful, can result in the site being unable to be built. Some HTML attributes use different keys in JSX (the most prominent being that JSX uses className
instead of class
). If you run into a situation where your embedded HTML snippet isn't working correctly, this is likely the cause.
Since we're bundling content from multiple repos, and because we want to make sure that moving docs to new paths doesn't result in breaking links, we're removing all relative links, instead preferring to use the full path to docs pages. Where you'd use something like [GitHub Enterprise](./github-enterprise.html)
to link to /cloud-docs/vcs/github-enterprise
, we're now being more explicit and using [GitHub Enterprise](/cloud-docs/vcs/github-enterprise)
. Furthermore you no longer need to include any .html
extension when writing URLs.
Previously static assets like images and PDFs were stored in terraform-website
at content/source/assets
. After the migration, they'll be stored in the public
folder of the terraform-website
reposity. All files within this folder will be available at the root of the site. For example, public/assets/files/press-kit.zip
will be available at https://www.terraform.io/assets/files/press-kit.zip
. Images will now be located in the public/img
folder. For example, public/img/logo-hashicorp.svg
can be referenced in MDX with the Markdown image syntax:
![Terraform Logo with HashiCorp Wordmark](/img/logo-hashicorp.svg)
For organizational purposes, images used in the docs should be placed in the public/img/docs
folder.
Redirects for old URLs beginning with /docs
are defined in a 1:1 mapping inside data/docs-redirects.js
. All other redirects are defined in redirects.next.js
with the following structure:
{
"source": "the originating URL",
"destination": "the URL you want to redirect to",
"permanent": true
}
It's important to note that redirects aren't processed for client-side navigations, so if you move a document, please update all internal references to the URL.
Thanks to the removal of Ruby and Middleman, you'll also be able to run the website locally more easily. With Node.js v14+ installed, the following commands will get the site running locally:
git clone https://github.com/hashicorp/terraform-website
cd terraform-website
git submodule update --init
npm install
npm start
This will start the site at http://localhost:3000
. As you click through the site, you'll notice that it takes a few seconds to load each page; this is because Next.js is building each page on the fly. To run the site in production mode, where each page is pre-generated, use the following:
npm run build
npx next start
The main code for terraform.io
will continue to live in the terraform-website
repo. That repo will contain two submodules: one for terraform
and another for terraform-cdk
. These submodules will point to the stable-website
branch of their respective repos, and have symlinks into the content
directory of terraform-website
.
Our Markdown syntax will largely remain the same; features like alerts and code blocks will work the same as they did previously.