|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +# Build script for Vercel deployment of @objectstack/server. |
| 5 | +# |
| 6 | +# Follows the Vercel deployment pattern: |
| 7 | +# - api/[[...route]].js is committed to the repo (Vercel detects it pre-build) |
| 8 | +# - esbuild bundles server/index.ts → api/_handler.js (self-contained bundle) |
| 9 | +# - The committed .js wrapper re-exports from _handler.js at runtime |
| 10 | +# - Studio SPA is built and copied to public/ for serving the UI |
| 11 | +# - External dependencies installed in api/node_modules/ (no symlinks) |
| 12 | +# |
| 13 | +# Steps: |
| 14 | +# 1. Build the project with turbo (includes studio) |
| 15 | +# 2. Bundle the API serverless function (→ api/_handler.js) |
| 16 | +# 3. Copy studio dist files to public/ for UI serving |
| 17 | +# 4. Install external deps in api/node_modules/ (resolve pnpm symlinks) |
| 18 | + |
| 19 | +echo "[build-vercel] Starting server build..." |
| 20 | + |
| 21 | +# 1. Build the project with turbo (from monorepo root) |
| 22 | +# This builds server, studio, and the account portal. |
| 23 | +cd ../.. |
| 24 | +pnpm turbo run build --filter=@objectstack/server --filter=@objectstack/studio --filter=@objectstack/account |
| 25 | +cd apps/server |
| 26 | + |
| 27 | +# 1b. Compile objectstack.config.ts → dist/objectstack.json (the metadata artifact). |
| 28 | +# MetadataPlugin reads this file at startup in local mode. Without it the kernel |
| 29 | +# cannot boot ("Cannot read artifact file … ENOENT"). |
| 30 | +echo "[build-vercel] Compiling objectstack artifact..." |
| 31 | +pnpm objectstack build |
| 32 | +echo "[build-vercel] ✓ dist/objectstack.json generated" |
| 33 | + |
| 34 | +# 2. Bundle API serverless function |
| 35 | +node scripts/bundle-api.mjs |
| 36 | + |
| 37 | +# 2b. Copy the artifact into api/dist/ so Vercel includes it in the function |
| 38 | +# deployment package. The function runs with CWD=/var/task and resolves the |
| 39 | +# artifact relative to its own directory (api/), so api/dist/objectstack.json |
| 40 | +# maps to /var/task/apps/server/api/dist/objectstack.json at runtime. |
| 41 | +echo "[build-vercel] Copying artifact into api/dist/..." |
| 42 | +mkdir -p api/dist |
| 43 | +cp dist/objectstack.json api/dist/objectstack.json |
| 44 | +echo "[build-vercel] ✓ api/dist/objectstack.json ready" |
| 45 | + |
| 46 | +# 3. Copy studio dist files to public/_studio/ for UI serving. |
| 47 | +# Studio is always mounted under /_studio/ (same convention as the CLI |
| 48 | +# static plugin). Vite builds with base: '/_studio/' so its asset URLs |
| 49 | +# and router basepath are already correct for this mount point. |
| 50 | +echo "[build-vercel] Copying studio dist to public/_studio/..." |
| 51 | +rm -rf public |
| 52 | +mkdir -p public/_studio |
| 53 | +if [ -d "../studio/dist" ]; then |
| 54 | + cp -r ../studio/dist/. public/_studio/ |
| 55 | + echo "[build-vercel] ✓ Copied studio dist to public/_studio/" |
| 56 | +else |
| 57 | + echo "[build-vercel] ⚠ Studio dist not found (skipped)" |
| 58 | +fi |
| 59 | + |
| 60 | +# 3b. Copy the account portal dist to public/_account/ — same pattern as |
| 61 | +# studio. The account SPA is always built with base: '/_account/'. |
| 62 | +echo "[build-vercel] Copying account dist to public/_account/..." |
| 63 | +mkdir -p public/_account |
| 64 | +if [ -d "../account/dist" ]; then |
| 65 | + cp -r ../account/dist/. public/_account/ |
| 66 | + echo "[build-vercel] ✓ Copied account dist to public/_account/" |
| 67 | +else |
| 68 | + echo "[build-vercel] ⚠ Account dist not found (skipped)" |
| 69 | +fi |
| 70 | + |
| 71 | +# 4. Install external dependencies in api/node_modules/ (no symlinks) |
| 72 | +# pnpm uses symlinks in node_modules/, which Vercel's serverless function |
| 73 | +# packaging cannot handle ("invalid deployment package" error). |
| 74 | +# We use npm to install external packages as real files next to the handler. |
| 75 | +echo "[build-vercel] Installing external dependencies for serverless function..." |
| 76 | +cat > api/_package.json << 'DEPS' |
| 77 | +{ |
| 78 | + "private": true, |
| 79 | + "dependencies": { |
| 80 | + "@libsql/client": "0.14.0", |
| 81 | + "pino": "10.3.1", |
| 82 | + "pino-pretty": "13.1.3" |
| 83 | + } |
| 84 | +} |
| 85 | +DEPS |
| 86 | +cd api |
| 87 | +mv _package.json package.json |
| 88 | +npm install --production --no-package-lock --ignore-scripts --loglevel error |
| 89 | +rm package.json |
| 90 | +cd .. |
| 91 | +echo "[build-vercel] ✓ External dependencies installed in api/node_modules/" |
| 92 | + |
| 93 | +echo "[build-vercel] Done. Static files in public/, serverless function in api/[[...route]].js → api/_handler.js" |
0 commit comments