nx-github-pages
v1.3.1
Published
This project was generated using [Nx](https://nx.dev).
Readme
Nx Github Pages
This project was generated using Nx.
A simple Nx plugin to enable deploying a static project to Github Pages.
[!NOTE]
This plugin was formerly published as @nx-dotnet/nx-ghpages. It was moved due to not being relevant to .NET and to decouple the releases. To view previous versions and changelogs checkout the nx-dotnet repo
Installation
To install the plugin, run:
nx add nx-github-pagesUsage
Pick a project to deploy and run:
nx g nx-github-pages:configuration --project=<project-name>After the configuration is generated, you can deploy the project by running:
nx run <project-name>:deployPull Request Preview Deployments
The deploy executor can also publish a pull request preview into a subdirectory of your gh-pages branch (e.g. https://<you>.github.io/<repo>/pr/123/) and post an updating comment on the pull request with the preview URL. The same deploy target handles both modes — it auto-detects a PR context from the environment (GITHUB_REF=refs/pull/<N>/merge or PR_NUMBER) and switches to preview mode when one is present. A companion cleanup-preview executor removes stale previews on a schedule.
Generate a preview-enabled target
nx g nx-github-pages:configuration \
--project=<project-name> \
--preview \
--previewUrl=https://<you>.github.io/<repo> \
--addCleanupTargetThis creates two things on the project:
{
"deploy": {
"executor": "nx-github-pages:deploy",
"options": {
"preview": { "url": "https://<you>.github.io/<repo>" },
"syncWithBaseBranch": true
/* ...any other deploy options... */
}
},
"cleanup-previews": {
"executor": "nx-github-pages:cleanup-preview",
"options": {}
}
}syncWithBaseBranch is enabled when --preview is passed so that non-PR deploys merge into gh-pages rather than force-pushing — that preserves the pr/* subdirectories published by previous preview runs.
Preview executor options
All standard deploy options still apply. Preview-specific options live under a preview object:
| Option | Default | Description |
| --------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------- |
| preview.pathPrefix | pr/${PR_NUMBER ?? GITHUB_SHA} | Subdirectory on the target branch to deploy into. |
| preview.url | Derived from CNAME or https://<owner>.github.io/<repo> | Base URL used in the PR comment. The pathPrefix is appended automatically. |
| preview.comment | true | Whether to upsert a PR comment with the preview link via the GitHub REST API. |
When the executor detects a PR context, it switches into preview mode: it clones the target branch, copies the build output into <pathPrefix>/, and pushes without force — so sibling PR folders are preserved. Outside of a PR (e.g. a push to main), the same target runs a standard deploy instead.
⚠️ Your build MUST use a matching base URL
Since the preview is served from a subdirectory, your framework needs to know about that subdirectory at build time, or every asset will 404 after deploy. The plugin enforces this by scanning the build output for references to the path prefix before pushing. If the check fails you'll get a descriptive error pointing at the right base URL flag for your framework.
Pass the prefix to the build step as an environment variable and consume it in your framework config:
PATH_PREFIX="/pr/${PR_NUMBER:-$GITHUB_SHA}"
# Vite
npx nx build my-app -- --base="$PATH_PREFIX/"
# Next.js (in next.config.js: basePath: process.env.NEXT_BASE_PATH)
NEXT_BASE_PATH="$PATH_PREFIX" npx nx build my-app
# Angular
npx nx build my-app -- --base-href="$PATH_PREFIX/"
# Astro
npx nx build my-app -- --base="$PATH_PREFIX"Then deploy as usual — preview mode is selected automatically when GITHUB_REF/PR_NUMBER indicate a pull request:
npx nx deploy my-appIf you serve previews through a CDN rewrite or some other scheme where the prefix legitimately does not appear in the built files, bypass the check with NX_GITHUB_PAGES_SKIP_BASE_URL_CHECK=true.
Required environment
The executor auto-detects context from standard GitHub Actions environment variables:
| Variable | Source | Purpose |
| ------------------- | ---------------------------- | ------------------------------------------------- |
| GITHUB_REPOSITORY | Actions runner | Owner/repo for the PR comment. |
| GITHUB_REF | Actions runner | Extracts the PR number from refs/pull/<N>/merge. Presence of a PR number activates preview mode. |
| PR_NUMBER | Set it yourself | Fallback for PR number; used in pathPrefix. Presence activates preview mode. |
| GITHUB_SHA | Actions runner | Included in the PR comment; fallback path prefix. |
| GH_TOKEN | secrets.GITHUB_TOKEN or PAT | Auth for git push and the Octokit comment. |
Example GitHub Actions workflow
name: PR Preview
on:
pull_request:
branches: [main]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- name: Build with preview base URL
run: npx nx build my-app -- --base="$PATH_PREFIX/"
env:
PATH_PREFIX: /pr/${{ github.event.number }}
- name: Deploy preview
run: npx nx deploy my-app
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.number }}Cleaning up stale previews
Add a scheduled workflow that runs the cleanup-preview executor. It clones the deployment branch, removes pr/* directories older than maxAgeDays (default 7), and updates each corresponding PR comment to say the preview has been cleaned up.
name: Cleanup PR Previews
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
all:
description: 'Cleanup every preview regardless of age'
type: boolean
default: false
jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx nx run my-app:cleanup-previews ${{ inputs.all && '--all' || '' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}cleanup-preview options: remote, baseBranch (default gh-pages), pathPrefix (default pr), maxAgeDays (default 7), all (default false), updatePrComments (default true).
