From c5efb315e0b0d001bbd79aacdacb3526e609f83c Mon Sep 17 00:00:00 2001 From: Ashelyn Dawn Date: Fri, 11 Jun 2021 00:23:10 -0600 Subject: [PATCH] Allow thumbnails to be served in webp --- .gitignore | 3 +- api/images.js | 64 ++++++++------------------------------ components/card/card.js | 5 ++- pages/store/item/[slug].js | 18 +++++++---- 4 files changed, 30 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 14300a6..161ad33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .next/ node_modules/ -.env -cache/ \ No newline at end of file +.env \ No newline at end of file diff --git a/api/images.js b/api/images.js index ecb1fb9..593d0ff 100644 --- a/api/images.js +++ b/api/images.js @@ -1,67 +1,29 @@ const router = require('express-promise-router')() const db = require('../db') const ensureAdmin = require('./middleware/ensureAdmin') -const fs = require('fs'); -const path = require('path'); - -const cacheRoot = path.join(__dirname, '../cache/images') - -fs.promises.mkdir(cacheRoot, {recursive: true}) - .catch(() => console.error("Could not create image cache dir: " + cacheRoot)); - -const memCache = {}; - -async function writeImageFile(uuid, size, data) { - if(size !== 'thumb' && size !== 'large') - throw new Error(`Unknown image size ${size}`); - - await fs.promises.writeFile(path.join(cacheRoot, `${uuid}-${size}`), data); -} - -async function getImage(uuid, size) { - // If we've already stored a mime type, that means we've written the file to disk - if(memCache[`${uuid}-${size}`]?.mime_type) { - return { - file: fs.createReadStream(path.join(cacheRoot, `${uuid}-${size}`)), - mime_type: memCache[`${uuid}-${size}`].mime_type - } - } - - // If we've stored a promise, that means we're currently retrieving it from the db - if(memCache[`${uuid}-${size}`]?.dbPromise) { - return await memCache[`${uuid}-${size}`]?.dbPromise; - } - - // Otherwise, retrieve it from the DB, and then write it to disk - const record = memCache[`${uuid}-${size}`] = {}; - record.dbPromise = db.item.getImage(uuid, size); - - const image = await record.dbPromise; - await writeImageFile(uuid, size, image.file); - - record.mime_type = image.mime_type; - delete record.dbPromise; - - return image; -} +const sharp = require('sharp') router.get('/:uuid/:size', async (req, res) => { + let extension if(req.params.size.includes('.')) { + extension = req.params.size.split('.').slice(1).join('.'); req.params.size = req.params.size.split('.')[0]; } - const image = await getImage(req.params.uuid, req.params.size) + const image = await db.item.getImage(req.params.uuid, req.params.size) const cacheSeconds = 60 * 60 * 24; res.set('Cache-Control', cacheSeconds); - res.set('Content-Type', image.mime_type) - if(Buffer.isBuffer(image.file)) - res.end(image.file) - else if (typeof image.file.pipe === 'function') - image.file.pipe(res) - else - throw new Error("Unable to send file to user"); + if(extension === "webp") { + const webp = await sharp(image.file).webp().toBuffer(); + res.set('Content-Type', "image/webp") + res.end(webp) + return; + } + + res.set('Content-Type', image.mime_type) + res.end(image.file) }) router.post('/:uuid/featured', ensureAdmin, async (req, res) => { diff --git a/components/card/card.js b/components/card/card.js index ed9683f..a0896a7 100644 --- a/components/card/card.js +++ b/components/card/card.js @@ -23,7 +23,10 @@ export default function Card({item}) {

{item.name}

{featuredImage && (
- + + + +
)}
{item.description}
diff --git a/pages/store/item/[slug].js b/pages/store/item/[slug].js index a60e54e..59085ab 100644 --- a/pages/store/item/[slug].js +++ b/pages/store/item/[slug].js @@ -39,16 +39,22 @@ export default function Item({item}){ {item.images && item.images.length > 0 && (
- + + + +
{item.images && item.images.length > 1 &&
{item.images.map((image, index) => ( - setSelected(index)} - className={index === selectedIndex ? styles.selectedImage : undefined} - src={`/api/images/${image.uuid}/thumb.png`} - /> + + + setSelected(index)} + className={index === selectedIndex ? styles.selectedImage : undefined} + src={`/api/images/${image.uuid}/thumb.png`} + /> + ))}
}