Skip to content

Commit

Permalink
feat: s3 for images (#304)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmbanan666 authored Feb 17, 2025
1 parent 4765645 commit d5fae13
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 69 deletions.
9 changes: 8 additions & 1 deletion apps/web-app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,12 @@ NUXT_SESSION_PASSWORD=""
# Locale for Nuxt I18n
NUXT_PUBLIC_LOCALE="en"

# S3 file storage
NUXT_S3_BUCKET=""
NUXT_S3_REGION=""
NUXT_S3_ENDPOINT=""
NUXT_S3_ACCESS_KEY_ID=""
NUXT_S3_SECRET_ACCESS_KEY=""

# App version
VERSION=""
VERSION=""
15 changes: 8 additions & 7 deletions packages/core/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ export default defineNuxtConfig({
},
runtimeConfig: {
channelId: 'burger',
storageProductsDirectory: 'products',
locale: 'en',
productsDirectory: '/products',
s3: {
bucket: '',
region: '',
endpoint: '',
accessKeyId: '',
secretAccessKey: '',
},
},
nitro: {
storage: {
fileSystem: {
driver: 'fs',
base: './../../.storage',
},
},
preset: fileURLToPath(new URL('./server/preset.ts', import.meta.url)),
experimental: {
tasks: true,
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@nuxtjs/i18n": "catalog:",
"@vueuse/core": "catalog:",
"@vueuse/nuxt": "catalog:",
"aws4fetch": "catalog:",
"bcrypt": "catalog:",
"sharp": "catalog:"
},
Expand Down
37 changes: 37 additions & 0 deletions packages/core/server/api/file/[mediaId]/[name].get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import sharp from 'sharp'

export default defineEventHandler(async (event) => {
try {
const { productsDirectory } = useRuntimeConfig()
const storage = useStorage('s3')

const mediaId = getRouterParam(event, 'mediaId')
const name = getRouterParam(event, 'name')
if (!mediaId || !name) {
throw createError({
statusCode: 400,
statusMessage: 'Missing name',
})
}

const itemName = `${productsDirectory}/${mediaId}/${name}`

const file = await storage.hasItem(itemName)
if (!file) {
throw createError({
statusCode: 404,
statusMessage: 'File not found',
})
}

setHeaders(event, {
'Cache-Control': 'max-age=31536000, immutable',
})

const raw = await storage.getItemRaw(itemName)

return sharp(raw as ArrayBuffer).toBuffer()
} catch (error) {
throw errorResolver(error)
}
})
31 changes: 0 additions & 31 deletions packages/core/server/api/file/[productId]/[name].get.ts

This file was deleted.

12 changes: 7 additions & 5 deletions packages/core/server/api/product/[id]/image.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const IMAGE_SIZES = [120, 300, 600, 800]

export default defineEventHandler(async (event) => {
try {
const { storageProductsDirectory } = useRuntimeConfig()
const { productsDirectory } = useRuntimeConfig()
const storage = useStorage('s3')

const id = getRouterParam(event, 'id')
if (!id) {
throw createError({
Expand Down Expand Up @@ -55,15 +57,15 @@ export default defineEventHandler(async (event) => {
.toFormat('jpg', { quality: 75 })
.toBuffer()
.then((data) => {
useStorage('fileSystem').setItemRaw(`${storageProductsDirectory}/${mediaId}/${size}.jpg`, data)
storage.setItemRaw(`${productsDirectory}/${mediaId}/${size}.jpg`, data)
})

await sharp(file.data.buffer as ArrayBuffer)
.resize({ width: size, height: size })
.toFormat('webp', { quality: 75 })
.toBuffer()
.then((data) => {
useStorage('fileSystem').setItemRaw(`${storageProductsDirectory}/${mediaId}/${size}.webp`, data)
storage.setItemRaw(`${productsDirectory}/${mediaId}/${size}.webp`, data)
})
}

Expand All @@ -73,8 +75,8 @@ export default defineEventHandler(async (event) => {
if (product?.mediaId) {
// Remove old images
for (const size of IMAGE_SIZES) {
await useStorage('fileSystem').removeItem(`${storageProductsDirectory}/${product.mediaId}/${size}.jpg`)
await useStorage('fileSystem').removeItem(`${storageProductsDirectory}/${product.mediaId}/${size}.webp`)
await storage.removeItem(`${productsDirectory}/${product.mediaId}/${size}.jpg`)
await storage.removeItem(`${productsDirectory}/${product.mediaId}/${size}.webp`)
}

await repository.media.delete(product.mediaId)
Expand Down
15 changes: 15 additions & 0 deletions packages/core/server/plugins/02.storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import s3Driver from 'unstorage/drivers/s3'

export default defineNitroPlugin(() => {
const { s3 } = useRuntimeConfig()

const driver = s3Driver({
bucket: s3.bucket,
region: s3.region,
endpoint: s3.endpoint,
accessKeyId: s3.accessKeyId,
secretAccessKey: s3.secretAccessKey,
})

useStorage().mount('s3', driver)
})
Loading

0 comments on commit d5fae13

Please sign in to comment.