This document covers the Vercel deployment configuration for the Prompt Optimizer web application. It explains how the web package (@prompt-optimizer/web) is built and deployed to Vercel as a static single-page application (SPA), including build configuration, environment variable management, and routing setup.
For Docker deployment, see Docker Deployment. For desktop distribution, see Desktop Distribution. For general environment configuration, see Environment Configuration and API Keys.
The Vercel deployment represents one of five deployment targets supported by the Prompt Optimizer monorepo. Unlike the Desktop or Docker deployments which can bypass CORS restrictions, Vercel deployment runs as a pure client-side application where all API calls originate directly from the user's browser to AI service providers.
Sources: README.md82-94 README_EN.md82-94 vercel.json1-32 Diagram 4 from context
The Vercel build is configured through vercel.json, which handles the monorepo structure by executing custom build and install commands.
| Configuration Key | Value | Purpose |
|---|---|---|
buildCommand | Complex conditional script | Handles both direct and extension-subfolder builds |
installCommand | Conditional pnpm install | Installs dependencies with Vercel analytics |
outputDirectory | packages/web/dist | Location of built static files |
rewrites | SPA routing rules | Ensures client-side routing works |
env | VITE_VERCEL_DEPLOYMENT: "true" | Build-time environment flag |
Sources: vercel.json1-32
The build command in vercel.json2 handles two scenarios:
Normal build (when in root directory):
Extension subdirectory build (when Vercel detects packages/extension as root):
This complexity addresses Vercel's automatic subdirectory detection when deploying from GitHub, ensuring the full monorepo is built regardless of which directory Vercel considers the root.
Sources: vercel.json2 package.json12-17
The simplest deployment method uses Vercel's clone button, which creates a new repository copy and deploys it immediately:
Limitations:
Sources: README.md82-83 README_EN.md82-83
This method provides better long-term maintainability:
Advantages:
Sources: README.md85-94 README_EN.md85-94
Vercel environment variables are configured through the Project Settings → Environment Variables section in the Vercel dashboard. All variables must use the VITE_ prefix to be embedded in the browser bundle during the build process.
Setting environment variables in Vercel:
All API keys must use the VITE_ prefix to be accessible in the browser bundle:
| Environment Variable | Purpose | Required |
|---|---|---|
VITE_OPENAI_API_KEY | OpenAI API access | No |
VITE_GEMINI_API_KEY | Google Gemini API access | No |
VITE_DEEPSEEK_API_KEY | DeepSeek API access | No |
VITE_ZHIPU_API_KEY | Zhipu AI API access | No |
VITE_SILICONFLOW_API_KEY | SiliconFlow API access | No |
VITE_CUSTOM_API_KEY_* | Custom model APIs (see below) | No |
VITE_CUSTOM_API_BASE_URL_* | Custom model base URLs | No |
VITE_CUSTOM_API_MODEL_* | Custom model names | No |
Multi-Custom Model Pattern:
The system supports unlimited custom models using a suffix-based naming convention:
The suffix (e.g., ollama, myapi) becomes the identifier for that custom model configuration.
Sources: README.md89-91 README.md272-288 README_EN.md89-92 README_EN.md275-288
Password protection via ACCESS_PASSWORD is not supported in Vercel deployments:
| Environment Variable | Supported in Vercel? | Notes |
|---|---|---|
ACCESS_PASSWORD | ❌ No | Requires NGINX or serverless function (not implemented) |
ACCESS_USERNAME | ❌ No | Docker-only feature |
Why not supported:
Alternatives:
Sources: README.md90 docker-compose.yml40-41 docker/generate-auth.sh1-46
The VITE_VERCEL_DEPLOYMENT environment variable is automatically set during Vercel builds:
This flag is defined in vercel.json24-30 and is embedded in the build. The application can use this to:
Example usage in code:
Sources: vercel.json24-30
The monorepo build follows a strict dependency order to ensure all packages are correctly built before the web application:
Build Artifacts Explained:
| Package | Build Tool | Output Location | Key Files |
|---|---|---|---|
@prompt-optimizer/core | tsup | packages/core/dist/ | index.js (ESM), index.cjs (CommonJS), index.d.ts (types) |
@prompt-optimizer/ui | Vite (library) | packages/ui/dist/ | index.js, style.css, *.vue.d.ts |
@prompt-optimizer/web | Vite (SPA) | packages/web/dist/ | index.html, assets/index-[hash].js, assets/index-[hash].css |
The root package.json12-17 defines the build pipeline:
Build execution:
packages/web/dist/ from CDNSources: package.json12-17 packages/core/package.json17 packages/ui/package.json26 packages/web/package.json8
The web package (packages/web/package.json8) uses Vite for bundling with SPA-optimized settings:
Configuration:
./ (relative paths for flexible hosting)packages/web/dist/Build output structure:
packages/web/dist/
├── index.html # Entry point with script/style tags
├── assets/
│ ├── index-[hash].js # Main application bundle (~200-300KB)
│ ├── index-[hash].css # Compiled styles (~50-100KB)
│ ├── vendor-[hash].js # Third-party libs (Vue, Naive UI, etc.)
│ └── [asset]-[hash].(woff2|png|svg) # Static assets
├── favicon.ico
└── robots.txt
Hash-based caching: All assets use content hashes in filenames, enabling aggressive CDN caching with automatic cache busting on updates.
Sources: packages/web/package.json8
Vercel's rewrites configuration ensures that Vue Router's client-side routing works correctly:
| Route Pattern | Destination | Purpose |
|---|---|---|
/api/:path* | /api/:path* | Reserved for future API routes (currently unused) |
/(.*) | /index.html | All other routes → SPA entry point |
This configuration means:
https://yourdomain.com/pro/multi) serves index.htmlThe application defines the following routes (handled client-side):
| Route | Workspace Component | Mode |
|---|---|---|
/basic/system | BasicSystemWorkspace | Basic system prompt optimization |
/basic/user | BasicUserWorkspace | Basic user prompt optimization |
/pro/multi | ContextSystemWorkspace | Multi-turn conversation testing |
/pro/variable | ContextUserWorkspace | Variable extraction and management |
/image/text2image | ImageText2ImageWorkspace | Text-to-image generation |
/image/image2image | ImageImage2ImageWorkspace | Image-to-image transformation |
Sources: vercel.json5-14 Diagram 3 from context
Vercel deployments use browser-based storage since no server-side persistence is available:
Storage Implementation:
All data remains entirely client-side and is never transmitted to Vercel's servers or any intermediate servers.
Sources: Diagram 2 from context, packages/core/src/services
As a pure client-side application deployed to Vercel's CDN, the web app is subject to browser CORS (Cross-Origin Resource Sharing) policies. This means API requests originate directly from the user's browser, not from a backend server.
Why CORS matters:
Browser security prevents JavaScript on https://your-vercel-domain.com from making requests to http://localhost:11434 (local Ollama) or enterprise APIs that don't allow arbitrary origins.
Problematic scenarios:
| Scenario | Issue | Error |
|---|---|---|
| Local Ollama without CORS config | Request blocked | CORS policy: No 'Access-Control-Allow-Origin' header |
| Commercial API with origin whitelist | Origin not in whitelist | CORS policy: Origin not allowed |
| Mixed content (HTTPS → HTTP) | Browser security policy | Mixed Content: blocked loading insecure endpoint |
| Strict Content Security Policy | CSP blocks external requests | Refused to connect: violates CSP directive |
Workarounds:
Desktop application (recommended): No CORS restrictions, runs as native app
Configure CORS on local services:
Deploy API proxy service: Use OneAPI, NewAPI, or custom proxy with proper CORS headers
Docker deployment (HTTP): Access via http://localhost:8081 avoids mixed content issues
Technical explanation:
When you configure an API key in the Vercel-deployed app, the API call flow is:
User Browser (https://your-app.vercel.app)
→ API Provider (https://api.openai.com) ✓ CORS allowed
→ Local Service (http://localhost:11434) ✗ CORS + Mixed Content blocked
Sources: README.md356-380 README_EN.md356-382 packages/core/src/services/llm/adapters
Vercel deployment is purely static – all files are served from CDN without server-side execution:
What's NOT possible:
| Feature | Why Not Available | Workaround |
|---|---|---|
| Server-side API key storage | No backend to store secrets | Users configure keys in browser |
| Request rate limiting | No server to track requests | Use provider's built-in limits |
| Centralized logging | No server to collect logs | Use browser DevTools console |
| Password protection (NGINX) | No NGINX or server middleware | Use Docker deployment (Docker Deployment) |
| API key validation | No backend to verify keys | Client attempts request and handles error |
Security implications:
API keys in browser: Users configure keys via UI, stored in IndexedDB
No backend exposure: Since there's no backend, there's nothing to secure or exploit
Client-side validation only: The app cannot enforce policies like:
For enterprise deployment with authentication and logging, use:
Sources: docker/generate-auth.sh1-46 packages/core/src/storage/dexie-storage.ts
Vercel free tier has build time limits:
The monorepo build typically completes in 2-4 minutes, well within free tier limits.
Sources: vercel.json1-32
After deployment completes, Vercel provides a deployment URL (e.g., https://prompt-optimizer-abc123.vercel.app). Verify the deployment using this checklist:
Detailed verification steps:
| Step | Action | Expected Result | Troubleshooting |
|---|---|---|---|
| 1 | Open deployment URL | App loads, shows workspace selector | Check build logs if 404/500 |
| 2 | Click navigation links | Smooth transitions, no page reload | Verify vercel.json5-14 rewrites |
| 3 | F12 → Application → Storage | IndexedDB: PromptOptimizerDB exists | Enable 3rd-party cookies if needed |
| 4 | Settings → Model Manager → Add Model | Can input API key and save | Check localStorage quota |
| 5 | Basic mode → Enter prompt → Optimize | Streaming response appears | Check CORS, API key validity |
Common issues:
vercel.json is committedSources: vercel.json5-14 packages/core/src/storage/dexie-storage.ts
Vercel supports custom domains through the dashboard:
Custom domains work identically to .vercel.app domains with the same routing and environment variable configuration.
Sources: README.md82-94 README_EN.md82-94
Refresh this wiki