UNPKG

3.36 kBPlain TextView Raw
1import {
2 Compiler,
3 CompilerFactory,
4 CompilerOptions,
5 Injectable,
6 Injector,
7 Inject,
8 NgModuleFactory,
9 NgModuleRef,
10 NgZone,
11 PlatformRef,
12 Provider,
13 Type,
14} from '@angular/core';
15
16import {PlatformException} from '../exception';
17import {array} from '../transformation';
18import {bootstrapModule} from './application';
19import {createPlatformInjector} from './injector';
20import {mapZoneToInjector} from './zone';
21
22@Injectable()
23export class ServerPlatform implements PlatformRef {
24 private readonly references = new Set<NgModuleRef<any>>();
25
26 private destroyers = new Array<() => void>();
27
28 constructor(@Inject(Injector) public injector: Injector) {}
29
30 compileModule<M>(moduleType: Type<M>, compilerOptions: CompilerOptions | Array<CompilerOptions> = []): Promise<NgModuleFactory<M>> {
31 const compiler = this.getCompiler(compilerOptions);
32
33 return compiler.compileModuleAsync(moduleType);
34 }
35
36 async bootstrapModule<M>(moduleType: Type<M>, compilerOptions: CompilerOptions | Array<CompilerOptions> = [], providers?: Array<Provider>): Promise<NgModuleRef<M>> {
37 const module = await this.compileModule(moduleType, compilerOptions);
38
39 return await this.bootstrapModuleFactory(module, providers);
40 }
41
42 async bootstrapModuleFactory<M>(module: NgModuleFactory<M>, providers?: Array<Provider>, bootstrap?: (moduleRef: NgModuleRef<M>) => void | Promise<void>): Promise<NgModuleRef<M>> {
43 const zone = new NgZone({enableLongStackTrace: true});
44
45 const injector = createPlatformInjector(this.injector, zone, providers);
46
47 const moduleRef = module.create(injector);
48
49 const unmap = mapZoneToInjector(Zone.current, moduleRef.injector);
50
51 moduleRef.onDestroy(() => {
52 unmap();
53
54 this.references.delete(moduleRef);
55 });
56
57 if (typeof bootstrap === 'function') {
58 await Promise.resolve(bootstrap(moduleRef));
59 }
60
61 await bootstrapModule(zone, moduleRef).then(() => this.references.add(moduleRef));
62
63 return moduleRef;
64 }
65
66 private getCompiler(compilerOptions?: CompilerOptions | Array<CompilerOptions>): Compiler {
67 const options = array(compilerOptions || {});
68
69 const instantiate = (compilerFactory: CompilerFactory) => compilerFactory.createCompiler(options);
70
71 return instantiate(this.injector.get(CompilerFactory));
72 }
73
74 onDestroy(callback: () => void) {
75 if (this.destroyed) {
76 throw new PlatformException(`It does not make sense to register an onDestroy handler after destroy has already taken place`);
77 }
78 this.destroyers.push(callback);
79 }
80
81 get destroyed(): boolean {
82 return this.destroyers == null;
83 }
84
85 async destroy() {
86 if (this.destroyed) {
87 return;
88 }
89
90 const destroyers = this.destroyers;
91
92 delete this.destroyers;
93
94 // The zone of an application zone at this point in the process is either already stable or will never become
95 // stable. We can deduce this because we already waited for it to become stable as part of the bootstrap, and
96 // either it did indeed become stable and therefore is still stable now, or we timed out waiting for it to become
97 // stable, which indicates a likelihood that the application will never become stable because it has some kind
98 // of setInterval running continuously.
99 this.references.forEach(module => module.destroy());
100
101 destroyers.forEach(handler => handler());
102 }
103}