diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml
index 3d8a64936..810a2c747 100644
--- a/.github/workflows/deploy-gh-pages.yml
+++ b/.github/workflows/deploy-gh-pages.yml
@@ -4,11 +4,15 @@ permissions:
contents: read
pages: write
id-token: write
+ actions: read
on:
- push:
- branches:
- - main
+ # Trigger after successful CI workflows complete
+ workflow_run:
+ workflows: ["Storybook and Chromatic CI", "Vitest Tests", "Tests CI"]
+ types: [completed]
+ branches: [main]
+ # Keep manual trigger for debugging
workflow_dispatch:
concurrency:
@@ -18,9 +22,11 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
+ # Only run if the triggering workflow succeeded (or manual dispatch)
+ if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -28,7 +34,7 @@ jobs:
version: 10
- name: Setup Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v5
with:
node-version: '24'
cache: 'pnpm'
@@ -36,194 +42,77 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- - name: Build Storybook
- run: pnpm build-storybook --output-dir dist/storybook
-
- - name: Build Nx Graph
- run: |
- mkdir -p dist/nx-graph
- pnpm nx graph --file=dist/nx-graph/index.html || echo "Nx graph generation skipped"
+ - name: Download Storybook artifact from latest CI run
continue-on-error: true
-
- - name: Build Vitest UI
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- mkdir -p dist/vitest-ui
- pnpm test:unit --run --reporter=html --reporter=json --outputFile.html=dist/vitest-ui/index.html --outputFile.json=dist/vitest-ui/results.json || echo "Vitest UI generation skipped"
+ echo "🔍 Downloading latest Storybook artifact..."
+
+ # Get latest successful Storybook workflow run
+ LATEST_RUN=$(gh api "repos/${{ github.repository }}/actions/workflows" \
+ --jq '.workflows[] | select(.name == "Storybook and Chromatic CI") | .id' | head -1)
+
+ if [ -n "$LATEST_RUN" ]; then
+ RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/$LATEST_RUN/runs?status=success&branch=main" \
+ --jq '.workflow_runs[0].id' 2>/dev/null || echo "")
+
+ if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]; then
+ # Download storybook-static artifact
+ ARTIFACT_ID=$(gh api "repos/${{ github.repository }}/actions/runs/$RUN_ID/artifacts" \
+ --jq '.artifacts[] | select(.name == "storybook-static") | .id' | head -1)
+
+ if [ -n "$ARTIFACT_ID" ]; then
+ gh api "repos/${{ github.repository }}/actions/artifacts/$ARTIFACT_ID/zip" > storybook-static.zip
+ unzip -q storybook-static.zip -d ./storybook-static
+ echo "✅ Downloaded and extracted Storybook artifact"
+ else
+ echo "⚠️ Storybook artifact not found, will build from source"
+ fi
+ else
+ echo "⚠️ No successful Storybook runs found, will build from source"
+ fi
+ else
+ echo "⚠️ Storybook workflow not found, will build from source"
+ fi
+
+ - name: Download Vitest reports from latest CI run
continue-on-error: true
-
- - name: Generate test coverage
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- mkdir -p dist/coverage
- pnpm test:unit --run --coverage --coverage.reporter=html --coverage.reportsDirectory=dist/coverage || echo "Coverage generation skipped"
- continue-on-error: true
+ echo "🔍 Downloading latest Vitest reports..."
- - name: Generate Knip report
- run: |
- mkdir -p dist/knip
- pnpm knip --reporter json > dist/knip/report.json || echo "{}" > dist/knip/report.json
- echo '
Knip ReportKnip Report
' > dist/knip/index.html
- cat dist/knip/report.json >> dist/knip/index.html
- echo '
' >> dist/knip/index.html
- continue-on-error: true
+ # Get latest successful Vitest workflow run
+ LATEST_RUN=$(gh api "repos/${{ github.repository }}/actions/workflows" \
+ --jq '.workflows[] | select(.name == "Vitest Tests") | .id' | head -1)
- - name: Create index page
- run: |
- cat > dist/index.html << 'EOF'
-
-
-
-
-
- ComfyUI Frontend - Development Tools
-
-
-
-
-
+ if [ -n "$LATEST_RUN" ]; then
+ RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/$LATEST_RUN/runs?status=success&branch=main" \
+ --jq '.workflow_runs[0].id' 2>/dev/null || echo "")
-
-
-
-
-
-
- EOF
+ - name: Build static assets (with artifact reuse)
+ run: ./scripts/build-gh-pages.sh
- name: Setup Pages
uses: actions/configure-pages@v4
@@ -231,8 +120,21 @@ jobs:
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
- path: './dist'
+ path: './docs/pages'
+ deploy-for-sno-deploy-ghpage-branch:
+ runs-on: ubuntu-latest
+ needs: build
+ if: github.ref == 'refs/heads/sno-deploy-ghpage'
+ steps:
+ - name: Debug deployment
+ run: |
+ echo "Contents of ./docs/pages:"
+ ls -la ./docs/pages
+ echo "Contents of ./docs/pages/vitest-reports (if exists):"
+ ls -la ./docs/pages/vitest-reports || echo "No vitest-reports directory"
+ echo "Preview URL: https://comfyorg-comfyui-frontend.vercel.app"
+
deploy:
environment:
name: github-pages
diff --git a/.github/workflows/storybook-and-chromatic-ci.yaml b/.github/workflows/storybook-and-chromatic-ci.yaml
index bfac96530..707ac5371 100644
--- a/.github/workflows/storybook-and-chromatic-ci.yaml
+++ b/.github/workflows/storybook-and-chromatic-ci.yaml
@@ -5,7 +5,7 @@ name: Storybook and Chromatic CI
on:
workflow_dispatch: # Allow manual triggering
pull_request:
- branches: [main]
+ branches: [main, sno-deploy-ghpage]
jobs:
# Post starting comment for non-forked PRs
diff --git a/.github/workflows/vitest-tests.yaml b/.github/workflows/vitest-tests.yaml
index 394145188..03a641d53 100644
--- a/.github/workflows/vitest-tests.yaml
+++ b/.github/workflows/vitest-tests.yaml
@@ -46,3 +46,20 @@ jobs:
- name: Run Vitest tests
run: pnpm test:unit
+
+ - name: Generate test reports (on main branch)
+ if: github.ref == 'refs/heads/main'
+ run: |
+ mkdir -p ./vitest-reports
+ pnpm exec vitest \
+ --reporter=json --outputFile.json="./vitest-reports/results.json" \
+ --reporter=html --outputFile.html="./vitest-reports/index.html" \
+ --run
+
+ - name: Upload Vitest reports artifact (on main branch)
+ if: github.ref == 'refs/heads/main'
+ uses: actions/upload-artifact@v4
+ with:
+ name: vitest-reports
+ path: vitest-reports/
+ retention-days: 7
diff --git a/.gitignore b/.gitignore
index 8f69ce164..d99406b0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,3 +92,14 @@ storybook-static
.github/instructions/nx.instructions.md
vite.config.*.timestamp*
vitest.config.*.timestamp*
+
+# Github Pages Build output
+/pages-dist
+
+# Generated reports in docs/pages (exclude JSON data, keep HTML templates)
+docs/pages/knip/report.json
+docs/pages/vitest-ui/results.json
+docs/pages/coverage/
+docs/pages/nx-graph/
+docs/pages/storybook/
+docs/pages/playwright-reports/
diff --git a/docs/pages/.gitignore b/docs/pages/.gitignore
new file mode 100644
index 000000000..d1b99b1d6
--- /dev/null
+++ b/docs/pages/.gitignore
@@ -0,0 +1,14 @@
+*
+!/.gitignore
+!/README.md
+!/index.html
+!/knip/
+!/knip/index.html
+knip/report.md
+!/vite.config.ts
+!/tsconfig.json
+/storybook/
+/nx-graph/
+/coverage/
+/vitest-ui/
+/playwright-reports/
diff --git a/docs/GITHUB_PAGES_DEPLOYMENT.md b/docs/pages/README.md
similarity index 90%
rename from docs/GITHUB_PAGES_DEPLOYMENT.md
rename to docs/pages/README.md
index aed110f60..940a7c1c2 100644
--- a/docs/GITHUB_PAGES_DEPLOYMENT.md
+++ b/docs/pages/README.md
@@ -33,11 +33,7 @@ The deployment is managed by the `.github/workflows/deploy-gh-pages.yml` workflo
2. **Build Process**:
- Installs dependencies with pnpm
- - Builds Storybook static site
- - Generates Nx dependency graph
- - Creates TypeDoc documentation
- - Runs tests and generates coverage reports
- - Generates Knip analysis report
+ - Runs `scripts/build-pages.sh` to generate Storybook, Nx dependency graph, Vitest reports, coverage, and Knip analysis
- Creates a landing page with links to all tools
3. **Deployment**:
@@ -49,7 +45,7 @@ The deployment is managed by the `.github/workflows/deploy-gh-pages.yml` workflo
### Build Steps
-Each tool is built in its own step with `continue-on-error: true`, ensuring that if one tool fails to build, the others will still be deployed.
+The build script handles optional tooling gracefully—if an individual tool fails to build, the remainder of the deployment still proceeds and the failure is logged as a warning.
#### Storybook (Required)
```bash
@@ -63,12 +59,12 @@ pnpm nx graph --file=dist/nx-graph/index.html
#### Test Coverage (Optional)
```bash
-pnpm test:unit --run --coverage --coverage.reporter=html
+pnpm exec vitest --run --coverage --coverage.reporter=html
```
#### Vitest Results (Optional)
```bash
-pnpm test:unit --run --reporter=html
+pnpm exec vitest --run --reporter=html --outputFile dist/vitest-ui/index.html
```
#### Knip Report (Optional)
diff --git a/docs/pages/index.html b/docs/pages/index.html
new file mode 100644
index 000000000..e27c6bcc9
--- /dev/null
+++ b/docs/pages/index.html
@@ -0,0 +1,215 @@
+
+
+
+
+
+ ComfyUI Frontend - Development Tools
+
+
+
+
+
+
+
+
diff --git a/docs/pages/tsconfig.json b/docs/pages/tsconfig.json
new file mode 100644
index 000000000..077f3c520
--- /dev/null
+++ b/docs/pages/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "composite": false
+ },
+ "include": [
+ "./vite.config.ts"
+ ]
+}
diff --git a/docs/pages/vite.config.ts b/docs/pages/vite.config.ts
new file mode 100644
index 000000000..b00b77ce4
--- /dev/null
+++ b/docs/pages/vite.config.ts
@@ -0,0 +1,46 @@
+import fs from 'node:fs'
+import { resolve } from 'node:path'
+import { defineConfig } from 'vite'
+
+const rootDir = __dirname
+const outDir = resolve(rootDir, '../pages-dist')
+
+const discoverHtmlEntries = () => {
+ const entries = new Map()
+ const topLevel = resolve(rootDir, 'index.html')
+ if (fs.existsSync(topLevel)) entries.set('index', topLevel)
+
+ for (const dirent of fs.readdirSync(rootDir, { withFileTypes: true })) {
+ if (!dirent.isDirectory() || dirent.name.startsWith('.')) continue
+ const candidate = resolve(rootDir, dirent.name, 'index.html')
+ if (fs.existsSync(candidate)) entries.set(dirent.name, candidate)
+ }
+
+ return entries.size > 0 ? Object.fromEntries(entries) : undefined
+}
+
+export default defineConfig({
+ root: rootDir,
+ base: '/ComfyUI_frontend',
+ appType: 'mpa',
+ logLevel: 'info',
+ publicDir: false,
+ server: {
+ open: '/index.html',
+ fs: {
+ allow: [rootDir],
+ strict: false
+ }
+ },
+ preview: {
+ open: '/index.html'
+ },
+ build: {
+ emptyOutDir: false,
+ outDir,
+ copyPublicDir: false,
+ rollupOptions: {
+ input: discoverHtmlEntries()
+ }
+ }
+})
diff --git a/scripts/build-pages.sh b/scripts/build-pages.sh
new file mode 100755
index 000000000..85615ca29
--- /dev/null
+++ b/scripts/build-pages.sh
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+set -Eeuo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+cd "$ROOT_DIR"
+DIST="./docs/pages"
+
+# Build or reuse Storybook
+echo "[build-pages] Setting up Storybook"
+rm -rf "$DIST/storybook"
+if [ -d "./storybook-static" ] && [ "$(find ./storybook-static -name '*.html' | wc -l)" -gt 0 ]; then
+ echo "✅ Reusing downloaded Storybook build"
+ cp -r "./storybook-static" "$DIST/storybook"
+elsew
+ echo "🔨 Building Storybook from source"
+ pnpm build-storybook && cp -r "storybook-static" "$DIST/storybook"
+fi
+
+echo "[build-pages] Generating Nx dependency graph"
+rm -rf "$DIST/nx-graph" && mkdir -p "$DIST/nx-graph"
+pnpm nx graph --file="$DIST/nx-graph/index.html"
+
+# Generate or reuse Vitest test reports
+echo "[build-pages] Setting up Vitest test reports"
+rm -rf "$DIST/vitest-ui" && mkdir -p "$DIST/vitest-ui"
+if [ -d "./.gh-pages-cache/vitest-reports" ]; then
+ echo "✅ Reusing downloaded Vitest reports"
+ cp -r "./.gh-pages-cache/vitest-reports/"* "$DIST/vitest-ui/" 2>/dev/null || echo "⚠️ No vitest reports to copy"
+else
+ echo "🔨 Generating Vitest reports from source"
+ pnpm exec vitest \
+ --reporter=json --outputFile.json="$DIST/vitest-ui/results.json" \
+ --reporter=html --outputFile.html="$DIST/vitest-ui/index.html" \
+ --run
+fi
+
+# Set up Playwright test reports if available
+echo "[build-pages] Setting up Playwright test reports"
+if [ -d "./.gh-pages-cache/playwright-reports" ]; then
+ echo "✅ Reusing downloaded Playwright reports"
+ mkdir -p "$DIST/playwright-reports"
+ cp -r "./.gh-pages-cache/playwright-reports/"* "$DIST/playwright-reports/" 2>/dev/null || echo "⚠️ No playwright reports to copy"
+fi
+
+echo "[build-pages] Generating coverage report"
+mkdir -p "$DIST/coverage"
+if pnpm exec vitest --run --coverage --coverage.reporter=html --coverage.reportsDirectory="$DIST/coverage"; then
+ echo "✅ Coverage report completed"
+else
+ echo "⚠️ Coverage report failed, continuing..."
+fi
+
+echo "[build-pages] Generating Knip report"
+mkdir -p "$DIST/knip"
+rm -f "$DIST/knip/report.md"
+if pnpm knip --reporter markdown --no-progress --no-exit-code > "$DIST/knip/report.md" 2>/dev/null && [ -s "$DIST/knip/report.md" ]; then
+ echo "✅ Knip report generated at $DIST/knip/report.md"
+else
+ echo "⚠️ Knip report failed, creating placeholder..."
+ cat > "$DIST/knip/report.md" <<'EOF'
+# Knip report
+
+> ⚠️ Knip report unavailable.
+>
+> Generation failed during build. See CI logs for details.
+EOF
+fi
+
+if cp "${ROOT_DIR}/docs/pages/knip/index.html" "$DIST/knip/index.html" 2>/dev/null; then
+ echo "✅ Knip HTML wrapper completed"
+else
+ echo "⚠️ Knip HTML wrapper missing, continuing..."
+fi
+
+echo "[build-pages] Landing page already exists at $DIST/index.html"
+
+echo "[build-pages] Build artifacts ready in $DIST"
+
+echo "[build-pages] Note: For local dev, you can develop the docs/pages/index.html using:
+ pnpm exec vite ${DIST}
+"