지난 1편에선 로컬에서 NextJs 의 API 서버에서 Multer 사용법을
2편에선 s3 에 업로드 하는 것을 기록해두었다.
이제 3편에서는 lamda 로 이미지 리사이징 하는 것을 기록해둔다.
import AWS from "aws-sdk"
import sharp from "sharp"
const s3 = new AWS.S3();
exports.handler = async(event, context, callback) => {
const Bucket = event.Records[0].s3.Bucket.name; //cultureplace
const Key = decodeURIComponent(event.Records[0].s3.object.key); // original/123_abc.png
console.log("Bucket", Bucket, "Key", Key);
const filename = Key.split("/")[Key.split("/").length - 1];
const ext = Key.split(".")[Key.split(".").length - 1];
const requiredFormat = ext === "jpg" ? "jpeg" : ext;
console.log("filename", filename, "ext", ext);
try {
const s3Object = await s3.getObject({ Bucket, Key }).promise();
console.log("original", s3Object.Body.length);
const resizedImage = await sharp(s3Object.Body).resize(400, 400, { fit: "inside" }).toFormat(requiredFormat).toBuffer();
await s3
.putObject({
Bucket,
Key: `thumb/${filename}`,
Body: resizedImage,
})
.promise();
console.log("put", resizedImage.length);
return callback(null, `thumb/${filename}`)
} catch (error) {
console.error(error)
return callback(error)
}
}
aws-upload.zip 로 lamda 폴더내에서 압축.
최신 버전의 AWS CLI의 경우:
https://awscli.amazonaws.com/AWSCLIV2.msi
제대로 동작하는지 보려면, cmd 에서 aws --version 체크 (만약 vc 터미널에서 반영안됐다면
vc 프로그램 종료 후 다시 시작)
소스코드 변경
api/imgupload/index.js
import nextConnect from "next-connect";
import multer from "multer";
import path from "path";
import dayjs from "dayjs";
import multerS3 from "multer-s3";
import AWS from "aws-sdk";
const app = nextConnect({
onError(error, req, res) {
res
.status(501)
.json({ error: `Sorry something Happened! ${error.message}` });
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
AWS.config.update({
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
region: "ap-northeast-2",
});
var upload = multer({
storage: multerS3({
s3: new AWS.S3(),
bucket: "cultureplace",
key(req, file, cb) {
const nowDate = dayjs(Date.now()).format("YYMMDDHHMM");
cb(null, `original/${nowDate}_${file.originalname}`);
},
}),
});
// var upload = multer({ storage: storage });
app.post(upload.array("file"), function (req, res) {
res.json(req.files.map((v) => v.location.replace(/\/original\//, "/thumb/")));
});
export default app;
export const config = {
api: {
bodyParser: false, // Disallow body parsing, consume as stream
},
};
pages/imgup.tsx
import React, { useCallback, useState } from "react";
import axios from "axios";
import { UiFileInputButton } from "./components/UiFileInputButton";
const IndexPage = () => {
const [thumb, setThumb] = useState<string[]>([]);
const [progress, setProgress] = useState<number>(0);
const onChange = useCallback(
async (formData: FormData) => {
const config = {
headers: { "content-type": "multipart/form-data" },
onUploadProgress: (event: { loaded: number; total: number }) => {
setProgress(Math.round((event.loaded * 100) / event.total));
},
};
axios.post<any>("/api/imgupload", formData, config).then((res) => {
setThumb([...thumb, ...res.data]);
});
},
[thumb]
);
return (
<>
<p>
<span>이미지 업로드</span>
<span>{progress}</span>
</p>
<UiFileInputButton
label="Upload Single File"
// allowMultipleFiles 가 false 일경우, 하나씩만 올릴 수 있다.
allowMultipleFiles={true}
uploadFileName="file"
onChange={onChange}
/>
<ul>
{thumb &&
thumb.map((item: string, i: number) => {
console.log("item", item);
return (
<li key={i}>
썸네일
<p>
<img src={item} width="300" alt="업로드이미지" />
</p>
<p>
원본
<img
src={item.replace(/\/thumb\//, "/original/")}
width="300"
alt="업로드이미지"
/>
</p>
</li>
);
})}
</ul>
</>
);
};
export default IndexPage;
이렇게 하면, 람다가 이미지 리사이징을 잘 해주는 것을 확인할 수 있다.
react-query 로 Infinity Scroll & Scroll restoration 을 만들어두었는데
오늘 만들어둔 이미지 관리 소스 + wywig 게시판 기능을 활용해서
상품을 등록하고 (상세페이지등록)
무한스크롤을 구현한 예제를 올려보겠다.