Skip to content

Commit d53eb67

Browse files
committed
Enhance CLI for Convex Self Static Hosting with new Cloudflare setup command and improved help instructions. Updated README to include quick setup steps for Cloudflare integration, detailed deployment instructions, and enhanced caching behavior descriptions. Refactored command handling for better usability and clarity.
1 parent 57f031e commit d53eb67

3 files changed

Lines changed: 659 additions & 44 deletions

File tree

README.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ A Convex component that enables self-hosting static React/Vite apps using Convex
99
- 🚀 **Simple deployment** - Upload your built files directly to Convex storage
1010
- 🔒 **Secure by default** - Upload API uses internal functions (not publicly accessible)
1111
- 🔄 **SPA support** - Automatic fallback to index.html for client-side routing
12-
-**Smart caching** - Hashed assets get long-term caching, HTML is always fresh
12+
-**Smart caching** - Hashed assets get long-term caching, HTML is always fresh with ETag support
1313
- 🧹 **Auto cleanup** - Old deployment files are automatically garbage collected
14+
- ☁️ **Cloudflare ready** - One-command CDN setup with automatic cache purging
1415
- 📦 **Zero config** - Works out of the box with Vite, Create React App, and other bundlers
1516

1617
## Installation
@@ -138,11 +139,24 @@ This means unauthorized users **cannot** upload files to your site, even if they
138139

139140
## CDN Setup (Cloudflare)
140141

141-
For production deployments, you can put Cloudflare in front of your Convex static site for:
142-
- **Edge caching** - Assets served from 300+ global PoPs
143-
- **Automatic compression** - Brotli/gzip handled by Cloudflare
144-
- **DDoS protection** - Built-in security
145-
- **Custom domains** - Use `yourapp.com` instead of `*.convex.site`
142+
For production deployments, put Cloudflare in front of your Convex static site for edge caching, compression, DDoS protection, and custom domains.
143+
144+
### Quick Setup (Recommended)
145+
146+
```bash
147+
npx @get-convex/self-static-hosting setup-cloudflare
148+
```
149+
150+
This interactive wizard will:
151+
1. Login to Cloudflare (via wrangler)
152+
2. Let you select or add a domain
153+
3. Configure DNS pointing to your Convex site
154+
4. Create an API token for cache purging
155+
5. Save credentials to `.env.local`
156+
157+
Then just deploy - cache is automatically purged!
158+
159+
### What You Get
146160

147161
### Cache Behavior
148162

src/cli/index.ts

Lines changed: 153 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,162 @@
11
#!/usr/bin/env node
22
/**
3-
* CLI entry point for @get-convex/self-static-hosting
3+
* CLI for Convex Self Static Hosting
44
*
55
* Commands:
6-
* init - Output integration instructions (LLM-friendly)
7-
* upload - Upload static files to Convex
6+
* upload Upload static files to Convex
7+
* setup-cloudflare Interactive Cloudflare CDN setup
8+
* init Print setup instructions
89
*/
910

10-
import { spawn } from "child_process";
11-
import { fileURLToPath } from "url";
12-
import { dirname, join } from "path";
11+
const command = process.argv[2];
1312

14-
const __dirname = dirname(fileURLToPath(import.meta.url));
13+
async function main() {
14+
switch (command) {
15+
case "upload":
16+
// Pass remaining args to upload command
17+
process.argv.splice(2, 1);
18+
await import("./upload.js");
19+
break;
1520

16-
const command = process.argv[2];
17-
const args = process.argv.slice(3);
18-
19-
if (command === "init") {
20-
// Run init command
21-
const initPath = join(__dirname, "init.js");
22-
await import(initPath);
23-
} else if (command === "upload" || !command || command === "--help" || command === "-h") {
24-
// Run upload command (default)
25-
const uploadPath = join(__dirname, "upload.js");
26-
const uploadArgs = command === "upload" ? args : process.argv.slice(2);
27-
28-
// Re-execute with upload script
29-
const child = spawn(process.execPath, [uploadPath, ...uploadArgs], {
30-
stdio: "inherit",
31-
});
32-
33-
child.on("exit", (code) => {
34-
process.exit(code ?? 0);
35-
});
36-
} else {
37-
console.error(`Unknown command: ${command}`);
38-
console.error("");
39-
console.error("Available commands:");
40-
console.error(" init Output integration instructions for your LLM");
41-
console.error(" upload Upload static files to Convex storage");
42-
console.error("");
43-
console.error("Examples:");
44-
console.error(" npx @get-convex/self-static-hosting init");
45-
console.error(" npx @get-convex/self-static-hosting upload --dist ./dist");
46-
process.exit(1);
21+
case "setup-cloudflare":
22+
case "setup-cf":
23+
case "cloudflare":
24+
await import("./setup-cloudflare.js");
25+
break;
26+
27+
case "init":
28+
printInitInstructions();
29+
break;
30+
31+
case "--help":
32+
case "-h":
33+
case undefined:
34+
printHelp();
35+
break;
36+
37+
default:
38+
console.error(`Unknown command: ${command}`);
39+
console.log("");
40+
printHelp();
41+
process.exit(1);
42+
}
43+
}
44+
45+
function printHelp() {
46+
console.log(`
47+
Convex Self Static Hosting CLI
48+
49+
Usage:
50+
npx @get-convex/self-static-hosting <command> [options]
51+
52+
Commands:
53+
upload Upload static files to Convex storage
54+
setup-cloudflare Interactive Cloudflare CDN setup wizard
55+
init Print setup instructions for integration
56+
57+
Examples:
58+
npx @get-convex/self-static-hosting upload
59+
npx @get-convex/self-static-hosting upload --dist ./build
60+
npx @get-convex/self-static-hosting setup-cloudflare
61+
npx @get-convex/self-static-hosting init
62+
63+
Run '<command> --help' for more information on a specific command.
64+
`);
65+
}
66+
67+
function printInitInstructions() {
68+
console.log(`
69+
# Convex Self Static Hosting - Setup Instructions
70+
71+
## 1. Install the component
72+
73+
\`\`\`bash
74+
npm install @get-convex/self-static-hosting
75+
\`\`\`
76+
77+
## 2. Add to convex.config.ts
78+
79+
\`\`\`typescript
80+
// convex/convex.config.ts
81+
import { defineApp } from "convex/server";
82+
import selfStaticHosting from "@get-convex/self-static-hosting/convex.config.js";
83+
84+
const app = defineApp();
85+
app.use(selfStaticHosting);
86+
87+
export default app;
88+
\`\`\`
89+
90+
## 3. Create HTTP routes
91+
92+
\`\`\`typescript
93+
// convex/http.ts
94+
import { httpRouter } from "convex/server";
95+
import { registerStaticRoutes } from "@get-convex/self-static-hosting";
96+
import { components } from "./_generated/api";
97+
98+
const http = httpRouter();
99+
100+
// Serve static files (use pathPrefix for CDN setups)
101+
registerStaticRoutes(http, components.selfStaticHosting, {
102+
pathPrefix: "/", // or "/app" to keep API routes separate
103+
spaFallback: true,
104+
});
105+
106+
export default http;
107+
\`\`\`
108+
109+
## 4. Expose upload API
110+
111+
\`\`\`typescript
112+
// convex/staticHosting.ts
113+
import { exposeUploadApi, exposeDeploymentQuery } from "@get-convex/self-static-hosting";
114+
import { components } from "./_generated/api";
115+
116+
// Internal functions for secure uploads
117+
export const { generateUploadUrl, recordAsset, gcOldAssets, listAssets } =
118+
exposeUploadApi(components.selfStaticHosting);
119+
120+
// Optional: Live reload notifications
121+
export const { getCurrentDeployment } =
122+
exposeDeploymentQuery(components.selfStaticHosting);
123+
\`\`\`
124+
125+
## 5. Add deploy script to package.json
126+
127+
\`\`\`json
128+
{
129+
"scripts": {
130+
"build": "vite build",
131+
"deploy:static": "npm run build && npx @get-convex/self-static-hosting upload"
132+
}
133+
}
134+
\`\`\`
135+
136+
## 6. Deploy
137+
138+
\`\`\`bash
139+
npm run deploy:static
140+
\`\`\`
141+
142+
## Optional: Cloudflare CDN Setup
143+
144+
\`\`\`bash
145+
npx @get-convex/self-static-hosting setup-cloudflare
146+
\`\`\`
147+
148+
This interactive wizard will:
149+
- Login to Cloudflare
150+
- Help you select or add a domain
151+
- Configure DNS pointing to your Convex site
152+
- Create an API token for cache purging
153+
- Save credentials to .env.local
154+
155+
Then just deploy - cache is purged automatically!
156+
`);
47157
}
158+
159+
main().catch((err) => {
160+
console.error("Error:", err);
161+
process.exit(1);
162+
});

0 commit comments

Comments
 (0)