@@ -34,6 +34,8 @@ import {
3434 getHostContext ,
3535} from 'react-reconciler/src/ReactFiberHostContext' ;
3636import { getResourceFormOnly } from './validateDOMNesting' ;
37+ import { getNamespace } from './ReactDOMHostConfig' ;
38+ import { SVG_NAMESPACE } from '../shared/DOMNamespaces' ;
3739
3840// The resource types we support. currently they match the form for the as argument.
3941// In the future this may need to change, especially when modules / scripts are supported
@@ -201,6 +203,28 @@ function getCurrentResourceRoot(): null | FloatRoot {
201203 return currentContainer ? currentContainer . getRootNode ( ) : null ;
202204}
203205
206+ // This resource type constraint can be loosened. It really is everything except PreloadResource
207+ // because that is the only one that does not have an optional instance type. Expand as needed.
208+ function resetInstance ( resource : ScriptResource | HeadResource ) {
209+ resource . instance = undefined ;
210+ }
211+
212+ export function clearRootResources ( rootContainer : Container ) : void {
213+ const rootNode : FloatRoot = ( rootContainer . getRootNode ( ) : any ) ;
214+ const resources = getResourcesFromRoot ( rootNode ) ;
215+
216+ // We can't actually delete the resource cache because this function is called
217+ // during commit after we have rendered. Instead we detatch any instances from
218+ // the Resource object if they are going to be cleared
219+
220+ // Styles stay put
221+ // Scripts get reset
222+ resources . scripts . forEach ( resetInstance ) ;
223+ // Head Resources get reset
224+ resources . head . forEach ( resetInstance ) ;
225+ // lastStructuredMeta stays put
226+ }
227+
204228// Preloads are somewhat special. Even if we don't have the Document
205229// used by the root that is rendering a component trying to insert a preload
206230// we can still seed the file cache by doing the preload on any document we have
@@ -1077,7 +1101,14 @@ function acquireHeadResource(resource: HeadResource): Instance {
10771101 props ,
10781102 root ,
10791103 ) ;
1080- insertResourceInstanceBefore ( root , instance , titles . item ( 0 ) ) ;
1104+ const firstTitle = titles [ 0 ] ;
1105+ insertResourceInstanceBefore (
1106+ root ,
1107+ instance ,
1108+ firstTitle && firstTitle . namespaceURI !== SVG_NAMESPACE
1109+ ? firstTitle
1110+ : null ,
1111+ ) ;
10811112 break ;
10821113 }
10831114 case 'meta' : {
@@ -1397,16 +1428,21 @@ function insertResourceInstanceBefore(
13971428
13981429export function isHostResourceType ( type : string , props : Props ) : boolean {
13991430 let resourceFormOnly : boolean ;
1431+ let namespace : string ;
14001432 if ( __DEV__ ) {
14011433 const hostContext = getHostContext ( ) ;
14021434 resourceFormOnly = getResourceFormOnly ( hostContext ) ;
1435+ namespace = getNamespace ( hostContext ) ;
14031436 }
14041437 switch ( type ) {
14051438 case 'base ':
1406- case 'meta':
1407- case 'title ': {
1439+ case 'meta': {
14081440 return true ;
14091441 }
1442+ case 'title ': {
1443+ const hostContext = getHostContext ( ) ;
1444+ return getNamespace ( hostContext ) !== SVG_NAMESPACE ;
1445+ }
14101446 case 'link' : {
14111447 const { onLoad , onError } = props ;
14121448 if ( onLoad || onError ) {
@@ -1417,6 +1453,11 @@ export function isHostResourceType(type: string, props: Props): boolean {
14171453 ' Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or' +
14181454 ' somewhere in the <body>.' ,
14191455 ) ;
1456+ } else if ( namespace === SVG_NAMESPACE ) {
1457+ console . error (
1458+ 'Cannot render a <link> with onLoad or onError listeners as a descendent of <svg>.' +
1459+ ' Try removing onLoad={...} and onError={...} or moving it above the <svg> ancestor.' ,
1460+ ) ;
14201461 }
14211462 }
14221463 return false ;
@@ -1426,11 +1467,18 @@ export function isHostResourceType(type: string, props: Props): boolean {
14261467 const { href , precedence , disabled } = props ;
14271468 if ( __DEV__ ) {
14281469 validateLinkPropsForStyleResource ( props ) ;
1429- if ( typeof precedence !== 'string' && resourceFormOnly ) {
1430- console . error (
1431- 'Cannot render a <link rel="stylesheet" /> outside the main document without knowing its precedence.' +
1432- ' Consider adding precedence="default" or moving it into the root <head> tag.' ,
1433- ) ;
1470+ if ( typeof precedence !== 'string' ) {
1471+ if ( resourceFormOnly ) {
1472+ console . error (
1473+ 'Cannot render a <link rel="stylesheet" /> outside the main document without knowing its precedence.' +
1474+ ' Consider adding precedence="default" or moving it into the root <head> tag.' ,
1475+ ) ;
1476+ } else if ( namespace === SVG_NAMESPACE ) {
1477+ console . error (
1478+ 'Cannot render a <link rel="stylesheet" /> as a descendent of an <svg> element without knowing its precedence.' +
1479+ ' Consider adding precedence="default" or moving it above the <svg> ancestor.' ,
1480+ ) ;
1481+ }
14341482 }
14351483 }
14361484 return (
@@ -1450,17 +1498,31 @@ export function isHostResourceType(type: string, props: Props): boolean {
14501498 // precedence with these for style resources
14511499 const { src , async , onLoad , onError } = props ;
14521500 if ( __DEV__ ) {
1453- if ( async !== true && resourceFormOnly ) {
1454- console . error (
1455- 'Cannot render a sync or defer <script> outside the main document without knowing its order.' +
1456- ' Try adding async="" or moving it into the root <head> tag.' ,
1457- ) ;
1458- } else if ( ( onLoad || onError ) && resourceFormOnly ) {
1459- console . error (
1460- 'Cannot render a <script> with onLoad or onError listeners outside the main document.' +
1461- ' Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or' +
1462- ' somewhere in the <body>.' ,
1463- ) ;
1501+ if ( async !== true ) {
1502+ if ( resourceFormOnly ) {
1503+ console . error (
1504+ 'Cannot render a sync or defer <script> outside the main document without knowing its order.' +
1505+ ' Try adding async="" or moving it into the root <head> tag.' ,
1506+ ) ;
1507+ } else if ( namespace === SVG_NAMESPACE ) {
1508+ console . error (
1509+ 'Cannot render a sync or defer <script> as a descendent of an <svg> element.' +
1510+ ' Try adding async="" or moving it above the ancestor <svg> element.' ,
1511+ ) ;
1512+ }
1513+ } else if ( onLoad || onError ) {
1514+ if ( resourceFormOnly ) {
1515+ console . error (
1516+ 'Cannot render a <script> with onLoad or onError listeners outside the main document.' +
1517+ ' Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or' +
1518+ ' somewhere in the <body>.' ,
1519+ ) ;
1520+ } else if ( namespace === SVG_NAMESPACE ) {
1521+ console . error (
1522+ 'Cannot render a <script> with onLoad or onError listeners as a descendent of an <svg> element.' +
1523+ ' Try removing onLoad={...} and onError={...} or moving it above the ancestor <svg> element.' ,
1524+ ) ;
1525+ }
14641526 }
14651527 }
14661528 return ( async : any ) && typeof src === 'string' && ! onLoad && ! onError ;
0 commit comments