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.
This commit is contained in:
Josh Story
2023-08-14 10:08:55 -07:00
committed by GitHub
parent 5ad8ef5772
commit 5ea1397b2b
3 changed files with 0 additions and 1058 deletions
@@ -79,15 +79,6 @@ import {
import {
getValueDescriptorExpectingObjectForWarning,
getValueDescriptorExpectingEnumForWarning,
describeDifferencesForStylesheets,
describeDifferencesForStylesheetOverPreinit,
describeDifferencesForScripts,
describeDifferencesForScriptOverPreinit,
describeDifferencesForPreinits,
describeDifferencesForPreinitOverStylesheet,
describeDifferencesForPreinitOverScript,
describeDifferencesForPreloads,
describeDifferencesForPreloadOverImplicitPreload,
} from '../shared/ReactDOMResourceValidation';
import {NotPending} from '../shared/ReactDOMFormActions';
@@ -2004,55 +1995,6 @@ function pushLink(
} else {
// This stylesheet refers to a Resource and we create a new one if necessary
let resource = resources.stylesMap.get(key);
if (__DEV__) {
const devResource = getAsResourceDEV(resource);
if (devResource) {
switch (devResource.__provenance) {
case 'rendered': {
const differenceDescription = describeDifferencesForStylesheets(
// Diff the props from the JSX element, not the derived resource props
props,
devResource.__originalProps,
);
if (differenceDescription) {
console.error(
'React encountered a <link rel="stylesheet" href="%s" .../> 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.%s',
href,
differenceDescription,
);
}
break;
}
case 'preinit': {
const differenceDescription =
describeDifferencesForStylesheetOverPreinit(
// Diff the props from the JSX element, not the derived resource props
props,
devResource.__propsEquivalent,
);
if (differenceDescription) {
console.error(
'React encountered a <link rel="stylesheet" precedence="%s" href="%s" .../> with props that conflict' +
' with the options provided to `ReactDOM.preinit("%s", { 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.%s',
precedence,
href,
href,
differenceDescription,
);
}
break;
}
}
}
}
if (!resource) {
const resourceProps = stylesheetPropsFromRawProps(props);
const preloadResource = resources.preloadsMap.get(key);
@@ -2076,9 +2018,6 @@ function pushLink(
props: resourceProps,
};
resources.stylesMap.set(key, resource);
if (__DEV__) {
markAsRenderedResourceDEV(resource, props);
}
let precedenceSet = resources.precedences.get(precedence);
if (!precedenceSet) {
precedenceSet = new Set();
@@ -2443,9 +2382,6 @@ function pushImg(
},
};
resources.preloadsMap.set(key, resource);
if (__DEV__) {
markAsRenderedResourceDEV(resource, props);
}
pushLinkImpl(resource.chunks, resource.props);
}
if (
@@ -2790,54 +2726,6 @@ function pushScript(
const key = getResourceKey('script', src);
// We can make this <script> into a ScriptResource
let resource = resources.scriptsMap.get(key);
if (__DEV__) {
const devResource = getAsResourceDEV(resource);
if (devResource) {
switch (devResource.__provenance) {
case 'rendered': {
const differenceDescription = describeDifferencesForScripts(
// Diff the props from the JSX element, not the derived resource props
props,
devResource.__originalProps,
);
if (differenceDescription) {
console.error(
'React encountered a <script async={true} src="%s" .../> 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.%s',
src,
differenceDescription,
);
}
break;
}
case 'preinit': {
const differenceDescription =
describeDifferencesForScriptOverPreinit(
// Diff the props from the JSX element, not the derived resource props
props,
devResource.__propsEquivalent,
);
if (differenceDescription) {
console.error(
'React encountered a <script async={true} src="%s" .../> with props that conflict' +
' with the options provided to `ReactDOM.preinit("%s", { 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.%s',
src,
src,
differenceDescription,
);
}
break;
}
}
}
}
if (!resource) {
resource = {
type: 'script',
@@ -2846,9 +2734,6 @@ function pushScript(
props: null,
};
resources.scriptsMap.set(key, resource);
if (__DEV__) {
markAsRenderedResourceDEV(resource, props);
}
// Add to the script flushing queue
resources.scripts.add(resource);
@@ -4874,30 +4759,6 @@ type TResource<
state: ResourceStateTag,
props: P,
};
// Dev extensions.
// Stylesheets and Scripts rendered with jsx
type RenderedResourceDEV = {
__provenance: 'rendered',
__originalProps: any,
};
// Preloads, Stylesheets, and Scripts from ReactDOM.preload or ReactDOM.preinit
type ImperativeResourceDEV = {
__provenance: 'preload' | 'preinit',
__originalHref: string,
__originalOptions: any,
__propsEquivalent: any,
};
// Preloads created for normal components we rendered but know we can preload early such as
// sync Scripts and stylesheets without precedence or with onLoad/onError handlers
type ImplicitResourceDEV = {
__provenance: 'implicit',
__underlyingProps: any,
__impliedProps: any,
};
type ResourceDEV =
| RenderedResourceDEV
| ImperativeResourceDEV
| ImplicitResourceDEV;
type PreconnectProps = {
rel: 'preconnect' | 'dns-prefetch',
@@ -5193,61 +5054,6 @@ function preload(href: string, options: PreloadOptions) {
key = getResourceKey(as, href);
}
let resource = resources.preloadsMap.get(key);
if (__DEV__) {
const devResource = getAsResourceDEV(resource);
if (devResource) {
switch (devResource.__provenance) {
case 'preload': {
const differenceDescription = describeDifferencesForPreloads(
options,
devResource.__originalOptions,
);
if (differenceDescription) {
console.error(
'ReactDOM.preload(): The options provided conflict with another call to `ReactDOM.preload("%s", { as: "%s", ...})`.' +
' 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.%s',
href,
as,
differenceDescription,
);
}
break;
}
case 'implicit': {
const differenceDescription =
describeDifferencesForPreloadOverImplicitPreload(
options,
devResource.__impliedProps,
);
if (differenceDescription) {
const elementDescription =
as === 'style'
? '<link rel="stylesheet" ... />'
: as === 'script'
? '<script ... />'
: null;
if (elementDescription) {
console.error(
'ReactDOM.preload(): For `href` "%s", The options provided conflict with props on a matching %s element. When the preload' +
' options disagree with the underlying resource it usually means the browser will not be able to use the preload when the resource' +
' is fetched, negating any benefit the preload would provide. React will preload the resource using props derived from the resource instead' +
' and ignore the options provided to the `ReactDOM.preload()` call. In general, preloading is useful when you expect to' +
' render a resource soon but have not yet done so. In this case since the underlying resource was already rendered the preload call' +
' may be extraneous. Try removing the call, otherwise try adjusting both the props on the %s and the options' +
' passed to `ReactDOM.preload()` to agree.%s',
href,
elementDescription,
elementDescription,
differenceDescription,
);
}
}
break;
}
}
}
}
if (!resource) {
resource = {
type: 'preload',
@@ -5256,16 +5062,6 @@ function preload(href: string, options: PreloadOptions) {
props: preloadPropsFromPreloadOptions(href, as, options),
};
resources.preloadsMap.set(key, resource);
if (__DEV__) {
markAsImperativeResourceDEV(
resource,
'preload',
href,
options,
resource.props,
);
}
pushLinkImpl(resource.chunks, resource.props);
}
if (as === 'font') {
@@ -5323,64 +5119,6 @@ function preinit(href: string, options: PreinitOptions): void {
const key = getResourceKey(as, href);
let resource = resources.stylesMap.get(key);
const precedence = options.precedence || 'default';
if (__DEV__) {
const devResource = getAsResourceDEV(resource);
if (devResource) {
const resourceProps = stylesheetPropsFromPreinitOptions(
href,
precedence,
options,
);
const propsEquivalent = {
...resourceProps,
precedence: options.precedence,
['data-precedence']: null,
};
switch (devResource.__provenance) {
case 'rendered': {
const differenceDescription =
describeDifferencesForPreinitOverStylesheet(
// Diff the props from the JSX element, not the derived resource props
propsEquivalent,
devResource.__originalProps,
);
if (differenceDescription) {
console.error(
'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.' +
' 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.%s',
href,
devResource.__originalProps.precedence,
href,
differenceDescription,
);
}
break;
}
case 'preinit': {
const differenceDescription = describeDifferencesForPreinits(
// Diff the props from the JSX element, not the derived resource props
propsEquivalent,
devResource.__propsEquivalent,
);
if (differenceDescription) {
console.error(
'ReactDOM.preinit(): For `href` "%s", the options provided conflict with another call to `ReactDOM.preinit("%s", { 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`.%s',
href,
href,
differenceDescription,
);
}
break;
}
}
}
}
if (!resource) {
let state = NoState;
const preloadResource = resources.preloadsMap.get(key);
@@ -5394,13 +5132,6 @@ function preinit(href: string, options: PreinitOptions): void {
props: stylesheetPropsFromPreinitOptions(href, precedence, options),
};
resources.stylesMap.set(key, resource);
if (__DEV__) {
markAsImperativeResourceDEV(resource, 'preinit', href, options, {
...resource.props,
precedence,
['data-precedence']: undefined,
});
}
let precedenceSet = resources.precedences.get(precedence);
if (!precedenceSet) {
precedenceSet = new Set();
@@ -5434,53 +5165,6 @@ function preinit(href: string, options: PreinitOptions): void {
const src = href;
const key = getResourceKey(as, src);
let resource = resources.scriptsMap.get(key);
if (__DEV__) {
const devResource = getAsResourceDEV(resource);
if (devResource) {
const propsEquivalent = scriptPropsFromPreinitOptions(src, options);
switch (devResource.__provenance) {
case 'rendered': {
const differenceDescription =
describeDifferencesForPreinitOverScript(
// Diff the props from the JSX element, not the derived resource props
propsEquivalent,
devResource.__originalProps,
);
if (differenceDescription) {
console.error(
'ReactDOM.preinit(): For `href` "%s", the options provided conflict with props found on a <script async={true} src="%s" .../> 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.%s',
href,
href,
differenceDescription,
);
}
break;
}
case 'preinit': {
const differenceDescription = describeDifferencesForPreinits(
// Diff the props from the JSX element, not the derived resource props
propsEquivalent,
devResource.__propsEquivalent,
);
if (differenceDescription) {
console.error(
'ReactDOM.preinit(): For `href` "%s", the options provided conflict with another call to `ReactDOM.preinit("%s", { 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`.%s',
href,
href,
differenceDescription,
);
}
break;
}
}
}
}
if (!resource) {
resource = {
type: 'script',
@@ -5490,15 +5174,6 @@ function preinit(href: string, options: PreinitOptions): void {
};
resources.scriptsMap.set(key, resource);
const resourceProps = scriptPropsFromPreinitOptions(src, options);
if (__DEV__) {
markAsImperativeResourceDEV(
resource,
'preinit',
href,
options,
resourceProps,
);
}
resources.scripts.add(resource);
pushScriptImpl(resource.chunks, resourceProps);
flushResources(request);
@@ -5724,73 +5399,5 @@ export function hoistResources(
}
}
function markAsRenderedResourceDEV(
resource: Resource,
originalProps: any,
): void {
if (__DEV__) {
const devResource: RenderedResourceDEV = (resource: any);
if (typeof devResource.__provenance === 'string') {
console.error(
'Resource already marked for DEV type. This is a bug in React.',
);
}
devResource.__provenance = 'rendered';
devResource.__originalProps = originalProps;
} else {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'markAsRenderedResourceDEV was included in a production build. This is a bug in React.',
);
}
}
function markAsImperativeResourceDEV(
resource: Resource,
provenance: 'preload' | 'preinit',
originalHref: string,
originalOptions: any,
propsEquivalent: any,
): void {
if (__DEV__) {
const devResource: ImperativeResourceDEV = (resource: any);
if (typeof devResource.__provenance === 'string') {
console.error(
'Resource already marked for DEV type. This is a bug in React.',
);
}
devResource.__provenance = provenance;
devResource.__originalHref = originalHref;
devResource.__originalOptions = originalOptions;
devResource.__propsEquivalent = propsEquivalent;
} else {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'markAsImperativeResourceDEV was included in a production build. This is a bug in React.',
);
}
}
function getAsResourceDEV(
resource: null | void | Resource,
): null | ResourceDEV {
if (__DEV__) {
if (resource) {
if (typeof (resource: any).__provenance === 'string') {
return (resource: any);
}
console.error(
'Resource was not marked for DEV type. This is a bug in React.',
);
}
return null;
} else {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'getAsResourceDEV was included in a production build. This is a bug in React.',
);
}
}
export type TransitionStatus = FormStatus;
export const NotPendingTransition: TransitionStatus = NotPending;
@@ -125,406 +125,3 @@ export function getValueDescriptorExpectingEnumForWarning(thing: any): string {
? JSON.stringify(thing)
: `something with type "${typeof thing}"`;
}
type PropDifferences = {
missing: {
[string]: any,
},
extra: {
[string]: any,
},
different: {
[string]: {
original: any,
latest: any,
},
},
};
function compareResourcePropsForWarning(
newProps: any,
currentProps: any,
): null | PropDifferences {
if (__DEV__) {
let propDiffs: null | PropDifferences = null;
const allProps = Array.from(
new Set(Object.keys(currentProps).concat(Object.keys(newProps))),
);
for (let i = 0; i < allProps.length; i++) {
const propName = allProps[i];
const newValue = newProps[propName];
const currentValue = currentProps[propName];
if (
newValue !== currentValue &&
!(newValue == null && currentValue == null)
) {
if (newValue == null) {
if (propDiffs === null) {
propDiffs = ({
missing: {},
extra: {},
different: {},
}: PropDifferences);
}
propDiffs.missing[propName] = currentValue;
} else if (currentValue == null) {
if (propDiffs === null) {
propDiffs = ({
missing: {},
extra: {},
different: {},
}: PropDifferences);
}
propDiffs.extra[propName] = newValue;
} else {
if (propDiffs === null) {
propDiffs = ({
missing: {},
extra: {},
different: {},
}: PropDifferences);
}
propDiffs.different[propName] = {
original: currentValue,
latest: newValue,
};
}
}
}
return propDiffs;
}
return null;
}
export function describeDifferencesForStylesheets(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
if (propName === 'media') {
description += `\n "${propName}" missing for props, original value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from original props`;
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, original value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
export function describeDifferencesForStylesheetOverPreinit(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (
propName === 'precedence' ||
propName === 'crossOrigin' ||
propName === 'integrity'
) {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, option missing`;
} else {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, option not available with ReactDOM.preinit()`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
if (propName === 'precedence' && originalValue === 'default') {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, missing from options`;
} else {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, option value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
}
return description;
}
export function describeDifferencesForPreinitOverStylesheet(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
if (propName === 'precedence' && propValue !== 'default') {
description += `\n "${propName}" missing from options, prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (
propName === 'precedence' ||
propName === 'crossOrigin' ||
propName === 'integrity'
) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from props`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, prop value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
export function describeDifferencesForPreinits(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
if (propName === 'precedence' && propValue !== 'default') {
description += `\n "${propName}" missing from options, original option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (
(propName === 'precedence' && propValue !== 'default') ||
propName === 'crossOrigin' ||
propName === 'integrity'
) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from original options`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, original option value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
const preloadOptionsForComparison = ['as', 'crossOrigin', 'integrity', 'media'];
export function describeDifferencesForPreloads(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" missing from options, original option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from original options`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, original option value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
}
return description;
}
export function describeDifferencesForPreloadOverImplicitPreload(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" missing from options, underlying prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from underlying props`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
if (preloadOptionsForComparison.includes(propName)) {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, underlying prop value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
}
return description;
}
export function describeDifferencesForScripts(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.missing) {
const propValue = diff.missing[propName];
description += `\n "${propName}" missing for props, original value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}`;
}
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from original props`;
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, original value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
export function describeDifferencesForScriptOverPreinit(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (propName === 'crossOrigin' || propName === 'integrity') {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, option missing`;
} else {
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, option not available with ReactDOM.preinit()`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" prop value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, option value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
export function describeDifferencesForPreinitOverScript(
newProps: any,
currentProps: any,
): string {
const diff = compareResourcePropsForWarning(newProps, currentProps);
if (!diff) return '';
let description = '';
for (const propName in diff.extra) {
const propValue = diff.extra[propName];
if (propName === 'crossOrigin' || propName === 'integrity') {
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
propValue,
)}, missing from props`;
}
}
for (const propName in diff.different) {
const latestValue = diff.different[propName].latest;
const originalValue = diff.different[propName].original;
description += `\n "${propName}" option value: ${getValueDescriptorExpectingEnumForWarning(
latestValue,
)}, prop value: ${getValueDescriptorExpectingEnumForWarning(
originalValue,
)}`;
}
return description;
}
-262
View File
@@ -4295,40 +4295,6 @@ body {
]);
});
// @gate enableFloat
it('warns if you pass incompatible options to two `ReactDOM.preload(...)` with the same href', async () => {
function Component() {
ReactDOM.preload('foo', {
as: 'font',
crossOrigin: 'use-credentials',
});
ReactDOM.preload('foo', {
as: 'font',
integrity: 'some hash',
crossOrigin: 'anonymous',
});
ReactDOM.preload('foo', {
as: 'font',
extra: 'ignored',
});
}
await expect(async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<Component />
</body>
</html>,
);
});
}).toErrorDev([
'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"',
'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"',
]);
});
it('supports fetchPriority', async () => {
function Component({isServer}) {
ReactDOM.preload(isServer ? 'highserver' : 'highclient', {
@@ -4759,122 +4725,6 @@ body {
]);
});
// @gate enableFloat
it('warns if you pass options to `ReactDOM.preinit(..., { as: "style", ... })` incompatible with props from an existing <link rel="stylesheet" .../>', async () => {
function Component() {
ReactDOM.preinit('foo', {
as: 'style',
integrity: 'some hash',
crossOrigin: 'use-credentials',
});
}
await expect(async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<link
rel="stylesheet"
href="foo"
precedence="foo"
crossOrigin="anonymous"
/>
<Component />
</body>
</html>,
);
});
}).toErrorDev([
'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"',
]);
});
// @gate enableFloat
it('warns if you pass incompatible options to two `ReactDOM.preinit(..., { as: "style", ... })` with the same href', async () => {
function Component() {
ReactDOM.preinit('foo', {
as: 'style',
precedence: 'foo',
crossOrigin: 'use-credentials',
});
ReactDOM.preinit('foo', {
as: 'style',
integrity: 'some hash',
crossOrigin: 'anonymous',
});
}
await expect(async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<Component />
</body>
</html>,
);
});
}).toErrorDev([
'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"',
]);
});
// @gate enableFloat
it('warns if you pass options to `ReactDOM.preinit(..., { as: "script", ... })` incompatible with props from an existing <script async={true} .../>', async () => {
function Component() {
ReactDOM.preinit('foo', {
as: 'script',
integrity: 'some hash',
crossOrigin: 'use-credentials',
});
}
await expect(async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<script async={true} src="foo" crossOrigin="anonymous" />
<Component />
</body>
</html>,
);
});
}).toErrorDev([
'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"',
]);
});
// @gate enableFloat
it('warns if you pass incompatible options to two `ReactDOM.preinit(..., { as: "script", ... })` with the same href', async () => {
function Component() {
ReactDOM.preinit('foo', {
as: 'script',
crossOrigin: 'use-credentials',
});
ReactDOM.preinit('foo', {
as: 'script',
integrity: 'some hash',
crossOrigin: 'anonymous',
});
}
await expect(async () => {
await act(() => {
renderToPipeableStream(
<html>
<body>
<Component />
</body>
</html>,
);
});
}).toErrorDev([
'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"',
]);
});
it('accepts a `nonce` option for `as: "script"`', async () => {
function Component({src}) {
ReactDOM.preinit(src, {as: 'script', nonce: 'R4nD0m'});
@@ -5892,57 +5742,6 @@ body {
]);
});
// @gate enableFloat
it('warns if you provide different props between <link re="stylesheet" .../> and ReactDOM.preinit(..., {as: "style"}) for the same `href`', async () => {
function App() {
ReactDOM.preinit('foo', {as: 'style'});
return (
<html>
<body>
<link rel="stylesheet" href="foo" precedence="foo" media="all" />
hello
</body>
</html>
);
}
await expect(async () => {
await act(() => {
const {pipe} = renderToPipeableStream(<App />);
pipe(writable);
});
}).toErrorDev([
'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',
]);
});
// @gate enableFloat
it('warns if you provide different props between two <link re="stylesheet" .../> that share the same `href`', async () => {
function App() {
return (
<html>
<body>
<link rel="stylesheet" href="foo" precedence="foo" media="all" />
<link
rel="stylesheet"
href="foo"
precedence="bar"
data-extra="foo"
/>
hello
</body>
</html>
);
}
await expect(async () => {
await act(() => {
const {pipe} = renderToPipeableStream(<App />);
pipe(writable);
});
}).toErrorDev([
'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"',
]);
});
// @gate enableFloat
it('will not block displaying a Suspense boundary on a stylesheet with media that does not match', async () => {
await act(() => {
@@ -6720,67 +6519,6 @@ background-color: green;
</div>,
);
});
// @gate enableFloat
it('warns if you provide different props between <script async={true} .../> and ReactDOM.preinit(..., {as: "script"}) for the same `href`', async () => {
function App() {
ReactDOM.preinit('foo', {as: 'script', integrity: 'some hash'});
return (
<html>
<body>
<script
async={true}
src="foo"
integrity="different hash"
data-foo=""
/>
hello
</body>
</html>
);
}
await expect(async () => {
await act(() => {
const {pipe} = renderToPipeableStream(<App />);
pipe(writable);
});
}).toErrorDev([
'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"',
]);
});
// @gate enableFloat
it('warns if you provide different props between two <script async={true} .../> that share the same `src`', async () => {
function App() {
return (
<html>
<body>
<script
async={true}
src="foo"
integrity="some hash"
data-foo=""
/>
<script
async={true}
src="foo"
integrity="different hash"
data-bar=""
/>
hello
</body>
</html>
);
}
await expect(async () => {
await act(() => {
const {pipe} = renderToPipeableStream(<App />);
pipe(writable);
});
}).toErrorDev([
'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"',
]);
});
});
describe('Hoistables', () => {