1 | import {
|
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 |
|
16 | import {PlatformException} from '../exception';
|
17 | import {array} from '../transformation';
|
18 | import {bootstrapModule} from './application';
|
19 | import {createPlatformInjector} from './injector';
|
20 | import {mapZoneToInjector} from './zone';
|
21 |
|
22 | @Injectable()
|
23 | export 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 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | this.references.forEach(module => module.destroy());
|
100 |
|
101 | destroyers.forEach(handler => handler());
|
102 | }
|
103 | }
|