Add support for preload media to ReactDOM (#28635)
This PR adds support for `media` option to `ReactDOM.preload()`, which is needed when images differ between screen sizes (for example mobile vs desktop)
Marius Craciunoiu committed
Mar 28, 2024 at 11:04 UTC
78328c0c4d70c9b9ee4ad2d6a2319c95e628dd2d
3 files changed
+87
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+85
@@ -4261,6 +4261,91 @@ body {
4261
);
4262
});
4263
4264
+ it('should handle media on image preload', async () => {
4265
+ function App({isClient}) {
4266
+ ReactDOM.preload('/server', {
4267
+ as: 'image',
4268
+ imageSrcSet: '/server',
4269
+ imageSizes: '100vw',
4270
+ media: 'print and (min-width: 768px)',
4271
+ });
4272
+
4273
+ if (isClient) {
4274
+ ReactDOM.preload('/client', {
4275
+ as: 'image',
4276
+ imageSrcSet: '/client',
4277
+ imageSizes: '100vw',
4278
+ media: 'screen and (max-width: 480px)',
4279
+ });
4280
+ }
4281
+
4282
+ return (
4283
+ <html>
4284
+ <body>hello</body>
4285
+ </html>
4286
+ );
4287
+ }
4288
+
4289
+ await act(() => {
4290
+ renderToPipeableStream(<App />).pipe(writable);
4291
+ });
4292
+ expect(getMeaningfulChildren(document)).toEqual(
4293
+ <html>
4294
+ <head>
4295
+ <link
4296
+ rel="preload"
4297
+ as="image"
4298
+ imagesrcset="/server"
4299
+ imagesizes="100vw"
4300
+ media="print and (min-width: 768px)"
4301
+ />
4302
+ </head>
4303
+ <body>hello</body>
4304
+ </html>,
4305
+ );
4306
+
4307
+ const root = ReactDOMClient.hydrateRoot(document, <App />);
4308
+ await waitForAll([]);
4309
+ expect(getMeaningfulChildren(document)).toEqual(
4310
+ <html>
4311
+ <head>
4312
+ <link
4313
+ rel="preload"
4314
+ as="image"
4315
+ imagesrcset="/server"
4316
+ imagesizes="100vw"
4317
+ media="print and (min-width: 768px)"
4318
+ />
4319
+ </head>
4320
+ <body>hello</body>
4321
+ </html>,
4322
+ );
4323
+
4324
+ root.render(<App isClient={true} />);
4325
+ await waitForAll([]);
4326
+ expect(getMeaningfulChildren(document)).toEqual(
4327
+ <html>
4328
+ <head>
4329
+ <link
4330
+ rel="preload"
4331
+ as="image"
4332
+ imagesrcset="/server"
4333
+ imagesizes="100vw"
4334
+ media="print and (min-width: 768px)"
4335
+ />
4336
+ <link
4337
+ rel="preload"
4338
+ as="image"
4339
+ imagesrcset="/client"
4340
+ imagesizes="100vw"
4341
+ media="screen and (max-width: 480px)"
4342
+ />
4343
+ </head>
4344
+ <body>hello</body>
4345
+ </html>,
4346
+ );
4347
+ });
4348
+
4349
it('should warn if you preload a stylesheet and then render a style tag with the same href', async () => {
4350
const style = 'body { color: red; }';
4351
function App() {
packages/react-dom/src/shared/ReactDOMFloat.js
+1
@@ -139,6 +139,7 @@ export function preload(href: string, options: PreloadOptions) {
139
: undefined,
140
imageSizes:
141
typeof options.imageSizes === 'string' ? options.imageSizes : undefined,
142
+ media: typeof options.media === 'string' ? options.media : undefined,
143
});
144
}
145
// We don't error because preload needs to be resilient to being called in a variety of scopes
packages/react-dom/src/shared/ReactDOMTypes.js
+1
@@ -16,6 +16,7 @@ export type PreloadOptions = {
16
crossOrigin?: string,
17
integrity?: string,
18
type?: string,
19
+ media?: string,
20
nonce?: string,
21
fetchPriority?: FetchPriorityEnum,
22
imageSrcSet?: string,