Phase 3 - Code Examples
Code Examples
Section titled “Code Examples”Biome Configuration
Section titled “Biome Configuration”{ "$schema": "https://biomejs.dev/schemas/2.4.9/schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, "files": { "includes": [ "src/**/*.{astro,ts,tsx,js,jsx,md,mdx}", "docs/**/*.{md,mdx}", "scripts/**/*.{ts,js,mjs}", "*.{md,mdx,ts,js,mjs}" ] }, "formatter": { "enabled": true, "formatWithErrors": true, "indentStyle": "space", "indentWidth": 2, "lineEnding": "lf", "lineWidth": 100, "attributePosition": "auto" }, "javascript": { "formatter": { "jsxQuoteStyle": "double", "quoteProperties": "asNeeded", "trailingCommas": "all", "semicolons": "always", "arrowParentheses": "always", "bracketSpacing": true, "bracketSameLine": false, "quoteStyle": "double" } }, "css": { "formatter": { "enabled": true } }, "linter": { "enabled": true, "rules": { "recommended": true, "complexity": { "noBannedTypes": "error", "noUselessTypeConstraint": "error" }, "correctness": { "noUnusedVariables": "error", "useExhaustiveDependencies": "error" }, "suspicious": { "noExplicitAny": "error", "noImplicitAnyLet": "error" }, "a11y": { "recommended": true }, "style": { "noNonNullAssertion": "warn", "useAsConstAssertion": "warn", "useBlockStatements": "warn", "noParameterAssign": "warn", "useDefaultParameterLast": "warn", "useEnumInitializers": "warn", "useSelfClosingElements": "warn", "useSingleVarDeclarator": "warn", "useNumberNamespace": "warn", "noInferrableTypes": "warn", "noUselessElse": "warn" } } }}The project config also defines a
useNamingConventionrule and anoverridesarray (per-glob rules for Markdown, scripts, Astro, CSS, tests, and config files). See the repo'sbiome.jsonfor the authoritative, complete configuration.
Husky & Commitlint Configuration
Section titled “Husky & Commitlint Configuration”module.exports = { extends: ["@commitlint/config-conventional"],};The project relies on the conventional preset's defaults — it already enforces the
standard type set (feat, fix, docs, style, refactor, perf, test,
chore, ci, build, revert), lower-case subjects, and a 100-character
header limit. No custom rules block is needed.
Installation:
pnpm add -D @commitlint/cli @commitlint/config-conventional# Install Huskypnpm add -D husky lint-stagedpnpm exec husky init
# Create pre-commit hookecho 'pnpm exec lint-staged' > .husky/pre-commit.husky/pre-commit:
pnpm exec lint-staged.husky/commit-msg:
pnpm exec commitlint --edit "$1".husky/pre-push:
#!/usr/bin/env sh# Run the unit test suite before pushing so failures surface locally# instead of in CI. Skip with --no-verify if you have a deliberate reason# (e.g. pushing WIP for backup).pnpm run test:unitHusky 9 hook files are plain shell commands — the
husky.shsourcing boilerplate from Husky 8 is gone.
Updated Package Scripts
Section titled “Updated Package Scripts”// package.json — everyday scripts (the ones a cloner actually runs).// See package.json for the full maintainer & advanced set (ADR-052 taxonomy).{ "scripts": { "predev": "pnpm run tokens:build", "dev": "astro dev", "dev:host": "astro dev --host", "dev:debug": "astro dev --verbose", "build": "pnpm run env:validate && pnpm run tokens:build && astro build", "build:ci": "pnpm run env:validate && pnpm run tokens:build && astro build --verbose", "preview": "astro preview", "preview:build": "pnpm run build && astro preview", "tokens:build": "tsx scripts/src/build-tokens.ts", "format": "biome format . --write", "format:check": "biome format .", "lint": "biome check .", "lint:md": "markdownlint-cli2 \"**/*.md\" \"**/*.mdx\"", "lint:md:fix": "markdownlint-cli2 \"**/*.md\" \"**/*.mdx\" --fix", "check": "SITE_URL=${SITE_URL:-http://localhost:4321} astro check", "check:types": "tsc --noEmit", "quality": "pnpm run format && pnpm run lint && pnpm run lint:md && pnpm run check", "quality:ci": "pnpm run format:check && pnpm run lint && pnpm run lint:md && pnpm run check && pnpm run test:unit && pnpm run agents:check && pnpm run version:check && pnpm run og:check && pnpm run docs:count", "test": "SITE_URL=http://localhost:4321 vitest", "test:unit": "SITE_URL=http://localhost:4321 vitest run", "test:coverage": "SITE_URL=http://localhost:4321 vitest run --coverage", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:a11y": "playwright test --grep=\"@a11y\"", "clean": "rm -rf dist .astro tokens/dist", "clean:all": "rm -rf dist .astro tokens/dist node_modules/.cache", "prepare": "husky" }}Note on Local vs. CI Scripts: The
qualityscript is designed for fast local checks (it formats in place). Thequality:ciscript is the CI variant:format:check,lint,lint:md,check,test:unit, plus the repo’s consistency gates (agents:check,version:check,og:check,docs:count). End-to-end tests are not part ofquality:ci— CI runs Playwright as a separate step inci.yml.
Lint-staged Configuration
Section titled “Lint-staged Configuration”// package.json - lint-staged configuration{ "lint-staged": { "*.{astro,ts,tsx,js,jsx,json,yml,yaml}": "biome check --write --no-errors-on-unmatched", "*.{md,mdx}": "markdownlint-cli2 --fix" }}GitHub Actions CI Workflow
Section titled “GitHub Actions CI Workflow”This is the starter’s actual workflow. A single build-test job runs the full quality gate (quality:ci), unit tests with coverage, budget and contrast validation, the build, the JS/image/font budget gates, Playwright e2e, and the dependency/SBOM security scans; link-check, semgrep, and gitleaks run as separate jobs.
name: CI
on: push: branches: [master, develop] pull_request: branches: [master, develop]
permissions: contents: read security-events: write
jobs: build-test: runs-on: ubuntu-latest env: SITE_URL: https://${{ github.repository_owner }}.github.io
steps: - name: Checkout uses: actions/checkout@v7
- name: Setup Node.js uses: actions/setup-node@v7 with: node-version-file: '.nvmrc'
- name: Setup PNPM uses: pnpm/action-setup@v6 with: run_install: false
- name: Get pnpm store directory shell: bash run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT id: pnpm-cache
- name: Cache pnpm store uses: actions/cache@v6 with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: ${{ runner.os }}-pnpm-store-
- name: Install dependencies run: pnpm install --frozen-lockfile
- name: Lint, format & type-check run: pnpm run quality:ci
- name: Unit tests with coverage run: pnpm run test:coverage
- name: Upload coverage report if: always() uses: actions/upload-artifact@v7 with: name: coverage-report path: coverage/ retention-days: 14 if-no-files-found: ignore
- name: Validate budget overrides run: pnpm run budgets:validate
- name: Validate semantic color contrast run: pnpm run design:validate
- name: Build site run: pnpm run build
- name: Enforce JS bundle size budget shell: bash run: | set -e JS_BUNDLE_PATH="dist/_astro" JS_SIZE_LIMIT_BYTES=163840 # 160 KB raw JS if [ ! -d "$JS_BUNDLE_PATH" ]; then echo "JS bundle path not found. Skipping size check." exit 0 fi JS_SIZE=$(find "$JS_BUNDLE_PATH" -name "*.js" -type f -exec stat -c%s {} + | awk '{sum+=$1} END {print sum}') JS_SIZE=${JS_SIZE:-0} echo "Total raw JS size: $JS_SIZE bytes (limit: $JS_SIZE_LIMIT_BYTES)" if [ "$JS_SIZE" -gt "$JS_SIZE_LIMIT_BYTES" ]; then echo "::error::JavaScript bundle size ($JS_SIZE bytes) exceeds limit ($JS_SIZE_LIMIT_BYTES bytes)" exit 1 fi
- name: Enforce per-image size budget — source (ADR-057) run: pnpm run images:gate
- name: Enforce per-image size budget — build output (ADR-057) # Catches oversized emitted raster, e.g. heavyweight PNG fallbacks # generated alongside AVIF/WebP. run: IMAGE_GATE_ROOTS=dist pnpm run images:gate
- name: Enforce font preload budget (ADR-058) run: pnpm run fonts:gate
- name: Install Playwright browsers run: pnpm exec playwright install --with-deps chromium
- name: Run E2E tests (Chromium) run: pnpm exec playwright test --project=chromium
- name: Security audit (high severity) run: pnpm run audit:ci
- name: Trivy SBOM scan uses: aquasecurity/trivy-action@v0.36.0 with: scan-type: 'fs' format: 'sarif' output: 'trivy-results.sarif'
- name: Upload security results if: success() && (hashFiles('trivy-results.sarif') != '') uses: github/codeql-action/upload-sarif@v4 continue-on-error: true with: sarif_file: 'trivy-results.sarif'
link-check: runs-on: ubuntu-latest
steps: - name: Checkout uses: actions/checkout@v7
- name: Check markdown links uses: gaurav-nelson/github-action-markdown-link-check@v1 continue-on-error: true with: use-quiet-mode: 'yes' use-verbose-mode: 'no' config-file: '.markdown-link-check.json' folder-path: 'docs/' file-extension: '.md'
# SAST + secret scanning (ADR-046). Both are halt-on-violation gates (ADR-039): # the scan command exits non-zero on a finding and fails the build. # Run in their official containers — Semgrep's docs mandate the semgrep/semgrep # image, and the gitleaks CLI avoids the gitleaks-action org-license requirement. semgrep: name: Semgrep SAST runs-on: ubuntu-latest # Dependabot PRs only touch manifests and run with a restricted token; skip. if: github.actor != 'dependabot[bot]' container: image: semgrep/semgrep steps: - name: Checkout uses: actions/checkout@v7
- name: Semgrep scan # --error exits 1 on findings; --config p/* pulls public registry rulesets. run: semgrep scan --config p/javascript --config p/typescript --config p/secrets --error
gitleaks: name: Secret scan runs-on: ubuntu-latest if: github.actor != 'dependabot[bot]' container: image: ghcr.io/gitleaks/gitleaks:v8.30.1 steps: - name: Checkout uses: actions/checkout@v7
- name: Gitleaks scan # `dir` scans the working tree; --exit-code 1 fails the build on any leak. run: gitleaks dir . --config .gitleaks.toml --exit-code 1 --verboseBranch Protection Rules (3.10)
Section titled “Branch Protection Rules (3.10)”Implementing branch protection ensures that your master branch always stays in a releasable state. The rules below apply to both MVP and Showcase tracks.
-
Create a protection rule
- Navigate to Repository → Settings → Branches → Branch protection rules.
- Click Add rule and set Branch name pattern to
master(or your default branch).
-
Require status checks to pass
- Enable Require status checks to pass before merging.
- Select the checks created by the CI workflow above (context names follow
<workflow> / <job name>; jobs without aname:key surface under their job id):CI / build-test– quality gate, unit tests, budgets, build, e2e, security auditCI / link-check– markdown link checkCI / Semgrep SASTandCI / Secret scan– security gates
- Keep Require branches to be up to date before merging enabled to prevent stale merges.
-
Additional recommended settings
- Require a pull-request review before merging →
1approving review. - Dismiss stale pull request approvals when new commits are pushed.
- Require linear history to avoid merge commits.
- Include administrators so that rules apply to everyone.
- Require a pull-request review before merging →
-
Automating with
ghCLI (optional)The same rule can be applied programmatically:
Terminal window gh api \--method PUT \-H "Accept: application/vnd.github+json" \/repos/:owner/:repo/branches/master/protection \-F required_status_checks.strict=true \-F required_status_checks.contexts[]='CI / build-test' \-F required_status_checks.contexts[]='CI / link-check' \-F required_status_checks.contexts[]='CI / Semgrep SAST' \-F required_status_checks.contexts[]='CI / Secret scan' \-F enforce_admins=true \-F required_pull_request_reviews.dismiss_stale_reviews=true \-F required_pull_request_reviews.required_approving_review_count=1 \-F restrictions=null
Once the rule is in place, any pull request that does not pass the CI workflow will be blocked from merging, completing step 3.10 of this phase.
VSCode Settings (optional)
Section titled “VSCode Settings (optional)”The starter does not ship a .vscode/ directory — editor configuration is left to each developer. If you want format-on-save with Biome in VSCode, a suggested settings.json:
// .vscode/settings.json (not shipped with the starter — create it yourself if wanted){ "editor.formatOnSave": true, "editor.defaultFormatter": "biomejs.biome", "editor.codeActionsOnSave": { "quickfix.biome": "explicit", "source.organizeImports.biome": "explicit" }, "[astro]": { "editor.defaultFormatter": "astro-build.astro-vscode" }, "files.associations": { "*.css": "tailwindcss" }, "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "tailwindCSS.experimental.classRegex": [ ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], ["clsx\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] ]}Contributing Guidelines
Section titled “Contributing Guidelines”# Contributing Guide
## Development Setup
1. Install dependencies:
```bash pnpm install ```
2. Build design tokens:
```bash pnpm run tokens:build # Note: You'll need to create the './scripts/src/build-tokens.ts' file as part of implementing the design token system (Phase 2). ```
3. Start development server:
```bash pnpm run dev ```