React Deploy to Cloudflare Pages
react-deploy-pages@1.0.0 Template Build a React web app and publish it to Cloudflare Pages, with per-branch previews.
Start from it
flightstack template use react-deploy-pages What it does
Install, build and deploy a React web app to Cloudflare Pages in one job, asserting the built bundle before upload. Deploying a non-production branch produces a preview URL rather than touching the live site.
Inputs
-
projectNamestring required - The Cloudflare Pages project to deploy to.
-
branchstring - Branch to deploy as. Empty uses the branch that triggered the run, which is what makes non-production branches land as previews.
-
workingDirstring default. - Directory holding package.json.
-
outputDirstring defaultdist - Directory the build writes to, and what gets uploaded.
-
buildboolean defaulttrue - Install dependencies and build before deploying.
-
buildScriptstring defaultbuild - The npm script that produces the production bundle.
-
packageManagerauto | npm | pnpm | yarn | bun defaultauto - Which package manager to use.
-
envobject - Build-time environment variables, compiled INTO the bundle and therefore public. Never put a secret here.
-
mustContainarray - Strings that must appear in the built JavaScript.
-
mustNotContainarray - Strings that must NOT appear, checked before the upload.
-
includestring default*.js - Filename pattern the assertions are checked against.
-
wranglerVersionstring defaultlatest - Version of wrangler to run via npx.
Definition
name: React Deploy to Cloudflare Pages
description: >-
Build a React web app and publish it to Cloudflare Pages, with per-branch
preview deployments.
triggers:
- type: push
branches: [main]
jobs:
deploy:
name: Deploy to Pages
type: plugin/react-deploy-pages
with:
projectName: postwire-console
outputDir: apps/console/dist
env:
VITE_API_URL: https://api.postwire.ai
mustNotContain:
- "localhost:"
plugin:
name: react-deploy-pages
displayName: React Deploy to Cloudflare Pages
description: >-
Install, build and deploy a React web app to Cloudflare Pages. Deploying a
non-production branch produces a preview URL rather than touching the live
site.
category: deploy
requiredTools:
- name: nodejs
version: ">=20.0.0"
supportedPlatforms:
- linux
- macos
- windows
parameters:
type: object
properties:
projectName:
type: string
description: The Cloudflare Pages project to deploy to.
branch:
type: string
default: ""
description: >-
Branch to deploy as. Empty uses the branch that triggered the run,
which is what makes non-production branches land as previews.
workingDir:
type: string
default: "."
description: Directory holding package.json.
outputDir:
type: string
default: dist
description: Directory the build writes to, and what gets uploaded.
build:
type: boolean
default: true
description: Install dependencies and build before deploying.
buildScript:
type: string
default: build
description: The npm script that produces the production bundle.
packageManager:
type: string
enum: [auto, npm, pnpm, yarn, bun]
default: auto
description: Which package manager to use.
env:
type: object
description: >-
Build-time environment variables, compiled INTO the bundle and
therefore public. Never put a secret here.
mustContain:
type: array
description: Strings that must appear in the built JavaScript.
mustNotContain:
type: array
description: Strings that must NOT appear, checked before the upload.
include:
type: string
default: "*.js"
description: Filename pattern the assertions are checked against.
wranglerVersion:
type: string
default: latest
description: Version of wrangler to run via npx.
required: [projectName]
script: |
set -euo pipefail
cd "{{workingDir}}"
if [ -z "${CLOUDFLARE_API_TOKEN:-}" ] || [ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ]; then
echo "No Cloudflare credentials." >&2
echo "Set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as pipeline secret variables." >&2
exit 1
fi
pm="{{packageManager}}"
if [ "$pm" = "auto" ]; then
if [ -f pnpm-lock.yaml ]; then pm=pnpm
elif [ -f yarn.lock ]; then pm=yarn
elif [ -f bun.lockb ] || [ -f bun.lock ]; then pm=bun
else pm=npm
fi
fi
case "$pm" in
pnpm|yarn) corepack enable >/dev/null 2>&1 || true ;;
esac
{{#build}}
echo "--- installing dependencies"
case "$pm" in
npm) if [ -f package-lock.json ]; then npm ci; else npm install; fi ;;
pnpm) pnpm install --frozen-lockfile ;;
yarn) yarn install --immutable || yarn install --frozen-lockfile ;;
bun) bun install --frozen-lockfile ;;
esac
echo "--- building"
{{#each env}}
export {{@key}}="{{this}}"
{{/each}}
"$pm" run "{{buildScript}}"
{{/build}}
out="{{outputDir}}"
if [ ! -d "$out" ]; then
echo "nothing to deploy: '$out' does not exist" >&2
exit 1
fi
failed=0
{{#each mustContain}}
if grep -rqF --include="{{include}}" -- '{{this}}' "$out"; then
echo "ok: bundle contains '{{this}}'"
else
echo "FAIL: '{{this}}' is missing from the bundle - refusing to deploy" >&2
failed=1
fi
{{/each}}
{{#each mustNotContain}}
if grep -rqF --include="{{include}}" -- '{{this}}' "$out"; then
echo "FAIL: '{{this}}' appears in the bundle - refusing to deploy" >&2
failed=1
else
echo "ok: bundle is free of '{{this}}'"
fi
{{/each}}
[ "$failed" = "0" ] || exit 1
# The triggering ref is a full ref name often enough to matter
# (refs/heads/main); Pages wants the short branch.
branch="{{branch}}"
if [ -z "$branch" ]; then
branch="{{BRANCH}}"
fi
branch="${branch#refs/heads/}"
echo "--- deploying to Pages project '{{projectName}}' as branch '$branch'"
npx --yes wrangler@{{wranglerVersion}} pages deploy "$out" \
--project-name "{{projectName}}" \
--branch "$branch" \
--commit-hash "{{COMMIT_SHA}}"