Skip to content

ddev/ddev.com

Repository files navigation

ddev.com Astro code

Source code for ddev.com’s static front end, built with Astro to keep things organized, maintainable, and fast.

Overview

Main Ingredients

Project Structure

The file structure follows a typical Astro project layout.

Most pages are built with Astro components, while blog posts and authors are sourced from local Markdown that’s validated with tidy schemas we get using content collections.

  • cache/ – custom, project-specific folder for caching GitHub responses in local developent to reduce API calls.
  • public/ – images and redirects that will be copied verbatim into the generated dist/ directory.
  • src/ – components, layouts, styles, and supporting TypeScript/JavaScript.
    • components/ – indiviaul .astro components used in pages. (You can also use components for UI frameworks like Vue, React, and Svelte!)
    • content/ – configuration and Markdown for the blog’s content collections.
    • layouts/ – contains the single component we use for every page.
    • lib/ – helper code for fetching data from GitHub, building the search index, injecting read time into frontmatter, and handling common formatting.
    • pages/.astro pages whose filenames directly translate into routes for the site.
    • styles/ – global PostCSS that’s not already handled by the Tailwind plugin.
  • .env.example – file you’ll want to rename .env and populate for a new environment.
  • .nvmrc – Node.js version to support nvm use.
  • .prettierrc – rules for Prettier code formatting.
  • astro.config.mjs – Astro configuration.
  • package.json – standard file that details the project’s packages and versions.
  • README.md – you are here! 👋
  • tailwind.config.cjsconfiguration for Tailwind and the Tailwind Typography plugin we’re using.
  • tsconfig.jsonTypeScript configuration.

Development

Commands

All commands are run from the root of the project, from a terminal:

Command Action
npm install Installs dependencies
npm run dev Starts local dev server at localhost:3000
npm run build Build your production site to ./dist/
npm run preview Preview your build locally, before deploying
npm run astro ... Run CLI commands like astro add, astro preview
npm run astro --help Get help using the Astro CLI
npm run textlint Run textlint on content collections
npm run textlint:fix Apply fixable updates to resolve texlint errors

Local Development Setup

  1. Run cp .env.example .env to create a .env file for environment variables. (Don’t check this in!)
  2. Create a classic GitHub access token with these scopes: repo, read:org, read:user, and read:project.
  3. Paste the GitHub token after .env’s GITHUB_TOKEN=.

DDEV setup

DDEV already has all the dependencies included.

  1. Run ddev start to start and set up the project’s dependencies.

To rebuild a static copy of the site, run ddev npm run build. The contents of the dist/ folder are what gets deployed to Cloudflare Pages and can be found at https://.ddev.site. The dev server runs on a web_extra_daemons, it includes Vite HMR (hot module reloading) among other features and it can be found at https://.ddev.site:4321.

Troubleshooting steps

Setup without DDEV

Check out the project in your favorite Node.js environment, ideally running nvm. We’ll install dependencies, add a GitHub API key, and run a local dev server with a hot-reloading browser URL.

  1. Run nvm use to make sure you’re running an appropriate Node.js version.
  2. Run npm install to set up the project’s dependencies.
  3. Run npm run dev to start Astro’s dev server. If it fails then run npm cache clean --force && npm install && npm run dev.
  4. Visit the URL displayed in your terminal. (Probably http://localhost:4321/.) The site will automatically refresh as you work on it, displaying errors in the relevant terminal or browser console.

To generate a static copy of the site, run npm run build. The contents of the dist/ folder are exactly what get deployed to Cloudflare Pages. You can preview locally by running npm run preview or using a tool like serve.

Switching from Without DDEV to with DDEV

Make sure to delete your node_modules/ directory and run ddev npm install. The change in architecture can create odd issues otherwise.

Managing Content

The site’s content lives in either .astro components that resemble souped-up HTML, or Markdown files organized into schema-validated content collections.

Blog Posts

Blog posts are Markdown files with frontmatter that live in src/content/blog/.

To add a new blog post, use this Markdown as a template:

---
title: "It’s A Post!"
pubDate: 2023-01-01
summary:
author: Randy Fay
featureImage:
  src: /img/blog/kebab-case.jpg
  alt:
  caption:
  credit:
categories:
  - DevOps
---

Name your file with a kebab-case, URL-and-SEO-friendly slug with a .md extension, and drop it in the src/content/blog/ directory.

Give it a succinct title, and if you include a feature image be sure to write descriptive alt text along with an optional caption and image credit. The caption: and credit: fields can both use Markdown, but you’ll probably need to wrap the whole value in straight quotes (").

The Astro build doesn’t do any fancy image sizing or optimization, so be sure any images you add are production-ready: an appropriate format for the image type (JPEG, PNG, or SVG), with size no larger than ~1–2MB and dimensions no greater than 2000px or so. Use an app like ImageOptim to quickly apply lossless compression.

Choose whichever categories apply, with special attention to the first because it’ll be displayed on post summary cards:

  • Announcements (releases, organization news, etc.)
  • Community (events, third-party developments, etc.)
  • DevOps (workflows, infrastructure, etc.)
  • Performance (benchmarking, tips, etc.)
  • Guides (how-to style posts)
  • Videos (posts that include or primarily feature video content)

💡 If you’re publishing work from a new author, add an entry for them in src/content/authors/! The "name" value needs to match the one you’re using in your post frontmatter.

Pages

Add a .astro file to the pages/ directory, where its name will become the page slug. Use an existing page to grab and re-use whatever layout and components you can to save yourself time and encourage consistency with the rest of the site.

If you need to dynamically add multiple pages, see files with brackets like src/blog/[page].astro, src/blog/category/[slug].astro, and src/blog/author/[slug].astro for examples.

Textlint

A basic textlint configuration lives in .textlintrc and runs against src/content/** to try and help keep language consistent and accurate. This doesn’t yet conform to the DDEV docs spellcheck rules and massive exclusion list, but ideally the two can someday converge.

Textlint’s default terminology catches a lot of accepted best practices on its own, where the only major override is to allow “website” (instead of its suggested “site”) because it’s rampant in blog posts and documentation. Same with the “front end” and “back end” conundrum and two-word “command line”.

Run npm run textlint to check everything, and you can apply “fixable” changes using npm run textlint:fix. Be careful automating fixes to be sure they don’t have any unintended side effects!

Sponsor Management

The src/featured-sponsors.json file is used for manually curating prominent sponsors.

While it’s a bit of a pain and still relies on coercion in some places, it lets us collect pristine, brand-friendly resources in one place and use them in different contexts.

It’s used to display sponsor details in a few places:

  1. The homepage “Featured Sponsors” list.
  2. The leading bubbles on the Support DDEV page’s “Sponsor Development” grid.
  3. The procedurally-generated featured sponsors light and dark SVG images used in the main project readme.

If you’re adding a new item to the array, choose whichever position it should appear in and use the following format:

{
  "name": "Platform.sh",
  "type": "major",
  "logo": "/logos/platform.sh.svg",
  "squareLogo": "/logos/platform.sh-square.svg",
  "url": "https://platform.sh",
  "github": "platformsh",
},
  • name – the human-friendly organization name. (Be sure this is formatted exactly as it’s used on the website or GitHub profile!)
  • type – can be "major" or "standard" depending on contribution level. (Not currently used but can affect styling later.)
  • logo – absolute, webroot-relative path for a logo you’ve added to the public/logos/ directory. Make sure this is a clean, optimized vector SVG file unless it’s a person’s headshot. (Again, follow the organization’s brand guide wherever possible!)
  • squareLogo – a square variant of the organization’s logo, to be used in places like the Support DDEV layout. No need to add this if logo is already square.
  • url – organization’s website URL.
  • github – optional GitHub username when relevant, which can be used to make sure the sponsor doesn’t appear twice in a list—as seen in the Sponsors.astro component.

Build & Deployment

For the site to exist at ddev.com, it needs to be built and hosted somewhere. Cloudflare Pages responds to commits in order to build and deploy the site.

On every push to the main branch, the following happens:

  • GitHub Actions tests the site using this workflow.
  • Cloudflare Pages runs npm run build, and deploys the resulting output from dist/.
    • Cloudflare Pages is also configured to build previews for branches on this repository. It will automatically add a comment with the build status and eventual URL(s) to any PR.

Secrets

The site uses Octokit to make REST and GraphQL API requests for repository and contribution details from github.com. It needs an API token to authenticate these requests to function and avoid hitting quota limits.

GitHub supplies its own private GITHUB_TOKEN in the GitHub Actions build environment. In any other environment, including local development, you’ll need to populate a GITHUB_TOKEN environment variable with a classic GitHub personal access token that has repo, read:org, read:user, and read:project scopes.

A valid Personal Access Token (PAT) must also be supplied to Cloudflare.

Resources