Skip to content
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

chore: Doc page with Fetch runtime setup examples #364

Merged
merged 10 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ jobs:
- name: Use PNPM
uses: pnpm/action-setup@v2.2.4

- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest

- name: Get pnpm store directory
id: pnpm-cache
run: |
Expand Down
3 changes: 2 additions & 1 deletion docs/src/pages/backend-adapters/_meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"express": "Express",
"fastify": "Fastify"
"fastify": "Fastify",
"fetch": "Fetch / Edge Runtimes"
}
138 changes: 138 additions & 0 deletions docs/src/pages/backend-adapters/fetch.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { Callout, Steps } from "nextra-theme-docs";

# Getting started with Fetch / Edge Runtimes

UploadThing is compatible with any runtime that follow the
[WinterCG](https://wintercg.org/).

## Common setup

### Package Setup

<Steps>

### Install the package

import { Tab, Tabs } from "nextra-theme-docs";

```sh npm2yarn
npm install uploadthing
```

#### Add env variables

<Callout>
If you don't already have a uploadthing secret key, [sign
up](https://uploadthing.com/sign-in) and create one from the
[dashboard!](https://uploadthing.com/dashboard)
</Callout>

```bash copy
UPLOADTHING_SECRET=... # A secret key for your app (starts with sk_live_)
UPLOADTHING_APP_ID=... # Your app id
```

### Set Up A FileRouter

All files uploaded to uploadthing are associated with a FileRoute. Following
example is very minimalistic. To get full insight into what you can do with the
FileRoutes, please refer to the
[File Router API](/api-reference/server#file-routes).

```ts copy filename="uploadthing.ts"
import { createUploadthing, type FileRouter } from "uploadthing/server";

const f = createUploadthing();

export const uploadRouter = {
videoAndImage: f({
image: {
maxFileSize: "4MB",
maxFileCount: 4,
},
video: {
maxFileSize: "16MB",
},
}).onUploadComplete((data) => {
console.log("upload completed", data);
}),
} satisfies FileRouter;

export type OurFileRouter = typeof uploadRouter;
```

</Steps>

## Runtimes-specific setup

### Astro

```ts filename="pages/api/uploadthing.ts"
import { createServerHandler } from "uploadthing/server";

import { uploadRouter } from "../../server/uploadthing";

export const { GET, POST } = createServerHandler({
router: uploadRouter,
config: {
uploadthingId: import.meta.env.UPLOADTHING_APPID,
uploadthingSecret: import.meta.env.UPLOADTHING_SECRET,
callbackUrl: "http://localhost:4321/api/uploadthing",
},
});
```

### Elysia

```ts filename="src/index.ts"
import { Elysia } from "elysia";
import { uploadRouter } from "uploadthing.ts";

import { createServerHandler } from "uploadthing/server";

const { GET, POST } = createServerHandler({
router: uploadRouter,
});

const app = new Elysia().get("/", () => "Hello Elysia");

app.group("/api/uploadthing", (app) =>
app
.post("/", (context) => POST(context.request))
.get("/", (context) => GET(context.request)),
);

app.listen(3000);
```

### Hono

```ts filename="src/index.ts"
import { Hono } from "hono";

import { createServerHandler } from "uploadthing/server";

import { uploadRouter } from "./uploadthing.ts";

const { GET, POST } = createServerHandler({
router: uploadRouter,
});

const app = new Hono();

const ut = new Hono()
.get("/", (context) => GET(context.req.raw))
.post("/", (context) => POST(context.req.raw));

app.route("/api/uploadthing", ut);

export default app;
```

## Use the FileRouter in your app

Please refer to client side examples:

- [NextJS App directory](/nextjs/appdir#creating-the-uploadthing-components-optional)
- [NextJS Pages directory](/nextjs/appdir#creating-the-uploadthing-components-optional)
- [SolidStart](/solid#use-the-filerouter-in-your-app-1)
18 changes: 18 additions & 0 deletions examples/minimal-elysia-react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Minimal Elysia example for UploadThing

<a href="https://stackblitz.com/github/pingdotgg/uploadthing/tree/main/examples/minimal-elysia-react">
<img height="64" src="https://github.com/pingdotgg/uploadthing/assets/51714798/45907a4e-aa64-401a-afb3-b6c6df6eb71f" />
</a>

## QuickStart

1. Grab an API key from the UploadThing dashboard:
https://uploadthing.com/dashboard
2. `cp server/.env.example server/.env` and paste in your API key in the newly
created `.env` file
3. `pnpm dev`
4. Upload files!

## Further reference

Check out the docs at: https://docs.uploadthing.com/backend-adapters/fastify
14 changes: 14 additions & 0 deletions examples/minimal-elysia-react/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.tailwindcss.com"></script>
<title>UploadThing + Elysia</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions examples/minimal-elysia-react/client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@example/minimal-elysia-react-client",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"start": "vite preview"
},
"dependencies": {
"@uploadthing/react": "5.6.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"uploadthing": "^5.6.0"
},
"devDependencies": {
"@types/react": "18.2.8",
"@types/react-dom": "18.2.4",
"@vitejs/plugin-react-swc": "^3.3.2",
"typescript": "^5.1.6",
"vite": "^4.4.9"
}
}
31 changes: 31 additions & 0 deletions examples/minimal-elysia-react/client/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";
import ReactDOM from "react-dom/client";

import { UploadButton } from "./uploadthing";

function App() {
return (
<main className="flex flex-col items-center gap-4 py-8">
<h1 className="text-xl font-bold">Elysia + Vite + Uploadthing</h1>
<div>
<UploadButton
endpoint="videoAndImage"
onClientUploadComplete={(file) => {
console.log("uploaded", file);
alert("Upload complete");
}}
onUploadError={(error) => {
console.error(error, error.cause);
alert("Upload failed");
}}
/>
</div>
</main>
);
}

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
9 changes: 9 additions & 0 deletions examples/minimal-elysia-react/client/src/uploadthing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { generateComponents } from "@uploadthing/react";
import { generateReactHelpers } from "@uploadthing/react/hooks";

import type { OurFileRouter } from "../../server/src/router";

export const { UploadButton, UploadDropzone, Uploader } =
generateComponents<OurFileRouter>();

export const { useUploadThing } = generateReactHelpers<OurFileRouter>();
26 changes: 26 additions & 0 deletions examples/minimal-elysia-react/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"types": ["vite/client"],

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
10 changes: 10 additions & 0 deletions examples/minimal-elysia-react/client/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
12 changes: 12 additions & 0 deletions examples/minimal-elysia-react/client/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": "http://localhost:3000",
},
},
});
21 changes: 21 additions & 0 deletions examples/minimal-elysia-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@example/minimal-elysia-react",
"private": true,
"version": "0.0.0",
"type": "module",
"workspaces": [
"client",
"server"
],
"scripts": {
"dev": "concurrently \"npm run -w client dev\" \"npm run -w server dev\"",
"build": "npm run -w client build && npm run -w server build",
"start": "concurrently \"npm run -w client start\" \"npm run -w server start\""
},
"devDependencies": {
"@uploadthing/react": "5.6.0",
"concurrently": "^8.2.1",
"typescript": "^5.1.6",
"uploadthing": "^5.6.0"
}
}
3 changes: 3 additions & 0 deletions examples/minimal-elysia-react/server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Go to https://uploadthing.com/dashboard to get your API secret
UPLOADTHING_SECRET='sk_live_xxx'
UPLOADTHING_APP_ID='xxx'
20 changes: 20 additions & 0 deletions examples/minimal-elysia-react/server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@example/minimal-elysia-react-server",
"private": true,
"scripts": {
"build": "echo 'bun build works weirdly in monorepos'",
"dev": "NODE_ENV=development bun run src/index.ts",
"start": "bun run src/index.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"elysia": "^0.6.23",
"uploadthing": "^5.6.0"
},
"devDependencies": {
"bun-types": "1.0.2",
"typescript": "^5.1.6"
}
}
19 changes: 19 additions & 0 deletions examples/minimal-elysia-react/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Elysia } from "elysia";

import { createServerHandler } from "uploadthing/server";

import { uploadRouter } from "./router";

const { GET, POST } = createServerHandler({
router: uploadRouter,
});

const app = new Elysia();

app.group("/api/uploadthing", (app) =>
app
.post("/", (context) => POST(context.request))
.get("/", (context) => GET(context.request)),
);

app.listen(3000);
19 changes: 19 additions & 0 deletions examples/minimal-elysia-react/server/src/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createUploadthing, type FileRouter } from "uploadthing/server";

const f = createUploadthing();

export const uploadRouter = {
videoAndImage: f({
image: {
maxFileSize: "4MB",
maxFileCount: 4,
},
video: {
maxFileSize: "16MB",
},
}).onUploadComplete((data) => {
console.log("upload completed", data);
}),
} satisfies FileRouter;

export type OurFileRouter = typeof uploadRouter;
Loading