I’m using multer-s3-transform
, which allows me to manipulate the image coming in, before uploading it to my bucket. Here’s what I have:
const singleImageUploadJpg = multer({ storage: multerS3({ s3: s3, bucket: "muh-bucket", acl: "public-read", key: function(req, file, cb) { const fileName = uuid.v4(); cb(null, fileName); }, shouldTransform: function(req, file, cb) { cb(null, true); }, transforms: [ { id: "original", key: function(req, file, cb) { cb(null, `${uuid.v4()}.jpg`); }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } }, { id: "small", key: function(req, file, cb) { cb(null, `${uuid.v4()}_small.jpg`); }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } } ] }), limits: { fileSize: 50 * 1024 * 1024 } }).single("image");
The problem is that the uuid will always be different for the small and the original versions. How can I make const fileName = uuid.v4()
passed down to each callback, so that they’d have the same name, with _small
being the only difference?
Advertisement
Answer
I assume that multer calls the functions provided repeatedly, which is why you don’t do the obvious thing Jim Nilsson suggested. Also, sadly, you’ve said that the file
you receive in the transform callback doesn’t have the name you specify earlier.
Two possibilities, both assuming that either the file
object or the req
object you receive is the same in both callbacks:
- Your own expando property
- A
WeakMap
Expando property
You could try to piggyback it on the file
/req
(I use file
below), like so (see ***
comments):
const singleImageUploadJpg = multer({ storage: multerS3({ s3: s3, bucket: "muh-bucket", acl: "public-read", key: function(req, file, cb) { file.__uuid__ = uuid.v4(); // *** cb(null, file.__uuid__); }, shouldTransform: function(req, file, cb) { cb(null, true); }, transforms: [ { id: "original", key: function(req, file, cb) { cb(null, `${uuid.v4()}.jpg`); }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } }, { id: "small", key: function(req, file, cb) { cb(null, `${file.__uuid__}_small.jpg`); // *** }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } } ] }), limits: { fileSize: 50 * 1024 * 1024 } }).single("image");
That would probably be doing something undocumented, though, which means you need to be careful to test with every “dot release” of the library you upgrade to.
WeakMap
:
Alternatively, you could use a WeakMap
keyed by the file
or req
(I use file
below):
const nameMap = new WeakMap(); const singleImageUploadJpg = multer({ storage: multerS3({ s3: s3, bucket: "muh-bucket", acl: "public-read", key: function(req, file, cb) { const fileName = uuid.v4(); nameMap.set(file, fileName); // *** cb(null, fileName); }, shouldTransform: function(req, file, cb) { cb(null, true); }, transforms: [ { id: "original", key: function(req, file, cb) { cb(null, `${uuid.v4()}.jpg`); }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } }, { id: "small", key: function(req, file, cb) { const fileName = nameMap.get(file); // *** nameMap.delete(file); // *** (optional, presumably `file` will be released at some point, which would remove it automatically) cb(null, `${fileName}_small.jpg`); // *** }, transform: function(req, file, cb) { cb( null, sharp() .resize() .jpeg({ quality: 50 }) ); } } ] }), limits: { fileSize: 50 * 1024 * 1024 } }).single("image");