From 14290bc9817b420ea25f994ae523b19bb41fe311 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 22 Feb 2022 12:30:19 +0000 Subject: [PATCH] feat: add support for base64 props --- example/netlify.toml | 5 ++++ example/netlify/functions/gatsby.ts | 7 +++++ example/netlify/functions/ipx.ts | 2 +- example/public/index.html | 45 ++++++++++++++++++----------- src/index.ts | 20 +++++++++++-- src/utils.ts | 40 +++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 example/netlify/functions/gatsby.ts create mode 100644 src/utils.ts diff --git a/example/netlify.toml b/example/netlify.toml index 18426a4..d96cc8f 100644 --- a/example/netlify.toml +++ b/example/netlify.toml @@ -3,3 +3,8 @@ publish = "public/" [functions] external_node_modules = ["fsevents"] + +[[redirects]] +from = "/_gatsby/image/*" +to = "/.netlify/builders/gatsby" +status = 200 diff --git a/example/netlify/functions/gatsby.ts b/example/netlify/functions/gatsby.ts new file mode 100644 index 0000000..08eb5a8 --- /dev/null +++ b/example/netlify/functions/gatsby.ts @@ -0,0 +1,7 @@ +import { createIPXHandler } from '@netlify/ipx' + +export const handler = createIPXHandler({ + domains: ['images.unsplash.com'], + propsEncoding: 'base64', + basePath: '/_gatsby/image/' +}) diff --git a/example/netlify/functions/ipx.ts b/example/netlify/functions/ipx.ts index 00611d5..15236a5 100644 --- a/example/netlify/functions/ipx.ts +++ b/example/netlify/functions/ipx.ts @@ -2,5 +2,5 @@ import { createIPXHandler } from '@netlify/ipx' export const handler = createIPXHandler({ domains: ['images.unsplash.com'], - basePath: '/.netlify/functions/ipx/' + basePath: '/.netlify/builders/ipx/' }) diff --git a/example/public/index.html b/example/public/index.html index bcd1cfe..0283814 100644 --- a/example/public/index.html +++ b/example/public/index.html @@ -1,26 +1,37 @@ - - Netlify Optimized Images - - - -

Netlify Optimized Images

-
- -
/.netlify/functions/f_webp,w_450/img/test.jpg
+ + Netlify Optimized Images + + -
- -
/.netlify/functions/f_webp,w_450/img/https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba
+ +

Netlify Optimized Images

- + + - - + \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 7c612bf..e6ab511 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,12 +5,14 @@ import { builder, Handler } from '@netlify/functions' import { parseURL } from 'ufo' import etag from 'etag' import { loadSourceImage } from './http' +import { decodeBase64Params } from './utils' export function createIPXHandler ({ cacheDir = join(tmpdir(), 'ipx-cache'), basePath = '/_ipx', + propsEncoding, ...opts -}: Partial & { cacheDir?: string; basePath?: string } = {}) { +}: Partial & { cacheDir?: string; basePath?: string, propsEncoding?: 'base64' } = {}) { const ipx = createIPX({ ...opts, dir: join(cacheDir, 'cache') }) const handler: Handler = async (event, _context) => { @@ -20,8 +22,22 @@ export function createIPXHandler ({ const requestEtag = event.headers['if-none-match'] const url = event.path.replace(basePath, '') - const [modifiers = '_', ...segments] = url.substr(1).split('/') + // eslint-disable-next-line prefer-const + let [modifiers = '_', ...segments] = url.slice(1).split('/') let id = decodeURIComponent(segments.join('/')) + + if (propsEncoding === 'base64') { + const params = decodeBase64Params(url) + if (params.error) { + return { + statusCode: 400, + body: params.error + } + } + id = params.id + modifiers = params.modifiers + } + const requestHeaders: Record = {} const isLocal = !id.startsWith('http') if (isLocal) { diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..35246f6 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,40 @@ +/** + * Support for Gatsby-style base64-encoded URLs + */ +export function decodeBase64Params (path:string) { + const [url, transform] = path.split('/') + if (!url || !transform) { + return { + error: 'Bad Request' + } + } + const id = Buffer.from(url, 'base64').toString('utf8') + // Strip the extension + const transforms = Buffer.from(transform.split('.')[0], 'base64').toString( + 'utf8' + ) + if (!id || !transforms) { + return { + error: 'Bad Request' + } + } + const params = new URLSearchParams(transforms) + + // [ipx modifier name, gatsby modifier name] + const props = [ + ['width', 'w'], + ['height', 'h'], + ['format', 'fm'] + ] + + const modifiers: Array = [] + + for (const [modifier, prop] of props) { + const value = params.get(prop) + if (value) { + modifiers.push(`${modifier}_${value}`) + } + } + + return { id, modifiers: modifiers.join(',') } +}