A POC of Angular Elements with zone.js.
In ng-conf 2018, robwormald described the use cases of Angular Elements.
-
If the
Angular Elementsis used inside an Angular application, thenzone.jsis already loaded, so user can develop theAngular Elementsin normal way.- Pro: User can develop
Angular Elementjust like they develop normalAngular Component, and user can easily expose a lot of existingAngular ComponenttoAngular Element. - Con: In this case, there is a limitation that the
Angular Elementneed to run in aAngular App Host.
- Pro: User can develop
-
If the
Angular Elementsis used inside an non-angular application, such as inside a web app which developed with pure js or jquery or react, then we should not usezone.js, becausezone.jswill monkey-patch a lot ofglobal/windowAPIs such assetTimeout/Promise, so usingzone.jswill impact the APIs outside ofAngular Elements. Instead, we usenoop zone.- Pro: Don't need to worry about
zone.js, no Window API will be patched, and the bundle size is smaller (zone.jswill be 12k). - Con: User need to take care of
Change Detectionthemselves, and existingAngular Componentwill not be easily exported asAngular Elementin this way.
- Pro: Don't need to worry about
So my idea is add a 3rd option.
- if there is a way to let
zone.jsonly patchglobal/windowAPIs when weenter Angular Elementsandrestore the original delegatewhen weexit Angular Elements. We can developAngular Elements with zone.jswithout impact outside world.- Pro: Still has
ngZone, user can still developAngular Elementjust like developing normalAngular Component. And of course, the existingAngular Componentcan easily be exported asAngular Element. And user don't need to worry aboutzone.jswill impact other parts of the webapp which are outside ofAngular Element. - Con: User still need to load
zone.js, which will be12kbundle.
- Pro: Still has
- First import
zone.js/dist/zone.jswill not monkey-patch anything untilZone.__init__()is called. - Call
Zone.__init__()before bootstrapAngular Elements. - After
BootStrap, restore all monkey-patched APIs tonativeone.
try {
Zone.__init__(); // monkey patch window APIs
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then(ref => {
// Ensure Angular destroys itself on hot reloads.
if (window['ngRef']) {
window['ngRef'].destroy();
}
window['ngRef'] = ref;
// Otherise, log the boot error
})
.catch(err => console.error(err));
} finally {
Zone.__unloadAll_patch(); // detach the monkey patch, so all window APIs was restored to native one.
}- Inside
zone.run()/zone.runGuarded(),reload all patchesbefore run andunload all patchesafter run.
So monkey patched version of window API only exists inside Angular Elements
Here is the demo link DEMO.
In the demo, there is an angular Element with zone.js, and it will run inside of angular zone, and outside there is a button Click outside of Angular Element, click the button will check eventHandler/setTimeout/Promise is monkey patched or not, and print error stack traces to verify no zone related stack frames are inside.
