Repository: facebook/react
Pull request: Add support for preload media to ReactDOM

## Summary

This PR adds support for `media` option to `ReactDOM.preload()`, which is needed when images differ between screen sizes (for example mobile vs desktop).

Tests copied from https://github.com/facebook/react/pull/27129 (thanks @damnsamn!)

## How did you test this change?

Ran the tests from https://github.com/facebook/react/pull/27129 before:

```sh
yarn test ReactDOMFloat

  ● ReactDOMFloat › should handle media on image preload

    expect(received).toEqual(expected) // deep equality

    - Expected  - 1
    + Received  + 0

    @@ -2,11 +2,10 @@
        <head>
          <link
            as="image"
            imagesizes="100vw"
            imagesrcset="/server"
    -       media="print and (min-width: 768px)"
            rel="preload"
          />
        </head>
        <body>
          hello

      4290 |       renderToPipeableStream(<App />).pipe(writable);
      4291 |     });
    > 4292 |     expect(getMeaningfulChildren(document)).toEqual(
           |                                             ^
      4293 |       <html>
      4294 |         <head>
      4295 |           <link

      at Object.<anonymous> (packages/react-dom/src/__tests__/ReactDOMFloat-test.js:4292:45)

```

After:

```
Test Suites: 1 passed, 1 total
Tests:       1 skipped, 109 passed, 110 total
Snapshots:   0 total
Time:        25.541 s
Ran all test suites matching /ReactDOMFloat/i.
✨  Done in 27.84s.
```


Changed files:
filename: packages/react-dom/src/__tests__/ReactDOMFloat-test.js
patch: @@ -4261,6 +4261,91 @@ body {
     );
   });
 
+  it('should handle media on image preload', async () => {
+    function App({isClient}) {
+      ReactDOM.preload('/server', {
+        as: 'image',
+        imageSrcSet: '/server',
+        imageSizes: '100vw',
+        media: 'print and (min-width: 768px)',
+      });
+
+      if (isClient) {
+        ReactDOM.preload('/client', {
+          as: 'image',
+          imageSrcSet: '/client',
+          imageSizes: '100vw',
+          media: 'screen and (max-width: 480px)',
+        });
+      }
+
+      return (
+        <html>
+          <body>hello</body>
+        </html>
+      );
+    }
+
+    await act(() => {
+      renderToPipeableStream(<App />).pipe(writable);
+    });
+    expect(getMeaningfulChildren(document)).toEqual(
+      <html>
+        <head>
+          <link
+            rel="preload"
+            as="image"
+            imagesrcset="/server"
+            imagesizes="100vw"
+            media="print and (min-width: 768px)"
+          />
+        </head>
+        <body>hello</body>
+      </html>,
+    );
+
+    const root = ReactDOMClient.hydrateRoot(document, <App />);
+    await waitForAll([]);
+    expect(getMeaningfulChildren(document)).toEqual(
+      <html>
+        <head>
+          <link
+            rel="preload"
+            as="image"
+            imagesrcset="/server"
+            imagesizes="100vw"
+            media="print and (min-width: 768px)"
+          />
+        </head>
+        <body>hello</body>
+      </html>,
+    );
+
+    root.render(<App isClient={true} />);
+    await waitForAll([]);
+    expect(getMeaningfulChildren(document)).toEqual(
+      <html>
+        <head>
+          <link
+            rel="preload"
+            as="image"
+            imagesrcset="/server"
+            imagesizes="100vw"
+            media="print and (min-width: 768px)"
+          />
+          <link
+            rel="preload"
+            as="image"
+            imagesrcset="/client"
+            imagesizes="100vw"
+            media="screen and (max-width: 480px)"
+          />
+        </head>
+        <body>hello</body>
+      </html>,
+    );
+  });
+
   it('should warn if you preload a stylesheet and then render a style tag with the same href', async () => {
     const style = 'body { color: red; }';
     function App() {

filename: packages/react-dom/src/shared/ReactDOMFloat.js
patch: @@ -139,6 +139,7 @@ export function preload(href: string, options: PreloadOptions) {
           : undefined,
       imageSizes:
         typeof options.imageSizes === 'string' ? options.imageSizes : undefined,
+      media: typeof options.media === 'string' ? options.media : undefined,
     });
   }
   // We don't error because preload needs to be resilient to being called in a variety of scopes

filename: packages/react-dom/src/shared/ReactDOMTypes.js
patch: @@ -16,6 +16,7 @@ export type PreloadOptions = {
   crossOrigin?: string,
   integrity?: string,
   type?: string,
+  media?: string,
   nonce?: string,
   fetchPriority?: FetchPriorityEnum,
   imageSrcSet?: string,