Skip to content

Scaffold

FieldValue
TypeSkill Resource
Source~/.copilot/skills/frontend/scripts/scaffold.sh
DescriptionNot specified

Source Content

#!/usr/bin/env bash
#
# scaffold.sh — lay down David's standard dmwd-io Astro 5 (SSR) starter and
# install dependencies. One command, no reinvention.
#
# Usage:
# scaffold.sh <target-dir> [--name <pkg-name>] [--no-install] [--force]
#
# <target-dir> where to create the project (created if missing)
# --name <name> package.json name (default: the target dir basename)
# --no-install lay files down but skip `pnpm install`
# --force overwrite existing template files in the target
#
# What it does:
# 1. Copies the template tree (.npmrc, astro.config.mjs, tsconfig.json,
# biome.json, src/content/config.ts, Taskfile.yml) into <target-dir>.
# 2. Writes a package.json pinned to the dmwd-io Astro 5 stack.
# 3. Adds .gitignore, .env.example, and a minimal src/ entry so the app runs.
# 4. Runs `pnpm install` (unless --no-install), warning if NPM_TOKEN is unset.
#
# Exit codes: 0 ok · 1 usage/precondition error · 2 copy/write failure.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATES="$SCRIPT_DIR/../templates/astro-starter"
# Pinned stack versions — bump deliberately, in one place. (Astro 5 line.)
ASTRO_VERSION="^5.18.2"
NODE_ADAPTER_VERSION="^9.5.5"
DESIGN_SYSTEM_VERSION="latest"
BIOME_VERSION="^2.5.0"
TYPESCRIPT_VERSION="^6.0.3"
TS_PLUGIN_VERSION="^1.10.0"
# --- args -------------------------------------------------------------------
TARGET=""
PKG_NAME=""
DO_INSTALL=1
FORCE=0
die() { echo "scaffold.sh: $*" >&2; exit 1; }
while [ $# -gt 0 ]; do
case "$1" in
--name) PKG_NAME="${2:-}"; shift 2 ;;
--no-install) DO_INSTALL=0; shift ;;
--force) FORCE=1; shift ;;
-h | --help) sed -n '2,30p' "$0"; exit 0 ;;
-*) die "unknown flag: $1" ;;
*) [ -z "$TARGET" ] && TARGET="$1" && shift || die "unexpected arg: $1" ;;
esac
done
[ -n "$TARGET" ] || die "missing <target-dir> (try --help)"
[ -d "$TEMPLATES" ] || die "templates dir not found at $TEMPLATES"
command -v pnpm >/dev/null 2>&1 || die "pnpm not found — install it: npm i -g pnpm"
mkdir -p "$TARGET"
TARGET="$(cd "$TARGET" && pwd)"
[ -z "$PKG_NAME" ] && PKG_NAME="$(basename "$TARGET")"
echo "==> Scaffolding dmwd-io Astro 5 project: $PKG_NAME"
echo " target: $TARGET"
# --- copy guard -------------------------------------------------------------
copy() {
local src="$1" dest="$2"
if [ -e "$dest" ] && [ "$FORCE" -ne 1 ]; then
echo " skip (exists, use --force): ${dest#"$TARGET"/}"
return 0
fi
mkdir -p "$(dirname "$dest")"
cp "$src" "$dest" || die "failed to copy $src"
echo " wrote: ${dest#"$TARGET"/}"
}
# --- 1. template tree -------------------------------------------------------
copy "$TEMPLATES/.npmrc" "$TARGET/.npmrc"
copy "$TEMPLATES/astro.config.mjs" "$TARGET/astro.config.mjs"
copy "$TEMPLATES/tsconfig.json" "$TARGET/tsconfig.json"
copy "$TEMPLATES/biome.json" "$TARGET/biome.json"
copy "$TEMPLATES/Taskfile.yml" "$TARGET/Taskfile.yml"
copy "$TEMPLATES/src/content/config.ts" "$TARGET/src/content/config.ts"
# --- 2. package.json --------------------------------------------------------
PKG_JSON="$TARGET/package.json"
if [ -e "$PKG_JSON" ] && [ "$FORCE" -ne 1 ]; then
echo " skip (exists, use --force): package.json"
else
cat > "$PKG_JSON" <<JSON
{
"name": "$PKG_NAME",
"type": "module",
"version": "0.0.0",
"private": true,
"packageManager": "pnpm@10.0.0",
"engines": { "node": ">=20.0.0" },
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "node ./dist/server/entry.mjs",
"check": "astro check",
"lint": "biome lint .",
"format": "biome format --write ."
},
"dependencies": {
"astro": "$ASTRO_VERSION",
"@astrojs/node": "$NODE_ADAPTER_VERSION",
"@dmwd-io/design-system": "$DESIGN_SYSTEM_VERSION"
},
"devDependencies": {
"@astrojs/ts-plugin": "$TS_PLUGIN_VERSION",
"@biomejs/biome": "$BIOME_VERSION",
"typescript": "$TYPESCRIPT_VERSION"
}
}
JSON
echo " wrote: package.json"
fi
# --- 3. supporting files ----------------------------------------------------
GITIGNORE="$TARGET/.gitignore"
if [ -e "$GITIGNORE" ] && [ "$FORCE" -ne 1 ]; then
echo " skip (exists, use --force): .gitignore"
else
cat > "$GITIGNORE" <<'GIT'
# build
dist/
.astro/
# deps
node_modules/
# env / secrets — never commit
.env
.env.local
.env.*.local
# editor / os
.DS_Store
*.log
GIT
echo " wrote: .gitignore"
fi
ENV_EXAMPLE="$TARGET/.env.example"
if [ -e "$ENV_EXAMPLE" ] && [ "$FORCE" -ne 1 ]; then
echo " skip (exists, use --force): .env.example"
else
cat > "$ENV_EXAMPLE" <<'ENV'
# Copy to .env.local and fill in. .env.local is gitignored.
# Required to install the private @dmwd-io design-system from GitHub Packages.
# A GitHub PAT (or CI GITHUB_TOKEN) with read:packages scope.
NPM_TOKEN=
# Astro standalone server bind address (defaults are fine locally).
HOST=0.0.0.0
PORT=4321
ENV
echo " wrote: .env.example"
fi
# Minimal runnable entry so `task dev` shows a page immediately.
INDEX="$TARGET/src/pages/index.astro"
if [ -e "$INDEX" ] && [ "$FORCE" -ne 1 ]; then
echo " skip (exists, use --force): src/pages/index.astro"
else
mkdir -p "$TARGET/src/pages"
cat > "$INDEX" <<'ASTRO'
---
// SSR by default (astro.config.mjs output: "server").
// Opt a page out with: export const prerender = true;
const now = new Date().toLocaleString("en-US");
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>dmwd-io Astro starter</title>
</head>
<body>
<main>
<h1>dmwd-io Astro 5 starter</h1>
<p>Server-rendered at {now}. Edit <code>src/pages/index.astro</code>.</p>
</main>
</body>
</html>
ASTRO
echo " wrote: src/pages/index.astro"
fi
# Keep the blog content dir tracked so the content collection resolves.
mkdir -p "$TARGET/src/content/blog"
[ -e "$TARGET/src/content/blog/.gitkeep" ] || : > "$TARGET/src/content/blog/.gitkeep"
# --- 4. install -------------------------------------------------------------
if [ "$DO_INSTALL" -eq 1 ]; then
if [ -z "${NPM_TOKEN:-}" ]; then
echo
echo " WARNING: NPM_TOKEN is not set. @dmwd-io/design-system will 401."
echo " Export it, then re-run: cd $TARGET && pnpm install"
echo " (Skipping install so the scaffold still completes.)"
else
echo
echo "==> pnpm install"
(cd "$TARGET" && pnpm install)
fi
else
echo
echo " --no-install: skipped dependency install."
fi
echo
echo "==> Done. Next:"
echo " cd $TARGET"
[ "$DO_INSTALL" -eq 1 ] && [ -z "${NPM_TOKEN:-}" ] && echo " export NPM_TOKEN=... # then: pnpm install"
echo " task dev # or: pnpm dev"