-
Notifications
You must be signed in to change notification settings - Fork 13.4k
chore(build): add Vercel preview builds for framework test apps #31073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ShaneK
wants to merge
2
commits into
main
Choose a base branch
from
chore/vercel-previews
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+376
−1
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,354 @@ | ||
| #!/bin/bash | ||
| # | ||
| # Vercel preview build script | ||
| # | ||
| # Builds core component tests (same as before) plus framework test apps | ||
| # (Angular, React, Vue) so they're all accessible from a single preview URL. | ||
| # | ||
| # Core tests: /src/components/{name}/test/{scenario} | ||
| # Angular test app: /angular/ | ||
| # React test app: /react/ | ||
| # Vue test app: /vue/ | ||
| # | ||
| set -e | ||
|
|
||
| # Vercel places core/ at /vercel/path1 (bind mount). The full repo clone | ||
| # lives at /vercel/path0. We can't rely on `..` to reach it, so we search. | ||
| CORE_DIR=$(pwd) | ||
| OUTPUT_DIR="${CORE_DIR}/../_vercel_output" | ||
|
|
||
| # Find the actual repo root (the directory containing packages/) | ||
| REPO_ROOT="" | ||
| for candidate in /vercel/path0 /vercel/path1 "${CORE_DIR}/.."; do | ||
| if [ -d "${candidate}/packages" ]; then | ||
| REPO_ROOT="${candidate}" | ||
| break | ||
| fi | ||
| done | ||
|
|
||
| echo "=== Ionic Framework Preview Build ===" | ||
| echo "Core dir: ${CORE_DIR}" | ||
| echo "Repo root: ${REPO_ROOT:-NOT FOUND}" | ||
| if [ -z "${REPO_ROOT}" ]; then | ||
| echo "(This is expected in some Vercel configs -- framework test apps will be skipped)" | ||
| fi | ||
|
|
||
| rm -rf "${OUTPUT_DIR}" | ||
| mkdir -p "${OUTPUT_DIR}" | ||
|
|
||
| # Step 1 - Build Core (dependencies already installed by Vercel installCommand) | ||
| echo "" | ||
| echo "--- Step 1: Building Core ---" | ||
| npm run build | ||
|
|
||
| # Copy core files to output. The test HTML files use relative paths like | ||
| # ../../../../../dist/ionic/ionic.esm.js so the directory structure must | ||
| # be preserved exactly. | ||
| echo "Copying core output..." | ||
| cp -r "${CORE_DIR}/src" "${OUTPUT_DIR}/src" | ||
| cp -r "${CORE_DIR}/dist" "${OUTPUT_DIR}/dist" | ||
| cp -r "${CORE_DIR}/css" "${OUTPUT_DIR}/css" | ||
| mkdir -p "${OUTPUT_DIR}/scripts" | ||
| cp -r "${CORE_DIR}/scripts/testing" "${OUTPUT_DIR}/scripts/testing" | ||
|
|
||
| # Generate directory index pages so users can browse core test pages. | ||
| # Creates an index.html in every directory under src/components/ that | ||
| # doesn't already have one. Only includes child directories that eventually | ||
| # lead to a test page (an index.html). Prunes snapshot dirs and dead ends. | ||
| echo "Generating directory indexes for core tests..." | ||
| generate_dir_index() { | ||
| local dir="$1" | ||
| local url_path="$2" | ||
| # Skip if an index.html already exists (it's an actual test page) | ||
| [ -f "${dir}/index.html" ] && return | ||
|
|
||
| local entries="" | ||
| for child in "${dir}"/*/; do | ||
| [ -d "${child}" ] || continue | ||
| local name=$(basename "${child}") | ||
| # Skip snapshot directories and hidden dirs | ||
| case "${name}" in *-snapshots|.*) continue ;; esac | ||
| # Only include if there's at least one index.html somewhere underneath | ||
| find "${child}" -name "index.html" -print -quit | grep -q . || continue | ||
| entries="${entries}<a href=\"${name}/\">${name}/</a>\n" | ||
| done | ||
|
|
||
| [ -z "${entries}" ] && return | ||
|
|
||
| cat > "${dir}/index.html" << IDXEOF | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Index of ${url_path}</title> | ||
| <style> | ||
| body { font-family: monospace; padding: 1.5rem; background: #f5f5f5; } | ||
| h1 { font-size: 1rem; margin-bottom: 1rem; color: #333; } | ||
| a { display: block; padding: 4px 0; color: #1565c0; text-decoration: none; } | ||
| a:hover { text-decoration: underline; } | ||
| .up { margin-bottom: 0.5rem; color: #666; } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <h1>Index of ${url_path}</h1> | ||
| <a class="up" href="../">../</a> | ||
| $(echo -e "${entries}") | ||
| </body> | ||
| </html> | ||
| IDXEOF | ||
| } | ||
|
|
||
| # Walk all directories under src/ (bottom-up so parent indexes reflect pruned children) | ||
| find "${OUTPUT_DIR}/src" -depth -type d | while IFS= read -r dir; do | ||
| url_path="${dir#${OUTPUT_DIR}}" | ||
| generate_dir_index "${dir}" "${url_path}/" | ||
| done | ||
|
|
||
| # Vercel mounts core/ at a separate path (path1) from the repo clone (path0). | ||
| # Framework packages reference core via relative paths (../../core/css etc.), | ||
| # which resolve to path0/core/ -- not path1/ where we just built. | ||
| # Symlink path0/core -> path1 so those references find the build outputs. | ||
| if [ -n "${REPO_ROOT}" ] && [ "${CORE_DIR}" != "${REPO_ROOT}/core" ] && [ -d "${REPO_ROOT}/core" ]; then | ||
| echo "Linking ${REPO_ROOT}/core -> ${CORE_DIR} (so framework builds find core outputs)" | ||
| rm -rf "${REPO_ROOT}/core" | ||
| ln -s "${CORE_DIR}" "${REPO_ROOT}/core" | ||
| fi | ||
|
|
||
| # Check if the full repo is available | ||
| if [ -z "${REPO_ROOT}" ]; then | ||
| echo "" | ||
| echo "WARNING: Could not find repo root (no directory with packages/ found)" | ||
| echo "Only core tests will be deployed (framework test apps require the full repo)." | ||
|
|
||
| # Generate landing page and exit -- core tests are still useful | ||
| cat > "${OUTPUT_DIR}/index.html" << 'LANDING_EOF' | ||
| <!DOCTYPE html> | ||
| <html lang="en"><head><meta charset="UTF-8"><title>Ionic Framework - Preview</title></head> | ||
| <body><h1>Ionic Framework Preview</h1><p>Core tests only. Browse to /src/components/{name}/test/{scenario}/</p></body> | ||
| </html> | ||
| LANDING_EOF | ||
|
|
||
| echo "=== Preview build complete (core only) ===" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Step 2 - Build Framework Packages (parallel) | ||
| echo "" | ||
| echo "--- Step 2: Building Framework Packages ---" | ||
|
|
||
| build_angular_pkgs() { | ||
| (cd "${REPO_ROOT}/packages/angular" && npm install && npm run sync && npm run build) || return 1 | ||
| (cd "${REPO_ROOT}/packages/angular-server" && npm install && npm run build) || return 1 | ||
| } | ||
|
|
||
| build_react_pkgs() { | ||
| (cd "${REPO_ROOT}/packages/react" && npm install && npm run sync && npm run build) || return 1 | ||
| (cd "${REPO_ROOT}/packages/react-router" && npm install && npm run build) || return 1 | ||
| } | ||
|
|
||
| build_vue_pkgs() { | ||
| (cd "${REPO_ROOT}/packages/vue" && npm install && npm run sync && npm run build) || return 1 | ||
| (cd "${REPO_ROOT}/packages/vue-router" && npm install && npm run build) || return 1 | ||
| } | ||
|
thetaPC marked this conversation as resolved.
|
||
|
|
||
| build_angular_pkgs > /tmp/vercel-angular-pkg.log 2>&1 & | ||
| PID_ANG=$! | ||
| build_react_pkgs > /tmp/vercel-react-pkg.log 2>&1 & | ||
| PID_REACT=$! | ||
| build_vue_pkgs > /tmp/vercel-vue-pkg.log 2>&1 & | ||
| PID_VUE=$! | ||
|
|
||
| ANG_PKG_OK=true; REACT_PKG_OK=true; VUE_PKG_OK=true | ||
| wait $PID_ANG || { echo "Angular packages failed:"; tail -30 /tmp/vercel-angular-pkg.log; ANG_PKG_OK=false; } | ||
| wait $PID_REACT || { echo "React packages failed:"; tail -30 /tmp/vercel-react-pkg.log; REACT_PKG_OK=false; } | ||
| wait $PID_VUE || { echo "Vue packages failed:"; tail -30 /tmp/vercel-vue-pkg.log; VUE_PKG_OK=false; } | ||
|
|
||
| if ! $ANG_PKG_OK || ! $REACT_PKG_OK || ! $VUE_PKG_OK; then | ||
| echo "ERROR: Some framework package builds failed." | ||
| echo "Core tests will still be deployed. Skipping failed framework test apps." | ||
| else | ||
| echo "All framework packages built." | ||
| fi | ||
|
|
||
| # Step 3 - Build Framework Test Apps (parallel) | ||
| echo "" | ||
| echo "--- Step 3: Building Framework Test Apps ---" | ||
|
|
||
| # Find the best available app version for a given package. | ||
| # Scans the apps/ directory and picks the newest version (reverse version sort). | ||
| pick_app() { | ||
| local apps_dir="$1/apps" | ||
| [ -d "${apps_dir}" ] || return 1 | ||
| local app | ||
| app=$(ls -1d "${apps_dir}"/*/ 2>/dev/null | xargs -n1 basename | sort -V -r | head -1) | ||
| [ -n "${app}" ] && echo "${app}" && return 0 | ||
| return 1 | ||
| } | ||
|
|
||
| build_angular_test() { | ||
| local APP | ||
| APP=$(pick_app "${REPO_ROOT}/packages/angular/test") || { | ||
| echo "[angular] No test app found, skipping." | ||
| return 0 | ||
| } | ||
| echo "[angular] Building ${APP}..." | ||
|
|
||
| cd "${REPO_ROOT}/packages/angular/test" | ||
| ./build.sh "${APP}" | ||
| cd "build/${APP}" | ||
| npm install | ||
| npm run sync | ||
| # --base-href sets <base href="/angular/"> so Angular Router works under the sub-path | ||
| npm run build -- --base-href /angular/ | ||
|
|
||
| # Output path assumes the 'browser' builder. If migrated to 'application' builder, update this. | ||
| if [ ! -d "dist/test-app/browser" ]; then | ||
| echo "[angular] ERROR: Expected output at dist/test-app/browser/ not found." | ||
| return 1 | ||
| fi | ||
| mkdir -p "${OUTPUT_DIR}/angular" | ||
| cp -r dist/test-app/browser/* "${OUTPUT_DIR}/angular/" | ||
| echo "[angular] Done." | ||
| } | ||
|
|
||
| build_react_test() { | ||
| local APP | ||
| APP=$(pick_app "${REPO_ROOT}/packages/react/test") || { | ||
| echo "[react] No test app found, skipping." | ||
| return 0 | ||
| } | ||
| echo "[react] Building ${APP}..." | ||
|
|
||
| cd "${REPO_ROOT}/packages/react/test" | ||
| ./build.sh "${APP}" | ||
| cd "build/${APP}" | ||
| npm install | ||
| npm run sync | ||
| # --base sets Vite's base URL; import.meta.env.BASE_URL is read by IonReactRouter basename | ||
| npx vite build --base /react/ | ||
|
|
||
| mkdir -p "${OUTPUT_DIR}/react" | ||
| cp -r dist/* "${OUTPUT_DIR}/react/" | ||
| echo "[react] Done." | ||
| } | ||
|
|
||
| build_vue_test() { | ||
| local APP | ||
| APP=$(pick_app "${REPO_ROOT}/packages/vue/test") || { | ||
| echo "[vue] No test app found, skipping." | ||
| return 0 | ||
| } | ||
| echo "[vue] Building ${APP}..." | ||
|
|
||
| cd "${REPO_ROOT}/packages/vue/test" | ||
| ./build.sh "${APP}" | ||
| cd "build/${APP}" | ||
| npm install | ||
| npm run sync | ||
| # Vue Router already reads import.meta.env.BASE_URL which Vite sets from --base | ||
| npx vite build --base /vue/ | ||
|
|
||
| mkdir -p "${OUTPUT_DIR}/vue" | ||
| cp -r dist/* "${OUTPUT_DIR}/vue/" | ||
| echo "[vue] Done." | ||
| } | ||
|
|
||
| # TODO: Add build_react_router_test() when reactrouter6-* apps are added to | ||
| # packages/react-router/test/apps/ | ||
|
|
||
| TEST_FAILED="" | ||
|
|
||
| if $ANG_PKG_OK; then | ||
| build_angular_test > /tmp/vercel-angular-test.log 2>&1 & | ||
| PID_ANG_TEST=$! | ||
| fi | ||
| if $REACT_PKG_OK; then | ||
| build_react_test > /tmp/vercel-react-test.log 2>&1 & | ||
| PID_REACT_TEST=$! | ||
| fi | ||
| if $VUE_PKG_OK; then | ||
| build_vue_test > /tmp/vercel-vue-test.log 2>&1 & | ||
| PID_VUE_TEST=$! | ||
| fi | ||
|
|
||
| if $ANG_PKG_OK; then | ||
| wait $PID_ANG_TEST || { echo "Angular test app failed:"; tail -30 /tmp/vercel-angular-test.log; TEST_FAILED="${TEST_FAILED} angular"; } | ||
| fi | ||
| if $REACT_PKG_OK; then | ||
| wait $PID_REACT_TEST || { echo "React test app failed:"; tail -30 /tmp/vercel-react-test.log; TEST_FAILED="${TEST_FAILED} react"; } | ||
| fi | ||
| if $VUE_PKG_OK; then | ||
| wait $PID_VUE_TEST || { echo "Vue test app failed:"; tail -30 /tmp/vercel-vue-test.log; TEST_FAILED="${TEST_FAILED} vue"; } | ||
| fi | ||
|
|
||
| if [ -n "${TEST_FAILED}" ]; then | ||
| echo "" | ||
| echo "WARNING: Some test app builds failed:${TEST_FAILED}" | ||
| echo "Core tests and successful framework apps will still be deployed." | ||
| fi | ||
|
|
||
| # Step 4 - Landing Page | ||
| echo "" | ||
| echo "--- Step 4: Generating landing page ---" | ||
|
|
||
| cat > "${OUTPUT_DIR}/index.html" << 'LANDING_EOF' | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Ionic Framework - Preview</title> | ||
| <style> | ||
| * { margin: 0; padding: 0; box-sizing: border-box; } | ||
| body { | ||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | ||
| background: #f5f5f5; padding: 2rem; color: #333; | ||
| } | ||
| .container { max-width: 680px; margin: 0 auto; } | ||
| h1 { font-size: 1.4rem; margin-bottom: 0.25rem; } | ||
| .subtitle { color: #666; margin-bottom: 1.5rem; font-size: 0.875rem; } | ||
| .cards { display: grid; gap: 0.75rem; } | ||
| a.card { | ||
| background: #fff; border-radius: 8px; padding: 1rem 1.25rem; | ||
| text-decoration: none; color: inherit; | ||
| border: 1px solid #e0e0e0; transition: border-color 0.15s; | ||
| } | ||
| a.card:hover { border-color: #4f8ef7; } | ||
| .card h2 { font-size: 1rem; margin-bottom: 0.2rem; display: flex; align-items: center; gap: 0.5rem; } | ||
| .card p { color: #666; font-size: 0.8rem; } | ||
| hr { border: none; border-top: 1px solid #e0e0e0; margin: 1rem 0; } | ||
| .tip { font-size: 0.75rem; color: #999; margin-top: 1rem; } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div class="container"> | ||
| <h1>Ionic Framework Preview</h1> | ||
| <p class="subtitle">Component test apps for manual validation</p> | ||
| <div class="cards"> | ||
| <a class="card" href="/src/components/"> | ||
| <h2>Core Components</h2> | ||
| <p>Browse to /src/components/{name}/test/{scenario}/</p> | ||
| </a> | ||
| <hr> | ||
| <a class="card" href="/angular/"> | ||
| <h2>Angular</h2> | ||
| <p>@ionic/angular standalone + lazy-loaded component tests</p> | ||
| </a> | ||
| <a class="card" href="/react/"> | ||
| <h2>React</h2> | ||
| <p>@ionic/react overlays, hooks, tabs, form controls</p> | ||
| </a> | ||
| <a class="card" href="/vue/"> | ||
| <h2>Vue</h2> | ||
| <p>@ionic/vue overlays, router, tabs, lifecycle</p> | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </body> | ||
| </html> | ||
| LANDING_EOF | ||
|
|
||
| echo "" | ||
| echo "=== Preview build complete ===" | ||
| ls -la "${OUTPUT_DIR}" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "$schema": "https://openapi.vercel.sh/vercel.json", | ||
| "framework": null, | ||
| "installCommand": "npm install", | ||
| "buildCommand": "bash scripts/vercel-build.sh", | ||
| "outputDirectory": "../_vercel_output", | ||
| "rewrites": [ | ||
| { "source": "/angular/:path*", "destination": "/angular/index.html" }, | ||
| { "source": "/react/:path*", "destination": "/react/index.html" }, | ||
| { "source": "/vue/:path*", "destination": "/vue/index.html" } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,9 @@ | ||
| /// <reference types="react-scripts" /> | ||
|
|
||
| interface ImportMetaEnv { | ||
| readonly BASE_URL?: string; | ||
| } | ||
|
|
||
| interface ImportMeta { | ||
| readonly env?: ImportMetaEnv; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.