Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/burgil/nextjs-cloudflare-fullstack
Did you think CloudFlare Pages can only run static html files? Think again! Through the power of CloudfFlare Functions we are able to deploy a full-stack application with a backend and a frontend directly connected. (Using CloudFlare Workers + Pages through Functions) - NEW! NextJS Support
https://github.com/burgil/nextjs-cloudflare-fullstack
Last synced: 10 days ago
JSON representation
Did you think CloudFlare Pages can only run static html files? Think again! Through the power of CloudfFlare Functions we are able to deploy a full-stack application with a backend and a frontend directly connected. (Using CloudFlare Workers + Pages through Functions) - NEW! NextJS Support
- Host: GitHub
- URL: https://github.com/burgil/nextjs-cloudflare-fullstack
- Owner: burgil
- Created: 2024-12-20T04:35:28.000Z (12 days ago)
- Default Branch: main
- Last Pushed: 2024-12-20T05:11:25.000Z (12 days ago)
- Last Synced: 2024-12-20T05:27:53.145Z (12 days ago)
- Language: TypeScript
- Size: 0 Bytes
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Instructions to use Next.JS with CF FullStack
[Demo](https://nextjscfsupport.pages.dev)
![Next.JS with CF FullStack](preview.png)
**Buy Why?**
**VERCEL:**
`16MB per request x 1 million requests = 16 million megabytes / 1024MB = 15625TB x $20 per 1 TB = 312,500$ on vercel`
`1MB per request x 1 million requests = 1 million megabytes / 1024MB = 976TB x $20 per 1 TB = 19,520$ on vercel`
**CLOUDFLARE:**
`any MB per request x 1 million requests = free - NO CREDIT CARD REQUIRED`
**THE CATCH:**
(+$0.60 per additional million and only for backend traffic, AKA cloudflare workers - And for the frontend traffic it's 100% free - AKA cloudflare pages - Frontend traffic means all your HTML,CSS,JS,PNG and etc files)
*You also get a free database to use... Look nothing is really free, but it's the cheapest by far. And no credit card is required to start!*
> THANK YOU CLOUDFLARE FOR ALLOWING ME TO GROW (REALISTICALLY) AS I GO β π©π
*Only 500 builds per month? And what do they mean by 1 build at a time?*
> A build counts for when you run `pnpm deploy`, it takes around 30 seconds to complete, during this 30 seconds only 1 built can be made, and only 500 builds per month, look they need to distribute your HTML,CSS,JS,PNG.. files on all their 275+ data centers (tons of computers) and you get it for free so no complains! or just pay them $20 lol!
**Don't believe me?**
*Check for yourself* [here](https://workers.cloudflare.com/) and [here](https://pages.cloudflare.com/) (Scroll down for the pricing - **No credit card required to start**)
> [!IMPORTANT]
> You don't have to clone this repository, The entire reproduction steps can be found below!## Next.JS SSG (Static Site Generation)
By default, Next.js pre-renders pages using [Static Generation](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) without fetching data. Here's an example:
```ts
function About() {
returnAbout
}
export default About
```**But, You need to understand [Static Exports](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports)**
## Instructions
### 1. Create a new Next.JS project or use an existing one
```bash
npx create-next-app@latestcd my-app
pnpm dev
http://localhost:3000
CTRL+C
```### 2. Install the workers types
```bash
pnpm add -D @cloudflare/workers-types
```### 3. Create wrangler.toml
Modify the name in `wrangler.toml`
```toml
#:schema node_modules/wrangler/config-schema.json
name = "nextjscfsupport"
compatibility_date = "2024-12-20"
pages_build_output_dir = "./out"
# compatibility_flags = ["nodejs_compat"][vars]
API_HOST = "example.com"
API_ACCOUNT_ID = "example_user"
SERVICE_X_DATA = { URL = "service-x-api.dev.example", MY_ID = 123 }# Automatically place your workloads in an optimal location to minimize latency.
# If you are running back-end logic in a Pages Function, running it closer to your back-end infrastructure
# rather than the end user may result in better performance.
# Docs: https://developers.cloudflare.com/pages/functions/smart-placement/#smart-placement
# [placement]
# mode = "smart"# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
# Docs:
# - https://developers.cloudflare.com/pages/functions/bindings/#environment-variables
# Note: Use secrets to store sensitive data.
# - https://developers.cloudflare.com/pages/functions/bindings/#secrets
# [vars]
# MY_VARIABLE = "production_value"# Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflareβs global network
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#workers-ai
# [ai]
# binding = "AI"# Bind a D1 database. D1 is Cloudflareβs native serverless SQL database.
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#d1-databases
# [[d1_databases]]
# binding = "EXAMPLED1"
# database_name = "example-d1"
# database_id = "1-2-3-4-5"
# # preview_database_id = "DB" # Required for Pages local development# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
# Docs: https://developers.cloudflare.com/workers/runtime-apis/durable-objects
# [[durable_objects.bindings]]
# name = "MY_DURABLE_OBJECT"
# class_name = "MyDurableObject"
# script_name = 'my-durable-object'# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#kv-namespaces
# [[kv_namespaces]]
# binding = "EXAMPLEKV"
# id = "id here"# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#queue-producers
# [[queues.producers]]
# binding = "MY_QUEUE"
# queue = "my-queue"# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#r2-buckets
# [[r2_buckets]]
# binding = "MY_BUCKET"
# bucket_name = "my-bucket"# Bind another Worker service. Use this binding to call another Worker without network overhead.
# Docs: https://developers.cloudflare.com/pages/functions/bindings/#service-bindings
# [[services]]
# binding = "MY_SERVICE"
# service = "my-service"# To use different bindings for preview and production environments, follow the examples below.
# When using environment-specific overrides for bindings, ALL bindings must be specified on a per-environment basis.
# Docs: https://developers.cloudflare.com/pages/functions/wrangler-configuration#environment-specific-overrides######## PREVIEW environment config ########
# [env.preview.vars]
# API_KEY = "xyz789"# [[env.preview.kv_namespaces]]
# binding = "MY_KV_NAMESPACE"
# id = ""######## PRODUCTION environment config ########
# [env.production.vars]
# API_KEY = "abc123"# [[env.production.kv_namespaces]]
# binding = "MY_KV_NAMESPACE"
# id = ""
```### 4. Add to .gitignore
```text
# wrangler files
.wrangler
.dev.vars
```### 5. Modify package.json
```json
"scripts": {
"dev": "next dev --turbopack",
"start": "next dev --turbopack",
"start:backend": "pnpm dlx wrangler pages dev pages",
"build": "next build",
"deploy": "next build && pnpm dlx wrangler pages deploy ./out",
"deploy:test": "pnpm dlx wrangler pages dev ./out",
"lint": "next lint"
```### 6. Modify next.config.ts
```ts
import type { NextConfig } from "next";// Since we want the development server to redirect traffic to /api/ from the frontend at http://localhost:3000 to the backend at http://localhost:8788
// We need to set up "rewrites", NextJS warns you that these rewrites will not work in production after you build
// But we don't care because wrangler automatically binds the "functions" directory to the frontend on production
// We just need it to work in development too
const warn = console.warn;
console.warn = (...args) => {
if (args[0].trim().includes('Specified "rewrites" will not automatically work with "output: export". See more info here: https://nextjs.org/docs/messages/export-no-custom-routes')) return;
if (args[0].trim().includes('rewrites, redirects, and headers are not applied when exporting your application, detected (rewrites). See more info here: https://nextjs.org/docs/messages/export-no-custom-routes')) return;
warn(...args);
}const nextConfig: NextConfig = {
output: 'export',// https://stackoverflow.com/questions/60925133/proxy-to-backend-with-default-next-js-dev-server
async rewrites() {
return [
{
source: "/api/:path*/",
destination: `${process.env.NEXT_PUBLIC_BASE_URL || 'http://127.0.0.1:8788'}/api/:path*/`,
},
];
},// Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
trailingSlash: true,// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
// skipTrailingSlashRedirect: true,// Optional: Change the output directory `out` -> `dist`
// distDir: 'dist',
};export default nextConfig;
```
### 7. Modify tsconfig.json
```json
{
"compilerOptions": {
...
"types": ["@cloudflare/workers-types"],
```### 8. Create functions/api/login.ts
Create your first backend route for `/api/login`
For now I used an example GET request but you can google `"cloudflare workers/functions post request"`, gpt it or ask Burgil how to use POST requests..
```ts
interface Env {
API_HOST: string;
}export const onRequest: PagesFunction = async (context) => {
return new Response(`Hello from backend! TODO Login Route! - API host: ${context.env.API_HOST}`);
};
```Enjoy TypeScript support out of the box! **(Rare Feature!)**
You have full access to all CF Workers types, For example:
```ts
interface Env {
KVDB: KVNamespace;
D1DB: D1Database;
API_KEY: string;
}
```### 9. To start the frontend run
```bash
pnpm start
```[http://localhost:3000](http://localhost:3000)
### 10. To start the backend run
```bash
pnpm start:backend
```[http://localhost:8788/api/login](http://localhost:8788/api/login)
### 11. To deploy run
```bash
pnpm run deploy
```### 12. Connecting the Frontend with the Backend
A) Create `my-app\src\app\LoginButton.tsx` or wherever else you want it
```ts
"use client"export default function LoginButton() {
async function handleLogin() {
try {
const response = await fetch("/api/login"/*, {
method: "POST",
body: JSON.stringify({
email,
pass
})
}*/)
const data = await response.text();
alert(data)
} catch (e) {
console.log("Failed to login!", e);
alert("Failed to login! Check the console...");
}
}return (
Test Login API
)
}
```B) Modify `my-app\src\app\page.tsx`
```diff
+ import LoginButton from "./LoginButton";
-
+
++
+
+ CF Pages
+
+
+ CF Workers
+
+
```### 13. Installation Logs
npx create-next-app@latest
```text
PS C:\Projects\nextjs> npx create-next-app@latest
Need to install the following packages:
[email protected]
Ok to proceed? (y) yβ What is your project named? ... my-app
β Would you like to use TypeScript? ... No / Yes
β Would you like to use ESLint? ... No / Yes
β Would you like to use Tailwind CSS? ... No / Yes
β Would you like your code inside a `src/` directory? ... No / Yes
β Would you like to use App Router? (recommended) ... No / Yes
β Would you like to use Turbopack for `next dev`? ... No / Yes
β Would you like to customize the import alias (`@/*` by default)? ... No / Yes
β What import alias would you like configured? ... @/*
Creating a new Next.js app in C:\Projects\nextjs\my-app.Using npm.
Initializing project with template: app-tw
Installing dependencies:
- react
- react-dom
- nextInstalling devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- postcss
- tailwindcss
- eslint
- eslint-config-next
- @eslint/eslintrcadded 370 packages, and audited 371 packages in 1m
140 packages are looking for funding
run `npm fund` for detailsfound 0 vulnerabilities
Initialized a git repository.Success! Created my-app at C:\Projects\nextjs\my-app
```### 14. Build + Deploy Logs
pnpm run deploy
```text
PS A:\Projects\nextjs\my-app> pnpm run deploy> [email protected] deploy A:\Projects\nextjs\my-app
> next build && pnpm dlx wrangler pages deploy ./outβ² Next.js 15.1.2
Creating an optimized production build ...
β Compiled successfully
β Linting and checking validity of types
β Collecting page data
β Generating static pages (5/5)
β Collecting build traces
β Exporting (3/3)
β Finalizing page optimizationRoute (app) Size First Load JS
β β / 5.82 kB 111 kB
β β /_not-found 977 B 106 kB
+ First Load JS shared by all 105 kB
β chunks/35-2e16dc7683c22009.js 50.6 kB
β chunks/b26ba64e-d9c16b6181b85011.js 52.9 kB
β other shared chunks (total) 1.95 kBβ (Static) prerendered as static content
β² [WARNING] Warning: Your working directory is a git repo and has uncommitted changes
To silence this warning, pass in --commit-dirty=true
β¨ Compiled Worker successfully
β¨ Success! Uploaded 4 files (28 already uploaded) (1.71 sec)β¨ Uploading Functions bundle
π Deploying...
β¨ Deployment complete! Take a peek over at https://535b50d2.nextjscfsupport.pages.dev
```Ignore the `535b50d2` part.
Now open your website, in my case [https://nextjscfsupport.pages.dev](https://nextjscfsupport.pages.dev)
Click the Test Login API button - As you can see it works in both production and development.
To add a .com domain simply [get one](https://domains.cloudflare.com/) and connect it in the [dashboard](https://dash.cloudflare.com/)
> [!NOTE]
> Note: Creating a `.pages.dev` domain initially takes a lot of time so wait like 5 minutes before the page is working### 15. What's next?
1. Learn about D1 / KV databases to get the best database on the planet.
2. Make a POST route that returns JSON and call it from the client.
3. Ask burgil how to connect the D1 / KV database to your login system.
4. Enjoy your super fast and super cheap and efficient website