Remove excess validation (#27223)
stacked on #27222 When I initially developed Float I was trying to be extremely clever in how to explain when there are mismatching Resource instances. I still think that we should do some kind of validation here but I want to implement something much simpler. In practice there are not many cases where you would accidentally create the same resource twice but with differing props. Since I am going to land `preloadModule` and `preinitModule` soon and I want to avoid adding to the overly complex dev validation there I am going to remove it now and add something later that is simplified.
Josh Story committed
Aug 14, 2023 at 10:08 UTC
5ea1397b2b62875dfb521cf8de0efcc15d0df797
3 files changed
-1058
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
-393
@@ -79,15 +79,6 @@ import {
79
import {
80
getValueDescriptorExpectingObjectForWarning,
81
getValueDescriptorExpectingEnumForWarning,
82
- describeDifferencesForStylesheets,
83
- describeDifferencesForStylesheetOverPreinit,
84
- describeDifferencesForScripts,
85
- describeDifferencesForScriptOverPreinit,
86
- describeDifferencesForPreinits,
87
- describeDifferencesForPreinitOverStylesheet,
88
- describeDifferencesForPreinitOverScript,
89
- describeDifferencesForPreloads,
90
- describeDifferencesForPreloadOverImplicitPreload,
82
} from '../shared/ReactDOMResourceValidation';
83
84
import {NotPending} from '../shared/ReactDOMFormActions';
@@ -2004,55 +1995,6 @@ function pushLink(
1995
} else {
1996
// This stylesheet refers to a Resource and we create a new one if necessary
1997
let resource = resources.stylesMap.get(key);
2007
- if (__DEV__) {
2008
- const devResource = getAsResourceDEV(resource);
2009
- if (devResource) {
2010
- switch (devResource.__provenance) {
2011
- case 'rendered': {
2012
- const differenceDescription = describeDifferencesForStylesheets(
2013
- // Diff the props from the JSX element, not the derived resource props
2014
- props,
2015
- devResource.__originalProps,
2016
- );
2017
- if (differenceDescription) {
2018
- console.error(
2019
- 'React encountered a <link rel="stylesheet" href="%s" .../> with a `precedence` prop that has props that conflict' +
2020
- ' with another hoistable stylesheet with the same `href`. When using `precedence` with <link rel="stylsheet" .../>' +
2021
- ' the props from the first encountered instance will be used and props from later instances will be ignored.' +
2022
- ' Update the props on either <link rel="stylesheet" .../> instance so they agree.%s',
2023
- href,
2024
- differenceDescription,
2025
- );
2026
- }
2027
- break;
2028
- }
2029
- case 'preinit': {
2030
- const differenceDescription =
2031
- describeDifferencesForStylesheetOverPreinit(
2032
- // Diff the props from the JSX element, not the derived resource props
2033
- props,
2034
- devResource.__propsEquivalent,
2035
- );
2036
- if (differenceDescription) {
2037
- console.error(
2038
- 'React encountered a <link rel="stylesheet" precedence="%s" href="%s" .../> with props that conflict' +
2039
- ' with the options provided to `ReactDOM.preinit("%s", { as: "style", ... })`. React will use the first props or preinitialization' +
2040
- ' options encountered when rendering a hoistable stylesheet with a particular `href` and will ignore any newer props or' +
2041
- ' options. The first instance of this stylesheet resource was created using the `ReactDOM.preinit()` function.' +
2042
- ' Please note, `ReactDOM.preinit()` is modeled off of module import assertions capabilities and does not support' +
2043
- ' arbitrary props. If you need to have props not included with the preinit options you will need to rely on rendering' +
2044
- ' <link> tags only.%s',
2045
- precedence,
2046
- href,
2047
- href,
2048
- differenceDescription,
2049
- );
2050
- }
2051
- break;
2052
- }
2053
- }
2054
- }
2055
- }
1998
if (!resource) {
1999
const resourceProps = stylesheetPropsFromRawProps(props);
2000
const preloadResource = resources.preloadsMap.get(key);
@@ -2076,9 +2018,6 @@ function pushLink(
2018
props: resourceProps,
2019
};
2020
resources.stylesMap.set(key, resource);
2079
- if (__DEV__) {
2080
- markAsRenderedResourceDEV(resource, props);
2081
- }
2021
let precedenceSet = resources.precedences.get(precedence);
2022
if (!precedenceSet) {
2023
precedenceSet = new Set();
@@ -2443,9 +2382,6 @@ function pushImg(
2382
},
2383
};
2384
resources.preloadsMap.set(key, resource);
2446
- if (__DEV__) {
2447
- markAsRenderedResourceDEV(resource, props);
2448
- }
2385
pushLinkImpl(resource.chunks, resource.props);
2386
}
2387
if (
@@ -2790,54 +2726,6 @@ function pushScript(
2726
const key = getResourceKey('script', src);
2727
// We can make this <script> into a ScriptResource
2728
let resource = resources.scriptsMap.get(key);
2793
- if (__DEV__) {
2794
- const devResource = getAsResourceDEV(resource);
2795
- if (devResource) {
2796
- switch (devResource.__provenance) {
2797
- case 'rendered': {
2798
- const differenceDescription = describeDifferencesForScripts(
2799
- // Diff the props from the JSX element, not the derived resource props
2800
- props,
2801
- devResource.__originalProps,
2802
- );
2803
- if (differenceDescription) {
2804
- console.error(
2805
- 'React encountered a <script async={true} src="%s" .../> that has props that conflict' +
2806
- ' with another hoistable script with the same `src`. When rendering hoistable scripts (async scripts without any loading handlers)' +
2807
- ' the props from the first encountered instance will be used and props from later instances will be ignored.' +
2808
- ' Update the props on both <script async={true} .../> instance so they agree.%s',
2809
- src,
2810
- differenceDescription,
2811
- );
2812
- }
2813
- break;
2814
- }
2815
- case 'preinit': {
2816
- const differenceDescription =
2817
- describeDifferencesForScriptOverPreinit(
2818
- // Diff the props from the JSX element, not the derived resource props
2819
- props,
2820
- devResource.__propsEquivalent,
2821
- );
2822
- if (differenceDescription) {
2823
- console.error(
2824
- 'React encountered a <script async={true} src="%s" .../> with props that conflict' +
2825
- ' with the options provided to `ReactDOM.preinit("%s", { as: "script", ... })`. React will use the first props or preinitialization' +
2826
- ' options encountered when rendering a hoistable script with a particular `src` and will ignore any newer props or' +
2827
- ' options. The first instance of this script resource was created using the `ReactDOM.preinit()` function.' +
2828
- ' Please note, `ReactDOM.preinit()` is modeled off of module import assertions capabilities and does not support' +
2829
- ' arbitrary props. If you need to have props not included with the preinit options you will need to rely on rendering' +
2830
- ' <script> tags only.%s',
2831
- src,
2832
- src,
2833
- differenceDescription,
2834
- );
2835
- }
2836
- break;
2837
- }
2838
- }
2839
- }
2840
- }
2729
if (!resource) {
2730
resource = {
2731
type: 'script',
@@ -2846,9 +2734,6 @@ function pushScript(
2734
props: null,
2735
};
2736
resources.scriptsMap.set(key, resource);
2849
- if (__DEV__) {
2850
- markAsRenderedResourceDEV(resource, props);
2851
- }
2737
// Add to the script flushing queue
2738
resources.scripts.add(resource);
2739
@@ -4874,30 +4759,6 @@ type TResource<
4759
state: ResourceStateTag,
4760
props: P,
4761
};
4877
-// Dev extensions.
4878
-// Stylesheets and Scripts rendered with jsx
4879
-type RenderedResourceDEV = {
4880
- __provenance: 'rendered',
4881
- __originalProps: any,
4882
-};
4883
-// Preloads, Stylesheets, and Scripts from ReactDOM.preload or ReactDOM.preinit
4884
-type ImperativeResourceDEV = {
4885
- __provenance: 'preload' | 'preinit',
4886
- __originalHref: string,
4887
- __originalOptions: any,
4888
- __propsEquivalent: any,
4889
-};
4890
-// Preloads created for normal components we rendered but know we can preload early such as
4891
-// sync Scripts and stylesheets without precedence or with onLoad/onError handlers
4892
-type ImplicitResourceDEV = {
4893
- __provenance: 'implicit',
4894
- __underlyingProps: any,
4895
- __impliedProps: any,
4896
-};
4897
-type ResourceDEV =
4898
- | RenderedResourceDEV
4899
- | ImperativeResourceDEV
4900
- | ImplicitResourceDEV;
4762
4763
type PreconnectProps = {
4764
rel: 'preconnect' | 'dns-prefetch',
@@ -5193,61 +5054,6 @@ function preload(href: string, options: PreloadOptions) {
5054
key = getResourceKey(as, href);
5055
}
5056
let resource = resources.preloadsMap.get(key);
5196
- if (__DEV__) {
5197
- const devResource = getAsResourceDEV(resource);
5198
- if (devResource) {
5199
- switch (devResource.__provenance) {
5200
- case 'preload': {
5201
- const differenceDescription = describeDifferencesForPreloads(
5202
- options,
5203
- devResource.__originalOptions,
5204
- );
5205
- if (differenceDescription) {
5206
- console.error(
5207
- 'ReactDOM.preload(): The options provided conflict with another call to `ReactDOM.preload("%s", { as: "%s", ...})`.' +
5208
- ' React will always use the options it first encounters when preloading a resource for a given `href` and `as` type, and any later options will be ignored if different.' +
5209
- ' Try updating all calls to `ReactDOM.preload()` with the same `href` and `as` type to use the same options, or eliminate one of the calls.%s',
5210
- href,
5211
- as,
5212
- differenceDescription,
5213
- );
5214
- }
5215
- break;
5216
- }
5217
- case 'implicit': {
5218
- const differenceDescription =
5219
- describeDifferencesForPreloadOverImplicitPreload(
5220
- options,
5221
- devResource.__impliedProps,
5222
- );
5223
- if (differenceDescription) {
5224
- const elementDescription =
5225
- as === 'style'
5226
- ? '<link rel="stylesheet" ... />'
5227
- : as === 'script'
5228
- ? '<script ... />'
5229
- : null;
5230
- if (elementDescription) {
5231
- console.error(
5232
- 'ReactDOM.preload(): For `href` "%s", The options provided conflict with props on a matching %s element. When the preload' +
5233
- ' options disagree with the underlying resource it usually means the browser will not be able to use the preload when the resource' +
5234
- ' is fetched, negating any benefit the preload would provide. React will preload the resource using props derived from the resource instead' +
5235
- ' and ignore the options provided to the `ReactDOM.preload()` call. In general, preloading is useful when you expect to' +
5236
- ' render a resource soon but have not yet done so. In this case since the underlying resource was already rendered the preload call' +
5237
- ' may be extraneous. Try removing the call, otherwise try adjusting both the props on the %s and the options' +
5238
- ' passed to `ReactDOM.preload()` to agree.%s',
5239
- href,
5240
- elementDescription,
5241
- elementDescription,
5242
- differenceDescription,
5243
- );
5244
- }
5245
- }
5246
- break;
5247
- }
5248
- }
5249
- }
5250
- }
5057
if (!resource) {
5058
resource = {
5059
type: 'preload',
@@ -5256,16 +5062,6 @@ function preload(href: string, options: PreloadOptions) {
5062
props: preloadPropsFromPreloadOptions(href, as, options),
5063
};
5064
resources.preloadsMap.set(key, resource);
5259
- if (__DEV__) {
5260
- markAsImperativeResourceDEV(
5261
- resource,
5262
- 'preload',
5263
- href,
5264
- options,
5265
- resource.props,
5266
- );
5267
- }
5268
-
5065
pushLinkImpl(resource.chunks, resource.props);
5066
}
5067
if (as === 'font') {
@@ -5323,64 +5119,6 @@ function preinit(href: string, options: PreinitOptions): void {
5119
const key = getResourceKey(as, href);
5120
let resource = resources.stylesMap.get(key);
5121
const precedence = options.precedence || 'default';
5326
- if (__DEV__) {
5327
- const devResource = getAsResourceDEV(resource);
5328
- if (devResource) {
5329
- const resourceProps = stylesheetPropsFromPreinitOptions(
5330
- href,
5331
- precedence,
5332
- options,
5333
- );
5334
- const propsEquivalent = {
5335
- ...resourceProps,
5336
- precedence: options.precedence,
5337
- ['data-precedence']: null,
5338
- };
5339
- switch (devResource.__provenance) {
5340
- case 'rendered': {
5341
- const differenceDescription =
5342
- describeDifferencesForPreinitOverStylesheet(
5343
- // Diff the props from the JSX element, not the derived resource props
5344
- propsEquivalent,
5345
- devResource.__originalProps,
5346
- );
5347
- if (differenceDescription) {
5348
- console.error(
5349
- 'ReactDOM.preinit(): For `href` "%s", the options provided conflict with props found on a <link rel="stylesheet" precedence="%s" href="%s" .../> that was already rendered.' +
5350
- ' React will always use the props or options it first encounters for a hoistable stylesheet for a given `href` and any later props or options will be ignored if different.' +
5351
- ' Generally, ReactDOM.preinit() is useful when you are not yet rendering a stylesheet but you anticipate it will be used soon.' +
5352
- ' In this case the stylesheet was already rendered so preinitializing it does not provide any additional benefit.' +
5353
- ' To resolve, try making the props and options agree between the <link rel="stylesheet" .../> and the `ReactDOM.preinit()` call or' +
5354
- ' remove the `ReactDOM.preinit()` call.%s',
5355
- href,
5356
- devResource.__originalProps.precedence,
5357
- href,
5358
- differenceDescription,
5359
- );
5360
- }
5361
- break;
5362
- }
5363
- case 'preinit': {
5364
- const differenceDescription = describeDifferencesForPreinits(
5365
- // Diff the props from the JSX element, not the derived resource props
5366
- propsEquivalent,
5367
- devResource.__propsEquivalent,
5368
- );
5369
- if (differenceDescription) {
5370
- console.error(
5371
- 'ReactDOM.preinit(): For `href` "%s", the options provided conflict with another call to `ReactDOM.preinit("%s", { as: "style", ... })`.' +
5372
- ' React will always use the options it first encounters when preinitializing a hoistable stylesheet for a given `href` and any later options will be ignored if different.' +
5373
- ' Try updating all calls to `ReactDOM.preinit()` for a given `href` to use the same options, or only call `ReactDOM.preinit()` once per `href`.%s',
5374
- href,
5375
- href,
5376
- differenceDescription,
5377
- );
5378
- }
5379
- break;
5380
- }
5381
- }
5382
- }
5383
- }
5122
if (!resource) {
5123
let state = NoState;
5124
const preloadResource = resources.preloadsMap.get(key);
@@ -5394,13 +5132,6 @@ function preinit(href: string, options: PreinitOptions): void {
5132
props: stylesheetPropsFromPreinitOptions(href, precedence, options),
5133
};
5134
resources.stylesMap.set(key, resource);
5397
- if (__DEV__) {
5398
- markAsImperativeResourceDEV(resource, 'preinit', href, options, {
5399
- ...resource.props,
5400
- precedence,
5401
- ['data-precedence']: undefined,
5402
- });
5403
- }
5135
let precedenceSet = resources.precedences.get(precedence);
5136
if (!precedenceSet) {
5137
precedenceSet = new Set();
@@ -5434,53 +5165,6 @@ function preinit(href: string, options: PreinitOptions): void {
5165
const src = href;
5166
const key = getResourceKey(as, src);
5167
let resource = resources.scriptsMap.get(key);
5437
- if (__DEV__) {
5438
- const devResource = getAsResourceDEV(resource);
5439
- if (devResource) {
5440
- const propsEquivalent = scriptPropsFromPreinitOptions(src, options);
5441
- switch (devResource.__provenance) {
5442
- case 'rendered': {
5443
- const differenceDescription =
5444
- describeDifferencesForPreinitOverScript(
5445
- // Diff the props from the JSX element, not the derived resource props
5446
- propsEquivalent,
5447
- devResource.__originalProps,
5448
- );
5449
- if (differenceDescription) {
5450
- console.error(
5451
- 'ReactDOM.preinit(): For `href` "%s", the options provided conflict with props found on a <script async={true} src="%s" .../> that was already rendered.' +
5452
- ' React will always use the props or options it first encounters for a hoistable script for a given `href` and any later props or options will be ignored if different.' +
5453
- ' Generally, ReactDOM.preinit() is useful when you are not yet rendering a script but you anticipate it will be used soon and want to go beyond preloading it and have it' +
5454
- ' execute early. In this case the script was already rendered so preinitializing it does not provide any additional benefit.' +
5455
- ' To resolve, try making the props and options agree between the <script .../> and the `ReactDOM.preinit()` call or remove the `ReactDOM.preinit()` call.%s',
5456
- href,
5457
- href,
5458
- differenceDescription,
5459
- );
5460
- }
5461
- break;
5462
- }
5463
- case 'preinit': {
5464
- const differenceDescription = describeDifferencesForPreinits(
5465
- // Diff the props from the JSX element, not the derived resource props
5466
- propsEquivalent,
5467
- devResource.__propsEquivalent,
5468
- );
5469
- if (differenceDescription) {
5470
- console.error(
5471
- 'ReactDOM.preinit(): For `href` "%s", the options provided conflict with another call to `ReactDOM.preinit("%s", { as: "script", ... })`.' +
5472
- ' React will always use the options it first encounters when preinitializing a hoistable script for a given `href` and any later options will be ignored if different.' +
5473
- ' Try updating all calls to `ReactDOM.preinit()` for a given `href` to use the same options, or only call `ReactDOM.preinit()` once per `href`.%s',
5474
- href,
5475
- href,
5476
- differenceDescription,
5477
- );
5478
- }
5479
- break;
5480
- }
5481
- }
5482
- }
5483
- }
5168
if (!resource) {
5169
resource = {
5170
type: 'script',
@@ -5490,15 +5174,6 @@ function preinit(href: string, options: PreinitOptions): void {
5174
};
5175
resources.scriptsMap.set(key, resource);
5176
const resourceProps = scriptPropsFromPreinitOptions(src, options);
5493
- if (__DEV__) {
5494
- markAsImperativeResourceDEV(
5495
- resource,
5496
- 'preinit',
5497
- href,
5498
- options,
5499
- resourceProps,
5500
- );
5501
- }
5177
resources.scripts.add(resource);
5178
pushScriptImpl(resource.chunks, resourceProps);
5179
flushResources(request);
@@ -5724,73 +5399,5 @@ export function hoistResources(
5399
}
5400
}
5401
5727
-function markAsRenderedResourceDEV(
5728
- resource: Resource,
5729
- originalProps: any,
5730
-): void {
5731
- if (__DEV__) {
5732
- const devResource: RenderedResourceDEV = (resource: any);
5733
- if (typeof devResource.__provenance === 'string') {
5734
- console.error(
5735
- 'Resource already marked for DEV type. This is a bug in React.',
5736
- );
5737
- }
5738
- devResource.__provenance = 'rendered';
5739
- devResource.__originalProps = originalProps;
5740
- } else {
5741
- // eslint-disable-next-line react-internal/prod-error-codes
5742
- throw new Error(
5743
- 'markAsRenderedResourceDEV was included in a production build. This is a bug in React.',
5744
- );
5745
- }
5746
-}
5747
-
5748
-function markAsImperativeResourceDEV(
5749
- resource: Resource,
5750
- provenance: 'preload' | 'preinit',
5751
- originalHref: string,
5752
- originalOptions: any,
5753
- propsEquivalent: any,
5754
-): void {
5755
- if (__DEV__) {
5756
- const devResource: ImperativeResourceDEV = (resource: any);
5757
- if (typeof devResource.__provenance === 'string') {
5758
- console.error(
5759
- 'Resource already marked for DEV type. This is a bug in React.',
5760
- );
5761
- }
5762
- devResource.__provenance = provenance;
5763
- devResource.__originalHref = originalHref;
5764
- devResource.__originalOptions = originalOptions;
5765
- devResource.__propsEquivalent = propsEquivalent;
5766
- } else {
5767
- // eslint-disable-next-line react-internal/prod-error-codes
5768
- throw new Error(
5769
- 'markAsImperativeResourceDEV was included in a production build. This is a bug in React.',
5770
- );
5771
- }
5772
-}
5773
-
5774
-function getAsResourceDEV(
5775
- resource: null | void | Resource,
5776
-): null | ResourceDEV {
5777
- if (__DEV__) {
5778
- if (resource) {
5779
- if (typeof (resource: any).__provenance === 'string') {
5780
- return (resource: any);
5781
- }
5782
- console.error(
5783
- 'Resource was not marked for DEV type. This is a bug in React.',
5784
- );
5785
- }
5786
- return null;
5787
- } else {
5788
- // eslint-disable-next-line react-internal/prod-error-codes
5789
- throw new Error(
5790
- 'getAsResourceDEV was included in a production build. This is a bug in React.',
5791
- );
5792
- }
5793
-}
5794
-
5402
export type TransitionStatus = FormStatus;
5403
export const NotPendingTransition: TransitionStatus = NotPending;
packages/react-dom-bindings/src/shared/ReactDOMResourceValidation.js
-403
@@ -125,406 +125,3 @@ export function getValueDescriptorExpectingEnumForWarning(thing: any): string {
125
? JSON.stringify(thing)
126
: `something with type "${typeof thing}"`;
127
}
128
-
129
-type PropDifferences = {
130
- missing: {
131
- [string]: any,
132
- },
133
- extra: {
134
- [string]: any,
135
- },
136
- different: {
137
- [string]: {
138
- original: any,
139
- latest: any,
140
- },
141
- },
142
-};
143
-function compareResourcePropsForWarning(
144
- newProps: any,
145
- currentProps: any,
146
-): null | PropDifferences {
147
- if (__DEV__) {
148
- let propDiffs: null | PropDifferences = null;
149
-
150
- const allProps = Array.from(
151
- new Set(Object.keys(currentProps).concat(Object.keys(newProps))),
152
- );
153
-
154
- for (let i = 0; i < allProps.length; i++) {
155
- const propName = allProps[i];
156
- const newValue = newProps[propName];
157
- const currentValue = currentProps[propName];
158
- if (
159
- newValue !== currentValue &&
160
- !(newValue == null && currentValue == null)
161
- ) {
162
- if (newValue == null) {
163
- if (propDiffs === null) {
164
- propDiffs = ({
165
- missing: {},
166
- extra: {},
167
- different: {},
168
- }: PropDifferences);
169
- }
170
- propDiffs.missing[propName] = currentValue;
171
- } else if (currentValue == null) {
172
- if (propDiffs === null) {
173
- propDiffs = ({
174
- missing: {},
175
- extra: {},
176
- different: {},
177
- }: PropDifferences);
178
- }
179
- propDiffs.extra[propName] = newValue;
180
- } else {
181
- if (propDiffs === null) {
182
- propDiffs = ({
183
- missing: {},
184
- extra: {},
185
- different: {},
186
- }: PropDifferences);
187
- }
188
- propDiffs.different[propName] = {
189
- original: currentValue,
190
- latest: newValue,
191
- };
192
- }
193
- }
194
- }
195
-
196
- return propDiffs;
197
- }
198
- return null;
199
-}
200
-
201
-export function describeDifferencesForStylesheets(
202
- newProps: any,
203
- currentProps: any,
204
-): string {
205
- const diff = compareResourcePropsForWarning(newProps, currentProps);
206
- if (!diff) return '';
207
-
208
- let description = '';
209
-
210
- for (const propName in diff.missing) {
211
- const propValue = diff.missing[propName];
212
- if (propName === 'media') {
213
- description += `\n "${propName}" missing for props, original value: ${getValueDescriptorExpectingEnumForWarning(
214
- propValue,
215
- )}`;
216
- }
217
- }
218
- for (const propName in diff.extra) {
219
- const propValue = diff.extra[propName];
220
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
221
- propValue,
222
- )}, missing from original props`;
223
- }
224
- for (const propName in diff.different) {
225
- const latestValue = diff.different[propName].latest;
226
- const originalValue = diff.different[propName].original;
227
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
228
- latestValue,
229
- )}, original value: ${getValueDescriptorExpectingEnumForWarning(
230
- originalValue,
231
- )}`;
232
- }
233
- return description;
234
-}
235
-
236
-export function describeDifferencesForStylesheetOverPreinit(
237
- newProps: any,
238
- currentProps: any,
239
-): string {
240
- const diff = compareResourcePropsForWarning(newProps, currentProps);
241
- if (!diff) return '';
242
-
243
- let description = '';
244
-
245
- for (const propName in diff.extra) {
246
- const propValue = diff.extra[propName];
247
- if (
248
- propName === 'precedence' ||
249
- propName === 'crossOrigin' ||
250
- propName === 'integrity'
251
- ) {
252
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
253
- propValue,
254
- )}, option missing`;
255
- } else {
256
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
257
- propValue,
258
- )}, option not available with ReactDOM.preinit()`;
259
- }
260
- }
261
- for (const propName in diff.different) {
262
- const latestValue = diff.different[propName].latest;
263
- const originalValue = diff.different[propName].original;
264
- if (propName === 'precedence' && originalValue === 'default') {
265
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
266
- latestValue,
267
- )}, missing from options`;
268
- } else {
269
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
270
- latestValue,
271
- )}, option value: ${getValueDescriptorExpectingEnumForWarning(
272
- originalValue,
273
- )}`;
274
- }
275
- }
276
- return description;
277
-}
278
-
279
-export function describeDifferencesForPreinitOverStylesheet(
280
- newProps: any,
281
- currentProps: any,
282
-): string {
283
- const diff = compareResourcePropsForWarning(newProps, currentProps);
284
- if (!diff) return '';
285
-
286
- let description = '';
287
- for (const propName in diff.missing) {
288
- const propValue = diff.missing[propName];
289
- if (propName === 'precedence' && propValue !== 'default') {
290
- description += `\n "${propName}" missing from options, prop value: ${getValueDescriptorExpectingEnumForWarning(
291
- propValue,
292
- )}`;
293
- }
294
- }
295
- for (const propName in diff.extra) {
296
- const propValue = diff.extra[propName];
297
- if (
298
- propName === 'precedence' ||
299
- propName === 'crossOrigin' ||
300
- propName === 'integrity'
301
- ) {
302
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
303
- propValue,
304
- )}, missing from props`;
305
- }
306
- }
307
- for (const propName in diff.different) {
308
- const latestValue = diff.different[propName].latest;
309
- const originalValue = diff.different[propName].original;
310
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
311
- latestValue,
312
- )}, prop value: ${getValueDescriptorExpectingEnumForWarning(
313
- originalValue,
314
- )}`;
315
- }
316
- return description;
317
-}
318
-
319
-export function describeDifferencesForPreinits(
320
- newProps: any,
321
- currentProps: any,
322
-): string {
323
- const diff = compareResourcePropsForWarning(newProps, currentProps);
324
- if (!diff) return '';
325
-
326
- let description = '';
327
- for (const propName in diff.missing) {
328
- const propValue = diff.missing[propName];
329
- if (propName === 'precedence' && propValue !== 'default') {
330
- description += `\n "${propName}" missing from options, original option value: ${getValueDescriptorExpectingEnumForWarning(
331
- propValue,
332
- )}`;
333
- }
334
- }
335
- for (const propName in diff.extra) {
336
- const propValue = diff.extra[propName];
337
- if (
338
- (propName === 'precedence' && propValue !== 'default') ||
339
- propName === 'crossOrigin' ||
340
- propName === 'integrity'
341
- ) {
342
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
343
- propValue,
344
- )}, missing from original options`;
345
- }
346
- }
347
- for (const propName in diff.different) {
348
- const latestValue = diff.different[propName].latest;
349
- const originalValue = diff.different[propName].original;
350
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
351
- latestValue,
352
- )}, original option value: ${getValueDescriptorExpectingEnumForWarning(
353
- originalValue,
354
- )}`;
355
- }
356
- return description;
357
-}
358
-
359
-const preloadOptionsForComparison = ['as', 'crossOrigin', 'integrity', 'media'];
360
-
361
-export function describeDifferencesForPreloads(
362
- newProps: any,
363
- currentProps: any,
364
-): string {
365
- const diff = compareResourcePropsForWarning(newProps, currentProps);
366
- if (!diff) return '';
367
-
368
- let description = '';
369
- for (const propName in diff.missing) {
370
- const propValue = diff.missing[propName];
371
- if (preloadOptionsForComparison.includes(propName)) {
372
- description += `\n "${propName}" missing from options, original option value: ${getValueDescriptorExpectingEnumForWarning(
373
- propValue,
374
- )}`;
375
- }
376
- }
377
- for (const propName in diff.extra) {
378
- const propValue = diff.extra[propName];
379
- if (preloadOptionsForComparison.includes(propName)) {
380
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
381
- propValue,
382
- )}, missing from original options`;
383
- }
384
- }
385
- for (const propName in diff.different) {
386
- const latestValue = diff.different[propName].latest;
387
- const originalValue = diff.different[propName].original;
388
- if (preloadOptionsForComparison.includes(propName)) {
389
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
390
- latestValue,
391
- )}, original option value: ${getValueDescriptorExpectingEnumForWarning(
392
- originalValue,
393
- )}`;
394
- }
395
- }
396
- return description;
397
-}
398
-
399
-export function describeDifferencesForPreloadOverImplicitPreload(
400
- newProps: any,
401
- currentProps: any,
402
-): string {
403
- const diff = compareResourcePropsForWarning(newProps, currentProps);
404
- if (!diff) return '';
405
-
406
- let description = '';
407
- for (const propName in diff.missing) {
408
- const propValue = diff.missing[propName];
409
- if (preloadOptionsForComparison.includes(propName)) {
410
- description += `\n "${propName}" missing from options, underlying prop value: ${getValueDescriptorExpectingEnumForWarning(
411
- propValue,
412
- )}`;
413
- }
414
- }
415
- for (const propName in diff.extra) {
416
- const propValue = diff.extra[propName];
417
- if (preloadOptionsForComparison.includes(propName)) {
418
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
419
- propValue,
420
- )}, missing from underlying props`;
421
- }
422
- }
423
- for (const propName in diff.different) {
424
- const latestValue = diff.different[propName].latest;
425
- const originalValue = diff.different[propName].original;
426
- if (preloadOptionsForComparison.includes(propName)) {
427
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
428
- latestValue,
429
- )}, underlying prop value: ${getValueDescriptorExpectingEnumForWarning(
430
- originalValue,
431
- )}`;
432
- }
433
- }
434
- return description;
435
-}
436
-
437
-export function describeDifferencesForScripts(
438
- newProps: any,
439
- currentProps: any,
440
-): string {
441
- const diff = compareResourcePropsForWarning(newProps, currentProps);
442
- if (!diff) return '';
443
-
444
- let description = '';
445
-
446
- for (const propName in diff.missing) {
447
- const propValue = diff.missing[propName];
448
- description += `\n "${propName}" missing for props, original value: ${getValueDescriptorExpectingEnumForWarning(
449
- propValue,
450
- )}`;
451
- }
452
- for (const propName in diff.extra) {
453
- const propValue = diff.extra[propName];
454
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
455
- propValue,
456
- )}, missing from original props`;
457
- }
458
- for (const propName in diff.different) {
459
- const latestValue = diff.different[propName].latest;
460
- const originalValue = diff.different[propName].original;
461
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
462
- latestValue,
463
- )}, original value: ${getValueDescriptorExpectingEnumForWarning(
464
- originalValue,
465
- )}`;
466
- }
467
- return description;
468
-}
469
-
470
-export function describeDifferencesForScriptOverPreinit(
471
- newProps: any,
472
- currentProps: any,
473
-): string {
474
- const diff = compareResourcePropsForWarning(newProps, currentProps);
475
- if (!diff) return '';
476
-
477
- let description = '';
478
-
479
- for (const propName in diff.extra) {
480
- const propValue = diff.extra[propName];
481
- if (propName === 'crossOrigin' || propName === 'integrity') {
482
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
483
- propValue,
484
- )}, option missing`;
485
- } else {
486
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
487
- propValue,
488
- )}, option not available with ReactDOM.preinit()`;
489
- }
490
- }
491
- for (const propName in diff.different) {
492
- const latestValue = diff.different[propName].latest;
493
- const originalValue = diff.different[propName].original;
494
- description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
495
- latestValue,
496
- )}, option value: ${getValueDescriptorExpectingEnumForWarning(
497
- originalValue,
498
- )}`;
499
- }
500
- return description;
501
-}
502
-
503
-export function describeDifferencesForPreinitOverScript(
504
- newProps: any,
505
- currentProps: any,
506
-): string {
507
- const diff = compareResourcePropsForWarning(newProps, currentProps);
508
- if (!diff) return '';
509
-
510
- let description = '';
511
-
512
- for (const propName in diff.extra) {
513
- const propValue = diff.extra[propName];
514
- if (propName === 'crossOrigin' || propName === 'integrity') {
515
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
516
- propValue,
517
- )}, missing from props`;
518
- }
519
- }
520
- for (const propName in diff.different) {
521
- const latestValue = diff.different[propName].latest;
522
- const originalValue = diff.different[propName].original;
523
- description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
524
- latestValue,
525
- )}, prop value: ${getValueDescriptorExpectingEnumForWarning(
526
- originalValue,
527
- )}`;
528
- }
529
- return description;
530
-}
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
-262
@@ -4295,40 +4295,6 @@ body {
4295
]);
4296
});
4297
4298
- // @gate enableFloat
4299
- it('warns if you pass incompatible options to two `ReactDOM.preload(...)` with the same href', async () => {
4300
- function Component() {
4301
- ReactDOM.preload('foo', {
4302
- as: 'font',
4303
- crossOrigin: 'use-credentials',
4304
- });
4305
- ReactDOM.preload('foo', {
4306
- as: 'font',
4307
- integrity: 'some hash',
4308
- crossOrigin: 'anonymous',
4309
- });
4310
- ReactDOM.preload('foo', {
4311
- as: 'font',
4312
- extra: 'ignored',
4313
- });
4314
- }
4315
-
4316
- await expect(async () => {
4317
- await act(() => {
4318
- renderToPipeableStream(
4319
- <html>
4320
- <body>
4321
- <Component />
4322
- </body>
4323
- </html>,
4324
- );
4325
- });
4326
- }).toErrorDev([
4327
- 'Warning: ReactDOM.preload(): The options provided conflict with another call to `ReactDOM.preload("foo", { as: "font", ...})`. React will always use the options it first encounters when preloading a resource for a given `href` and `as` type, and any later options will be ignored if different. Try updating all calls to `ReactDOM.preload()` with the same `href` and `as` type to use the same options, or eliminate one of the calls.\n "integrity" option value: "some hash", missing from original options\n "crossOrigin" option value: "anonymous", original option value: "use-credentials"',
4328
- 'Warning: ReactDOM.preload(): The options provided conflict with another call to `ReactDOM.preload("foo", { as: "font", ...})`. React will always use the options it first encounters when preloading a resource for a given `href` and `as` type, and any later options will be ignored if different. Try updating all calls to `ReactDOM.preload()` with the same `href` and `as` type to use the same options, or eliminate one of the calls.\n "crossOrigin" missing from options, original option value: "use-credentials"',
4329
- ]);
4330
- });
4331
-
4298
it('supports fetchPriority', async () => {
4299
function Component({isServer}) {
4300
ReactDOM.preload(isServer ? 'highserver' : 'highclient', {
@@ -4759,122 +4725,6 @@ body {
4725
]);
4726
});
4727
4762
- // @gate enableFloat
4763
- it('warns if you pass options to `ReactDOM.preinit(..., { as: "style", ... })` incompatible with props from an existing <link rel="stylesheet" .../>', async () => {
4764
- function Component() {
4765
- ReactDOM.preinit('foo', {
4766
- as: 'style',
4767
- integrity: 'some hash',
4768
- crossOrigin: 'use-credentials',
4769
- });
4770
- }
4771
-
4772
- await expect(async () => {
4773
- await act(() => {
4774
- renderToPipeableStream(
4775
- <html>
4776
- <body>
4777
- <link
4778
- rel="stylesheet"
4779
- href="foo"
4780
- precedence="foo"
4781
- crossOrigin="anonymous"
4782
- />
4783
- <Component />
4784
- </body>
4785
- </html>,
4786
- );
4787
- });
4788
- }).toErrorDev([
4789
- 'ReactDOM.preinit(): For `href` "foo", the options provided conflict with props found on a <link rel="stylesheet" precedence="foo" href="foo" .../> that was already rendered. React will always use the props or options it first encounters for a hoistable stylesheet for a given `href` and any later props or options will be ignored if different. Generally, ReactDOM.preinit() is useful when you are not yet rendering a stylesheet but you anticipate it will be used soon. In this case the stylesheet was already rendered so preinitializing it does not provide any additional benefit. To resolve, try making the props and options agree between the <link rel="stylesheet" .../> and the `ReactDOM.preinit()` call or remove the `ReactDOM.preinit()` call.\n "precedence" missing from options, prop value: "foo"\n "integrity" option value: "some hash", missing from props\n "crossOrigin" option value: "use-credentials", prop value: "anonymous"',
4790
- ]);
4791
- });
4792
-
4793
- // @gate enableFloat
4794
- it('warns if you pass incompatible options to two `ReactDOM.preinit(..., { as: "style", ... })` with the same href', async () => {
4795
- function Component() {
4796
- ReactDOM.preinit('foo', {
4797
- as: 'style',
4798
- precedence: 'foo',
4799
- crossOrigin: 'use-credentials',
4800
- });
4801
- ReactDOM.preinit('foo', {
4802
- as: 'style',
4803
- integrity: 'some hash',
4804
- crossOrigin: 'anonymous',
4805
- });
4806
- }
4807
-
4808
- await expect(async () => {
4809
- await act(() => {
4810
- renderToPipeableStream(
4811
- <html>
4812
- <body>
4813
- <Component />
4814
- </body>
4815
- </html>,
4816
- );
4817
- });
4818
- }).toErrorDev([
4819
- 'ReactDOM.preinit(): For `href` "foo", the options provided conflict with another call to `ReactDOM.preinit("foo", { as: "style", ... })`. React will always use the options it first encounters when preinitializing a hoistable stylesheet for a given `href` and any later options will be ignored if different. Try updating all calls to `ReactDOM.preinit()` for a given `href` to use the same options, or only call `ReactDOM.preinit()` once per `href`.\n "precedence" missing from options, original option value: "foo"\n "integrity" option value: "some hash", missing from original options\n "crossOrigin" option value: "anonymous", original option value: "use-credentials"',
4820
- ]);
4821
- });
4822
-
4823
- // @gate enableFloat
4824
- it('warns if you pass options to `ReactDOM.preinit(..., { as: "script", ... })` incompatible with props from an existing <script async={true} .../>', async () => {
4825
- function Component() {
4826
- ReactDOM.preinit('foo', {
4827
- as: 'script',
4828
- integrity: 'some hash',
4829
- crossOrigin: 'use-credentials',
4830
- });
4831
- }
4832
-
4833
- await expect(async () => {
4834
- await act(() => {
4835
- renderToPipeableStream(
4836
- <html>
4837
- <body>
4838
- <script async={true} src="foo" crossOrigin="anonymous" />
4839
- <Component />
4840
- </body>
4841
- </html>,
4842
- );
4843
- });
4844
- }).toErrorDev([
4845
- 'ReactDOM.preinit(): For `href` "foo", the options provided conflict with props found on a <script async={true} src="foo" .../> that was already rendered. React will always use the props or options it first encounters for a hoistable script for a given `href` and any later props or options will be ignored if different. Generally, ReactDOM.preinit() is useful when you are not yet rendering a script but you anticipate it will be used soon and want to go beyond preloading it and have it execute early. In this case the script was already rendered so preinitializing it does not provide any additional benefit. To resolve, try making the props and options agree between the <script .../> and the `ReactDOM.preinit()` call or remove the `ReactDOM.preinit()` call.\n "integrity" option value: "some hash", missing from props\n "crossOrigin" option value: "use-credentials", prop value: "anonymous"',
4846
- ]);
4847
- });
4848
-
4849
- // @gate enableFloat
4850
- it('warns if you pass incompatible options to two `ReactDOM.preinit(..., { as: "script", ... })` with the same href', async () => {
4851
- function Component() {
4852
- ReactDOM.preinit('foo', {
4853
- as: 'script',
4854
- crossOrigin: 'use-credentials',
4855
- });
4856
- ReactDOM.preinit('foo', {
4857
- as: 'script',
4858
- integrity: 'some hash',
4859
- crossOrigin: 'anonymous',
4860
- });
4861
- }
4862
-
4863
- await expect(async () => {
4864
- await act(() => {
4865
- renderToPipeableStream(
4866
- <html>
4867
- <body>
4868
- <Component />
4869
- </body>
4870
- </html>,
4871
- );
4872
- });
4873
- }).toErrorDev([
4874
- 'ReactDOM.preinit(): For `href` "foo", the options provided conflict with another call to `ReactDOM.preinit("foo", { as: "script", ... })`. React will always use the options it first encounters when preinitializing a hoistable script for a given `href` and any later options will be ignored if different. Try updating all calls to `ReactDOM.preinit()` for a given `href` to use the same options, or only call `ReactDOM.preinit()` once per `href`.\n "integrity" option value: "some hash", missing from original options\n "crossOrigin" option value: "anonymous", original option value: "use-credentials"',
4875
- ]);
4876
- });
4877
-
4728
it('accepts a `nonce` option for `as: "script"`', async () => {
4729
function Component({src}) {
4730
ReactDOM.preinit(src, {as: 'script', nonce: 'R4nD0m'});
@@ -5892,57 +5742,6 @@ body {
5742
]);
5743
});
5744
5895
- // @gate enableFloat
5896
- it('warns if you provide different props between <link re="stylesheet" .../> and ReactDOM.preinit(..., {as: "style"}) for the same `href`', async () => {
5897
- function App() {
5898
- ReactDOM.preinit('foo', {as: 'style'});
5899
- return (
5900
- <html>
5901
- <body>
5902
- <link rel="stylesheet" href="foo" precedence="foo" media="all" />
5903
- hello
5904
- </body>
5905
- </html>
5906
- );
5907
- }
5908
- await expect(async () => {
5909
- await act(() => {
5910
- const {pipe} = renderToPipeableStream(<App />);
5911
- pipe(writable);
5912
- });
5913
- }).toErrorDev([
5914
- 'Warning: React encountered a <link rel="stylesheet" precedence="foo" href="foo" .../> with props that conflict with the options provided to `ReactDOM.preinit("foo", { as: "style", ... })`. React will use the first props or preinitialization options encountered when rendering a hoistable stylesheet with a particular `href` and will ignore any newer props or options. The first instance of this stylesheet resource was created using the `ReactDOM.preinit()` function. Please note, `ReactDOM.preinit()` is modeled off of module import assertions capabilities and does not support arbitrary props. If you need to have props not included with the preinit options you will need to rely on rendering <link> tags only.\n "media" prop value: "all", option not available with ReactDOM.preinit()\n "precedence" prop value: "foo", missing from options',
5915
- ]);
5916
- });
5917
-
5918
- // @gate enableFloat
5919
- it('warns if you provide different props between two <link re="stylesheet" .../> that share the same `href`', async () => {
5920
- function App() {
5921
- return (
5922
- <html>
5923
- <body>
5924
- <link rel="stylesheet" href="foo" precedence="foo" media="all" />
5925
- <link
5926
- rel="stylesheet"
5927
- href="foo"
5928
- precedence="bar"
5929
- data-extra="foo"
5930
- />
5931
- hello
5932
- </body>
5933
- </html>
5934
- );
5935
- }
5936
- await expect(async () => {
5937
- await act(() => {
5938
- const {pipe} = renderToPipeableStream(<App />);
5939
- pipe(writable);
5940
- });
5941
- }).toErrorDev([
5942
- 'Warning: React encountered a <link rel="stylesheet" href="foo" .../> with a `precedence` prop that has props that conflict with another hoistable stylesheet with the same `href`. When using `precedence` with <link rel="stylsheet" .../> the props from the first encountered instance will be used and props from later instances will be ignored. Update the props on either <link rel="stylesheet" .../> instance so they agree.\n "media" missing for props, original value: "all"\n "data-extra" prop value: "foo", missing from original props\n "precedence" prop value: "bar", original value: "foo"',
5943
- ]);
5944
- });
5945
-
5745
// @gate enableFloat
5746
it('will not block displaying a Suspense boundary on a stylesheet with media that does not match', async () => {
5747
await act(() => {
@@ -6720,67 +6519,6 @@ background-color: green;
6519
</div>,
6520
);
6521
});
6723
-
6724
- // @gate enableFloat
6725
- it('warns if you provide different props between <script async={true} .../> and ReactDOM.preinit(..., {as: "script"}) for the same `href`', async () => {
6726
- function App() {
6727
- ReactDOM.preinit('foo', {as: 'script', integrity: 'some hash'});
6728
- return (
6729
- <html>
6730
- <body>
6731
- <script
6732
- async={true}
6733
- src="foo"
6734
- integrity="different hash"
6735
- data-foo=""
6736
- />
6737
- hello
6738
- </body>
6739
- </html>
6740
- );
6741
- }
6742
- await expect(async () => {
6743
- await act(() => {
6744
- const {pipe} = renderToPipeableStream(<App />);
6745
- pipe(writable);
6746
- });
6747
- }).toErrorDev([
6748
- 'Warning: React encountered a <script async={true} src="foo" .../> with props that conflict with the options provided to `ReactDOM.preinit("foo", { as: "script", ... })`. React will use the first props or preinitialization options encountered when rendering a hoistable script with a particular `src` and will ignore any newer props or options. The first instance of this script resource was created using the `ReactDOM.preinit()` function. Please note, `ReactDOM.preinit()` is modeled off of module import assertions capabilities and does not support arbitrary props. If you need to have props not included with the preinit options you will need to rely on rendering <script> tags only.\n "data-foo" prop value: an empty string, option not available with ReactDOM.preinit()\n "integrity" prop value: "different hash", option value: "some hash"',
6749
- ]);
6750
- });
6751
-
6752
- // @gate enableFloat
6753
- it('warns if you provide different props between two <script async={true} .../> that share the same `src`', async () => {
6754
- function App() {
6755
- return (
6756
- <html>
6757
- <body>
6758
- <script
6759
- async={true}
6760
- src="foo"
6761
- integrity="some hash"
6762
- data-foo=""
6763
- />
6764
- <script
6765
- async={true}
6766
- src="foo"
6767
- integrity="different hash"
6768
- data-bar=""
6769
- />
6770
- hello
6771
- </body>
6772
- </html>
6773
- );
6774
- }
6775
- await expect(async () => {
6776
- await act(() => {
6777
- const {pipe} = renderToPipeableStream(<App />);
6778
- pipe(writable);
6779
- });
6780
- }).toErrorDev([
6781
- 'React encountered a <script async={true} src="foo" .../> that has props that conflict with another hoistable script with the same `src`. When rendering hoistable scripts (async scripts without any loading handlers) the props from the first encountered instance will be used and props from later instances will be ignored. Update the props on both <script async={true} .../> instance so they agree.\n "data-foo" missing for props, original value: an empty string\n "data-bar" prop value: an empty string, missing from original props\n "integrity" prop value: "different hash", original value: "some hash"',
6782
- ]);
6783
- });
6522
});
6523
6524
describe('Hoistables', () => {