@rebask/core 0.3.0 → 0.4.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.
Files changed (139) hide show
  1. package/dist/components/image.d.ts +16 -3
  2. package/dist/components/image.d.ts.map +1 -1
  3. package/dist/components/image.js +50 -68
  4. package/dist/components/link.d.ts.map +1 -1
  5. package/dist/components/link.js +6 -2
  6. package/dist/lib/image-optimization/fetch-remote-image.d.ts +17 -0
  7. package/dist/lib/image-optimization/fetch-remote-image.d.ts.map +1 -0
  8. package/dist/lib/image-optimization/fetch-remote-image.js +157 -0
  9. package/dist/lib/image-optimization/get-img-props.d.ts +3 -5
  10. package/dist/lib/image-optimization/get-img-props.d.ts.map +1 -1
  11. package/dist/lib/image-optimization/get-img-props.js +66 -40
  12. package/dist/lib/image-optimization/handler.d.ts +0 -3
  13. package/dist/lib/image-optimization/handler.d.ts.map +1 -1
  14. package/dist/lib/image-optimization/handler.js +339 -124
  15. package/dist/lib/image-optimization/image-config.d.ts +31 -4
  16. package/dist/lib/image-optimization/image-config.d.ts.map +1 -1
  17. package/dist/lib/image-optimization/image-config.js +6 -0
  18. package/dist/lib/image-optimization/image-error.d.ts +8 -0
  19. package/dist/lib/image-optimization/image-error.d.ts.map +1 -0
  20. package/dist/lib/image-optimization/image-error.js +10 -0
  21. package/dist/lib/image-optimization/image-plugin.d.ts.map +1 -1
  22. package/dist/lib/image-optimization/image-plugin.js +27 -14
  23. package/dist/lib/image-optimization/is-private-ip.d.ts +2 -0
  24. package/dist/lib/image-optimization/is-private-ip.d.ts.map +1 -0
  25. package/dist/lib/image-optimization/is-private-ip.js +43 -0
  26. package/dist/lib/image-optimization/match-patterns.d.ts +4 -0
  27. package/dist/lib/image-optimization/match-patterns.d.ts.map +1 -0
  28. package/dist/lib/image-optimization/match-patterns.js +39 -0
  29. package/dist/lib/image-optimization/read-body.d.ts +2 -0
  30. package/dist/lib/image-optimization/read-body.d.ts.map +1 -0
  31. package/dist/lib/image-optimization/read-body.js +27 -0
  32. package/dist/lib/image-optimization/static-image-loader.d.ts +2 -0
  33. package/dist/lib/image-optimization/static-image-loader.d.ts.map +1 -0
  34. package/dist/lib/image-optimization/static-image-loader.js +60 -0
  35. package/dist/lib/server-router/build-entries.d.ts.map +1 -1
  36. package/dist/lib/server-router/route-entries.js +1 -1
  37. package/dist/vite.d.ts.map +1 -1
  38. package/dist/vite.js +12 -4
  39. package/package.json +2 -1
  40. package/dist/__type_probe__.d.ts +0 -2
  41. package/dist/__type_probe__.d.ts.map +0 -1
  42. package/dist/__type_probe__.js +0 -4
  43. package/dist/components/error-boundary-client.d.ts +0 -49
  44. package/dist/components/error-boundary-client.d.ts.map +0 -1
  45. package/dist/components/error-boundary-client.js +0 -71
  46. package/dist/components/error-boundary.browser.d.ts +0 -8
  47. package/dist/components/error-boundary.browser.d.ts.map +0 -1
  48. package/dist/components/error-boundary.browser.js +0 -6
  49. package/dist/components/error.d.ts +0 -2
  50. package/dist/components/error.d.ts.map +0 -1
  51. package/dist/components/error.js +0 -5
  52. package/dist/components/not-found-activator.d.ts +0 -11
  53. package/dist/components/not-found-activator.d.ts.map +0 -1
  54. package/dist/components/not-found-activator.js +0 -26
  55. package/dist/components/not-found-boundary-client.d.ts +0 -3
  56. package/dist/components/not-found-boundary-client.d.ts.map +0 -1
  57. package/dist/components/not-found-boundary-client.js +0 -20
  58. package/dist/components/not-found-boundary.browser.d.ts +0 -8
  59. package/dist/components/not-found-boundary.browser.d.ts.map +0 -1
  60. package/dist/components/not-found-boundary.browser.js +0 -4
  61. package/dist/components/not-found-boundary.d.ts +0 -8
  62. package/dist/components/not-found-boundary.d.ts.map +0 -1
  63. package/dist/components/not-found-boundary.js +0 -9
  64. package/dist/components/not-found-thrower.d.ts +0 -2
  65. package/dist/components/not-found-thrower.d.ts.map +0 -1
  66. package/dist/components/not-found-thrower.js +0 -7
  67. package/dist/components/not-found.d.ts +0 -2
  68. package/dist/components/not-found.d.ts.map +0 -1
  69. package/dist/components/not-found.js +0 -5
  70. package/dist/components/status-page.d.ts +0 -6
  71. package/dist/components/status-page.d.ts.map +0 -1
  72. package/dist/components/status-page.js +0 -61
  73. package/dist/handler.d.ts +0 -12
  74. package/dist/handler.d.ts.map +0 -1
  75. package/dist/handler.js +0 -21
  76. package/dist/handlers/rsc/constants.d.ts +0 -3
  77. package/dist/handlers/rsc/constants.d.ts.map +0 -1
  78. package/dist/handlers/rsc/constants.js +0 -2
  79. package/dist/handlers/rsc/create-response.d.ts +0 -3
  80. package/dist/handlers/rsc/create-response.d.ts.map +0 -1
  81. package/dist/handlers/rsc/create-response.js +0 -378
  82. package/dist/handlers/rsc/render-with-retries.d.ts +0 -4
  83. package/dist/handlers/rsc/render-with-retries.d.ts.map +0 -1
  84. package/dist/handlers/rsc/render-with-retries.js +0 -154
  85. package/dist/handlers/rsc/retry-loop.d.ts +0 -3
  86. package/dist/handlers/rsc/retry-loop.d.ts.map +0 -1
  87. package/dist/handlers/rsc/retry-loop.js +0 -145
  88. package/dist/handlers/rsc/stream-rsc-payload.d.ts +0 -9
  89. package/dist/handlers/rsc/stream-rsc-payload.d.ts.map +0 -1
  90. package/dist/handlers/rsc/stream-rsc-payload.js +0 -20
  91. package/dist/handlers/rsc/types.d.ts +0 -26
  92. package/dist/handlers/rsc/types.d.ts.map +0 -1
  93. package/dist/handlers/rsc/types.js +0 -7
  94. package/dist/handlers/rsc.d.ts +0 -20
  95. package/dist/handlers/rsc.d.ts.map +0 -1
  96. package/dist/handlers/rsc.js +0 -872
  97. package/dist/integration.d.ts +0 -14
  98. package/dist/integration.d.ts.map +0 -1
  99. package/dist/integration.js +0 -9
  100. package/dist/lib/dev-module-load-race.d.ts +0 -8
  101. package/dist/lib/dev-module-load-race.d.ts.map +0 -1
  102. package/dist/lib/dev-module-load-race.js +0 -31
  103. package/dist/lib/dev-page-exports.d.ts +0 -5
  104. package/dist/lib/dev-page-exports.d.ts.map +0 -1
  105. package/dist/lib/dev-page-exports.js +0 -14
  106. package/dist/lib/environment-names.d.ts +0 -11
  107. package/dist/lib/environment-names.d.ts.map +0 -1
  108. package/dist/lib/environment-names.js +0 -10
  109. package/dist/lib/initial-hash-scroll.d.ts.map +0 -1
  110. package/dist/lib/not-found.d.ts +0 -5
  111. package/dist/lib/not-found.d.ts.map +0 -1
  112. package/dist/lib/not-found.js +0 -7
  113. package/dist/lib/page-exports.d.ts +0 -9
  114. package/dist/lib/page-exports.d.ts.map +0 -1
  115. package/dist/lib/page-exports.js +0 -47
  116. package/dist/lib/pattern-segments.d.ts +0 -8
  117. package/dist/lib/pattern-segments.d.ts.map +0 -1
  118. package/dist/lib/pattern-segments.js +0 -22
  119. package/dist/lib/ppr/cache-status.d.ts +0 -3
  120. package/dist/lib/ppr/cache-status.d.ts.map +0 -1
  121. package/dist/lib/ppr/cache-status.js +0 -5
  122. package/dist/lib/server-router-contract.d.ts +0 -42
  123. package/dist/lib/server-router-contract.d.ts.map +0 -1
  124. package/dist/lib/server-router-contract.js +0 -6
  125. package/dist/lib/server-router-loader.d.ts +0 -10
  126. package/dist/lib/server-router-loader.d.ts.map +0 -1
  127. package/dist/lib/server-router-loader.js +0 -180
  128. package/dist/lib/server-router.d.ts +0 -8
  129. package/dist/lib/server-router.d.ts.map +0 -1
  130. package/dist/lib/server-router.js +0 -173
  131. package/dist/plugins/ppr-upgrade.d.ts +0 -36
  132. package/dist/plugins/ppr-upgrade.d.ts.map +0 -1
  133. package/dist/plugins/ppr-upgrade.js +0 -32
  134. package/dist/plugins/server-router-fallback.d.ts +0 -15
  135. package/dist/plugins/server-router-fallback.d.ts.map +0 -1
  136. package/dist/plugins/server-router-fallback.js +0 -30
  137. package/dist/server.d.ts +0 -10
  138. package/dist/server.d.ts.map +0 -1
  139. package/dist/server.js +0 -57
@@ -5,6 +5,9 @@ import { warnOnce } from "./warn-once.js";
5
5
  const VALID_LOADING_VALUES = ["lazy", "eager", undefined];
6
6
  // Object-fit values that are not valid background-size values
7
7
  const INVALID_BACKGROUND_SIZE_VALUES = ["-moz-initial", "fill", "none", "scale-down", undefined];
8
+ const allImgs = new Map();
9
+ let perfObserver;
10
+ const preparedConfigs = new WeakMap();
8
11
  function isStaticRequire(src) {
9
12
  return src.default !== undefined;
10
13
  }
@@ -33,7 +36,8 @@ function getWidths({ deviceSizes, allSizes }, width, sizes) {
33
36
  // Find all the "vw" percent sizes used in the sizes prop
34
37
  const viewportWidthRe = /(^|\s)(1?\d?\d)vw/g;
35
38
  const percentSizes = [];
36
- for (let match; (match = viewportWidthRe.exec(sizes)); match) {
39
+ let match;
40
+ while ((match = viewportWidthRe.exec(sizes))) {
37
41
  percentSizes.push(parseInt(match[2]));
38
42
  }
39
43
  if (percentSizes.length) {
@@ -58,14 +62,14 @@ function getWidths({ deviceSizes, allSizes }, width, sizes) {
58
62
  // > wasteful as the human eye cannot see that level of detail without
59
63
  // > something like a magnifying glass.
60
64
  // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html
61
- [width, width * 2 /*, width * 3*/].map((w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1])),
65
+ [width, width * 2].map((w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1])),
62
66
  ];
63
67
  return { widths, kind: "x" };
64
68
  }
65
69
  /**
66
70
  * A shared function, used on both client and server, to generate the props for <img>.
67
71
  */
68
- export function getImgProps({ src, sizes, unoptimized = false, preload = false, loading, className, quality, width, height, fill = false, style, onLoad: _onLoad, placeholder = "empty", blurDataURL, fetchPriority, decoding = "async", ...rest }, _state) {
72
+ export function getImgProps({ src, sizes, unoptimized = false, preload = false, loading, className, quality, width, height, fill = false, style, loader: loaderProp, placeholder = "empty", blurDataURL, fetchPriority, decoding = "async", ...rest }, _state) {
69
73
  const { imgConf, showAltText, blurComplete } = _state;
70
74
  let config;
71
75
  const c = imgConf || imageConfigDefault;
@@ -73,19 +77,22 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
73
77
  config = c;
74
78
  }
75
79
  else {
76
- const allSizes = [...c.deviceSizes, ...c.imageSizes].sort((a, b) => a - b);
77
- const deviceSizes = c.deviceSizes.sort((a, b) => a - b);
78
- const qualities = c.qualities?.sort((a, b) => a - b);
79
- config = { ...c, allSizes, deviceSizes, qualities };
80
+ const prepared = preparedConfigs.get(c);
81
+ if (prepared) {
82
+ config = prepared;
83
+ }
84
+ else {
85
+ const allSizes = [...c.deviceSizes, ...c.imageSizes].sort((a, b) => a - b);
86
+ const deviceSizes = [...c.deviceSizes].sort((a, b) => a - b);
87
+ const qualities = c.qualities ? [...c.qualities].sort((a, b) => a - b) : undefined;
88
+ config = { ...c, allSizes, deviceSizes, qualities };
89
+ preparedConfigs.set(c, config);
90
+ }
80
91
  }
81
- const loader = rest.loader || defaultLoader;
82
- // Remove property so it's not spread on <img> element
83
- delete rest.loader;
84
- delete rest.srcSet;
92
+ const loader = loaderProp || defaultLoader;
85
93
  // This special value indicates that the user
86
94
  // didn't define a "loader" prop.
87
95
  const isDefaultLoader = "__rebask_img_default" in loader;
88
- let staticSrc = "";
89
96
  let widthInt = getInt(width);
90
97
  let heightInt = getInt(height);
91
98
  let blurWidth;
@@ -98,10 +105,10 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
98
105
  if (!staticImageData.height || !staticImageData.width) {
99
106
  throw new Error(`An object should only be passed to the image component src parameter if it comes from a static image import. It must include height and width. Received ${JSON.stringify(staticImageData)}`);
100
107
  }
101
- blurWidth = staticImageData.blurWidth;
102
- blurHeight = staticImageData.blurHeight;
103
- blurDataURL = blurDataURL || staticImageData.blurDataURL;
104
- staticSrc = staticImageData.src;
108
+ blurWidth = staticImageData.blur?.width;
109
+ blurHeight = staticImageData.blur?.height;
110
+ blurDataURL = blurDataURL || staticImageData.blur?.dataURL;
111
+ src = staticImageData.src;
105
112
  if (!fill) {
106
113
  if (!widthInt && !heightInt) {
107
114
  widthInt = staticImageData.width;
@@ -117,7 +124,6 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
117
124
  }
118
125
  }
119
126
  }
120
- src = typeof src === "string" ? src : staticSrc;
121
127
  let isLazy = !preload && (loading === "lazy" || typeof loading === "undefined");
122
128
  if (!src || src.startsWith("data:") || src.startsWith("blob:")) {
123
129
  // https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
@@ -133,13 +139,7 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
133
139
  }
134
140
  const qualityInt = getInt(quality);
135
141
  if (import.meta.env.DEV) {
136
- if (!src) {
137
- // React doesn't show the stack trace and there's
138
- // no `src` to help identify which image, so we
139
- // instead console.error(ref) during mount.
140
- unoptimized = true;
141
- }
142
- else {
142
+ if (src) {
143
143
  if (fill) {
144
144
  if (width) {
145
145
  throw new Error(`Image with src "${src}" has both "width" and "fill" properties. Only one should be used.`);
@@ -170,12 +170,10 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
170
170
  else if (isNaN(heightInt)) {
171
171
  throw new Error(`Image with src "${src}" has invalid "height" property. Expected a numeric value in pixels but received "${height}".`);
172
172
  }
173
- const startsWithSpaceOrControl = src.length > 0 && src.charCodeAt(0) <= 0x20;
174
- if (startsWithSpaceOrControl) {
173
+ if (src.length > 0 && src.charCodeAt(0) <= 0x20) {
175
174
  throw new Error(`Image with src "${src}" cannot start with a space or control character. Use src.trimStart() to remove it or encodeURIComponent(src) to keep it.`);
176
175
  }
177
- const endsWithSpaceOrControl = src.length > 0 && src.charCodeAt(src.length - 1) <= 0x20;
178
- if (endsWithSpaceOrControl) {
176
+ if (src.length > 0 && src.charCodeAt(src.length - 1) <= 0x20) {
179
177
  throw new Error(`Image with src "${src}" cannot end with a space or control character. Use src.trimEnd() to remove it or encodeURIComponent(src) to keep it.`);
180
178
  }
181
179
  }
@@ -191,12 +189,10 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
191
189
  !placeholder.startsWith("data:image/")) {
192
190
  throw new Error(`Image with src "${src}" has invalid "placeholder" property "${placeholder}".`);
193
191
  }
194
- if (placeholder !== "empty") {
195
- if (widthInt && heightInt && widthInt * heightInt < 1600) {
196
- warnOnce(`Image with src "${src}" is smaller than 40x40. Consider removing the "placeholder" property to improve performance.`);
197
- }
192
+ if (placeholder !== "empty" && widthInt && heightInt && widthInt * heightInt < 1600) {
193
+ warnOnce(`Image with src "${src}" is smaller than 40x40. Consider removing the "placeholder" property to improve performance.`);
198
194
  }
199
- if (qualityInt && config.qualities && !config.qualities.includes(qualityInt)) {
195
+ if (qualityInt && config.qualities?.length && !config.qualities.includes(qualityInt)) {
200
196
  warnOnce(`Image with src "${src}" is using quality "${qualityInt}" which is not configured in images.qualities [${config.qualities.join(", ")}]. Please update your config to [${[...config.qualities, qualityInt].sort().join(", ")}].`);
201
197
  }
202
198
  if (placeholder === "blur" && !blurDataURL) {
@@ -205,6 +201,7 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
205
201
  Possible solutions:
206
202
  - Add a "blurDataURL" property, the contents should be a small Data URL to represent the image
207
203
  - Change the "src" property to a static import with one of the supported file types: ${VALID_BLUR_EXT.join(",")} (animated images not supported)
204
+ - Install \`sharp\` so Rebask can generate the blur placeholder for static imports
208
205
  - Remove the "placeholder" property, effectively no blur effect`);
209
206
  }
210
207
  }
@@ -219,6 +216,7 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
219
216
  bottom: 0,
220
217
  }
221
218
  : {}, showAltText ? {} : { color: "transparent" }, style);
219
+ const objectFit = imgStyle.objectFit || "cover";
222
220
  const backgroundImage = !blurComplete && placeholder !== "empty"
223
221
  ? placeholder === "blur"
224
222
  ? `url("data:image/svg+xml;charset=utf-8,${getImageBlurSvg({
@@ -227,11 +225,10 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
227
225
  blurWidth,
228
226
  blurHeight,
229
227
  blurDataURL: blurDataURL || "", // assume not undefined
230
- objectFit: imgStyle.objectFit || "cover",
228
+ objectFit,
231
229
  })}")`
232
230
  : `url("${placeholder}")` // assume `data:image/`
233
231
  : null;
234
- const objectFit = imgStyle.objectFit || "cover";
235
232
  const backgroundSize = !INVALID_BACKGROUND_SIZE_VALUES.includes(objectFit)
236
233
  ? objectFit
237
234
  : objectFit === "fill"
@@ -265,18 +262,16 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
265
262
  }
266
263
  else {
267
264
  const { widths, kind } = getWidths(config, widthInt, sizes);
268
- const last = widths.length - 1;
265
+ const urls = widths.map((width) => loader({ config, src, quality: qualityInt, width }));
269
266
  imgSizes = !sizes && kind === "w" ? "100vw" : sizes;
270
- imgSrcSet = widths
271
- .map((w, i) => `${loader({ config, src, quality: qualityInt, width: w })} ${kind === "w" ? w : i + 1}${kind}`)
272
- .join(", ");
267
+ imgSrcSet = urls.map((url, i) => `${url} ${kind === "w" ? widths[i] : i + 1}${kind}`).join(", ");
273
268
  // It's intended to keep `src` the last attribute because React updates
274
269
  // attributes in order. If we keep `src` the first one, Safari will
275
270
  // immediately start to fetch `src`, before `sizes` and `srcSet` are even
276
271
  // updated by React. That causes multiple unnecessary requests if `srcSet`
277
272
  // and `sizes` are defined.
278
273
  // This bug cannot be reproduced in Chrome or Firefox.
279
- imgSrc = loader({ config, src, quality: qualityInt, width: widths[last] });
274
+ imgSrc = urls[urls.length - 1];
280
275
  }
281
276
  const loadingFinal = isLazy ? "lazy" : loading;
282
277
  const props = {
@@ -293,5 +288,36 @@ export function getImgProps({ src, sizes, unoptimized = false, preload = false,
293
288
  src: imgSrc,
294
289
  };
295
290
  const meta = { unoptimized, preload, placeholder, fill };
291
+ if (import.meta.env.DEV && typeof window !== "undefined") {
292
+ if (!perfObserver && window.PerformanceObserver) {
293
+ perfObserver = new PerformanceObserver((entryList) => {
294
+ for (const entry of entryList.getEntries()) {
295
+ const imgSrc = entry.element?.src ?? "";
296
+ const image = allImgs.get(imgSrc);
297
+ if (image &&
298
+ image.loading === "lazy" &&
299
+ image.placeholder === "empty" &&
300
+ !image.src.startsWith("data:") &&
301
+ !image.src.startsWith("blob:")) {
302
+ warnOnce(`Image with src "${image.src}" was detected as the Largest Contentful Paint (LCP). Please add the \`loading="eager"\` property if this image is above the fold.`);
303
+ }
304
+ }
305
+ });
306
+ try {
307
+ perfObserver.observe({ type: "largest-contentful-paint", buffered: true });
308
+ }
309
+ catch (error) {
310
+ console.error(error);
311
+ }
312
+ }
313
+ let fullUrl;
314
+ try {
315
+ fullUrl = new URL(props.src);
316
+ }
317
+ catch {
318
+ fullUrl = new URL(props.src, window.location.href);
319
+ }
320
+ allImgs.set(fullUrl.href, { src, loading: loadingFinal, placeholder });
321
+ }
296
322
  return { props, meta };
297
323
  }
@@ -1,5 +1,2 @@
1
- /**
2
- * Handler for image optimization requests.
3
- */
4
1
  export declare function handleImage(request: Request, sharp: any): Promise<Response>;
5
2
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/image-optimization/handler.ts"],"names":[],"mappings":"AAkFA;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgHjF"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/lib/image-optimization/handler.ts"],"names":[],"mappings":"AA+TA,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6LjF"}