@samitouri / QOS-React-1 / commits / 1a001dac62

[Fizz][Float] When src or srcSet is a data URI we should not preload the image (#27218)

Data URI's in images can't effectively be preloaded (the URI contains the data so preloading only duplicates the data in the stream. If we encounter an image with this protocol in the src attribute we should avoid preloading it.

Josh Story committed Aug 12, 2023 at 09:21 UTC 1a001dac6220a64d98ae33a28e89dde78100d6c5
2 files changed +51 -3
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+21 -3
@@ -2392,14 +2392,32 @@ function pushImg(
2392 props: Object,
2393 resources: Resources,
2394 ): null {
2395 + const {src, srcSet} = props;
2396 if (
2397 props.loading !== 'lazy' &&
2397 - typeof props.src === 'string' &&
2398 - props.fetchPriority !== 'low'
2398 + (typeof src === 'string' || typeof srcSet === 'string') &&
2399 + props.fetchPriority !== 'low' &&
2400 + // We exclude data URIs in src and srcSet since these should not be preloaded
2401 + !(
2402 + typeof src === 'string' &&
2403 + src[4] === ':' &&
2404 + (src[0] === 'd' || src[0] === 'D') &&
2405 + (src[1] === 'a' || src[1] === 'A') &&
2406 + (src[2] === 't' || src[2] === 'T') &&
2407 + (src[3] === 'a' || src[3] === 'A')
2408 + ) &&
2409 + !(
2410 + typeof srcSet === 'string' &&
2411 + srcSet[4] === ':' &&
2412 + (srcSet[0] === 'd' || srcSet[0] === 'D') &&
2413 + (srcSet[1] === 'a' || srcSet[1] === 'A') &&
2414 + (srcSet[2] === 't' || srcSet[2] === 'T') &&
2415 + (srcSet[3] === 'a' || srcSet[3] === 'A')
2416 + )
2417 ) {
2418 // We have a suspensey image and ought to preload it to optimize the loading of display blocking
2419 // resources.
2402 - const {src, srcSet, sizes} = props;
2420 + const {sizes} = props;
2421 const key = getImagePreloadKey(src, srcSet, sizes);
2422 let resource = resources.preloadsMap.get(key);
2423 if (!resource) {
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+30
@@ -3969,6 +3969,36 @@ body {
3969 );
3970 });
3971
3972 + it('should not preload images that have a data URIs for src or srcSet', async () => {
3973 + function App() {
3974 + return (
3975 + <html>
3976 + <body>
3977 + <img src="data:1" />
3978 + <img src="data:2" srcSet="ss2" />
3979 + <img srcSet="data:3a, data:3b 2x" />
3980 + <img src="4" srcSet="data:4a, data4b 2x" />
3981 + </body>
3982 + </html>
3983 + );
3984 + }
3985 + await act(() => {
3986 + renderToPipeableStream(<App />).pipe(writable);
3987 + });
3988 +
3989 + expect(getMeaningfulChildren(document)).toEqual(
3990 + <html>
3991 + <head />
3992 + <body>
3993 + <img src="data:1" />
3994 + <img src="data:2" srcset="ss2" />
3995 + <img srcset="data:3a, data:3b 2x" />
3996 + <img src="4" srcset="data:4a, data4b 2x" />
3997 + </body>
3998 + </html>,
3999 + );
4000 + });
4001 +
4002 describe('ReactDOM.prefetchDNS(href)', () => {
4003 it('creates a dns-prefetch resource when called', async () => {
4004 function App({url}) {