From 8272d7eeb5e7372f4c723d1e2fb068e2ca90d2aa Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Thu, 12 Dec 2024 14:36:50 +0700 Subject: [PATCH] refactor: remove assetBaseUrl from image loaders Asset base url is now automatically added by builder or component generator and passed to loader as is. Saas loader removes /cgi/asset when detected. All other loaders just use full relative path without changes which simplifies them a lot. --- fixtures/ssg-netlify-by-project-id/app/constants.mjs | 6 +++--- fixtures/ssg/app/constants.mjs | 7 +------ .../webstudio-cloudflare-template/app/constants.mjs | 2 +- .../app/constants.mjs | 6 +++--- .../app/constants.mjs | 6 +++--- fixtures/webstudio-remix-vercel/app/constants.mjs | 6 +++--- packages/cli/templates/defaults/app/constants.mjs | 2 +- .../netlify-edge-functions/app/constants.mjs | 6 +++--- .../cli/templates/netlify-functions/app/constants.mjs | 6 +++--- packages/cli/templates/ssg-netlify/app/constants.mjs | 6 +++--- packages/cli/templates/ssg-vercel/app/constants.mjs | 6 +++--- packages/cli/templates/ssg/app/constants.mjs | 7 +------ packages/cli/templates/vercel/app/constants.mjs | 6 +++--- packages/image/src/image-loader.test.ts | 10 ++++++++++ packages/image/src/image-loaders.ts | 11 ++++++++--- packages/sdk-components-react/src/image.tsx | 10 ++-------- 16 files changed, 51 insertions(+), 52 deletions(-) diff --git a/fixtures/ssg-netlify-by-project-id/app/constants.mjs b/fixtures/ssg-netlify-by-project-id/app/constants.mjs index 04ca9c832d8e..12bd87557169 100644 --- a/fixtures/ssg-netlify-by-project-id/app/constants.mjs +++ b/fixtures/ssg-netlify-by-project-id/app/constants.mjs @@ -16,17 +16,17 @@ export const imageLoader = (props) => { } if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/fixtures/ssg/app/constants.mjs b/fixtures/ssg/app/constants.mjs index 4c4ccc88cd9a..54a32d62959e 100644 --- a/fixtures/ssg/app/constants.mjs +++ b/fixtures/ssg/app/constants.mjs @@ -2,7 +2,6 @@ * We use mjs extension as constants in this file is shared with the build script * and we use `node --eval` to extract the constants. */ -import { UrlCanParse } from "@webstudio-is/image"; export const assetBaseUrl = "/assets/"; export const imageBaseUrl = "/assets/"; @@ -11,9 +10,5 @@ export const imageBaseUrl = "/assets/"; * @type {import("@webstudio-is/image").ImageLoader} */ export const imageLoader = ({ src }) => { - if (UrlCanParse(src)) { - return src; - } - - return assetBaseUrl + src; + return src; }; diff --git a/fixtures/webstudio-cloudflare-template/app/constants.mjs b/fixtures/webstudio-cloudflare-template/app/constants.mjs index 67e6b2c6b099..dc5dbb0f5cb7 100644 --- a/fixtures/webstudio-cloudflare-template/app/constants.mjs +++ b/fixtures/webstudio-cloudflare-template/app/constants.mjs @@ -9,5 +9,5 @@ export const imageBaseUrl = "/assets/"; * @type {import("@webstudio-is/image").ImageLoader} */ export const imageLoader = ({ src }) => { - return assetBaseUrl + src; + return src; }; diff --git a/fixtures/webstudio-remix-netlify-edge-functions/app/constants.mjs b/fixtures/webstudio-remix-netlify-edge-functions/app/constants.mjs index 7ab5bfffab88..ea957793b6bd 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/app/constants.mjs +++ b/fixtures/webstudio-remix-netlify-edge-functions/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/fixtures/webstudio-remix-netlify-functions/app/constants.mjs b/fixtures/webstudio-remix-netlify-functions/app/constants.mjs index 7ab5bfffab88..ea957793b6bd 100644 --- a/fixtures/webstudio-remix-netlify-functions/app/constants.mjs +++ b/fixtures/webstudio-remix-netlify-functions/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/fixtures/webstudio-remix-vercel/app/constants.mjs b/fixtures/webstudio-remix-vercel/app/constants.mjs index 097e2f43888d..7a8ec5918977 100644 --- a/fixtures/webstudio-remix-vercel/app/constants.mjs +++ b/fixtures/webstudio-remix-vercel/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://vercel.com/blog/build-your-own-web-framework#automatic-image-optimization return ( "/_vercel/image?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/cli/templates/defaults/app/constants.mjs b/packages/cli/templates/defaults/app/constants.mjs index 67e6b2c6b099..dc5dbb0f5cb7 100644 --- a/packages/cli/templates/defaults/app/constants.mjs +++ b/packages/cli/templates/defaults/app/constants.mjs @@ -9,5 +9,5 @@ export const imageBaseUrl = "/assets/"; * @type {import("@webstudio-is/image").ImageLoader} */ export const imageLoader = ({ src }) => { - return assetBaseUrl + src; + return src; }; diff --git a/packages/cli/templates/netlify-edge-functions/app/constants.mjs b/packages/cli/templates/netlify-edge-functions/app/constants.mjs index 7ab5bfffab88..ea957793b6bd 100644 --- a/packages/cli/templates/netlify-edge-functions/app/constants.mjs +++ b/packages/cli/templates/netlify-edge-functions/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/cli/templates/netlify-functions/app/constants.mjs b/packages/cli/templates/netlify-functions/app/constants.mjs index 7ab5bfffab88..ea957793b6bd 100644 --- a/packages/cli/templates/netlify-functions/app/constants.mjs +++ b/packages/cli/templates/netlify-functions/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/cli/templates/ssg-netlify/app/constants.mjs b/packages/cli/templates/ssg-netlify/app/constants.mjs index 04ca9c832d8e..12bd87557169 100644 --- a/packages/cli/templates/ssg-netlify/app/constants.mjs +++ b/packages/cli/templates/ssg-netlify/app/constants.mjs @@ -16,17 +16,17 @@ export const imageLoader = (props) => { } if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://docs.netlify.com/image-cdn/overview/ return ( "/.netlify/images?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/cli/templates/ssg-vercel/app/constants.mjs b/packages/cli/templates/ssg-vercel/app/constants.mjs index 1559b1e003f1..7024371ed6ec 100644 --- a/packages/cli/templates/ssg-vercel/app/constants.mjs +++ b/packages/cli/templates/ssg-vercel/app/constants.mjs @@ -16,17 +16,17 @@ export const imageLoader = (props) => { } if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://vercel.com/blog/build-your-own-web-framework#automatic-image-optimization return ( "/_vercel/image?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/cli/templates/ssg/app/constants.mjs b/packages/cli/templates/ssg/app/constants.mjs index 4c4ccc88cd9a..54a32d62959e 100644 --- a/packages/cli/templates/ssg/app/constants.mjs +++ b/packages/cli/templates/ssg/app/constants.mjs @@ -2,7 +2,6 @@ * We use mjs extension as constants in this file is shared with the build script * and we use `node --eval` to extract the constants. */ -import { UrlCanParse } from "@webstudio-is/image"; export const assetBaseUrl = "/assets/"; export const imageBaseUrl = "/assets/"; @@ -11,9 +10,5 @@ export const imageBaseUrl = "/assets/"; * @type {import("@webstudio-is/image").ImageLoader} */ export const imageLoader = ({ src }) => { - if (UrlCanParse(src)) { - return src; - } - - return assetBaseUrl + src; + return src; }; diff --git a/packages/cli/templates/vercel/app/constants.mjs b/packages/cli/templates/vercel/app/constants.mjs index 097e2f43888d..7a8ec5918977 100644 --- a/packages/cli/templates/vercel/app/constants.mjs +++ b/packages/cli/templates/vercel/app/constants.mjs @@ -10,17 +10,17 @@ export const imageBaseUrl = "/assets/"; */ export const imageLoader = (props) => { if (process.env.NODE_ENV !== "production") { - return assetBaseUrl + props.src; + return props.src; } if (props.format === "raw") { - return assetBaseUrl + props.src; + return props.src; } // https://vercel.com/blog/build-your-own-web-framework#automatic-image-optimization return ( "/_vercel/image?url=" + - encodeURIComponent(assetBaseUrl + props.src) + + encodeURIComponent(props.src) + "&w=" + props.width + "&q=" + diff --git a/packages/image/src/image-loader.test.ts b/packages/image/src/image-loader.test.ts index 1de820301006..f6b5e784d218 100644 --- a/packages/image/src/image-loader.test.ts +++ b/packages/image/src/image-loader.test.ts @@ -30,6 +30,16 @@ describe("Asset image transforms", () => { decodePathFragment(resultUrl.pathname.slice(imageBaseUrl.length)) ).toBe(assetName); }); + + test("strip /cgi/asset from src", () => { + expect( + wsImageLoader({ + width: 128, + src: "/cgi/asset/my-image.webp", + quality: 100, + }) + ).toEqual("/cgi/image/my-image.webp?width=128&quality=100&format=auto"); + }); }); describe("Remote src image transforms", () => { diff --git a/packages/image/src/image-loaders.ts b/packages/image/src/image-loaders.ts index 56bb619f8f51..20b5aab041c7 100644 --- a/packages/image/src/image-loaders.ts +++ b/packages/image/src/image-loaders.ts @@ -21,7 +21,6 @@ const encodePathFragment = (fragment: string) => { export const wsImageLoader: ImageLoader = (props) => { const width = props.format === "raw" ? 16 : props.width; const quality = props.format === "raw" ? 100 : props.quality; - const { format, src } = props; if (process.env.NODE_ENV !== "production") { warnOnce( @@ -30,9 +29,15 @@ export const wsImageLoader: ImageLoader = (props) => { ); } + // support both "/cgi/asset/name" and "name" as inputs + let src = props.src; + if (src.startsWith("/cgi/asset")) { + src = src.slice("/cgi/asset".length); + } + const resultUrl = new URL("/cgi/image/", NON_EXISTING_DOMAIN); - if (format !== "raw") { + if (props.format !== "raw") { resultUrl.searchParams.set("width", width.toString()); resultUrl.searchParams.set("quality", quality.toString()); @@ -44,7 +49,7 @@ export const wsImageLoader: ImageLoader = (props) => { resultUrl.searchParams.set("fit", props.fit); } } - resultUrl.searchParams.set("format", format ?? "auto"); + resultUrl.searchParams.set("format", props.format ?? "auto"); resultUrl.pathname = joinPath(resultUrl.pathname, encodePathFragment(src)); diff --git a/packages/sdk-components-react/src/image.tsx b/packages/sdk-components-react/src/image.tsx index 0001f6acf4fd..1f335255db8c 100644 --- a/packages/sdk-components-react/src/image.tsx +++ b/packages/sdk-components-react/src/image.tsx @@ -31,7 +31,7 @@ export const Image = forwardRef< // cast to string when invalid value type is provided with binding const src = String(props.src ?? ""); - const { imageLoader, renderer, assetBaseUrl } = useContext(ReactSdkContext); + const { imageLoader, renderer } = useContext(ReactSdkContext); let decoding = decodingProp; @@ -60,12 +60,6 @@ export const Image = forwardRef< } } - let assetName = src; - - if (src.startsWith(assetBaseUrl)) { - assetName = src.slice(assetBaseUrl.length); - } - return ( );