diff --git a/public/images/cubeit-intranet-retrospect/mediaquery.gif b/public/images/cubeit-intranet-retrospect/mediaquery.gif deleted file mode 100644 index 764f81a..0000000 Binary files a/public/images/cubeit-intranet-retrospect/mediaquery.gif and /dev/null differ diff --git a/public/images/cubeit-intranet-retrospect/mediaquery.webp b/public/images/cubeit-intranet-retrospect/mediaquery.webp new file mode 100644 index 0000000..9ecb43a Binary files /dev/null and b/public/images/cubeit-intranet-retrospect/mediaquery.webp differ diff --git a/public/images/cubeit-intranet-retrospect/random-profile-image.gif b/public/images/cubeit-intranet-retrospect/random-profile-image.gif deleted file mode 100644 index 1e661f8..0000000 Binary files a/public/images/cubeit-intranet-retrospect/random-profile-image.gif and /dev/null differ diff --git a/public/images/cubeit-intranet-retrospect/random-profile-image.webp b/public/images/cubeit-intranet-retrospect/random-profile-image.webp new file mode 100644 index 0000000..12a0d5d Binary files /dev/null and b/public/images/cubeit-intranet-retrospect/random-profile-image.webp differ diff --git a/scripts/sharp-api.ts b/scripts/sharp-api.ts index 1bd1244..33aa2f1 100644 --- a/scripts/sharp-api.ts +++ b/scripts/sharp-api.ts @@ -18,10 +18,7 @@ export const SHARP_OPTIONS: { avif: { quality: 65, }, - gif: { - effort: 7, - dither: 0.5, - }, + gif: {}, } export type SharpOptionType = keyof typeof SHARP_OPTIONS @@ -31,7 +28,7 @@ export const SHARP_OPTIONS_TYPE_MAPPER = { jpeg: 'jpeg', webp: 'webp', avif: 'avif', - gif: 'gif', + gif: 'webp', } as const satisfies { [key: string]: SharpOptionType } export type SharpFileType = keyof typeof SHARP_OPTIONS_TYPE_MAPPER @@ -96,7 +93,15 @@ export const sharpImages = async () => { const sharpOptionType = SHARP_OPTIONS_TYPE_MAPPER[fileType] const sharpOption = SHARP_OPTIONS[sharpOptionType] - const sharpedFilePath = filePath.replace(`.${fileType}`, `.sharp.${fileType}`) + const metadata = await sharp(filePath).metadata() + const isAnimatedWebp = fileType === 'webp' && metadata.pages && metadata.pages > 1 + + if (isAnimatedWebp) { + console.log(`::✧:: Skipping animated WebP file ${filename}`) + continue + } + + const sharpedFilePath = filePath.replace(`.${fileType}`, `.sharp.${sharpOptionType}`) await sharp(filePath, fileType === 'gif' ? { animated: true } : {}) [sharpOptionType](sharpOption) @@ -114,9 +119,8 @@ export const sharpImages = async () => { } if (processedResult.percentChange > 0) { - await fs.writeFile(filePath, await fs.readFile(sharpedFilePath)) - if (fileType !== 'gif') { + await fs.writeFile(filePath, await fs.readFile(sharpedFilePath)) const avifPath = filePath.replace(`.${fileType}`, '.avif') await sharp(filePath).avif(SHARP_OPTIONS.avif).toFile(avifPath) const avifStats = await fs.stat(avifPath) @@ -134,12 +138,22 @@ export const sharpImages = async () => { } } + if (fileType === 'gif') { + const webpPath = filePath.replace('.gif', '.webp') + await fs.rename(sharpedFilePath, webpPath) + const webpFilename = path.basename(webpPath) + mdxUpdates += await updateMdxReferences(filename, webpFilename) + await unlink(filePath) + } + sharpedImageList.push(processedResult) } else { unSharpedImageList.push(processedResult) } - await unlink(sharpedFilePath) + if (fileType !== 'gif') { + await unlink(sharpedFilePath) + } } catch (error) { console.log('::error::', error) } diff --git a/src/content/post/blog/cubeit-intranet-retrospect.mdx b/src/content/post/blog/cubeit-intranet-retrospect.mdx index a15f51f..f117601 100644 --- a/src/content/post/blog/cubeit-intranet-retrospect.mdx +++ b/src/content/post/blog/cubeit-intranet-retrospect.mdx @@ -73,7 +73,7 @@ SQLite3는 선택사항이었지만, 김민태 강사님께서 SQL 문을 사용 디자인이 나와야 개발을 시작할 수 있어서 레퍼런스를 활용해 주말에 빠르게 작업했다. 조장님(진짜 디자이너)이 레퍼런스도 구해주시고 피드백도 빠르게 주셔서 좀 더 수월하게 작업할 수 있었다. -![반응형으로 구현한 모습](/images/cubeit-intranet-retrospect/mediaquery.gif) +![반응형으로 구현한 모습](/images/cubeit-intranet-retrospect/mediaquery.webp) ## 역할 @@ -139,7 +139,7 @@ Cube.IT 인트라넷 서비스는 크게 **로그인, 홈, 프로필, 구성원, 이미지 파일을 업로드하면 **Cloudinary**를 이용해 **url로 변환**한 다음, **데이터베이스에 저장**한다. 그대로 데이터베이스에 저장할 수도 있었지만, 용량 최적화를 위해 Cloudinary 서비스를 이용했다. -![랜덤 프로필 이미지 생성](/images/cubeit-intranet-retrospect/random-profile-image.gif) +![랜덤 프로필 이미지 생성](/images/cubeit-intranet-retrospect/random-profile-image.webp) `기본 이미지 설정`을 클릭하면 [DiceBear](https://www.dicebear.com/) API의 Lorelei 스타일 **아바타를 랜덤으로 설정**해주는 이스터에그 같은 기능을 추가했다. 처음 만들었을 때 재미있어서 홀린 듯이 계속 눌러봤던 기억이 있다. 🤣