Deployment
Build
npm run sync # regenerate fonts.css, inline-text-safelist.css
npm run build # ensure native bindings, then astro build (outputs to dist/)Integration order in astro.config.mjs matters:
astro:assetsiconexpressiveCode(optional)alpinejscontentHmr(dev only)fonts(Astro Fonts)astro-compress— must be last when it runs
Image: false is set in astro-compress because CmsImage already uses astro:assets for optimisation. On Cloudflare Pages (CF_PAGES=1) compress is skipped for faster incremental preview builds. experimental.incrementalBuild plus cacheKey on getStaticPaths rebuilds only pages whose content fingerprint changed.
Bunny CDN
The MagiCMS web editor (apps/web) deploys from this product repo’s main via .github/workflows/deploy.yml:
pnpm install --frozen-lockfilepnpm --filter @magiccms/web run build- Upload every file in
apps/web/buildto Bunny Storage undermagicms/. - Upload
index.htmllast (so the CDN serves the new shell first). - Purge the Bunny CDN pull zone.
MIME types are mapped explicitly (js/css/html/svg/json/png/ico/woff2) — Bunny will otherwise guess.
Customer sites use the same pattern for production: GitHub Actions on main → Bunny. Do not turn on Cloudflare Pages production deploys for those sites.
Cloudflare Pages preview
Customer sites preview on Cloudflare Pages from the draft branch. Saving in MagiCMS is a commit on draft; Pages builds that commit. MagiCMS polls the GitHub check and loads the hash URL (https://<8hex>.<project>.pages.dev) in the editor iframe.
Set previewUrl to https://*.<project>.pages.dev. The Preview site header link opens https://draft.<project>.pages.dev.
Pages project settings: production branch may stay main, but turn automatic production deployments off. Preview branches: Custom, include draft only. Do not set PREVIEW=true on Pages (that flag is Node SSR, not this flow).
Linux native bindings: root optionalDependencies for linux-x64-gnu plus scripts/ensure-native-bindings.mjs so npm ci on Pages does not miss Tailwind/Vite binaries from a macOS lockfile.
Branch sync
.github/workflows/sync-branches.yml runs on push to main. It merges main into draft only. If the merge fails, the workflow logs the HTTP status — manual sync is required.
Manual sync fallback:
git checkout draft && git pull --rebase && git merge main && git push
git checkout main