@@ -34,6 +34,8 @@ import {
34
34
getHostContext ,
35
35
} from 'react-reconciler/src/ReactFiberHostContext' ;
36
36
import { getResourceFormOnly } from './validateDOMNesting' ;
37
+ import { getNamespace } from './ReactDOMHostConfig' ;
38
+ import { SVG_NAMESPACE } from '../shared/DOMNamespaces' ;
37
39
38
40
// The resource types we support. currently they match the form for the as argument.
39
41
// In the future this may need to change, especially when modules / scripts are supported
@@ -201,6 +203,28 @@ function getCurrentResourceRoot(): null | FloatRoot {
201
203
return currentContainer ? currentContainer . getRootNode ( ) : null ;
202
204
}
203
205
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
+
204
228
// Preloads are somewhat special. Even if we don't have the Document
205
229
// used by the root that is rendering a component trying to insert a preload
206
230
// 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 {
1077
1101
props ,
1078
1102
root ,
1079
1103
) ;
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
+ ) ;
1081
1112
break ;
1082
1113
}
1083
1114
case 'meta' : {
@@ -1397,16 +1428,21 @@ function insertResourceInstanceBefore(
1397
1428
1398
1429
export function isHostResourceType ( type : string , props : Props ) : boolean {
1399
1430
let resourceFormOnly : boolean ;
1431
+ let namespace : string ;
1400
1432
if ( __DEV__ ) {
1401
1433
const hostContext = getHostContext ( ) ;
1402
1434
resourceFormOnly = getResourceFormOnly ( hostContext ) ;
1435
+ namespace = getNamespace ( hostContext ) ;
1403
1436
}
1404
1437
switch ( type ) {
1405
1438
case 'base ':
1406
- case 'meta':
1407
- case 'title ': {
1439
+ case 'meta': {
1408
1440
return true ;
1409
1441
}
1442
+ case 'title ': {
1443
+ const hostContext = getHostContext ( ) ;
1444
+ return getNamespace ( hostContext ) !== SVG_NAMESPACE ;
1445
+ }
1410
1446
case 'link' : {
1411
1447
const { onLoad , onError } = props ;
1412
1448
if ( onLoad || onError ) {
@@ -1417,6 +1453,11 @@ export function isHostResourceType(type: string, props: Props): boolean {
1417
1453
' Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or' +
1418
1454
' somewhere in the <body>.' ,
1419
1455
) ;
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
+ ) ;
1420
1461
}
1421
1462
}
1422
1463
return false ;
@@ -1426,11 +1467,18 @@ export function isHostResourceType(type: string, props: Props): boolean {
1426
1467
const { href , precedence , disabled } = props ;
1427
1468
if ( __DEV__ ) {
1428
1469
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
+ }
1434
1482
}
1435
1483
}
1436
1484
return (
@@ -1450,17 +1498,31 @@ export function isHostResourceType(type: string, props: Props): boolean {
1450
1498
// precedence with these for style resources
1451
1499
const { src , async , onLoad , onError } = props ;
1452
1500
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
+ }
1464
1526
}
1465
1527
}
1466
1528
return ( async : any ) && typeof src === 'string' && ! onLoad && ! onError ;
0 commit comments