@webstudio-is/image 0.64.0 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,34 +28,22 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var image_loaders_exports = {};
30
30
  __export(image_loaders_exports, {
31
- cloudflareImageLoader: () => cloudflareImageLoader,
32
- localImageLoader: () => localImageLoader
31
+ createImageLoader: () => createImageLoader
33
32
  });
34
33
  module.exports = __toCommonJS(image_loaders_exports);
35
34
  var import_warn_once = __toESM(require("warn-once"), 1);
36
35
  var import_image_optimize = require("./image-optimize");
37
- const cloudflareImageLoader = (loaderOptions) => ({ width, src, quality }) => {
36
+ const createImageLoader = (loaderOptions) => ({ width, src, quality }) => {
38
37
  if (true) {
39
38
  (0, import_warn_once.default)(
40
39
  import_image_optimize.allSizes.includes(width) === false,
41
40
  "Width must be only from allowed values"
42
41
  );
43
42
  }
44
- const cdnUrl = loaderOptions?.cdnUrl ?? "/";
45
- const imageUrl = `${cdnUrl}${src}`;
46
- const options = `width=${width},quality=${quality},format=auto`;
47
- const pathname = `/cdn-cgi/image/${options}/${imageUrl}`;
48
- if (loaderOptions?.resizeOrigin != null) {
49
- const url = new URL(pathname, loaderOptions.resizeOrigin);
50
- return url.href;
51
- } else {
52
- return pathname;
53
- }
54
- };
55
- const localImageLoader = (options) => ({ width, src, quality }) => {
56
- const { publicPath = "/" } = options;
57
- const params = new URLSearchParams();
58
- params.set("width", `${width}`);
59
- params.set("quality", `${quality}`);
60
- return `${publicPath}${src}?${params.toString()}`;
43
+ const { imageBaseUrl } = loaderOptions;
44
+ const searchParams = new URLSearchParams();
45
+ searchParams.set("width", width.toString());
46
+ searchParams.set("quality", quality.toString());
47
+ searchParams.set("format", "auto");
48
+ return `${imageBaseUrl}${src}?${searchParams.toString()}`;
61
49
  };
package/lib/cjs/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,24 +15,16 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
28
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
20
  var src_exports = {};
30
21
  __export(src_exports, {
31
22
  Image: () => import_image.Image,
32
- imageProps: () => imageProps,
33
- loaders: () => loaders
23
+ imageProps: () => imageProps
34
24
  });
35
25
  module.exports = __toCommonJS(src_exports);
36
26
  var import_image = require("./image");
37
- var loaders = __toESM(require("./image-loaders"), 1);
27
+ __reExport(src_exports, require("./image-loaders"), module.exports);
38
28
  var import_image2 = require("./__generated__/image.props");
39
29
  const { loader, ...publicProps } = import_image2.props;
40
30
  const imageProps = {
@@ -1,31 +1,19 @@
1
1
  import warnOnce from "warn-once";
2
2
  import { allSizes } from "./image-optimize";
3
- const cloudflareImageLoader = (loaderOptions) => ({ width, src, quality }) => {
3
+ const createImageLoader = (loaderOptions) => ({ width, src, quality }) => {
4
4
  if (true) {
5
5
  warnOnce(
6
6
  allSizes.includes(width) === false,
7
7
  "Width must be only from allowed values"
8
8
  );
9
9
  }
10
- const cdnUrl = loaderOptions?.cdnUrl ?? "/";
11
- const imageUrl = `${cdnUrl}${src}`;
12
- const options = `width=${width},quality=${quality},format=auto`;
13
- const pathname = `/cdn-cgi/image/${options}/${imageUrl}`;
14
- if (loaderOptions?.resizeOrigin != null) {
15
- const url = new URL(pathname, loaderOptions.resizeOrigin);
16
- return url.href;
17
- } else {
18
- return pathname;
19
- }
20
- };
21
- const localImageLoader = (options) => ({ width, src, quality }) => {
22
- const { publicPath = "/" } = options;
23
- const params = new URLSearchParams();
24
- params.set("width", `${width}`);
25
- params.set("quality", `${quality}`);
26
- return `${publicPath}${src}?${params.toString()}`;
10
+ const { imageBaseUrl } = loaderOptions;
11
+ const searchParams = new URLSearchParams();
12
+ searchParams.set("width", width.toString());
13
+ searchParams.set("quality", quality.toString());
14
+ searchParams.set("format", "auto");
15
+ return `${imageBaseUrl}${src}?${searchParams.toString()}`;
27
16
  };
28
17
  export {
29
- cloudflareImageLoader,
30
- localImageLoader
18
+ createImageLoader
31
19
  };
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Image } from "./image";
2
- import * as loaders from "./image-loaders";
2
+ export * from "./image-loaders";
3
3
  import { props } from "./__generated__/image.props";
4
4
  const { loader, ...publicProps } = props;
5
5
  const imageProps = {
@@ -13,6 +13,5 @@ const imageProps = {
13
13
  };
14
14
  export {
15
15
  Image,
16
- imageProps,
17
- loaders
16
+ imageProps
18
17
  };
@@ -1,18 +1,9 @@
1
1
  import { type ImageLoader } from "./image-optimize";
2
- export type CloudflareImageLoaderOptions = {
3
- resizeOrigin?: string | null;
4
- cdnUrl?: string;
2
+ export type ImageLoaderOptions = {
3
+ imageBaseUrl: string;
5
4
  };
6
5
  /**
7
6
  * Default image loader in case of no loader provided
8
7
  * https://developers.cloudflare.com/images/image-resizing/url-format/
9
8
  **/
10
- export declare const cloudflareImageLoader: (loaderOptions: CloudflareImageLoaderOptions | null) => ImageLoader;
11
- type LocalImageLoaderOptions = {
12
- publicPath?: string;
13
- };
14
- /**
15
- * Fake pseudo loader for local testing purposes
16
- **/
17
- export declare const localImageLoader: (options: LocalImageLoaderOptions) => ImageLoader;
18
- export {};
9
+ export declare const createImageLoader: (loaderOptions: ImageLoaderOptions) => ImageLoader;
@@ -1,5 +1,5 @@
1
1
  import type { PropMeta } from "@webstudio-is/generate-arg-types";
2
2
  export { Image } from "./image";
3
3
  export type { ImageLoader } from "./image-optimize";
4
- export * as loaders from "./image-loaders";
4
+ export * from "./image-loaders";
5
5
  export declare const imageProps: Record<string, PropMeta>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/image",
3
- "version": "0.64.0",
3
+ "version": "0.66.0",
4
4
  "description": "Image optimization",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -8,7 +8,7 @@
8
8
  "dependencies": {
9
9
  "react": "^18.2.0",
10
10
  "warn-once": "^0.1.1",
11
- "@webstudio-is/generate-arg-types": "^0.64.0"
11
+ "@webstudio-is/generate-arg-types": "^0.66.0"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@jest/globals": "^29.3.1",
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type * as React from "react";
4
4
  import type { ComponentMeta, ComponentStory } from "@storybook/react";
5
- import { Image as ImagePrimitive, loaders } from "./";
5
+ import { Image as ImagePrimitive, createImageLoader } from "./";
6
6
 
7
7
  // to not allow include local assets everywhere, just enable it for this file
8
8
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -28,9 +28,11 @@ const imageSrc = USE_CLOUDFLARE_IMAGE_TRANSFORM
28
28
  ? REMOTE_SELF_DOMAIN_IMAGE
29
29
  : localLogoImage;
30
30
 
31
- const imageLoader = USE_CLOUDFLARE_IMAGE_TRANSFORM
32
- ? loaders.cloudflareImageLoader({ resizeOrigin: "https://webstudio.is" })
33
- : loaders.localImageLoader({ publicPath: "" });
31
+ const imageLoader = createImageLoader({
32
+ imageBaseUrl: USE_CLOUDFLARE_IMAGE_TRANSFORM
33
+ ? "https://webstudio.is/cdn-cgi/image/"
34
+ : "",
35
+ });
34
36
 
35
37
  const ImageBase: ComponentStory<
36
38
  React.ForwardRefExoticComponent<
@@ -1,19 +1,16 @@
1
1
  import warnOnce from "warn-once";
2
2
  import { allSizes, type ImageLoader } from "./image-optimize";
3
3
 
4
- export type CloudflareImageLoaderOptions = {
5
- // origin of transformation wrapper
6
- resizeOrigin?: string | null;
7
- // origin of cdn serving image
8
- cdnUrl?: string;
4
+ export type ImageLoaderOptions = {
5
+ imageBaseUrl: string;
9
6
  };
10
7
 
11
8
  /**
12
9
  * Default image loader in case of no loader provided
13
10
  * https://developers.cloudflare.com/images/image-resizing/url-format/
14
11
  **/
15
- export const cloudflareImageLoader =
16
- (loaderOptions: CloudflareImageLoaderOptions | null): ImageLoader =>
12
+ export const createImageLoader =
13
+ (loaderOptions: ImageLoaderOptions): ImageLoader =>
17
14
  ({ width, src, quality }) => {
18
15
  if (process.env.NODE_ENV !== "production") {
19
16
  warnOnce(
@@ -21,36 +18,12 @@ export const cloudflareImageLoader =
21
18
  "Width must be only from allowed values"
22
19
  );
23
20
  }
21
+ const { imageBaseUrl } = loaderOptions;
22
+ const searchParams = new URLSearchParams();
23
+ searchParams.set("width", width.toString());
24
+ searchParams.set("quality", quality.toString());
25
+ searchParams.set("format", "auto");
24
26
 
25
- const cdnUrl = loaderOptions?.cdnUrl ?? "/";
26
- const imageUrl = `${cdnUrl}${src}`;
27
-
28
- const options = `width=${width},quality=${quality},format=auto`;
29
27
  // Cloudflare docs say that we don't need to urlencode the path params
30
- const pathname = `/cdn-cgi/image/${options}/${imageUrl}`;
31
-
32
- if (loaderOptions?.resizeOrigin != null) {
33
- const url = new URL(pathname, loaderOptions.resizeOrigin);
34
- return url.href;
35
- } else {
36
- return pathname;
37
- }
38
- };
39
-
40
- type LocalImageLoaderOptions = {
41
- publicPath?: string;
42
- };
43
-
44
- /**
45
- * Fake pseudo loader for local testing purposes
46
- **/
47
- export const localImageLoader =
48
- (options: LocalImageLoaderOptions): ImageLoader =>
49
- ({ width, src, quality }) => {
50
- const { publicPath = "/" } = options;
51
- // Just emulate like we really resize the image
52
- const params = new URLSearchParams();
53
- params.set("width", `${width}`);
54
- params.set("quality", `${quality}`);
55
- return `${publicPath}${src}?${params.toString()}`;
28
+ return `${imageBaseUrl}${src}?${searchParams.toString()}`;
56
29
  };
@@ -1,6 +1,6 @@
1
1
  import { describe, test, expect } from "@jest/globals";
2
2
  import { getImageAttributes } from "./image-optimize";
3
- import { cloudflareImageLoader } from "./image-loaders";
3
+ import { createImageLoader } from "./image-loaders";
4
4
 
5
5
  describe("Image optimizations applied", () => {
6
6
  test("width is number, create pixel density descriptor 'x'", () => {
@@ -11,17 +11,14 @@ describe("Image optimizations applied", () => {
11
11
  srcSet: undefined,
12
12
  sizes: undefined,
13
13
  quality: 100,
14
- loader: cloudflareImageLoader({
15
- resizeOrigin: null,
16
- cdnUrl: "https://webstudio.is/",
17
- }),
14
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
18
15
  });
19
16
 
20
17
  expect(imgAttr).toMatchInlineSnapshot(`
21
18
  {
22
19
  "sizes": undefined,
23
- "src": "/cdn-cgi/image/width=256,quality=100,format=auto/https://webstudio.is/logo.webp",
24
- "srcSet": "/cdn-cgi/image/width=128,quality=100,format=auto/https://webstudio.is/logo.webp 1x, /cdn-cgi/image/width=256,quality=100,format=auto/https://webstudio.is/logo.webp 2x",
20
+ "src": "/asset/image/logo.webp?width=256&quality=100&format=auto",
21
+ "srcSet": "/asset/image/logo.webp?width=128&quality=100&format=auto 1x, /asset/image/logo.webp?width=256&quality=100&format=auto 2x",
25
22
  }
26
23
  `);
27
24
  });
@@ -34,17 +31,14 @@ describe("Image optimizations applied", () => {
34
31
  srcSet: undefined,
35
32
  sizes: undefined,
36
33
  quality: 90,
37
- loader: cloudflareImageLoader({
38
- resizeOrigin: null,
39
- cdnUrl: "https://webstudio.is/",
40
- }),
34
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
41
35
  });
42
36
 
43
37
  expect(imgAttr).toMatchInlineSnapshot(`
44
38
  {
45
39
  "sizes": "(min-width: 1280px) 50vw, 100vw",
46
- "src": "/cdn-cgi/image/width=3840,quality=90,format=auto/https://webstudio.is/logo.webp",
47
- "srcSet": "/cdn-cgi/image/width=384,quality=90,format=auto/https://webstudio.is/logo.webp 384w, /cdn-cgi/image/width=640,quality=90,format=auto/https://webstudio.is/logo.webp 640w, /cdn-cgi/image/width=750,quality=90,format=auto/https://webstudio.is/logo.webp 750w, /cdn-cgi/image/width=828,quality=90,format=auto/https://webstudio.is/logo.webp 828w, /cdn-cgi/image/width=1080,quality=90,format=auto/https://webstudio.is/logo.webp 1080w, /cdn-cgi/image/width=1200,quality=90,format=auto/https://webstudio.is/logo.webp 1200w, /cdn-cgi/image/width=1920,quality=90,format=auto/https://webstudio.is/logo.webp 1920w, /cdn-cgi/image/width=2048,quality=90,format=auto/https://webstudio.is/logo.webp 2048w, /cdn-cgi/image/width=3840,quality=90,format=auto/https://webstudio.is/logo.webp 3840w",
40
+ "src": "/asset/image/logo.webp?width=3840&quality=90&format=auto",
41
+ "srcSet": "/asset/image/logo.webp?width=384&quality=90&format=auto 384w, /asset/image/logo.webp?width=640&quality=90&format=auto 640w, /asset/image/logo.webp?width=750&quality=90&format=auto 750w, /asset/image/logo.webp?width=828&quality=90&format=auto 828w, /asset/image/logo.webp?width=1080&quality=90&format=auto 1080w, /asset/image/logo.webp?width=1200&quality=90&format=auto 1200w, /asset/image/logo.webp?width=1920&quality=90&format=auto 1920w, /asset/image/logo.webp?width=2048&quality=90&format=auto 2048w, /asset/image/logo.webp?width=3840&quality=90&format=auto 3840w",
48
42
  }
49
43
  `);
50
44
  });
@@ -57,17 +51,14 @@ describe("Image optimizations applied", () => {
57
51
  srcSet: undefined,
58
52
  sizes: "100vw",
59
53
  quality: 70,
60
- loader: cloudflareImageLoader({
61
- resizeOrigin: null,
62
- cdnUrl: "https://webstudio.is/",
63
- }),
54
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
64
55
  });
65
56
 
66
57
  expect(imgAttr).toMatchInlineSnapshot(`
67
58
  {
68
59
  "sizes": "100vw",
69
- "src": "/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp",
70
- "srcSet": "/cdn-cgi/image/width=640,quality=70,format=auto/https://webstudio.is/logo.webp 640w, /cdn-cgi/image/width=750,quality=70,format=auto/https://webstudio.is/logo.webp 750w, /cdn-cgi/image/width=828,quality=70,format=auto/https://webstudio.is/logo.webp 828w, /cdn-cgi/image/width=1080,quality=70,format=auto/https://webstudio.is/logo.webp 1080w, /cdn-cgi/image/width=1200,quality=70,format=auto/https://webstudio.is/logo.webp 1200w, /cdn-cgi/image/width=1920,quality=70,format=auto/https://webstudio.is/logo.webp 1920w, /cdn-cgi/image/width=2048,quality=70,format=auto/https://webstudio.is/logo.webp 2048w, /cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp 3840w",
60
+ "src": "/asset/image/logo.webp?width=3840&quality=70&format=auto",
61
+ "srcSet": "/asset/image/logo.webp?width=640&quality=70&format=auto 640w, /asset/image/logo.webp?width=750&quality=70&format=auto 750w, /asset/image/logo.webp?width=828&quality=70&format=auto 828w, /asset/image/logo.webp?width=1080&quality=70&format=auto 1080w, /asset/image/logo.webp?width=1200&quality=70&format=auto 1200w, /asset/image/logo.webp?width=1920&quality=70&format=auto 1920w, /asset/image/logo.webp?width=2048&quality=70&format=auto 2048w, /asset/image/logo.webp?width=3840&quality=70&format=auto 3840w",
71
62
  }
72
63
  `);
73
64
  });
@@ -80,17 +71,16 @@ describe("Image optimizations applied", () => {
80
71
  srcSet: undefined,
81
72
  sizes: "100vw",
82
73
  quality: 70,
83
- loader: cloudflareImageLoader({
84
- resizeOrigin: "https://resize-origin.is",
85
- cdnUrl: "https://webstudio.is/",
74
+ loader: createImageLoader({
75
+ imageBaseUrl: "https://resize-origin.is/asset/image/",
86
76
  }),
87
77
  });
88
78
 
89
79
  expect(imgAttr).toMatchInlineSnapshot(`
90
80
  {
91
81
  "sizes": "100vw",
92
- "src": "https://resize-origin.is/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp",
93
- "srcSet": "https://resize-origin.is/cdn-cgi/image/width=640,quality=70,format=auto/https://webstudio.is/logo.webp 640w, https://resize-origin.is/cdn-cgi/image/width=750,quality=70,format=auto/https://webstudio.is/logo.webp 750w, https://resize-origin.is/cdn-cgi/image/width=828,quality=70,format=auto/https://webstudio.is/logo.webp 828w, https://resize-origin.is/cdn-cgi/image/width=1080,quality=70,format=auto/https://webstudio.is/logo.webp 1080w, https://resize-origin.is/cdn-cgi/image/width=1200,quality=70,format=auto/https://webstudio.is/logo.webp 1200w, https://resize-origin.is/cdn-cgi/image/width=1920,quality=70,format=auto/https://webstudio.is/logo.webp 1920w, https://resize-origin.is/cdn-cgi/image/width=2048,quality=70,format=auto/https://webstudio.is/logo.webp 2048w, https://resize-origin.is/cdn-cgi/image/width=3840,quality=70,format=auto/https://webstudio.is/logo.webp 3840w",
82
+ "src": "https://resize-origin.is/asset/image/logo.webp?width=3840&quality=70&format=auto",
83
+ "srcSet": "https://resize-origin.is/asset/image/logo.webp?width=640&quality=70&format=auto 640w, https://resize-origin.is/asset/image/logo.webp?width=750&quality=70&format=auto 750w, https://resize-origin.is/asset/image/logo.webp?width=828&quality=70&format=auto 828w, https://resize-origin.is/asset/image/logo.webp?width=1080&quality=70&format=auto 1080w, https://resize-origin.is/asset/image/logo.webp?width=1200&quality=70&format=auto 1200w, https://resize-origin.is/asset/image/logo.webp?width=1920&quality=70&format=auto 1920w, https://resize-origin.is/asset/image/logo.webp?width=2048&quality=70&format=auto 2048w, https://resize-origin.is/asset/image/logo.webp?width=3840&quality=70&format=auto 3840w",
94
84
  }
95
85
  `);
96
86
  });
@@ -126,7 +116,7 @@ describe("Image optimizations not applied", () => {
126
116
  srcSet: undefined,
127
117
  sizes: undefined,
128
118
  quality: 100,
129
- loader: cloudflareImageLoader({ resizeOrigin: null }),
119
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
130
120
  });
131
121
 
132
122
  expect(imgAttr).toMatchInlineSnapshot(`
@@ -144,7 +134,7 @@ describe("Image optimizations not applied", () => {
144
134
  srcSet: "user-defined-srcset",
145
135
  sizes: undefined,
146
136
  quality: 100,
147
- loader: cloudflareImageLoader({ resizeOrigin: null }),
137
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
148
138
  });
149
139
 
150
140
  expect(imgAttr).toMatchInlineSnapshot(`
@@ -163,7 +153,7 @@ describe("Image optimizations not applied", () => {
163
153
  srcSet: undefined,
164
154
  sizes: undefined,
165
155
  quality: 100,
166
- loader: cloudflareImageLoader({ resizeOrigin: null }),
156
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
167
157
  });
168
158
 
169
159
  expect(imgAttr).toMatchInlineSnapshot(`null`);
@@ -177,7 +167,7 @@ describe("Image optimizations not applied", () => {
177
167
  srcSet: undefined,
178
168
  sizes: undefined,
179
169
  quality: 100,
180
- loader: cloudflareImageLoader({ resizeOrigin: null }),
170
+ loader: createImageLoader({ imageBaseUrl: "/asset/image/" }),
181
171
  });
182
172
 
183
173
  expect(imgAttr).toMatchInlineSnapshot(`null`);
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { PropMeta } from "@webstudio-is/generate-arg-types";
2
2
  export { Image } from "./image";
3
3
  export type { ImageLoader } from "./image-optimize";
4
- export * as loaders from "./image-loaders";
4
+ export * from "./image-loaders";
5
5
  import { props } from "./__generated__/image.props";
6
6
 
7
7
  // "loader" is our internal prop not intended to show up in the props panel