(req, res, next)
| 6 | import { setFastlySurrogateKey, SURROGATE_ENUMS } from './set-fastly-surrogate-key.js' |
| 7 | |
| 8 | export default async function dynamicAssets(req, res, next) { |
| 9 | if (!req.url.startsWith('/assets/')) return next() |
| 10 | |
| 11 | if (!(req.method === 'GET' || req.method === 'HEAD')) { |
| 12 | return res.status(405).type('text/plain').send('Method Not Allowed') |
| 13 | } |
| 14 | |
| 15 | // To protect from possible denial of service, we never allow what |
| 16 | // we're going to do (the image file operation), if the whole thing |
| 17 | // won't be aggressively cached. |
| 18 | // If we didn't do this, someone making 2 requests, ... |
| 19 | // |
| 20 | // > GET /assets/images/site/logo.web?random=10476583 |
| 21 | // > GET /assets/images/site/logo.web?random=20196996 |
| 22 | // |
| 23 | // ...would be treated as 2 distinct backend requests. Sure, each one |
| 24 | // would be cached in the CDN, but that's not helping if someone does... |
| 25 | // |
| 26 | // while (true) { |
| 27 | // startFetchThread(`/assets/images/site/logo.web?whatever=${rand()}`) |
| 28 | // } |
| 29 | // |
| 30 | // So we "force" any deviation of the URL to a redirect to the canonical |
| 31 | // URL (which, again, is heavily cached). |
| 32 | if (Object.keys(req.query).length > 0) { |
| 33 | // Cache the 404 so it won't be re-attempted over and over |
| 34 | defaultCacheControl(res) |
| 35 | |
| 36 | // This redirects to the same URL we're currently on, but with the |
| 37 | // query string part omitted. |
| 38 | // For example: |
| 39 | // |
| 40 | // > GET /assets/images/site/logo.web?foo=bar |
| 41 | // < 302 |
| 42 | // < location: /assets/images/site/logo.web |
| 43 | // |
| 44 | return res.redirect(302, req.path) |
| 45 | } |
| 46 | |
| 47 | if (req.path.endsWith('.webp')) { |
| 48 | // From PNG (if it exists) to WEBP |
| 49 | try { |
| 50 | const originalBuffer = await fs.readFile(req.path.slice(1).replace(/\.webp$/, '.png')) |
| 51 | const buffer = await sharp(originalBuffer) |
| 52 | // Note that by default, sharp will use a lossy compression. |
| 53 | // (i.e. `{lossless: false}` in the options) |
| 54 | // The difference is that a lossless image is slightly crisper |
| 55 | // but becomes on average 1.8x larger. |
| 56 | // Given how we serve images, no human would be able to tell the |
| 57 | // difference simply by looking at the image as it appears as an |
| 58 | // image tag in the web page. |
| 59 | // Also given that rendering-for-viewing is the "end of the line" |
| 60 | // for the image meaning it just ends up being viewed and not |
| 61 | // resaved as a source file. If we had intention to overwrite all |
| 62 | // original PNG source files to WEBP, we should consier lossless |
| 63 | // to preserve as much quality as possible at the source level. |
| 64 | // The default quality is 80% which, combined with `lossless:false` |
| 65 | // makes our images 2.8x smaller than the average PNG. |
nothing calls this directly
no test coverage detected