파일 업로드 기능을 간편하게 구현할 수 있도록 도와주는 라이브러리 (공식문서)
Github 계정으로 가입하고, API KEY를 받아 문서에 나온대로 하면 간단하게 파일 업로드 기능을 구현할 수 있다. 프로젝트에서는 설정 메뉴에서 계정 이미지를 수정하는 기능에 사용했다.
npm install uploadthing @uploadthing/react
// .env.local
UPLOADTHING_SECRET=추가1
PLOADTHING_APP_ID=추가2
app > api 폴더 내부에 uploadthing 폴더 생성
uploadthing 폴더 내부에 core.ts, route.ts 파일을 추가한다.
upload.ts는 uploadthing 라이브러리에서 제공하는 UploadButton을 넣었다.
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { UploadThingError } from "uploadthing/server";
const f = createUploadthing();
export const ourFileRouter = {
// 공식 문서에는 middleware가 있는데, 현 프로젝트의 경우 불필요하여 제거
avatarUploader: f({ image: { maxFileSize: "2MB" } }).onUploadComplete(
async ({ metadata, file }) => {}
),
} satisfies FileRouter;
export type OurFileRouter = typeof ourFileRouter;
import { createRouteHandler } from "uploadthing/next";
import { ourFileRouter } from "./core";
export const { GET, POST } = createRouteHandler({
router: ourFileRouter,
});
import {
generateUploadButton,
generateUploadDropzone,
} from "@uploadthing/react";
import type { OurFileRouter } from "./core";
export const UploadButton = generateUploadButton<OurFileRouter>();
export const UploadDropzone = generateUploadDropzone<OurFileRouter>();
return (
<Card>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
// ... 코드코드
<UploadButton
className="scale-75 ut-button:ring-primary ut-label:bg-red-50 ut-button:bg-primary/75 hover:ut-button:bg-primary/100 ut:button:transition-all ut-button:duration-500 ut-label:hidden ut-allowed-content:hidden"
endpoint="avatarUploader"
onUploadBegin={() => {
setAvatarUploading(true);
}}
onUploadError={(error) => {
form.setError("image", {
type: "validate",
message: error.message,
});
setAvatarUploading(false);
return;
}}
onClientUploadComplete={(res) => {
form.setValue("image", res[0].url!);
setAvatarUploading(false);
return;
}}
content={{
button({ ready }) {
if (ready) return <div>Change Avatar</div>;
return <div>Uploading...</div>;
},
}}
/>
</div>
<FormControl>
<Input
placeholder="User Image"
type="hidden"
disabled={status === "executing"}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</CardContent>
</Card>
);
import { withUt } from "uploadthing/tw";
export default withUt({
content: ["./src/**/*.{ts,tsx,mdx}"],
...
});
[data-ut-element="button"][data-state="uploading"]::after {
@apply bg-primary/50;
}