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';
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);
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();
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 (
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',
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
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',
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',
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') {
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);
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();
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',
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);
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;