feat(platform-server): wait on returned BEFORE_APP_SERIALIZED promises (#29120)

This update gives external tooling the ability for async providers to
finish resolving before the document is serialized. This is not a
breaking change since render already returns a promise. All returned
promises from `BEFORE_APP_SERIALIZED` providers will wait to be
resolved or rejected. Any rejected promises will only console.warn().

PR Close #29120
This commit is contained in:
Adam Bradley
2019-03-05 16:30:45 -06:00
committed by Andrew Kushnir
parent 6b98b534c8
commit 7102ea80a9
2 changed files with 97 additions and 5 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ApplicationRef, NgModuleFactory, NgModuleRef, PlatformRef, StaticProvider, Type} from '@angular/core';
import {ApplicationRef, NgModuleFactory, NgModuleRef, PlatformRef, StaticProvider, Type, ɵisPromise} from '@angular/core';
import {ɵTRANSITION_ID} from '@angular/platform-browser';
import {first} from 'rxjs/operators';
@ -45,12 +45,18 @@ the server-rendered app can be properly bootstrapped into a client app.`);
.then(() => {
const platformState = platform.injector.get(PlatformState);
const asyncPromises: Promise<any>[] = [];
// Run any BEFORE_APP_SERIALIZED callbacks just before rendering to string.
const callbacks = moduleRef.injector.get(BEFORE_APP_SERIALIZED, null);
if (callbacks) {
for (const callback of callbacks) {
try {
callback();
const callbackResult = callback();
if (ɵisPromise(callbackResult)) {
asyncPromises.push(callbackResult);
}
} catch (e) {
// Ignore exceptions.
console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e);
@ -58,9 +64,22 @@ the server-rendered app can be properly bootstrapped into a client app.`);
}
}
const output = platformState.renderToString();
platform.destroy();
return output;
const complete = () => {
const output = platformState.renderToString();
platform.destroy();
return output;
};
if (asyncPromises.length === 0) {
return complete();
}
return Promise
.all(asyncPromises.map(asyncPromise => {
return asyncPromise.catch(
e => { console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); });
}))
.then(complete);
});
});
}