Skip to content

Instantly share code, notes, and snippets.

@sod
Created July 17, 2020 15:28
Show Gist options
  • Save sod/97178a8650662300983f6ca08db178b7 to your computer and use it in GitHub Desktop.
Save sod/97178a8650662300983f6ca08db178b7 to your computer and use it in GitHub Desktop.
import {Directive, ElementRef, EmbeddedViewRef, ErrorHandler, Input, OnDestroy, OnInit, TemplateRef, ViewContainerRef} from '@angular/core';
import {SsrDocumentService} from 'app-next/js/application/app/shared/service/ssr-document.service';
import {Store} from '@ngrx/store';
import {selectNavigationId} from 'app-next/js/application/store/router/router.selector';
import {GlobalState} from 'app-next/js/application/store/global-state';
import {Subject} from 'rxjs';
import {filter, take, takeUntil} from 'rxjs/operators';
@Directive({
selector: '[rySsrRecycle]',
})
export class SsrRecycleDirective implements OnInit, OnDestroy {
@Input('rySsrRecycle')
public id: string;
private static disabled = false;
private prefix = 'ssr-recycle-';
private view?: EmbeddedViewRef<unknown>;
private prerenderElement?: Element;
private navigated$ = this.store.select(selectNavigationId).pipe(
filter((navigationId) => navigationId > 1),
take(1),
);
private destroy$ = new Subject<void>();
constructor(
private elementRef: ElementRef,
private viewContainerRef: ViewContainerRef,
private template: TemplateRef<void>,
private errorHandler: ErrorHandler,
private store: Store<GlobalState>,
private ssrDocumentService: SsrDocumentService,
) {}
public ngOnInit() {
const id = this.prefix + this.id;
if (environment_ssr) {
this.create('not in browser');
this.view!.rootNodes.forEach((node) => {
node.className += ' ' + id;
});
return;
}
if (SsrRecycleDirective.disabled) {
this.create('disabled');
return;
}
const prerender = this.ssrDocumentService.querySelector('.' + id);
const element: Comment = this.viewContainerRef.element.nativeElement;
if (prerender && element.parentElement) {
(window as any).ssrReused = ((window as any).ssrReused || []).concat(id);
this.prerenderElement = prerender;
element.parentElement.insertBefore(prerender, element);
this.navigated$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.create('navigated');
});
return;
}
this.create('ssr document missing');
// console.log(view.rootNodes[0]);
}
public ngOnDestroy() {
this.destroy$.next();
this.prerenderElement = undefined;
this.view = undefined;
}
private create(reason: string): void {
if (this.prerenderElement) {
this.prerenderElement.parentElement?.removeChild(this.prerenderElement);
this.prerenderElement = undefined;
}
if (!this.view) {
if (environment_browser && reason !== 'disabled') {
console.group('create ' + this.id);
// tslint:disable-next-line:no-console
console.log('reason: ' + reason);
console.time('create ' + this.id);
}
SsrRecycleDirective.disabled = true;
this.view = this.viewContainerRef.createEmbeddedView(this.template);
if (environment_browser && reason !== 'disabled') {
console.timeEnd('create ' + this.id);
console.groupEnd();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment