@@ -43,7 +43,21 @@ import {scheduleMicroTask} from './util/microtask';
43
43
import { stringify } from './util/stringify' ;
44
44
import { NgZone , NoopNgZone } from './zone/ng_zone' ;
45
45
46
- let _platform : PlatformRef ;
46
+ let _platformInjector : Injector | null = null ;
47
+
48
+ /**
49
+ * Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
50
+ * one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
51
+ */
52
+ export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken < boolean > ( 'AllowMultipleToken' ) ;
53
+
54
+ /**
55
+ * Internal token that allows to register extra callbacks that should be invoked during the
56
+ * `PlatformRef.destroy` operation. This token is needed to avoid a direct reference to the
57
+ * `PlatformRef` class (i.e. register the callback via `PlatformRef.onDestroy`), thus making the
58
+ * entire class tree-shakeable.
59
+ */
60
+ const PLATFORM_ON_DESTROY = new InjectionToken < ( ) => void > ( 'PlatformOnDestroy' ) ;
47
61
48
62
export function compileNgModuleFactory < M > (
49
63
injector : Injector , options : CompilerOptions ,
@@ -102,10 +116,6 @@ export function isBoundToModule<C>(cf: ComponentFactory<C>): boolean {
102
116
return ( cf as R3ComponentFactory < C > ) . isBoundToModule ;
103
117
}
104
118
105
- export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken < boolean > ( 'AllowMultipleToken' ) ;
106
-
107
-
108
-
109
119
/**
110
120
* A token for third-party components that can register themselves with NgProbe.
111
121
*
@@ -122,18 +132,18 @@ export class NgProbeToken {
122
132
* @publicApi
123
133
*/
124
134
export function createPlatform ( injector : Injector ) : PlatformRef {
125
- if ( _platform && ! _platform . destroyed &&
126
- ! _platform . injector . get ( ALLOW_MULTIPLE_PLATFORMS , false ) ) {
135
+ if ( _platformInjector && ! _platformInjector . get ( ALLOW_MULTIPLE_PLATFORMS , false ) ) {
127
136
const errorMessage = ( typeof ngDevMode === 'undefined' || ngDevMode ) ?
128
137
'There can be only one platform. Destroy the previous one to create a new one.' :
129
138
'' ;
130
139
throw new RuntimeError ( RuntimeErrorCode . MULTIPLE_PLATFORMS , errorMessage ) ;
131
140
}
132
141
publishDefaultGlobalUtils ( ) ;
133
- _platform = injector . get ( PlatformRef ) ;
142
+ _platformInjector = injector ;
143
+ const platform = injector . get ( PlatformRef ) ;
134
144
const inits = injector . get ( PLATFORM_INITIALIZER , null ) ;
135
- if ( inits ) inits . forEach ( ( init : any ) => init ( ) ) ;
136
- return _platform ;
145
+ if ( inits ) inits . forEach ( initFn => initFn ( ) ) ;
146
+ return platform ;
137
147
}
138
148
139
149
/**
@@ -155,16 +165,15 @@ export function createPlatformFactory(
155
165
return ( extraProviders : StaticProvider [ ] = [ ] ) => {
156
166
let platform = getPlatform ( ) ;
157
167
if ( ! platform || platform . injector . get ( ALLOW_MULTIPLE_PLATFORMS , false ) ) {
168
+ const platformProviders : StaticProvider [ ] = [
169
+ ...providers , //
170
+ ...extraProviders , //
171
+ { provide : marker , useValue : true }
172
+ ] ;
158
173
if ( parentPlatformFactory ) {
159
- parentPlatformFactory (
160
- providers . concat ( extraProviders ) . concat ( { provide : marker , useValue : true } ) ) ;
174
+ parentPlatformFactory ( platformProviders ) ;
161
175
} else {
162
- const injectedProviders : StaticProvider [ ] =
163
- providers . concat ( extraProviders ) . concat ( { provide : marker , useValue : true } , {
164
- provide : INJECTOR_SCOPE ,
165
- useValue : 'platform'
166
- } ) ;
167
- createPlatform ( Injector . create ( { providers : injectedProviders , name : desc } ) ) ;
176
+ createPlatform ( createPlatformInjector ( platformProviders , desc ) ) ;
168
177
}
169
178
}
170
179
return assertPlatform ( marker ) ;
@@ -195,16 +204,29 @@ export function assertPlatform(requiredToken: any): PlatformRef {
195
204
return platform ;
196
205
}
197
206
207
+ /**
208
+ * Helper function to create an instance of a platform injector (that maintains the 'platform'
209
+ * scope).
210
+ */
211
+ export function createPlatformInjector ( providers : StaticProvider [ ] = [ ] , name ?: string ) : Injector {
212
+ return Injector . create ( {
213
+ name,
214
+ providers : [
215
+ { provide : INJECTOR_SCOPE , useValue : 'platform' } ,
216
+ { provide : PLATFORM_ON_DESTROY , useValue : ( ) => _platformInjector = null } , //
217
+ ...providers
218
+ ] ,
219
+ } ) ;
220
+ }
221
+
198
222
/**
199
223
* Destroys the current Angular platform and all Angular applications on the page.
200
224
* Destroys all modules and listeners registered with the platform.
201
225
*
202
226
* @publicApi
203
227
*/
204
228
export function destroyPlatform ( ) : void {
205
- if ( _platform && ! _platform . destroyed ) {
206
- _platform . destroy ( ) ;
207
- }
229
+ getPlatform ( ) ?. destroy ( ) ;
208
230
}
209
231
210
232
/**
@@ -213,7 +235,7 @@ export function destroyPlatform(): void {
213
235
* @publicApi
214
236
*/
215
237
export function getPlatform ( ) : PlatformRef | null {
216
- return _platform && ! _platform . destroyed ? _platform : null ;
238
+ return _platformInjector ?. get ( PlatformRef ) ?? null ;
217
239
}
218
240
219
241
/**
@@ -417,6 +439,10 @@ export class PlatformRef {
417
439
}
418
440
this . _modules . slice ( ) . forEach ( module => module . destroy ( ) ) ;
419
441
this . _destroyListeners . forEach ( listener => listener ( ) ) ;
442
+
443
+ const destroyListener = this . _injector . get ( PLATFORM_ON_DESTROY , null ) ;
444
+ destroyListener ?.( ) ;
445
+
420
446
this . _destroyed = true ;
421
447
}
422
448
0 commit comments