77 */
88
99import { DOCUMENT } from '@angular/common' ;
10- import { Inject , Injectable , OnDestroy } from '@angular/core' ;
10+ import { APP_ID , Inject , Injectable , OnDestroy } from '@angular/core' ;
1111
1212@Injectable ( )
1313export class SharedStylesHost implements OnDestroy {
@@ -69,9 +69,12 @@ export class DomSharedStylesHost extends SharedStylesHost implements OnDestroy {
6969 // Maps all registered host nodes to a list of style nodes that have been added to the host node.
7070 private readonly styleRef = new Map < string , HTMLStyleElement [ ] > ( ) ;
7171 private hostNodes = new Set < Node > ( ) ;
72+ private styleNodesInDOM : Map < string , HTMLStyleElement > | null ;
7273
73- constructor ( @Inject ( DOCUMENT ) private readonly doc : any ) {
74+ constructor (
75+ @Inject ( DOCUMENT ) private readonly doc : Document , @Inject ( APP_ID ) private appId : string ) {
7476 super ( ) ;
77+ this . styleNodesInDOM = this . collectServerRenderedStyles ( ) ;
7578 this . resetHostNodes ( ) ;
7679 }
7780
@@ -84,14 +87,20 @@ export class DomSharedStylesHost extends SharedStylesHost implements OnDestroy {
8487 override onStyleRemoved ( style : string ) : void {
8588 const styleRef = this . styleRef ;
8689 const styleElements = styleRef . get ( style ) ;
87- styleElements ?. forEach ( e => e . remove ( ) ) ;
90+ styleElements ?. forEach ( node => node . remove ( ) ) ;
8891 styleRef . delete ( style ) ;
8992 }
9093
9194 override ngOnDestroy ( ) : void {
9295 super . ngOnDestroy ( ) ;
9396 this . styleRef . clear ( ) ;
9497 this . resetHostNodes ( ) ;
98+
99+ const styleNodesInDOM = this . styleNodesInDOM ;
100+ if ( styleNodesInDOM ) {
101+ styleNodesInDOM . forEach ( node => node . remove ( ) ) ;
102+ styleNodesInDOM . clear ( ) ;
103+ }
95104 }
96105
97106 addHost ( hostNode : Node ) : void {
@@ -106,16 +115,58 @@ export class DomSharedStylesHost extends SharedStylesHost implements OnDestroy {
106115 this . hostNodes . delete ( hostNode ) ;
107116 }
108117
118+ private collectServerRenderedStyles ( ) : Map < string , HTMLStyleElement > | null {
119+ const styles =
120+ this . doc . head ?. querySelectorAll < HTMLStyleElement > ( `style[ng-app="${ this . appId } "]` ) ;
121+
122+ if ( styles ?. length ) {
123+ const styleMap = new Map < string , HTMLStyleElement > ( ) ;
124+
125+ styles . forEach ( style => {
126+ if ( style . textContent != null ) {
127+ styleMap . set ( style . textContent , style ) ;
128+ }
129+ } ) ;
130+
131+ return styleMap ;
132+ }
133+
134+ return null ;
135+ }
136+
137+ private getStyleElement ( host : Node , style : string ) : HTMLStyleElement {
138+ const styleNodesInDOM = this . styleNodesInDOM ;
139+ const styleEl = styleNodesInDOM ?. get ( style ) ;
140+ if ( styleEl ?. parentNode === host ) {
141+ // `styleNodesInDOM` cannot be undefined due to the above `styleNodesInDOM?.get`.
142+ styleNodesInDOM ! . delete ( style ) ;
143+ styleEl . removeAttribute ( 'ng-app' ) ;
144+
145+ if ( typeof ngDevMode === 'undefined' || ngDevMode ) {
146+ // This attribute is solely used for debugging purposes.
147+ styleEl . setAttribute ( 'ng-style-reused' , '' ) ;
148+ }
149+
150+ return styleEl ;
151+ } else {
152+ const styleEl = this . doc . createElement ( 'style' ) ;
153+ styleEl . textContent = style ;
154+
155+ return styleEl ;
156+ }
157+ }
158+
109159 private addStyleToHost ( host : Node , style : string ) : void {
110- const styleEl = this . doc . createElement ( ' style' ) ;
111- styleEl . textContent = style ;
160+ const styleEl = this . getStyleElement ( host , style ) ;
161+
112162 host . appendChild ( styleEl ) ;
113163
114- const styleElRef = this . styleRef . get ( style ) ;
164+ const styleRef = this . styleRef ;
165+ const styleElRef = styleRef . get ( style ) ;
115166 if ( styleElRef ) {
116167 styleElRef . push ( styleEl ) ;
117168 } else {
118- this . styleRef . set ( style , [ styleEl ] ) ;
169+ styleRef . set ( style , [ styleEl ] ) ;
119170 }
120171 }
121172
0 commit comments