SSR zone macrotask utilities, solve tx page initial state

This commit is contained in:
Mononaut 2023-10-28 00:33:29 +00:00
parent 5b4132b551
commit c5822b11a0
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
7 changed files with 100 additions and 9 deletions

View File

@ -2,6 +2,7 @@ import { BrowserModule } from '@angular/platform-browser';
import { ModuleWithProviders, NgModule } from '@angular/core'; import { ModuleWithProviders, NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ZONE_SERVICE } from './injection-tokens';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './components/app/app.component'; import { AppComponent } from './components/app/app.component';
import { ElectrsApiService } from './services/electrs-api.service'; import { ElectrsApiService } from './services/electrs-api.service';
@ -13,6 +14,7 @@ import { WebsocketService } from './services/websocket.service';
import { AudioService } from './services/audio.service'; import { AudioService } from './services/audio.service';
import { SeoService } from './services/seo.service'; import { SeoService } from './services/seo.service';
import { OpenGraphService } from './services/opengraph.service'; import { OpenGraphService } from './services/opengraph.service';
import { ZoneService } from './services/zone-shim.service';
import { SharedModule } from './shared/shared.module'; import { SharedModule } from './shared/shared.module';
import { StorageService } from './services/storage.service'; import { StorageService } from './services/storage.service';
import { HttpCacheInterceptor } from './services/http-cache.interceptor'; import { HttpCacheInterceptor } from './services/http-cache.interceptor';
@ -42,7 +44,8 @@ const providers = [
CapAddressPipe, CapAddressPipe,
AppPreloadingStrategy, AppPreloadingStrategy,
ServicesApiServices, ServicesApiServices,
{ provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true },
{ provide: ZONE_SERVICE, useClass: ZoneService },
]; ];
@NgModule({ @NgModule({

View File

@ -2,9 +2,13 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server'; import { ServerModule } from '@angular/platform-server';
import { ZONE_SERVICE } from './injection-tokens';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { AppComponent } from './components/app/app.component'; import { AppComponent } from './components/app/app.component';
import { HttpCacheInterceptor } from './services/http-cache.interceptor'; import { HttpCacheInterceptor } from './services/http-cache.interceptor';
import { StateService } from './services/state.service';
import { ZoneService } from './services/zone.service';
@NgModule({ @NgModule({
imports: [ imports: [
@ -12,7 +16,8 @@ import { HttpCacheInterceptor } from './services/http-cache.interceptor';
ServerModule, ServerModule,
], ],
providers: [ providers: [
{ provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true },
{ provide: ZONE_SERVICE, useClass: ZoneService },
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })

View File

@ -1,4 +1,4 @@
import { Component, OnInit, AfterViewInit, OnDestroy, HostListener, ViewChild, ElementRef } from '@angular/core'; import { Component, OnInit, AfterViewInit, OnDestroy, HostListener, ViewChild, ElementRef, Inject, ChangeDetectorRef } from '@angular/core';
import { ElectrsApiService } from '../../services/electrs-api.service'; import { ElectrsApiService } from '../../services/electrs-api.service';
import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { import {
@ -28,6 +28,7 @@ import { Price, PriceService } from '../../services/price.service';
import { isFeatureActive } from '../../bitcoin.utils'; import { isFeatureActive } from '../../bitcoin.utils';
import { ServicesApiServices } from '../../services/services-api.service'; import { ServicesApiServices } from '../../services/services-api.service';
import { EnterpriseService } from '../../services/enterprise.service'; import { EnterpriseService } from '../../services/enterprise.service';
import { ZONE_SERVICE } from '../../injection-tokens';
interface Pool { interface Pool {
id: number; id: number;
@ -101,7 +102,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
inputIndex: number; inputIndex: number;
outputIndex: number; outputIndex: number;
graphExpanded: boolean = false; graphExpanded: boolean = false;
graphWidth: number = 1000; graphWidth: number = 1068;
graphHeight: number = 360; graphHeight: number = 360;
inOutLimit: number = 150; inOutLimit: number = 150;
maxInOut: number = 0; maxInOut: number = 0;
@ -141,6 +142,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
private priceService: PriceService, private priceService: PriceService,
private storageService: StorageService, private storageService: StorageService,
private enterpriseService: EnterpriseService, private enterpriseService: EnterpriseService,
private cd: ChangeDetectorRef,
@Inject(ZONE_SERVICE) private zoneService: any,
) {} ) {}
ngOnInit() { ngOnInit() {
@ -356,7 +359,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
} }
}); });
this.subscription = this.route.paramMap this.subscription = this.zoneService.wrapObservable(this.route.paramMap
.pipe( .pipe(
switchMap((params: ParamMap) => { switchMap((params: ParamMap) => {
const urlMatch = (params.get('id') || '').split(':'); const urlMatch = (params.get('id') || '').split(':');
@ -430,7 +433,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
} }
return of(tx); return of(tx);
}) })
) ))
.subscribe((tx: Transaction) => { .subscribe((tx: Transaction) => {
if (!tx) { if (!tx) {
this.fetchCachedTx$.next(this.txId); this.fetchCachedTx$.next(this.txId);
@ -503,6 +506,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
).subscribe(); ).subscribe();
setTimeout(() => { this.applyFragment(); }, 0); setTimeout(() => { this.applyFragment(); }, 0);
this.cd.detectChanges();
}, },
(error) => { (error) => {
this.error = error; this.error = error;
@ -785,9 +790,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
setGraphSize(): void { setGraphSize(): void {
this.isMobile = window.innerWidth < 850; this.isMobile = window.innerWidth < 850;
if (this.graphContainer?.nativeElement) { if (this.graphContainer?.nativeElement && this.stateService.isBrowser) {
setTimeout(() => { setTimeout(() => {
if (this.graphContainer?.nativeElement) { if (this.graphContainer?.nativeElement?.clientWidth) {
this.graphWidth = this.graphContainer.nativeElement.clientWidth; this.graphWidth = this.graphContainer.nativeElement.clientWidth;
} else { } else {
setTimeout(() => { this.setGraphSize(); }, 1); setTimeout(() => { this.setGraphSize(); }, 1);

View File

@ -0,0 +1,3 @@
import { InjectionToken } from '@angular/core';
export const ZONE_SERVICE = new InjectionToken('ZONE_TASK');

View File

@ -59,6 +59,7 @@ export class WebsocketService {
const theInitData = this.transferState.get<any>(initData, null); const theInitData = this.transferState.get<any>(initData, null);
if (theInitData) { if (theInitData) {
this.stateService.isLoadingWebSocket$.next(false);
this.handleResponse(theInitData.body); this.handleResponse(theInitData.body);
this.startSubscription(false, true); this.startSubscription(false, true);
} else { } else {

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ZoneService {
constructor() { }
wrapObservable<T>(obs: Observable<T>): Observable<T> {
return obs;
}
}

View File

@ -0,0 +1,60 @@
import { ApplicationRef, Injectable, NgZone } from '@angular/core';
import { Observable, Subscriber } from 'rxjs';
// global Zone object provided by zone.js
declare const Zone: any;
@Injectable({
providedIn: 'root'
})
export class ZoneService {
constructor(
private ngZone: NgZone,
private appRef: ApplicationRef,
) { }
wrapObservable<T>(obs: Observable<T>): Observable<T> {
return new Observable((subscriber: Subscriber<T>) => {
let task: any;
this.ngZone.run(() => {
task = Zone.current.scheduleMacroTask('wrapObservable', () => {}, {}, () => {}, () => {});
});
const subscription = obs.subscribe(
value => {
subscriber.next(value);
if (task) {
this.ngZone.run(() => {
this.appRef.tick();
});
task.invoke();
}
},
err => {
subscriber.error(err);
if (task) {
this.appRef.tick();
task.invoke();
}
},
() => {
subscriber.complete();
if (task) {
this.appRef.tick();
task.invoke();
}
}
);
return () => {
subscription.unsubscribe();
if (task) {
this.appRef.tick();
task.invoke();
}
};
});
}
}